##// END OF EJS Templates
Refactor: move IssuesController#context_menu to a new controller....
Eric Davis -
r3892:1fcc1bdc89ef
parent child
Show More
@@ -0,0 +1,33
1 class ContextMenusController < ApplicationController
2 helper :watchers
3
4 def issues
5 @issues = Issue.find_all_by_id(params[:ids], :include => :project)
6 if (@issues.size == 1)
7 @issue = @issues.first
8 @allowed_statuses = @issue.new_statuses_allowed_to(User.current)
9 end
10 projects = @issues.collect(&:project).compact.uniq
11 @project = projects.first if projects.size == 1
12
13 @can = {:edit => (@project && User.current.allowed_to?(:edit_issues, @project)),
14 :log_time => (@project && User.current.allowed_to?(:log_time, @project)),
15 :update => (@project && (User.current.allowed_to?(:edit_issues, @project) || (User.current.allowed_to?(:change_status, @project) && @allowed_statuses && !@allowed_statuses.empty?))),
16 :move => (@project && User.current.allowed_to?(:move_issues, @project)),
17 :copy => (@issue && @project.trackers.include?(@issue.tracker) && User.current.allowed_to?(:add_issues, @project)),
18 :delete => (@project && User.current.allowed_to?(:delete_issues, @project))
19 }
20 if @project
21 @assignables = @project.assignable_users
22 @assignables << @issue.assigned_to if @issue && @issue.assigned_to && !@assignables.include?(@issue.assigned_to)
23 @trackers = @project.trackers
24 end
25
26 @priorities = IssuePriority.all.reverse
27 @statuses = IssueStatus.find(:all, :order => 'position')
28 @back = back_url
29
30 render :layout => false
31 end
32
33 end
@@ -0,0 +1,89
1 require File.dirname(__FILE__) + '/../test_helper'
2
3 class ContextMenusControllerTest < ActionController::TestCase
4 fixtures :all
5
6 def test_context_menu_one_issue
7 @request.session[:user_id] = 2
8 get :issues, :ids => [1]
9 assert_response :success
10 assert_template 'context_menu'
11 assert_tag :tag => 'a', :content => 'Edit',
12 :attributes => { :href => '/issues/1/edit',
13 :class => 'icon-edit' }
14 assert_tag :tag => 'a', :content => 'Closed',
15 :attributes => { :href => '/issues/1/edit?issue%5Bstatus_id%5D=5',
16 :class => '' }
17 assert_tag :tag => 'a', :content => 'Immediate',
18 :attributes => { :href => '/issues/bulk_edit?ids%5B%5D=1&amp;issue%5Bpriority_id%5D=8',
19 :class => '' }
20 # Versions
21 assert_tag :tag => 'a', :content => '2.0',
22 :attributes => { :href => '/issues/bulk_edit?ids%5B%5D=1&amp;issue%5Bfixed_version_id%5D=3',
23 :class => '' }
24 assert_tag :tag => 'a', :content => 'eCookbook Subproject 1 - 2.0',
25 :attributes => { :href => '/issues/bulk_edit?ids%5B%5D=1&amp;issue%5Bfixed_version_id%5D=4',
26 :class => '' }
27
28 assert_tag :tag => 'a', :content => 'Dave Lopper',
29 :attributes => { :href => '/issues/bulk_edit?ids%5B%5D=1&amp;issue%5Bassigned_to_id%5D=3',
30 :class => '' }
31 assert_tag :tag => 'a', :content => 'Duplicate',
32 :attributes => { :href => '/projects/ecookbook/issues/1/copy',
33 :class => 'icon-duplicate' }
34 assert_tag :tag => 'a', :content => 'Copy',
35 :attributes => { :href => '/issues/move/new?copy_options%5Bcopy%5D=t&amp;ids%5B%5D=1',
36 :class => 'icon-copy' }
37 assert_tag :tag => 'a', :content => 'Move',
38 :attributes => { :href => '/issues/move/new?ids%5B%5D=1',
39 :class => 'icon-move' }
40 assert_tag :tag => 'a', :content => 'Delete',
41 :attributes => { :href => '/issues/destroy?ids%5B%5D=1',
42 :class => 'icon-del' }
43 end
44
45 def test_context_menu_one_issue_by_anonymous
46 get :issues, :ids => [1]
47 assert_response :success
48 assert_template 'context_menu'
49 assert_tag :tag => 'a', :content => 'Delete',
50 :attributes => { :href => '#',
51 :class => 'icon-del disabled' }
52 end
53
54 def test_context_menu_multiple_issues_of_same_project
55 @request.session[:user_id] = 2
56 get :issues, :ids => [1, 2]
57 assert_response :success
58 assert_template 'context_menu'
59 assert_tag :tag => 'a', :content => 'Edit',
60 :attributes => { :href => '/issues/bulk_edit?ids%5B%5D=1&amp;ids%5B%5D=2',
61 :class => 'icon-edit' }
62 assert_tag :tag => 'a', :content => 'Immediate',
63 :attributes => { :href => '/issues/bulk_edit?ids%5B%5D=1&amp;ids%5B%5D=2&amp;issue%5Bpriority_id%5D=8',
64 :class => '' }
65 assert_tag :tag => 'a', :content => 'Dave Lopper',
66 :attributes => { :href => '/issues/bulk_edit?ids%5B%5D=1&amp;ids%5B%5D=2&amp;issue%5Bassigned_to_id%5D=3',
67 :class => '' }
68 assert_tag :tag => 'a', :content => 'Copy',
69 :attributes => { :href => '/issues/move/new?copy_options%5Bcopy%5D=t&amp;ids%5B%5D=1&amp;ids%5B%5D=2',
70 :class => 'icon-copy' }
71 assert_tag :tag => 'a', :content => 'Move',
72 :attributes => { :href => '/issues/move/new?ids%5B%5D=1&amp;ids%5B%5D=2',
73 :class => 'icon-move' }
74 assert_tag :tag => 'a', :content => 'Delete',
75 :attributes => { :href => '/issues/destroy?ids%5B%5D=1&amp;ids%5B%5D=2',
76 :class => 'icon-del' }
77 end
78
79 def test_context_menu_multiple_issues_of_different_project
80 @request.session[:user_id] = 2
81 get :issues, :ids => [1, 2, 4]
82 assert_response :success
83 assert_template 'context_menu'
84 assert_tag :tag => 'a', :content => 'Delete',
85 :attributes => { :href => '#',
86 :class => 'icon-del disabled' }
87 end
88
89 end
@@ -1,367 +1,338
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2008 Jean-Philippe Lang
2 # Copyright (C) 2006-2008 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 IssuesController < ApplicationController
18 class IssuesController < ApplicationController
19 menu_item :new_issue, :only => [:new, :create]
19 menu_item :new_issue, :only => [:new, :create]
20 default_search_scope :issues
20 default_search_scope :issues
21
21
22 before_filter :find_issue, :only => [:show, :edit, :update]
22 before_filter :find_issue, :only => [:show, :edit, :update]
23 before_filter :find_issues, :only => [:bulk_edit, :move, :perform_move, :destroy]
23 before_filter :find_issues, :only => [:bulk_edit, :move, :perform_move, :destroy]
24 before_filter :find_project, :only => [:new, :create, :update_form]
24 before_filter :find_project, :only => [:new, :create, :update_form]
25 before_filter :authorize, :except => [:index, :changes, :context_menu]
25 before_filter :authorize, :except => [:index, :changes]
26 before_filter :find_optional_project, :only => [:index, :changes]
26 before_filter :find_optional_project, :only => [:index, :changes]
27 before_filter :check_for_default_issue_status, :only => [:new, :create]
27 before_filter :check_for_default_issue_status, :only => [:new, :create]
28 before_filter :build_new_issue_from_params, :only => [:new, :create]
28 before_filter :build_new_issue_from_params, :only => [:new, :create]
29 accept_key_auth :index, :show, :changes
29 accept_key_auth :index, :show, :changes
30
30
31 rescue_from Query::StatementInvalid, :with => :query_statement_invalid
31 rescue_from Query::StatementInvalid, :with => :query_statement_invalid
32
32
33 helper :journals
33 helper :journals
34 helper :projects
34 helper :projects
35 include ProjectsHelper
35 include ProjectsHelper
36 helper :custom_fields
36 helper :custom_fields
37 include CustomFieldsHelper
37 include CustomFieldsHelper
38 helper :issue_relations
38 helper :issue_relations
39 include IssueRelationsHelper
39 include IssueRelationsHelper
40 helper :watchers
40 helper :watchers
41 include WatchersHelper
41 include WatchersHelper
42 helper :attachments
42 helper :attachments
43 include AttachmentsHelper
43 include AttachmentsHelper
44 helper :queries
44 helper :queries
45 include QueriesHelper
45 include QueriesHelper
46 helper :sort
46 helper :sort
47 include SortHelper
47 include SortHelper
48 include IssuesHelper
48 include IssuesHelper
49 helper :timelog
49 helper :timelog
50 include Redmine::Export::PDF
50 include Redmine::Export::PDF
51
51
52 verify :method => [:post, :delete],
52 verify :method => [:post, :delete],
53 :only => :destroy,
53 :only => :destroy,
54 :render => { :nothing => true, :status => :method_not_allowed }
54 :render => { :nothing => true, :status => :method_not_allowed }
55
55
56 verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed }
56 verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed }
57 verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed }
57 verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed }
58
58
59 def index
59 def index
60 retrieve_query
60 retrieve_query
61 sort_init(@query.sort_criteria.empty? ? [['id', 'desc']] : @query.sort_criteria)
61 sort_init(@query.sort_criteria.empty? ? [['id', 'desc']] : @query.sort_criteria)
62 sort_update(@query.sortable_columns)
62 sort_update(@query.sortable_columns)
63
63
64 if @query.valid?
64 if @query.valid?
65 limit = case params[:format]
65 limit = case params[:format]
66 when 'csv', 'pdf'
66 when 'csv', 'pdf'
67 Setting.issues_export_limit.to_i
67 Setting.issues_export_limit.to_i
68 when 'atom'
68 when 'atom'
69 Setting.feeds_limit.to_i
69 Setting.feeds_limit.to_i
70 else
70 else
71 per_page_option
71 per_page_option
72 end
72 end
73
73
74 @issue_count = @query.issue_count
74 @issue_count = @query.issue_count
75 @issue_pages = Paginator.new self, @issue_count, limit, params['page']
75 @issue_pages = Paginator.new self, @issue_count, limit, params['page']
76 @issues = @query.issues(:include => [:assigned_to, :tracker, :priority, :category, :fixed_version],
76 @issues = @query.issues(:include => [:assigned_to, :tracker, :priority, :category, :fixed_version],
77 :order => sort_clause,
77 :order => sort_clause,
78 :offset => @issue_pages.current.offset,
78 :offset => @issue_pages.current.offset,
79 :limit => limit)
79 :limit => limit)
80 @issue_count_by_group = @query.issue_count_by_group
80 @issue_count_by_group = @query.issue_count_by_group
81
81
82 respond_to do |format|
82 respond_to do |format|
83 format.html { render :template => 'issues/index.rhtml', :layout => !request.xhr? }
83 format.html { render :template => 'issues/index.rhtml', :layout => !request.xhr? }
84 format.xml { render :layout => false }
84 format.xml { render :layout => false }
85 format.json { render :text => @issues.to_json, :layout => false }
85 format.json { render :text => @issues.to_json, :layout => false }
86 format.atom { render_feed(@issues, :title => "#{@project || Setting.app_title}: #{l(:label_issue_plural)}") }
86 format.atom { render_feed(@issues, :title => "#{@project || Setting.app_title}: #{l(:label_issue_plural)}") }
87 format.csv { send_data(issues_to_csv(@issues, @project), :type => 'text/csv; header=present', :filename => 'export.csv') }
87 format.csv { send_data(issues_to_csv(@issues, @project), :type => 'text/csv; header=present', :filename => 'export.csv') }
88 format.pdf { send_data(issues_to_pdf(@issues, @project, @query), :type => 'application/pdf', :filename => 'export.pdf') }
88 format.pdf { send_data(issues_to_pdf(@issues, @project, @query), :type => 'application/pdf', :filename => 'export.pdf') }
89 end
89 end
90 else
90 else
91 # Send html if the query is not valid
91 # Send html if the query is not valid
92 render(:template => 'issues/index.rhtml', :layout => !request.xhr?)
92 render(:template => 'issues/index.rhtml', :layout => !request.xhr?)
93 end
93 end
94 rescue ActiveRecord::RecordNotFound
94 rescue ActiveRecord::RecordNotFound
95 render_404
95 render_404
96 end
96 end
97
97
98 def changes
98 def changes
99 retrieve_query
99 retrieve_query
100 sort_init 'id', 'desc'
100 sort_init 'id', 'desc'
101 sort_update(@query.sortable_columns)
101 sort_update(@query.sortable_columns)
102
102
103 if @query.valid?
103 if @query.valid?
104 @journals = @query.journals(:order => "#{Journal.table_name}.created_on DESC",
104 @journals = @query.journals(:order => "#{Journal.table_name}.created_on DESC",
105 :limit => 25)
105 :limit => 25)
106 end
106 end
107 @title = (@project ? @project.name : Setting.app_title) + ": " + (@query.new_record? ? l(:label_changes_details) : @query.name)
107 @title = (@project ? @project.name : Setting.app_title) + ": " + (@query.new_record? ? l(:label_changes_details) : @query.name)
108 render :layout => false, :content_type => 'application/atom+xml'
108 render :layout => false, :content_type => 'application/atom+xml'
109 rescue ActiveRecord::RecordNotFound
109 rescue ActiveRecord::RecordNotFound
110 render_404
110 render_404
111 end
111 end
112
112
113 def show
113 def show
114 @journals = @issue.journals.find(:all, :include => [:user, :details], :order => "#{Journal.table_name}.created_on ASC")
114 @journals = @issue.journals.find(:all, :include => [:user, :details], :order => "#{Journal.table_name}.created_on ASC")
115 @journals.each_with_index {|j,i| j.indice = i+1}
115 @journals.each_with_index {|j,i| j.indice = i+1}
116 @journals.reverse! if User.current.wants_comments_in_reverse_order?
116 @journals.reverse! if User.current.wants_comments_in_reverse_order?
117 @changesets = @issue.changesets.visible.all
117 @changesets = @issue.changesets.visible.all
118 @changesets.reverse! if User.current.wants_comments_in_reverse_order?
118 @changesets.reverse! if User.current.wants_comments_in_reverse_order?
119 @allowed_statuses = @issue.new_statuses_allowed_to(User.current)
119 @allowed_statuses = @issue.new_statuses_allowed_to(User.current)
120 @edit_allowed = User.current.allowed_to?(:edit_issues, @project)
120 @edit_allowed = User.current.allowed_to?(:edit_issues, @project)
121 @priorities = IssuePriority.all
121 @priorities = IssuePriority.all
122 @time_entry = TimeEntry.new
122 @time_entry = TimeEntry.new
123 respond_to do |format|
123 respond_to do |format|
124 format.html { render :template => 'issues/show.rhtml' }
124 format.html { render :template => 'issues/show.rhtml' }
125 format.xml { render :layout => false }
125 format.xml { render :layout => false }
126 format.json { render :text => @issue.to_json, :layout => false }
126 format.json { render :text => @issue.to_json, :layout => false }
127 format.atom { render :action => 'changes', :layout => false, :content_type => 'application/atom+xml' }
127 format.atom { render :action => 'changes', :layout => false, :content_type => 'application/atom+xml' }
128 format.pdf { send_data(issue_to_pdf(@issue), :type => 'application/pdf', :filename => "#{@project.identifier}-#{@issue.id}.pdf") }
128 format.pdf { send_data(issue_to_pdf(@issue), :type => 'application/pdf', :filename => "#{@project.identifier}-#{@issue.id}.pdf") }
129 end
129 end
130 end
130 end
131
131
132 # Add a new issue
132 # Add a new issue
133 # The new issue will be created from an existing one if copy_from parameter is given
133 # The new issue will be created from an existing one if copy_from parameter is given
134 def new
134 def new
135 render :action => 'new', :layout => !request.xhr?
135 render :action => 'new', :layout => !request.xhr?
136 end
136 end
137
137
138 def create
138 def create
139 call_hook(:controller_issues_new_before_save, { :params => params, :issue => @issue })
139 call_hook(:controller_issues_new_before_save, { :params => params, :issue => @issue })
140 if @issue.save
140 if @issue.save
141 attachments = Attachment.attach_files(@issue, params[:attachments])
141 attachments = Attachment.attach_files(@issue, params[:attachments])
142 render_attachment_warning_if_needed(@issue)
142 render_attachment_warning_if_needed(@issue)
143 flash[:notice] = l(:notice_successful_create)
143 flash[:notice] = l(:notice_successful_create)
144 call_hook(:controller_issues_new_after_save, { :params => params, :issue => @issue})
144 call_hook(:controller_issues_new_after_save, { :params => params, :issue => @issue})
145 respond_to do |format|
145 respond_to do |format|
146 format.html {
146 format.html {
147 redirect_to(params[:continue] ? { :action => 'new', :issue => {:tracker_id => @issue.tracker, :parent_issue_id => @issue.parent_issue_id}.reject {|k,v| v.nil?} } :
147 redirect_to(params[:continue] ? { :action => 'new', :issue => {:tracker_id => @issue.tracker, :parent_issue_id => @issue.parent_issue_id}.reject {|k,v| v.nil?} } :
148 { :action => 'show', :id => @issue })
148 { :action => 'show', :id => @issue })
149 }
149 }
150 format.xml { render :action => 'show', :status => :created, :location => url_for(:controller => 'issues', :action => 'show', :id => @issue) }
150 format.xml { render :action => 'show', :status => :created, :location => url_for(:controller => 'issues', :action => 'show', :id => @issue) }
151 format.json { render :text => @issue.to_json, :status => :created, :location => url_for(:controller => 'issues', :action => 'show'), :layout => false }
151 format.json { render :text => @issue.to_json, :status => :created, :location => url_for(:controller => 'issues', :action => 'show'), :layout => false }
152 end
152 end
153 return
153 return
154 else
154 else
155 respond_to do |format|
155 respond_to do |format|
156 format.html { render :action => 'new' }
156 format.html { render :action => 'new' }
157 format.xml { render(:xml => @issue.errors, :status => :unprocessable_entity); return }
157 format.xml { render(:xml => @issue.errors, :status => :unprocessable_entity); return }
158 format.json { render :text => object_errors_to_json(@issue), :status => :unprocessable_entity, :layout => false }
158 format.json { render :text => object_errors_to_json(@issue), :status => :unprocessable_entity, :layout => false }
159 end
159 end
160 end
160 end
161 end
161 end
162
162
163 # Attributes that can be updated on workflow transition (without :edit permission)
163 # Attributes that can be updated on workflow transition (without :edit permission)
164 # TODO: make it configurable (at least per role)
164 # TODO: make it configurable (at least per role)
165 UPDATABLE_ATTRS_ON_TRANSITION = %w(status_id assigned_to_id fixed_version_id done_ratio) unless const_defined?(:UPDATABLE_ATTRS_ON_TRANSITION)
165 UPDATABLE_ATTRS_ON_TRANSITION = %w(status_id assigned_to_id fixed_version_id done_ratio) unless const_defined?(:UPDATABLE_ATTRS_ON_TRANSITION)
166
166
167 def edit
167 def edit
168 update_issue_from_params
168 update_issue_from_params
169
169
170 @journal = @issue.current_journal
170 @journal = @issue.current_journal
171
171
172 respond_to do |format|
172 respond_to do |format|
173 format.html { }
173 format.html { }
174 format.xml { }
174 format.xml { }
175 end
175 end
176 end
176 end
177
177
178 def update
178 def update
179 update_issue_from_params
179 update_issue_from_params
180
180
181 if @issue.save_issue_with_child_records(params, @time_entry)
181 if @issue.save_issue_with_child_records(params, @time_entry)
182 render_attachment_warning_if_needed(@issue)
182 render_attachment_warning_if_needed(@issue)
183 flash[:notice] = l(:notice_successful_update) unless @issue.current_journal.new_record?
183 flash[:notice] = l(:notice_successful_update) unless @issue.current_journal.new_record?
184
184
185 respond_to do |format|
185 respond_to do |format|
186 format.html { redirect_back_or_default({:action => 'show', :id => @issue}) }
186 format.html { redirect_back_or_default({:action => 'show', :id => @issue}) }
187 format.xml { head :ok }
187 format.xml { head :ok }
188 format.json { head :ok }
188 format.json { head :ok }
189 end
189 end
190 else
190 else
191 render_attachment_warning_if_needed(@issue)
191 render_attachment_warning_if_needed(@issue)
192 flash[:notice] = l(:notice_successful_update) unless @issue.current_journal.new_record?
192 flash[:notice] = l(:notice_successful_update) unless @issue.current_journal.new_record?
193 @journal = @issue.current_journal
193 @journal = @issue.current_journal
194
194
195 respond_to do |format|
195 respond_to do |format|
196 format.html { render :action => 'edit' }
196 format.html { render :action => 'edit' }
197 format.xml { render :xml => @issue.errors, :status => :unprocessable_entity }
197 format.xml { render :xml => @issue.errors, :status => :unprocessable_entity }
198 format.json { render :text => object_errors_to_json(@issue), :status => :unprocessable_entity, :layout => false }
198 format.json { render :text => object_errors_to_json(@issue), :status => :unprocessable_entity, :layout => false }
199 end
199 end
200 end
200 end
201 end
201 end
202
202
203 # Bulk edit a set of issues
203 # Bulk edit a set of issues
204 def bulk_edit
204 def bulk_edit
205 @issues.sort!
205 @issues.sort!
206 if request.post?
206 if request.post?
207 attributes = (params[:issue] || {}).reject {|k,v| v.blank?}
207 attributes = (params[:issue] || {}).reject {|k,v| v.blank?}
208 attributes.keys.each {|k| attributes[k] = '' if attributes[k] == 'none'}
208 attributes.keys.each {|k| attributes[k] = '' if attributes[k] == 'none'}
209 attributes[:custom_field_values].reject! {|k,v| v.blank?} if attributes[:custom_field_values]
209 attributes[:custom_field_values].reject! {|k,v| v.blank?} if attributes[:custom_field_values]
210
210
211 unsaved_issue_ids = []
211 unsaved_issue_ids = []
212 @issues.each do |issue|
212 @issues.each do |issue|
213 issue.reload
213 issue.reload
214 journal = issue.init_journal(User.current, params[:notes])
214 journal = issue.init_journal(User.current, params[:notes])
215 issue.safe_attributes = attributes
215 issue.safe_attributes = attributes
216 call_hook(:controller_issues_bulk_edit_before_save, { :params => params, :issue => issue })
216 call_hook(:controller_issues_bulk_edit_before_save, { :params => params, :issue => issue })
217 unless issue.save
217 unless issue.save
218 # Keep unsaved issue ids to display them in flash error
218 # Keep unsaved issue ids to display them in flash error
219 unsaved_issue_ids << issue.id
219 unsaved_issue_ids << issue.id
220 end
220 end
221 end
221 end
222 set_flash_from_bulk_issue_save(@issues, unsaved_issue_ids)
222 set_flash_from_bulk_issue_save(@issues, unsaved_issue_ids)
223 redirect_back_or_default({:controller => 'issues', :action => 'index', :project_id => @project})
223 redirect_back_or_default({:controller => 'issues', :action => 'index', :project_id => @project})
224 return
224 return
225 end
225 end
226 @available_statuses = Workflow.available_statuses(@project)
226 @available_statuses = Workflow.available_statuses(@project)
227 @custom_fields = @project.all_issue_custom_fields
227 @custom_fields = @project.all_issue_custom_fields
228 end
228 end
229
229
230 def destroy
230 def destroy
231 @hours = TimeEntry.sum(:hours, :conditions => ['issue_id IN (?)', @issues]).to_f
231 @hours = TimeEntry.sum(:hours, :conditions => ['issue_id IN (?)', @issues]).to_f
232 if @hours > 0
232 if @hours > 0
233 case params[:todo]
233 case params[:todo]
234 when 'destroy'
234 when 'destroy'
235 # nothing to do
235 # nothing to do
236 when 'nullify'
236 when 'nullify'
237 TimeEntry.update_all('issue_id = NULL', ['issue_id IN (?)', @issues])
237 TimeEntry.update_all('issue_id = NULL', ['issue_id IN (?)', @issues])
238 when 'reassign'
238 when 'reassign'
239 reassign_to = @project.issues.find_by_id(params[:reassign_to_id])
239 reassign_to = @project.issues.find_by_id(params[:reassign_to_id])
240 if reassign_to.nil?
240 if reassign_to.nil?
241 flash.now[:error] = l(:error_issue_not_found_in_project)
241 flash.now[:error] = l(:error_issue_not_found_in_project)
242 return
242 return
243 else
243 else
244 TimeEntry.update_all("issue_id = #{reassign_to.id}", ['issue_id IN (?)', @issues])
244 TimeEntry.update_all("issue_id = #{reassign_to.id}", ['issue_id IN (?)', @issues])
245 end
245 end
246 else
246 else
247 unless params[:format] == 'xml' || params[:format] == 'json'
247 unless params[:format] == 'xml' || params[:format] == 'json'
248 # display the destroy form if it's a user request
248 # display the destroy form if it's a user request
249 return
249 return
250 end
250 end
251 end
251 end
252 end
252 end
253 @issues.each(&:destroy)
253 @issues.each(&:destroy)
254 respond_to do |format|
254 respond_to do |format|
255 format.html { redirect_to :action => 'index', :project_id => @project }
255 format.html { redirect_to :action => 'index', :project_id => @project }
256 format.xml { head :ok }
256 format.xml { head :ok }
257 format.json { head :ok }
257 format.json { head :ok }
258 end
258 end
259 end
259 end
260
260
261 def context_menu
262 @issues = Issue.find_all_by_id(params[:ids], :include => :project)
263 if (@issues.size == 1)
264 @issue = @issues.first
265 @allowed_statuses = @issue.new_statuses_allowed_to(User.current)
266 end
267 projects = @issues.collect(&:project).compact.uniq
268 @project = projects.first if projects.size == 1
269
270 @can = {:edit => (@project && User.current.allowed_to?(:edit_issues, @project)),
271 :log_time => (@project && User.current.allowed_to?(:log_time, @project)),
272 :update => (@project && (User.current.allowed_to?(:edit_issues, @project) || (User.current.allowed_to?(:change_status, @project) && @allowed_statuses && !@allowed_statuses.empty?))),
273 :move => (@project && User.current.allowed_to?(:move_issues, @project)),
274 :copy => (@issue && @project.trackers.include?(@issue.tracker) && User.current.allowed_to?(:add_issues, @project)),
275 :delete => (@project && User.current.allowed_to?(:delete_issues, @project))
276 }
277 if @project
278 @assignables = @project.assignable_users
279 @assignables << @issue.assigned_to if @issue && @issue.assigned_to && !@assignables.include?(@issue.assigned_to)
280 @trackers = @project.trackers
281 end
282
283 @priorities = IssuePriority.all.reverse
284 @statuses = IssueStatus.find(:all, :order => 'position')
285 @back = back_url
286
287 render :layout => false
288 end
289
290 def update_form
261 def update_form
291 if params[:id].blank?
262 if params[:id].blank?
292 @issue = Issue.new
263 @issue = Issue.new
293 @issue.project = @project
264 @issue.project = @project
294 else
265 else
295 @issue = @project.issues.visible.find(params[:id])
266 @issue = @project.issues.visible.find(params[:id])
296 end
267 end
297 @issue.attributes = params[:issue]
268 @issue.attributes = params[:issue]
298 @allowed_statuses = ([@issue.status] + @issue.status.find_new_statuses_allowed_to(User.current.roles_for_project(@project), @issue.tracker)).uniq
269 @allowed_statuses = ([@issue.status] + @issue.status.find_new_statuses_allowed_to(User.current.roles_for_project(@project), @issue.tracker)).uniq
299 @priorities = IssuePriority.all
270 @priorities = IssuePriority.all
300
271
301 render :partial => 'attributes'
272 render :partial => 'attributes'
302 end
273 end
303
274
304 private
275 private
305 def find_issue
276 def find_issue
306 @issue = Issue.find(params[:id], :include => [:project, :tracker, :status, :author, :priority, :category])
277 @issue = Issue.find(params[:id], :include => [:project, :tracker, :status, :author, :priority, :category])
307 @project = @issue.project
278 @project = @issue.project
308 rescue ActiveRecord::RecordNotFound
279 rescue ActiveRecord::RecordNotFound
309 render_404
280 render_404
310 end
281 end
311
282
312 def find_project
283 def find_project
313 project_id = (params[:issue] && params[:issue][:project_id]) || params[:project_id]
284 project_id = (params[:issue] && params[:issue][:project_id]) || params[:project_id]
314 @project = Project.find(project_id)
285 @project = Project.find(project_id)
315 rescue ActiveRecord::RecordNotFound
286 rescue ActiveRecord::RecordNotFound
316 render_404
287 render_404
317 end
288 end
318
289
319 # Used by #edit and #update to set some common instance variables
290 # Used by #edit and #update to set some common instance variables
320 # from the params
291 # from the params
321 # TODO: Refactor, not everything in here is needed by #edit
292 # TODO: Refactor, not everything in here is needed by #edit
322 def update_issue_from_params
293 def update_issue_from_params
323 @allowed_statuses = @issue.new_statuses_allowed_to(User.current)
294 @allowed_statuses = @issue.new_statuses_allowed_to(User.current)
324 @priorities = IssuePriority.all
295 @priorities = IssuePriority.all
325 @edit_allowed = User.current.allowed_to?(:edit_issues, @project)
296 @edit_allowed = User.current.allowed_to?(:edit_issues, @project)
326 @time_entry = TimeEntry.new
297 @time_entry = TimeEntry.new
327
298
328 @notes = params[:notes]
299 @notes = params[:notes]
329 @issue.init_journal(User.current, @notes)
300 @issue.init_journal(User.current, @notes)
330 # User can change issue attributes only if he has :edit permission or if a workflow transition is allowed
301 # User can change issue attributes only if he has :edit permission or if a workflow transition is allowed
331 if (@edit_allowed || !@allowed_statuses.empty?) && params[:issue]
302 if (@edit_allowed || !@allowed_statuses.empty?) && params[:issue]
332 attrs = params[:issue].dup
303 attrs = params[:issue].dup
333 attrs.delete_if {|k,v| !UPDATABLE_ATTRS_ON_TRANSITION.include?(k) } unless @edit_allowed
304 attrs.delete_if {|k,v| !UPDATABLE_ATTRS_ON_TRANSITION.include?(k) } unless @edit_allowed
334 attrs.delete(:status_id) unless @allowed_statuses.detect {|s| s.id.to_s == attrs[:status_id].to_s}
305 attrs.delete(:status_id) unless @allowed_statuses.detect {|s| s.id.to_s == attrs[:status_id].to_s}
335 @issue.safe_attributes = attrs
306 @issue.safe_attributes = attrs
336 end
307 end
337
308
338 end
309 end
339
310
340 # TODO: Refactor, lots of extra code in here
311 # TODO: Refactor, lots of extra code in here
341 def build_new_issue_from_params
312 def build_new_issue_from_params
342 @issue = Issue.new
313 @issue = Issue.new
343 @issue.copy_from(params[:copy_from]) if params[:copy_from]
314 @issue.copy_from(params[:copy_from]) if params[:copy_from]
344 @issue.project = @project
315 @issue.project = @project
345 # Tracker must be set before custom field values
316 # Tracker must be set before custom field values
346 @issue.tracker ||= @project.trackers.find((params[:issue] && params[:issue][:tracker_id]) || params[:tracker_id] || :first)
317 @issue.tracker ||= @project.trackers.find((params[:issue] && params[:issue][:tracker_id]) || params[:tracker_id] || :first)
347 if @issue.tracker.nil?
318 if @issue.tracker.nil?
348 render_error l(:error_no_tracker_in_project)
319 render_error l(:error_no_tracker_in_project)
349 return false
320 return false
350 end
321 end
351 if params[:issue].is_a?(Hash)
322 if params[:issue].is_a?(Hash)
352 @issue.safe_attributes = params[:issue]
323 @issue.safe_attributes = params[:issue]
353 @issue.watcher_user_ids = params[:issue]['watcher_user_ids'] if User.current.allowed_to?(:add_issue_watchers, @project)
324 @issue.watcher_user_ids = params[:issue]['watcher_user_ids'] if User.current.allowed_to?(:add_issue_watchers, @project)
354 end
325 end
355 @issue.author = User.current
326 @issue.author = User.current
356 @issue.start_date ||= Date.today
327 @issue.start_date ||= Date.today
357 @priorities = IssuePriority.all
328 @priorities = IssuePriority.all
358 @allowed_statuses = @issue.new_statuses_allowed_to(User.current, true)
329 @allowed_statuses = @issue.new_statuses_allowed_to(User.current, true)
359 end
330 end
360
331
361 def check_for_default_issue_status
332 def check_for_default_issue_status
362 if IssueStatus.default.nil?
333 if IssueStatus.default.nil?
363 render_error l(:error_no_default_issue_status)
334 render_error l(:error_no_default_issue_status)
364 return false
335 return false
365 end
336 end
366 end
337 end
367 end
338 end
1 NO CONTENT: file renamed from app/views/issues/context_menu.rhtml to app/views/context_menus/issues.html.erb
NO CONTENT: file renamed from app/views/issues/context_menu.rhtml to app/views/context_menus/issues.html.erb
@@ -1,84 +1,84
1 <div class="contextual">
1 <div class="contextual">
2 <% if !@query.new_record? && @query.editable_by?(User.current) %>
2 <% if !@query.new_record? && @query.editable_by?(User.current) %>
3 <%= link_to l(:button_edit), {:controller => 'queries', :action => 'edit', :id => @query}, :class => 'icon icon-edit' %>
3 <%= link_to l(:button_edit), {:controller => 'queries', :action => 'edit', :id => @query}, :class => 'icon icon-edit' %>
4 <%= link_to l(:button_delete), {:controller => 'queries', :action => 'destroy', :id => @query}, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' %>
4 <%= link_to l(:button_delete), {:controller => 'queries', :action => 'destroy', :id => @query}, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' %>
5 <% end %>
5 <% end %>
6 </div>
6 </div>
7
7
8 <h2><%= @query.new_record? ? l(:label_issue_plural) : h(@query.name) %></h2>
8 <h2><%= @query.new_record? ? l(:label_issue_plural) : h(@query.name) %></h2>
9 <% html_title(@query.new_record? ? l(:label_issue_plural) : @query.name) %>
9 <% html_title(@query.new_record? ? l(:label_issue_plural) : @query.name) %>
10
10
11 <% form_tag({ :controller => 'queries', :action => 'new' }, :id => 'query_form') do %>
11 <% form_tag({ :controller => 'queries', :action => 'new' }, :id => 'query_form') do %>
12 <%= hidden_field_tag('project_id', @project.to_param) if @project %>
12 <%= hidden_field_tag('project_id', @project.to_param) if @project %>
13 <div id="query_form_content" class="hide-when-print">
13 <div id="query_form_content" class="hide-when-print">
14 <fieldset id="filters" class="collapsible <%= @query.new_record? ? "" : "collapsed" %>">
14 <fieldset id="filters" class="collapsible <%= @query.new_record? ? "" : "collapsed" %>">
15 <legend onclick="toggleFieldset(this);"><%= l(:label_filter_plural) %></legend>
15 <legend onclick="toggleFieldset(this);"><%= l(:label_filter_plural) %></legend>
16 <div style="<%= @query.new_record? ? "" : "display: none;" %>">
16 <div style="<%= @query.new_record? ? "" : "display: none;" %>">
17 <%= render :partial => 'queries/filters', :locals => {:query => @query} %>
17 <%= render :partial => 'queries/filters', :locals => {:query => @query} %>
18 </div>
18 </div>
19 </fieldset>
19 </fieldset>
20 <fieldset class="collapsible collapsed">
20 <fieldset class="collapsible collapsed">
21 <legend onclick="toggleFieldset(this);"><%= l(:label_options) %></legend>
21 <legend onclick="toggleFieldset(this);"><%= l(:label_options) %></legend>
22 <div style="display: none;">
22 <div style="display: none;">
23 <table>
23 <table>
24 <tr>
24 <tr>
25 <td><%= l(:field_column_names) %></td>
25 <td><%= l(:field_column_names) %></td>
26 <td><%= render :partial => 'queries/columns', :locals => {:query => @query} %></td>
26 <td><%= render :partial => 'queries/columns', :locals => {:query => @query} %></td>
27 </tr>
27 </tr>
28 <tr>
28 <tr>
29 <td><%= l(:field_group_by) %></td>
29 <td><%= l(:field_group_by) %></td>
30 <td><%= select_tag('group_by', options_for_select([[]] + @query.groupable_columns.collect {|c| [c.caption, c.name.to_s]}, @query.group_by)) %></td>
30 <td><%= select_tag('group_by', options_for_select([[]] + @query.groupable_columns.collect {|c| [c.caption, c.name.to_s]}, @query.group_by)) %></td>
31 </tr>
31 </tr>
32 </table>
32 </table>
33 </div>
33 </div>
34 </fieldset>
34 </fieldset>
35 </div>
35 </div>
36 <p class="buttons hide-when-print">
36 <p class="buttons hide-when-print">
37
37
38 <%= link_to_remote l(:button_apply),
38 <%= link_to_remote l(:button_apply),
39 { :url => { :set_filter => 1 },
39 { :url => { :set_filter => 1 },
40 :before => 'selectAllOptions("selected_columns");',
40 :before => 'selectAllOptions("selected_columns");',
41 :update => "content",
41 :update => "content",
42 :with => "Form.serialize('query_form')"
42 :with => "Form.serialize('query_form')"
43 }, :class => 'icon icon-checked' %>
43 }, :class => 'icon icon-checked' %>
44
44
45 <%= link_to_remote l(:button_clear),
45 <%= link_to_remote l(:button_clear),
46 { :url => { :set_filter => 1, :project_id => @project },
46 { :url => { :set_filter => 1, :project_id => @project },
47 :method => :get,
47 :method => :get,
48 :update => "content",
48 :update => "content",
49 }, :class => 'icon icon-reload' %>
49 }, :class => 'icon icon-reload' %>
50
50
51 <% if @query.new_record? && User.current.allowed_to?(:save_queries, @project, :global => true) %>
51 <% if @query.new_record? && User.current.allowed_to?(:save_queries, @project, :global => true) %>
52 <%= link_to l(:button_save), {}, :onclick => "selectAllOptions('selected_columns'); $('query_form').submit(); return false;", :class => 'icon icon-save' %>
52 <%= link_to l(:button_save), {}, :onclick => "selectAllOptions('selected_columns'); $('query_form').submit(); return false;", :class => 'icon icon-save' %>
53 <% end %>
53 <% end %>
54 </p>
54 </p>
55 <% end %>
55 <% end %>
56
56
57 <%= error_messages_for 'query' %>
57 <%= error_messages_for 'query' %>
58 <% if @query.valid? %>
58 <% if @query.valid? %>
59 <% if @issues.empty? %>
59 <% if @issues.empty? %>
60 <p class="nodata"><%= l(:label_no_data) %></p>
60 <p class="nodata"><%= l(:label_no_data) %></p>
61 <% else %>
61 <% else %>
62 <%= render :partial => 'issues/list', :locals => {:issues => @issues, :query => @query} %>
62 <%= render :partial => 'issues/list', :locals => {:issues => @issues, :query => @query} %>
63 <p class="pagination"><%= pagination_links_full @issue_pages, @issue_count %></p>
63 <p class="pagination"><%= pagination_links_full @issue_pages, @issue_count %></p>
64 <% end %>
64 <% end %>
65
65
66 <% other_formats_links do |f| %>
66 <% other_formats_links do |f| %>
67 <%= f.link_to 'Atom', :url => { :project_id => @project, :query_id => (@query.new_record? ? nil : @query), :key => User.current.rss_key } %>
67 <%= f.link_to 'Atom', :url => { :project_id => @project, :query_id => (@query.new_record? ? nil : @query), :key => User.current.rss_key } %>
68 <%= f.link_to 'CSV', :url => { :project_id => @project } %>
68 <%= f.link_to 'CSV', :url => { :project_id => @project } %>
69 <%= f.link_to 'PDF', :url => { :project_id => @project } %>
69 <%= f.link_to 'PDF', :url => { :project_id => @project } %>
70 <% end %>
70 <% end %>
71
71
72 <% end %>
72 <% end %>
73 <%= call_hook(:view_issues_index_bottom, { :issues => @issues, :project => @project, :query => @query }) %>
73 <%= call_hook(:view_issues_index_bottom, { :issues => @issues, :project => @project, :query => @query }) %>
74
74
75 <% content_for :sidebar do %>
75 <% content_for :sidebar do %>
76 <%= render :partial => 'issues/sidebar' %>
76 <%= render :partial => 'issues/sidebar' %>
77 <% end %>
77 <% end %>
78
78
79 <% content_for :header_tags do %>
79 <% content_for :header_tags do %>
80 <%= auto_discovery_link_tag(:atom, {:query_id => @query, :format => 'atom', :page => nil, :key => User.current.rss_key}, :title => l(:label_issue_plural)) %>
80 <%= auto_discovery_link_tag(:atom, {:query_id => @query, :format => 'atom', :page => nil, :key => User.current.rss_key}, :title => l(:label_issue_plural)) %>
81 <%= auto_discovery_link_tag(:atom, {:action => 'changes', :query_id => @query, :format => 'atom', :page => nil, :key => User.current.rss_key}, :title => l(:label_changes_details)) %>
81 <%= auto_discovery_link_tag(:atom, {:action => 'changes', :query_id => @query, :format => 'atom', :page => nil, :key => User.current.rss_key}, :title => l(:label_changes_details)) %>
82 <% end %>
82 <% end %>
83
83
84 <%= context_menu :controller => 'issues', :action => 'context_menu' %>
84 <%= context_menu issues_context_menu_path %>
@@ -1,133 +1,133
1 <%= render :partial => 'action_menu' %>
1 <%= render :partial => 'action_menu' %>
2
2
3 <h2><%= @issue.tracker.name %> #<%= @issue.id %></h2>
3 <h2><%= @issue.tracker.name %> #<%= @issue.id %></h2>
4
4
5 <div class="<%= @issue.css_classes %> details">
5 <div class="<%= @issue.css_classes %> details">
6 <%= avatar(@issue.author, :size => "50") %>
6 <%= avatar(@issue.author, :size => "50") %>
7
7
8 <div class="subject">
8 <div class="subject">
9 <%= render_issue_subject_with_tree(@issue) %>
9 <%= render_issue_subject_with_tree(@issue) %>
10 </div>
10 </div>
11 <p class="author">
11 <p class="author">
12 <%= authoring @issue.created_on, @issue.author %>.
12 <%= authoring @issue.created_on, @issue.author %>.
13 <% if @issue.created_on != @issue.updated_on %>
13 <% if @issue.created_on != @issue.updated_on %>
14 <%= l(:label_updated_time, time_tag(@issue.updated_on)) %>.
14 <%= l(:label_updated_time, time_tag(@issue.updated_on)) %>.
15 <% end %>
15 <% end %>
16 </p>
16 </p>
17
17
18 <table class="attributes">
18 <table class="attributes">
19 <tr>
19 <tr>
20 <th class="status"><%=l(:field_status)%>:</th><td class="status"><%= @issue.status.name %></td>
20 <th class="status"><%=l(:field_status)%>:</th><td class="status"><%= @issue.status.name %></td>
21 <th class="start-date"><%=l(:field_start_date)%>:</th><td class="start-date"><%= format_date(@issue.start_date) %></td>
21 <th class="start-date"><%=l(:field_start_date)%>:</th><td class="start-date"><%= format_date(@issue.start_date) %></td>
22 </tr>
22 </tr>
23 <tr>
23 <tr>
24 <th class="priority"><%=l(:field_priority)%>:</th><td class="priority"><%= @issue.priority.name %></td>
24 <th class="priority"><%=l(:field_priority)%>:</th><td class="priority"><%= @issue.priority.name %></td>
25 <th class="due-date"><%=l(:field_due_date)%>:</th><td class="due-date"><%= format_date(@issue.due_date) %></td>
25 <th class="due-date"><%=l(:field_due_date)%>:</th><td class="due-date"><%= format_date(@issue.due_date) %></td>
26 </tr>
26 </tr>
27 <tr>
27 <tr>
28 <th class="assigned-to"><%=l(:field_assigned_to)%>:</th><td class="assigned-to"><%= avatar(@issue.assigned_to, :size => "14") %><%= @issue.assigned_to ? link_to_user(@issue.assigned_to) : "-" %></td>
28 <th class="assigned-to"><%=l(:field_assigned_to)%>:</th><td class="assigned-to"><%= avatar(@issue.assigned_to, :size => "14") %><%= @issue.assigned_to ? link_to_user(@issue.assigned_to) : "-" %></td>
29 <th class="progress"><%=l(:field_done_ratio)%>:</th><td class="progress"><%= progress_bar @issue.done_ratio, :width => '80px', :legend => "#{@issue.done_ratio}%" %></td>
29 <th class="progress"><%=l(:field_done_ratio)%>:</th><td class="progress"><%= progress_bar @issue.done_ratio, :width => '80px', :legend => "#{@issue.done_ratio}%" %></td>
30 </tr>
30 </tr>
31 <tr>
31 <tr>
32 <th class="category"><%=l(:field_category)%>:</th><td class="category"><%=h @issue.category ? @issue.category.name : "-" %></td>
32 <th class="category"><%=l(:field_category)%>:</th><td class="category"><%=h @issue.category ? @issue.category.name : "-" %></td>
33 <% if User.current.allowed_to?(:view_time_entries, @project) %>
33 <% if User.current.allowed_to?(:view_time_entries, @project) %>
34 <th class="spent-time"><%=l(:label_spent_time)%>:</th>
34 <th class="spent-time"><%=l(:label_spent_time)%>:</th>
35 <td class="spent-time"><%= @issue.spent_hours > 0 ? (link_to l_hours(@issue.spent_hours), {:controller => 'timelog', :action => 'details', :project_id => @project, :issue_id => @issue}) : "-" %></td>
35 <td class="spent-time"><%= @issue.spent_hours > 0 ? (link_to l_hours(@issue.spent_hours), {:controller => 'timelog', :action => 'details', :project_id => @project, :issue_id => @issue}) : "-" %></td>
36 <% end %>
36 <% end %>
37 </tr>
37 </tr>
38 <tr>
38 <tr>
39 <th class="fixed-version"><%=l(:field_fixed_version)%>:</th><td class="fixed-version"><%= @issue.fixed_version ? link_to_version(@issue.fixed_version) : "-" %></td>
39 <th class="fixed-version"><%=l(:field_fixed_version)%>:</th><td class="fixed-version"><%= @issue.fixed_version ? link_to_version(@issue.fixed_version) : "-" %></td>
40 <% if @issue.estimated_hours %>
40 <% if @issue.estimated_hours %>
41 <th class="estimated-hours"><%=l(:field_estimated_hours)%>:</th><td class="estimated-hours"><%= l_hours(@issue.estimated_hours) %></td>
41 <th class="estimated-hours"><%=l(:field_estimated_hours)%>:</th><td class="estimated-hours"><%= l_hours(@issue.estimated_hours) %></td>
42 <% end %>
42 <% end %>
43 </tr>
43 </tr>
44 <%= render_custom_fields_rows(@issue) %>
44 <%= render_custom_fields_rows(@issue) %>
45 <%= call_hook(:view_issues_show_details_bottom, :issue => @issue) %>
45 <%= call_hook(:view_issues_show_details_bottom, :issue => @issue) %>
46 </table>
46 </table>
47 <hr />
47 <hr />
48
48
49 <div class="contextual">
49 <div class="contextual">
50 <%= link_to_remote_if_authorized(l(:button_quote), { :url => {:action => 'reply', :id => @issue} }, :class => 'icon icon-comment') unless @issue.description.blank? %>
50 <%= link_to_remote_if_authorized(l(:button_quote), { :url => {:action => 'reply', :id => @issue} }, :class => 'icon icon-comment') unless @issue.description.blank? %>
51 </div>
51 </div>
52
52
53 <p><strong><%=l(:field_description)%></strong></p>
53 <p><strong><%=l(:field_description)%></strong></p>
54 <div class="wiki">
54 <div class="wiki">
55 <%= textilizable @issue, :description, :attachments => @issue.attachments %>
55 <%= textilizable @issue, :description, :attachments => @issue.attachments %>
56 </div>
56 </div>
57
57
58 <%= link_to_attachments @issue %>
58 <%= link_to_attachments @issue %>
59
59
60 <%= call_hook(:view_issues_show_description_bottom, :issue => @issue) %>
60 <%= call_hook(:view_issues_show_description_bottom, :issue => @issue) %>
61
61
62 <% if !@issue.leaf? || User.current.allowed_to?(:manage_subtasks, @project) %>
62 <% if !@issue.leaf? || User.current.allowed_to?(:manage_subtasks, @project) %>
63 <hr />
63 <hr />
64 <div id="issue_tree">
64 <div id="issue_tree">
65 <div class="contextual">
65 <div class="contextual">
66 <%= link_to(l(:button_add), {:controller => 'issues', :action => 'new', :project_id => @project, :issue => {:parent_issue_id => @issue}}) if User.current.allowed_to?(:manage_subtasks, @project) %>
66 <%= link_to(l(:button_add), {:controller => 'issues', :action => 'new', :project_id => @project, :issue => {:parent_issue_id => @issue}}) if User.current.allowed_to?(:manage_subtasks, @project) %>
67 </div>
67 </div>
68 <p><strong><%=l(:label_subtask_plural)%></strong></p>
68 <p><strong><%=l(:label_subtask_plural)%></strong></p>
69 <%= render_descendants_tree(@issue) unless @issue.leaf? %>
69 <%= render_descendants_tree(@issue) unless @issue.leaf? %>
70 </div>
70 </div>
71 <% end %>
71 <% end %>
72
72
73 <% if authorize_for('issue_relations', 'new') || @issue.relations.present? %>
73 <% if authorize_for('issue_relations', 'new') || @issue.relations.present? %>
74 <hr />
74 <hr />
75 <div id="relations">
75 <div id="relations">
76 <%= render :partial => 'relations' %>
76 <%= render :partial => 'relations' %>
77 </div>
77 </div>
78 <% end %>
78 <% end %>
79
79
80 </div>
80 </div>
81
81
82 <% if @changesets.present? %>
82 <% if @changesets.present? %>
83 <div id="issue-changesets">
83 <div id="issue-changesets">
84 <h3><%=l(:label_associated_revisions)%></h3>
84 <h3><%=l(:label_associated_revisions)%></h3>
85 <%= render :partial => 'changesets', :locals => { :changesets => @changesets} %>
85 <%= render :partial => 'changesets', :locals => { :changesets => @changesets} %>
86 </div>
86 </div>
87 <% end %>
87 <% end %>
88
88
89 <% if @journals.present? %>
89 <% if @journals.present? %>
90 <div id="history">
90 <div id="history">
91 <h3><%=l(:label_history)%></h3>
91 <h3><%=l(:label_history)%></h3>
92 <%= render :partial => 'history', :locals => { :issue => @issue, :journals => @journals } %>
92 <%= render :partial => 'history', :locals => { :issue => @issue, :journals => @journals } %>
93 </div>
93 </div>
94 <% end %>
94 <% end %>
95
95
96
96
97 <div style="clear: both;"></div>
97 <div style="clear: both;"></div>
98 <%= render :partial => 'action_menu', :locals => {:replace_watcher => 'watcher2' } %>
98 <%= render :partial => 'action_menu', :locals => {:replace_watcher => 'watcher2' } %>
99
99
100 <div style="clear: both;"></div>
100 <div style="clear: both;"></div>
101 <% if authorize_for('issues', 'edit') %>
101 <% if authorize_for('issues', 'edit') %>
102 <div id="update" style="display:none;">
102 <div id="update" style="display:none;">
103 <h3><%= l(:button_update) %></h3>
103 <h3><%= l(:button_update) %></h3>
104 <%= render :partial => 'edit' %>
104 <%= render :partial => 'edit' %>
105 </div>
105 </div>
106 <% end %>
106 <% end %>
107
107
108 <% other_formats_links do |f| %>
108 <% other_formats_links do |f| %>
109 <%= f.link_to 'Atom', :url => {:key => User.current.rss_key} %>
109 <%= f.link_to 'Atom', :url => {:key => User.current.rss_key} %>
110 <%= f.link_to 'PDF' %>
110 <%= f.link_to 'PDF' %>
111 <% end %>
111 <% end %>
112
112
113 <% html_title "#{@issue.tracker.name} ##{@issue.id}: #{@issue.subject}" %>
113 <% html_title "#{@issue.tracker.name} ##{@issue.id}: #{@issue.subject}" %>
114
114
115 <% content_for :sidebar do %>
115 <% content_for :sidebar do %>
116 <%= render :partial => 'issues/sidebar' %>
116 <%= render :partial => 'issues/sidebar' %>
117
117
118 <% if User.current.allowed_to?(:add_issue_watchers, @project) ||
118 <% if User.current.allowed_to?(:add_issue_watchers, @project) ||
119 (@issue.watchers.present? && User.current.allowed_to?(:view_issue_watchers, @project)) %>
119 (@issue.watchers.present? && User.current.allowed_to?(:view_issue_watchers, @project)) %>
120 <div id="watchers">
120 <div id="watchers">
121 <%= render :partial => 'watchers/watchers', :locals => {:watched => @issue} %>
121 <%= render :partial => 'watchers/watchers', :locals => {:watched => @issue} %>
122 </div>
122 </div>
123 <% end %>
123 <% end %>
124 <% end %>
124 <% end %>
125
125
126 <% content_for :header_tags do %>
126 <% content_for :header_tags do %>
127 <%= auto_discovery_link_tag(:atom, {:format => 'atom', :key => User.current.rss_key}, :title => "#{@issue.project} - #{@issue.tracker} ##{@issue.id}: #{@issue.subject}") %>
127 <%= auto_discovery_link_tag(:atom, {:format => 'atom', :key => User.current.rss_key}, :title => "#{@issue.project} - #{@issue.tracker} ##{@issue.id}: #{@issue.subject}") %>
128 <%= stylesheet_link_tag 'scm' %>
128 <%= stylesheet_link_tag 'scm' %>
129 <%= javascript_include_tag 'context_menu' %>
129 <%= javascript_include_tag 'context_menu' %>
130 <%= stylesheet_link_tag 'context_menu' %>
130 <%= stylesheet_link_tag 'context_menu' %>
131 <% end %>
131 <% end %>
132 <div id="context-menu" style="display: none;"></div>
132 <div id="context-menu" style="display: none;"></div>
133 <%= javascript_tag "new ContextMenu('#{url_for(:controller => 'issues', :action => 'context_menu')}')" %>
133 <%= javascript_tag "new ContextMenu('#{issues_context_menu_path}')" %>
@@ -1,297 +1,298
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.connect 'time_entries/:id/edit', :action => 'edit', :controller => 'timelog'
17 map.connect 'time_entries/:id/edit', :action => 'edit', :controller => 'timelog'
18 map.connect 'projects/:project_id/time_entries/new', :action => 'edit', :controller => 'timelog'
18 map.connect 'projects/:project_id/time_entries/new', :action => 'edit', :controller => 'timelog'
19 map.connect 'projects/:project_id/issues/:issue_id/time_entries/new', :action => 'edit', :controller => 'timelog'
19 map.connect 'projects/:project_id/issues/:issue_id/time_entries/new', :action => 'edit', :controller => 'timelog'
20
20
21 map.with_options :controller => 'timelog' do |timelog|
21 map.with_options :controller => 'timelog' do |timelog|
22 timelog.connect 'projects/:project_id/time_entries', :action => 'details'
22 timelog.connect 'projects/:project_id/time_entries', :action => 'details'
23
23
24 timelog.with_options :action => 'details', :conditions => {:method => :get} do |time_details|
24 timelog.with_options :action => 'details', :conditions => {:method => :get} do |time_details|
25 time_details.connect 'time_entries'
25 time_details.connect 'time_entries'
26 time_details.connect 'time_entries.:format'
26 time_details.connect 'time_entries.:format'
27 time_details.connect 'issues/:issue_id/time_entries'
27 time_details.connect 'issues/:issue_id/time_entries'
28 time_details.connect 'issues/:issue_id/time_entries.:format'
28 time_details.connect 'issues/:issue_id/time_entries.:format'
29 time_details.connect 'projects/:project_id/time_entries.:format'
29 time_details.connect 'projects/:project_id/time_entries.:format'
30 time_details.connect 'projects/:project_id/issues/:issue_id/time_entries'
30 time_details.connect 'projects/:project_id/issues/:issue_id/time_entries'
31 time_details.connect 'projects/:project_id/issues/:issue_id/time_entries.:format'
31 time_details.connect 'projects/:project_id/issues/:issue_id/time_entries.:format'
32 end
32 end
33 timelog.connect 'projects/:project_id/time_entries/report', :action => 'report'
33 timelog.connect 'projects/:project_id/time_entries/report', :action => 'report'
34 timelog.with_options :action => 'report',:conditions => {:method => :get} do |time_report|
34 timelog.with_options :action => 'report',:conditions => {:method => :get} do |time_report|
35 time_report.connect 'time_entries/report'
35 time_report.connect 'time_entries/report'
36 time_report.connect 'time_entries/report.:format'
36 time_report.connect 'time_entries/report.:format'
37 time_report.connect 'projects/:project_id/time_entries/report.:format'
37 time_report.connect 'projects/:project_id/time_entries/report.:format'
38 end
38 end
39
39
40 timelog.with_options :action => 'edit', :conditions => {:method => :get} do |time_edit|
40 timelog.with_options :action => 'edit', :conditions => {:method => :get} do |time_edit|
41 time_edit.connect 'issues/:issue_id/time_entries/new'
41 time_edit.connect 'issues/:issue_id/time_entries/new'
42 end
42 end
43
43
44 timelog.connect 'time_entries/:id/destroy', :action => 'destroy', :conditions => {:method => :post}
44 timelog.connect 'time_entries/:id/destroy', :action => 'destroy', :conditions => {:method => :post}
45 end
45 end
46
46
47 map.connect 'projects/:id/wiki', :controller => 'wikis', :action => 'edit', :conditions => {:method => :post}
47 map.connect 'projects/:id/wiki', :controller => 'wikis', :action => 'edit', :conditions => {:method => :post}
48 map.connect 'projects/:id/wiki/destroy', :controller => 'wikis', :action => 'destroy', :conditions => {:method => :get}
48 map.connect 'projects/:id/wiki/destroy', :controller => 'wikis', :action => 'destroy', :conditions => {:method => :get}
49 map.connect 'projects/:id/wiki/destroy', :controller => 'wikis', :action => 'destroy', :conditions => {:method => :post}
49 map.connect 'projects/:id/wiki/destroy', :controller => 'wikis', :action => 'destroy', :conditions => {:method => :post}
50 map.with_options :controller => 'wiki' do |wiki_routes|
50 map.with_options :controller => 'wiki' do |wiki_routes|
51 wiki_routes.with_options :conditions => {:method => :get} do |wiki_views|
51 wiki_routes.with_options :conditions => {:method => :get} do |wiki_views|
52 wiki_views.connect 'projects/:id/wiki/:page', :action => 'special', :page => /page_index|date_index|export/i
52 wiki_views.connect 'projects/:id/wiki/:page', :action => 'special', :page => /page_index|date_index|export/i
53 wiki_views.connect 'projects/:id/wiki/:page', :action => 'index', :page => nil
53 wiki_views.connect 'projects/:id/wiki/:page', :action => 'index', :page => nil
54 wiki_views.connect 'projects/:id/wiki/:page/edit', :action => 'edit'
54 wiki_views.connect 'projects/:id/wiki/:page/edit', :action => 'edit'
55 wiki_views.connect 'projects/:id/wiki/:page/rename', :action => 'rename'
55 wiki_views.connect 'projects/:id/wiki/:page/rename', :action => 'rename'
56 wiki_views.connect 'projects/:id/wiki/:page/history', :action => 'history'
56 wiki_views.connect 'projects/:id/wiki/:page/history', :action => 'history'
57 wiki_views.connect 'projects/:id/wiki/:page/diff/:version/vs/:version_from', :action => 'diff'
57 wiki_views.connect 'projects/:id/wiki/:page/diff/:version/vs/:version_from', :action => 'diff'
58 wiki_views.connect 'projects/:id/wiki/:page/annotate/:version', :action => 'annotate'
58 wiki_views.connect 'projects/:id/wiki/:page/annotate/:version', :action => 'annotate'
59 end
59 end
60
60
61 wiki_routes.connect 'projects/:id/wiki/:page/:action',
61 wiki_routes.connect 'projects/:id/wiki/:page/:action',
62 :action => /edit|rename|destroy|preview|protect/,
62 :action => /edit|rename|destroy|preview|protect/,
63 :conditions => {:method => :post}
63 :conditions => {:method => :post}
64 end
64 end
65
65
66 map.with_options :controller => 'messages' do |messages_routes|
66 map.with_options :controller => 'messages' do |messages_routes|
67 messages_routes.with_options :conditions => {:method => :get} do |messages_views|
67 messages_routes.with_options :conditions => {:method => :get} do |messages_views|
68 messages_views.connect 'boards/:board_id/topics/new', :action => 'new'
68 messages_views.connect 'boards/:board_id/topics/new', :action => 'new'
69 messages_views.connect 'boards/:board_id/topics/:id', :action => 'show'
69 messages_views.connect 'boards/:board_id/topics/:id', :action => 'show'
70 messages_views.connect 'boards/:board_id/topics/:id/edit', :action => 'edit'
70 messages_views.connect 'boards/:board_id/topics/:id/edit', :action => 'edit'
71 end
71 end
72 messages_routes.with_options :conditions => {:method => :post} do |messages_actions|
72 messages_routes.with_options :conditions => {:method => :post} do |messages_actions|
73 messages_actions.connect 'boards/:board_id/topics/new', :action => 'new'
73 messages_actions.connect 'boards/:board_id/topics/new', :action => 'new'
74 messages_actions.connect 'boards/:board_id/topics/:id/replies', :action => 'reply'
74 messages_actions.connect 'boards/:board_id/topics/:id/replies', :action => 'reply'
75 messages_actions.connect 'boards/:board_id/topics/:id/:action', :action => /edit|destroy/
75 messages_actions.connect 'boards/:board_id/topics/:id/:action', :action => /edit|destroy/
76 end
76 end
77 end
77 end
78
78
79 map.with_options :controller => 'boards' do |board_routes|
79 map.with_options :controller => 'boards' do |board_routes|
80 board_routes.with_options :conditions => {:method => :get} do |board_views|
80 board_routes.with_options :conditions => {:method => :get} do |board_views|
81 board_views.connect 'projects/:project_id/boards', :action => 'index'
81 board_views.connect 'projects/:project_id/boards', :action => 'index'
82 board_views.connect 'projects/:project_id/boards/new', :action => 'new'
82 board_views.connect 'projects/:project_id/boards/new', :action => 'new'
83 board_views.connect 'projects/:project_id/boards/:id', :action => 'show'
83 board_views.connect 'projects/:project_id/boards/:id', :action => 'show'
84 board_views.connect 'projects/:project_id/boards/:id.:format', :action => 'show'
84 board_views.connect 'projects/:project_id/boards/:id.:format', :action => 'show'
85 board_views.connect 'projects/:project_id/boards/:id/edit', :action => 'edit'
85 board_views.connect 'projects/:project_id/boards/:id/edit', :action => 'edit'
86 end
86 end
87 board_routes.with_options :conditions => {:method => :post} do |board_actions|
87 board_routes.with_options :conditions => {:method => :post} do |board_actions|
88 board_actions.connect 'projects/:project_id/boards', :action => 'new'
88 board_actions.connect 'projects/:project_id/boards', :action => 'new'
89 board_actions.connect 'projects/:project_id/boards/:id/:action', :action => /edit|destroy/
89 board_actions.connect 'projects/:project_id/boards/:id/:action', :action => /edit|destroy/
90 end
90 end
91 end
91 end
92
92
93 map.with_options :controller => 'documents' do |document_routes|
93 map.with_options :controller => 'documents' do |document_routes|
94 document_routes.with_options :conditions => {:method => :get} do |document_views|
94 document_routes.with_options :conditions => {:method => :get} do |document_views|
95 document_views.connect 'projects/:project_id/documents', :action => 'index'
95 document_views.connect 'projects/:project_id/documents', :action => 'index'
96 document_views.connect 'projects/:project_id/documents/new', :action => 'new'
96 document_views.connect 'projects/:project_id/documents/new', :action => 'new'
97 document_views.connect 'documents/:id', :action => 'show'
97 document_views.connect 'documents/:id', :action => 'show'
98 document_views.connect 'documents/:id/edit', :action => 'edit'
98 document_views.connect 'documents/:id/edit', :action => 'edit'
99 end
99 end
100 document_routes.with_options :conditions => {:method => :post} do |document_actions|
100 document_routes.with_options :conditions => {:method => :post} do |document_actions|
101 document_actions.connect 'projects/:project_id/documents', :action => 'new'
101 document_actions.connect 'projects/:project_id/documents', :action => 'new'
102 document_actions.connect 'documents/:id/:action', :action => /destroy|edit/
102 document_actions.connect 'documents/:id/:action', :action => /destroy|edit/
103 end
103 end
104 end
104 end
105
105
106 map.resources :issue_moves, :only => [:new, :create], :path_prefix => '/issues', :as => 'move'
106 map.resources :issue_moves, :only => [:new, :create], :path_prefix => '/issues', :as => 'move'
107 map.auto_complete_issues '/issues/auto_complete', :controller => 'auto_completes', :action => 'issues'
107 map.auto_complete_issues '/issues/auto_complete', :controller => 'auto_completes', :action => 'issues'
108 # TODO: would look nicer as /issues/:id/preview
108 # TODO: would look nicer as /issues/:id/preview
109 map.preview_issue '/issues/preview/:id', :controller => 'previews', :action => 'issue'
109 map.preview_issue '/issues/preview/:id', :controller => 'previews', :action => 'issue'
110 map.issues_context_menu '/issues/context_menu', :controller => 'context_menus', :action => 'issues'
110
111
111 map.with_options :controller => 'issues' do |issues_routes|
112 map.with_options :controller => 'issues' do |issues_routes|
112 issues_routes.with_options :conditions => {:method => :get} do |issues_views|
113 issues_routes.with_options :conditions => {:method => :get} do |issues_views|
113 issues_views.connect 'issues', :action => 'index'
114 issues_views.connect 'issues', :action => 'index'
114 issues_views.connect 'issues.:format', :action => 'index'
115 issues_views.connect 'issues.:format', :action => 'index'
115 issues_views.connect 'projects/:project_id/issues', :action => 'index'
116 issues_views.connect 'projects/:project_id/issues', :action => 'index'
116 issues_views.connect 'projects/:project_id/issues.:format', :action => 'index'
117 issues_views.connect 'projects/:project_id/issues.:format', :action => 'index'
117 issues_views.connect 'projects/:project_id/issues/new', :action => 'new'
118 issues_views.connect 'projects/:project_id/issues/new', :action => 'new'
118 issues_views.connect 'projects/:project_id/issues/gantt', :controller => 'gantts', :action => 'show'
119 issues_views.connect 'projects/:project_id/issues/gantt', :controller => 'gantts', :action => 'show'
119 issues_views.connect 'projects/:project_id/issues/calendar', :controller => 'calendars', :action => 'show'
120 issues_views.connect 'projects/:project_id/issues/calendar', :controller => 'calendars', :action => 'show'
120 issues_views.connect 'projects/:project_id/issues/:copy_from/copy', :action => 'new'
121 issues_views.connect 'projects/:project_id/issues/:copy_from/copy', :action => 'new'
121 issues_views.connect 'issues/:id', :action => 'show', :id => /\d+/
122 issues_views.connect 'issues/:id', :action => 'show', :id => /\d+/
122 issues_views.connect 'issues/:id.:format', :action => 'show', :id => /\d+/
123 issues_views.connect 'issues/:id.:format', :action => 'show', :id => /\d+/
123 issues_views.connect 'issues/:id/edit', :action => 'edit', :id => /\d+/
124 issues_views.connect 'issues/:id/edit', :action => 'edit', :id => /\d+/
124 end
125 end
125 issues_routes.with_options :conditions => {:method => :post} do |issues_actions|
126 issues_routes.with_options :conditions => {:method => :post} do |issues_actions|
126 issues_actions.connect 'issues', :action => 'index'
127 issues_actions.connect 'issues', :action => 'index'
127 issues_actions.connect 'projects/:project_id/issues', :action => 'create'
128 issues_actions.connect 'projects/:project_id/issues', :action => 'create'
128 issues_actions.connect 'projects/:project_id/issues/gantt', :controller => 'gantts', :action => 'show'
129 issues_actions.connect 'projects/:project_id/issues/gantt', :controller => 'gantts', :action => 'show'
129 issues_actions.connect 'projects/:project_id/issues/calendar', :controller => 'calendars', :action => 'show'
130 issues_actions.connect 'projects/:project_id/issues/calendar', :controller => 'calendars', :action => 'show'
130 issues_actions.connect 'issues/:id/quoted', :controller => 'journals', :action => 'new', :id => /\d+/
131 issues_actions.connect 'issues/:id/quoted', :controller => 'journals', :action => 'new', :id => /\d+/
131 issues_actions.connect 'issues/:id/:action', :action => /edit|destroy/, :id => /\d+/
132 issues_actions.connect 'issues/:id/:action', :action => /edit|destroy/, :id => /\d+/
132 issues_actions.connect 'issues.:format', :action => 'create', :format => /xml/
133 issues_actions.connect 'issues.:format', :action => 'create', :format => /xml/
133 end
134 end
134 issues_routes.with_options :conditions => {:method => :put} do |issues_actions|
135 issues_routes.with_options :conditions => {:method => :put} do |issues_actions|
135 issues_actions.connect 'issues/:id/edit', :action => 'update', :id => /\d+/
136 issues_actions.connect 'issues/:id/edit', :action => 'update', :id => /\d+/
136 issues_actions.connect 'issues/:id.:format', :action => 'update', :id => /\d+/, :format => /xml/
137 issues_actions.connect 'issues/:id.:format', :action => 'update', :id => /\d+/, :format => /xml/
137 end
138 end
138 issues_routes.with_options :conditions => {:method => :delete} do |issues_actions|
139 issues_routes.with_options :conditions => {:method => :delete} do |issues_actions|
139 issues_actions.connect 'issues/:id.:format', :action => 'destroy', :id => /\d+/, :format => /xml/
140 issues_actions.connect 'issues/:id.:format', :action => 'destroy', :id => /\d+/, :format => /xml/
140 end
141 end
141 issues_routes.connect 'issues/gantt', :controller => 'gantts', :action => 'show'
142 issues_routes.connect 'issues/gantt', :controller => 'gantts', :action => 'show'
142 issues_routes.connect 'issues/calendar', :controller => 'calendars', :action => 'show'
143 issues_routes.connect 'issues/calendar', :controller => 'calendars', :action => 'show'
143 issues_routes.connect 'issues/:action'
144 issues_routes.connect 'issues/:action'
144 end
145 end
145
146
146 map.with_options :controller => 'issue_relations', :conditions => {:method => :post} do |relations|
147 map.with_options :controller => 'issue_relations', :conditions => {:method => :post} do |relations|
147 relations.connect 'issues/:issue_id/relations/:id', :action => 'new'
148 relations.connect 'issues/:issue_id/relations/:id', :action => 'new'
148 relations.connect 'issues/:issue_id/relations/:id/destroy', :action => 'destroy'
149 relations.connect 'issues/:issue_id/relations/:id/destroy', :action => 'destroy'
149 end
150 end
150
151
151 map.with_options :controller => 'reports', :conditions => {:method => :get} do |reports|
152 map.with_options :controller => 'reports', :conditions => {:method => :get} do |reports|
152 reports.connect 'projects/:id/issues/report', :action => 'issue_report'
153 reports.connect 'projects/:id/issues/report', :action => 'issue_report'
153 reports.connect 'projects/:id/issues/report/:detail', :action => 'issue_report_details'
154 reports.connect 'projects/:id/issues/report/:detail', :action => 'issue_report_details'
154 end
155 end
155
156
156 map.with_options :controller => 'news' do |news_routes|
157 map.with_options :controller => 'news' do |news_routes|
157 news_routes.with_options :conditions => {:method => :get} do |news_views|
158 news_routes.with_options :conditions => {:method => :get} do |news_views|
158 news_views.connect 'news', :action => 'index'
159 news_views.connect 'news', :action => 'index'
159 news_views.connect 'projects/:project_id/news', :action => 'index'
160 news_views.connect 'projects/:project_id/news', :action => 'index'
160 news_views.connect 'projects/:project_id/news.:format', :action => 'index'
161 news_views.connect 'projects/:project_id/news.:format', :action => 'index'
161 news_views.connect 'news.:format', :action => 'index'
162 news_views.connect 'news.:format', :action => 'index'
162 news_views.connect 'projects/:project_id/news/new', :action => 'new'
163 news_views.connect 'projects/:project_id/news/new', :action => 'new'
163 news_views.connect 'news/:id', :action => 'show'
164 news_views.connect 'news/:id', :action => 'show'
164 news_views.connect 'news/:id/edit', :action => 'edit'
165 news_views.connect 'news/:id/edit', :action => 'edit'
165 end
166 end
166 news_routes.with_options do |news_actions|
167 news_routes.with_options do |news_actions|
167 news_actions.connect 'projects/:project_id/news', :action => 'new'
168 news_actions.connect 'projects/:project_id/news', :action => 'new'
168 news_actions.connect 'news/:id/edit', :action => 'edit'
169 news_actions.connect 'news/:id/edit', :action => 'edit'
169 news_actions.connect 'news/:id/destroy', :action => 'destroy'
170 news_actions.connect 'news/:id/destroy', :action => 'destroy'
170 end
171 end
171 end
172 end
172
173
173 map.connect 'projects/:id/members/new', :controller => 'members', :action => 'new'
174 map.connect 'projects/:id/members/new', :controller => 'members', :action => 'new'
174
175
175 map.with_options :controller => 'users' do |users|
176 map.with_options :controller => 'users' do |users|
176 users.with_options :conditions => {:method => :get} do |user_views|
177 users.with_options :conditions => {:method => :get} do |user_views|
177 user_views.connect 'users', :action => 'index'
178 user_views.connect 'users', :action => 'index'
178 user_views.connect 'users/:id', :action => 'show', :id => /\d+/
179 user_views.connect 'users/:id', :action => 'show', :id => /\d+/
179 user_views.connect 'users/new', :action => 'add'
180 user_views.connect 'users/new', :action => 'add'
180 user_views.connect 'users/:id/edit/:tab', :action => 'edit', :tab => nil
181 user_views.connect 'users/:id/edit/:tab', :action => 'edit', :tab => nil
181 end
182 end
182 users.with_options :conditions => {:method => :post} do |user_actions|
183 users.with_options :conditions => {:method => :post} do |user_actions|
183 user_actions.connect 'users', :action => 'add'
184 user_actions.connect 'users', :action => 'add'
184 user_actions.connect 'users/new', :action => 'add'
185 user_actions.connect 'users/new', :action => 'add'
185 user_actions.connect 'users/:id/edit', :action => 'edit'
186 user_actions.connect 'users/:id/edit', :action => 'edit'
186 user_actions.connect 'users/:id/memberships', :action => 'edit_membership'
187 user_actions.connect 'users/:id/memberships', :action => 'edit_membership'
187 user_actions.connect 'users/:id/memberships/:membership_id', :action => 'edit_membership'
188 user_actions.connect 'users/:id/memberships/:membership_id', :action => 'edit_membership'
188 user_actions.connect 'users/:id/memberships/:membership_id/destroy', :action => 'destroy_membership'
189 user_actions.connect 'users/:id/memberships/:membership_id/destroy', :action => 'destroy_membership'
189 end
190 end
190 end
191 end
191
192
192 map.with_options :controller => 'projects' do |projects|
193 map.with_options :controller => 'projects' do |projects|
193 projects.with_options :conditions => {:method => :get} do |project_views|
194 projects.with_options :conditions => {:method => :get} do |project_views|
194 project_views.connect 'projects', :action => 'index'
195 project_views.connect 'projects', :action => 'index'
195 project_views.connect 'projects.:format', :action => 'index'
196 project_views.connect 'projects.:format', :action => 'index'
196 project_views.connect 'projects/new', :action => 'add'
197 project_views.connect 'projects/new', :action => 'add'
197 project_views.connect 'projects/:id', :action => 'show'
198 project_views.connect 'projects/:id', :action => 'show'
198 project_views.connect 'projects/:id.:format', :action => 'show'
199 project_views.connect 'projects/:id.:format', :action => 'show'
199 project_views.connect 'projects/:id/:action', :action => /roadmap|destroy|settings/
200 project_views.connect 'projects/:id/:action', :action => /roadmap|destroy|settings/
200 project_views.connect 'projects/:id/files', :action => 'list_files'
201 project_views.connect 'projects/:id/files', :action => 'list_files'
201 project_views.connect 'projects/:id/files/new', :action => 'add_file'
202 project_views.connect 'projects/:id/files/new', :action => 'add_file'
202 project_views.connect 'projects/:id/settings/:tab', :action => 'settings'
203 project_views.connect 'projects/:id/settings/:tab', :action => 'settings'
203 end
204 end
204
205
205 projects.with_options :action => 'activity', :conditions => {:method => :get} do |activity|
206 projects.with_options :action => 'activity', :conditions => {:method => :get} do |activity|
206 activity.connect 'projects/:id/activity'
207 activity.connect 'projects/:id/activity'
207 activity.connect 'projects/:id/activity.:format'
208 activity.connect 'projects/:id/activity.:format'
208 activity.connect 'activity', :id => nil
209 activity.connect 'activity', :id => nil
209 activity.connect 'activity.:format', :id => nil
210 activity.connect 'activity.:format', :id => nil
210 end
211 end
211
212
212 projects.with_options :conditions => {:method => :post} do |project_actions|
213 projects.with_options :conditions => {:method => :post} do |project_actions|
213 project_actions.connect 'projects/new', :action => 'add'
214 project_actions.connect 'projects/new', :action => 'add'
214 project_actions.connect 'projects', :action => 'add'
215 project_actions.connect 'projects', :action => 'add'
215 project_actions.connect 'projects.:format', :action => 'add', :format => /xml/
216 project_actions.connect 'projects.:format', :action => 'add', :format => /xml/
216 project_actions.connect 'projects/:id/:action', :action => /edit|destroy|archive|unarchive/
217 project_actions.connect 'projects/:id/:action', :action => /edit|destroy|archive|unarchive/
217 project_actions.connect 'projects/:id/files/new', :action => 'add_file'
218 project_actions.connect 'projects/:id/files/new', :action => 'add_file'
218 project_actions.connect 'projects/:id/activities/save', :action => 'save_activities'
219 project_actions.connect 'projects/:id/activities/save', :action => 'save_activities'
219 end
220 end
220
221
221 projects.with_options :conditions => {:method => :put} do |project_actions|
222 projects.with_options :conditions => {:method => :put} do |project_actions|
222 project_actions.conditions 'projects/:id.:format', :action => 'edit', :format => /xml/
223 project_actions.conditions 'projects/:id.:format', :action => 'edit', :format => /xml/
223 end
224 end
224
225
225 projects.with_options :conditions => {:method => :delete} do |project_actions|
226 projects.with_options :conditions => {:method => :delete} do |project_actions|
226 project_actions.conditions 'projects/:id.:format', :action => 'destroy', :format => /xml/
227 project_actions.conditions 'projects/:id.:format', :action => 'destroy', :format => /xml/
227 project_actions.conditions 'projects/:id/reset_activities', :action => 'reset_activities'
228 project_actions.conditions 'projects/:id/reset_activities', :action => 'reset_activities'
228 end
229 end
229 end
230 end
230
231
231 map.with_options :controller => 'versions' do |versions|
232 map.with_options :controller => 'versions' do |versions|
232 versions.connect 'projects/:project_id/versions/new', :action => 'new'
233 versions.connect 'projects/:project_id/versions/new', :action => 'new'
233 versions.with_options :conditions => {:method => :post} do |version_actions|
234 versions.with_options :conditions => {:method => :post} do |version_actions|
234 version_actions.connect 'projects/:project_id/versions/close_completed', :action => 'close_completed'
235 version_actions.connect 'projects/:project_id/versions/close_completed', :action => 'close_completed'
235 end
236 end
236 end
237 end
237
238
238 map.with_options :controller => 'issue_categories' do |categories|
239 map.with_options :controller => 'issue_categories' do |categories|
239 categories.connect 'projects/:project_id/issue_categories/new', :action => 'new'
240 categories.connect 'projects/:project_id/issue_categories/new', :action => 'new'
240 end
241 end
241
242
242 map.with_options :controller => 'repositories' do |repositories|
243 map.with_options :controller => 'repositories' do |repositories|
243 repositories.with_options :conditions => {:method => :get} do |repository_views|
244 repositories.with_options :conditions => {:method => :get} do |repository_views|
244 repository_views.connect 'projects/:id/repository', :action => 'show'
245 repository_views.connect 'projects/:id/repository', :action => 'show'
245 repository_views.connect 'projects/:id/repository/edit', :action => 'edit'
246 repository_views.connect 'projects/:id/repository/edit', :action => 'edit'
246 repository_views.connect 'projects/:id/repository/statistics', :action => 'stats'
247 repository_views.connect 'projects/:id/repository/statistics', :action => 'stats'
247 repository_views.connect 'projects/:id/repository/revisions', :action => 'revisions'
248 repository_views.connect 'projects/:id/repository/revisions', :action => 'revisions'
248 repository_views.connect 'projects/:id/repository/revisions.:format', :action => 'revisions'
249 repository_views.connect 'projects/:id/repository/revisions.:format', :action => 'revisions'
249 repository_views.connect 'projects/:id/repository/revisions/:rev', :action => 'revision'
250 repository_views.connect 'projects/:id/repository/revisions/:rev', :action => 'revision'
250 repository_views.connect 'projects/:id/repository/revisions/:rev/diff', :action => 'diff'
251 repository_views.connect 'projects/:id/repository/revisions/:rev/diff', :action => 'diff'
251 repository_views.connect 'projects/:id/repository/revisions/:rev/diff.:format', :action => 'diff'
252 repository_views.connect 'projects/:id/repository/revisions/:rev/diff.:format', :action => 'diff'
252 repository_views.connect 'projects/:id/repository/revisions/:rev/raw/*path', :action => 'entry', :format => 'raw', :requirements => { :rev => /[a-z0-9\.\-_]+/ }
253 repository_views.connect 'projects/:id/repository/revisions/:rev/raw/*path', :action => 'entry', :format => 'raw', :requirements => { :rev => /[a-z0-9\.\-_]+/ }
253 repository_views.connect 'projects/:id/repository/revisions/:rev/:action/*path', :requirements => { :rev => /[a-z0-9\.\-_]+/ }
254 repository_views.connect 'projects/:id/repository/revisions/:rev/:action/*path', :requirements => { :rev => /[a-z0-9\.\-_]+/ }
254 repository_views.connect 'projects/:id/repository/raw/*path', :action => 'entry', :format => 'raw'
255 repository_views.connect 'projects/:id/repository/raw/*path', :action => 'entry', :format => 'raw'
255 # TODO: why the following route is required?
256 # TODO: why the following route is required?
256 repository_views.connect 'projects/:id/repository/entry/*path', :action => 'entry'
257 repository_views.connect 'projects/:id/repository/entry/*path', :action => 'entry'
257 repository_views.connect 'projects/:id/repository/:action/*path'
258 repository_views.connect 'projects/:id/repository/:action/*path'
258 end
259 end
259
260
260 repositories.connect 'projects/:id/repository/:action', :conditions => {:method => :post}
261 repositories.connect 'projects/:id/repository/:action', :conditions => {:method => :post}
261 end
262 end
262
263
263 map.connect 'attachments/:id', :controller => 'attachments', :action => 'show', :id => /\d+/
264 map.connect 'attachments/:id', :controller => 'attachments', :action => 'show', :id => /\d+/
264 map.connect 'attachments/:id/:filename', :controller => 'attachments', :action => 'show', :id => /\d+/, :filename => /.*/
265 map.connect 'attachments/:id/:filename', :controller => 'attachments', :action => 'show', :id => /\d+/, :filename => /.*/
265 map.connect 'attachments/download/:id/:filename', :controller => 'attachments', :action => 'download', :id => /\d+/, :filename => /.*/
266 map.connect 'attachments/download/:id/:filename', :controller => 'attachments', :action => 'download', :id => /\d+/, :filename => /.*/
266
267
267 map.resources :groups
268 map.resources :groups
268
269
269 #left old routes at the bottom for backwards compat
270 #left old routes at the bottom for backwards compat
270 map.connect 'projects/:project_id/issues/:action', :controller => 'issues'
271 map.connect 'projects/:project_id/issues/:action', :controller => 'issues'
271 map.connect 'projects/:project_id/documents/:action', :controller => 'documents'
272 map.connect 'projects/:project_id/documents/:action', :controller => 'documents'
272 map.connect 'projects/:project_id/boards/:action/:id', :controller => 'boards'
273 map.connect 'projects/:project_id/boards/:action/:id', :controller => 'boards'
273 map.connect 'boards/:board_id/topics/:action/:id', :controller => 'messages'
274 map.connect 'boards/:board_id/topics/:action/:id', :controller => 'messages'
274 map.connect 'wiki/:id/:page/:action', :page => nil, :controller => 'wiki'
275 map.connect 'wiki/:id/:page/:action', :page => nil, :controller => 'wiki'
275 map.connect 'issues/:issue_id/relations/:action/:id', :controller => 'issue_relations'
276 map.connect 'issues/:issue_id/relations/:action/:id', :controller => 'issue_relations'
276 map.connect 'projects/:project_id/news/:action', :controller => 'news'
277 map.connect 'projects/:project_id/news/:action', :controller => 'news'
277 map.connect 'projects/:project_id/timelog/:action/:id', :controller => 'timelog', :project_id => /.+/
278 map.connect 'projects/:project_id/timelog/:action/:id', :controller => 'timelog', :project_id => /.+/
278 map.with_options :controller => 'repositories' do |omap|
279 map.with_options :controller => 'repositories' do |omap|
279 omap.repositories_show 'repositories/browse/:id/*path', :action => 'browse'
280 omap.repositories_show 'repositories/browse/:id/*path', :action => 'browse'
280 omap.repositories_changes 'repositories/changes/:id/*path', :action => 'changes'
281 omap.repositories_changes 'repositories/changes/:id/*path', :action => 'changes'
281 omap.repositories_diff 'repositories/diff/:id/*path', :action => 'diff'
282 omap.repositories_diff 'repositories/diff/:id/*path', :action => 'diff'
282 omap.repositories_entry 'repositories/entry/:id/*path', :action => 'entry'
283 omap.repositories_entry 'repositories/entry/:id/*path', :action => 'entry'
283 omap.repositories_entry 'repositories/annotate/:id/*path', :action => 'annotate'
284 omap.repositories_entry 'repositories/annotate/:id/*path', :action => 'annotate'
284 omap.connect 'repositories/revision/:id/:rev', :action => 'revision'
285 omap.connect 'repositories/revision/:id/:rev', :action => 'revision'
285 end
286 end
286
287
287 map.with_options :controller => 'sys' do |sys|
288 map.with_options :controller => 'sys' do |sys|
288 sys.connect 'sys/projects.:format', :action => 'projects', :conditions => {:method => :get}
289 sys.connect 'sys/projects.:format', :action => 'projects', :conditions => {:method => :get}
289 sys.connect 'sys/projects/:id/repository.:format', :action => 'create_project_repository', :conditions => {:method => :post}
290 sys.connect 'sys/projects/:id/repository.:format', :action => 'create_project_repository', :conditions => {:method => :post}
290 end
291 end
291
292
292 # Install the default route as the lowest priority.
293 # Install the default route as the lowest priority.
293 map.connect ':controller/:action/:id'
294 map.connect ':controller/:action/:id'
294 map.connect 'robots.txt', :controller => 'welcome', :action => 'robots'
295 map.connect 'robots.txt', :controller => 'welcome', :action => 'robots'
295 # Used for OpenID
296 # Used for OpenID
296 map.root :controller => 'account', :action => 'login'
297 map.root :controller => 'account', :action => 'login'
297 end
298 end
@@ -1,224 +1,225
1 require 'redmine/access_control'
1 require 'redmine/access_control'
2 require 'redmine/menu_manager'
2 require 'redmine/menu_manager'
3 require 'redmine/activity'
3 require 'redmine/activity'
4 require 'redmine/search'
4 require 'redmine/search'
5 require 'redmine/custom_field_format'
5 require 'redmine/custom_field_format'
6 require 'redmine/mime_type'
6 require 'redmine/mime_type'
7 require 'redmine/core_ext'
7 require 'redmine/core_ext'
8 require 'redmine/themes'
8 require 'redmine/themes'
9 require 'redmine/hook'
9 require 'redmine/hook'
10 require 'redmine/plugin'
10 require 'redmine/plugin'
11 require 'redmine/wiki_formatting'
11 require 'redmine/wiki_formatting'
12 require 'redmine/scm/base'
12 require 'redmine/scm/base'
13
13
14 begin
14 begin
15 require_library_or_gem 'RMagick' unless Object.const_defined?(:Magick)
15 require_library_or_gem 'RMagick' unless Object.const_defined?(:Magick)
16 rescue LoadError
16 rescue LoadError
17 # RMagick is not available
17 # RMagick is not available
18 end
18 end
19
19
20 if RUBY_VERSION < '1.9'
20 if RUBY_VERSION < '1.9'
21 require 'faster_csv'
21 require 'faster_csv'
22 else
22 else
23 require 'csv'
23 require 'csv'
24 FCSV = CSV
24 FCSV = CSV
25 end
25 end
26
26
27 Redmine::Scm::Base.add "Subversion"
27 Redmine::Scm::Base.add "Subversion"
28 Redmine::Scm::Base.add "Darcs"
28 Redmine::Scm::Base.add "Darcs"
29 Redmine::Scm::Base.add "Mercurial"
29 Redmine::Scm::Base.add "Mercurial"
30 Redmine::Scm::Base.add "Cvs"
30 Redmine::Scm::Base.add "Cvs"
31 Redmine::Scm::Base.add "Bazaar"
31 Redmine::Scm::Base.add "Bazaar"
32 Redmine::Scm::Base.add "Git"
32 Redmine::Scm::Base.add "Git"
33 Redmine::Scm::Base.add "Filesystem"
33 Redmine::Scm::Base.add "Filesystem"
34
34
35 Redmine::CustomFieldFormat.map do |fields|
35 Redmine::CustomFieldFormat.map do |fields|
36 fields.register Redmine::CustomFieldFormat.new('string', :label => :label_string, :order => 1)
36 fields.register Redmine::CustomFieldFormat.new('string', :label => :label_string, :order => 1)
37 fields.register Redmine::CustomFieldFormat.new('text', :label => :label_text, :order => 2)
37 fields.register Redmine::CustomFieldFormat.new('text', :label => :label_text, :order => 2)
38 fields.register Redmine::CustomFieldFormat.new('int', :label => :label_integer, :order => 3)
38 fields.register Redmine::CustomFieldFormat.new('int', :label => :label_integer, :order => 3)
39 fields.register Redmine::CustomFieldFormat.new('float', :label => :label_float, :order => 4)
39 fields.register Redmine::CustomFieldFormat.new('float', :label => :label_float, :order => 4)
40 fields.register Redmine::CustomFieldFormat.new('list', :label => :label_list, :order => 5)
40 fields.register Redmine::CustomFieldFormat.new('list', :label => :label_list, :order => 5)
41 fields.register Redmine::CustomFieldFormat.new('date', :label => :label_date, :order => 6)
41 fields.register Redmine::CustomFieldFormat.new('date', :label => :label_date, :order => 6)
42 fields.register Redmine::CustomFieldFormat.new('bool', :label => :label_boolean, :order => 7)
42 fields.register Redmine::CustomFieldFormat.new('bool', :label => :label_boolean, :order => 7)
43 end
43 end
44
44
45 # Permissions
45 # Permissions
46 Redmine::AccessControl.map do |map|
46 Redmine::AccessControl.map do |map|
47 map.permission :view_project, {:projects => [:show, :activity]}, :public => true
47 map.permission :view_project, {:projects => [:show, :activity]}, :public => true
48 map.permission :search_project, {:search => :index}, :public => true
48 map.permission :search_project, {:search => :index}, :public => true
49 map.permission :add_project, {:projects => :add}, :require => :loggedin
49 map.permission :add_project, {:projects => :add}, :require => :loggedin
50 map.permission :edit_project, {:projects => [:settings, :edit]}, :require => :member
50 map.permission :edit_project, {:projects => [:settings, :edit]}, :require => :member
51 map.permission :select_project_modules, {:projects => :modules}, :require => :member
51 map.permission :select_project_modules, {:projects => :modules}, :require => :member
52 map.permission :manage_members, {:projects => :settings, :members => [:new, :edit, :destroy, :autocomplete_for_member]}, :require => :member
52 map.permission :manage_members, {:projects => :settings, :members => [:new, :edit, :destroy, :autocomplete_for_member]}, :require => :member
53 map.permission :manage_versions, {:projects => :settings, :versions => [:new, :edit, :close_completed, :destroy]}, :require => :member
53 map.permission :manage_versions, {:projects => :settings, :versions => [:new, :edit, :close_completed, :destroy]}, :require => :member
54 map.permission :add_subprojects, {:projects => :add}, :require => :member
54 map.permission :add_subprojects, {:projects => :add}, :require => :member
55
55
56 map.project_module :issue_tracking do |map|
56 map.project_module :issue_tracking do |map|
57 # Issue categories
57 # Issue categories
58 map.permission :manage_categories, {:projects => :settings, :issue_categories => [:new, :edit, :destroy]}, :require => :member
58 map.permission :manage_categories, {:projects => :settings, :issue_categories => [:new, :edit, :destroy]}, :require => :member
59 # Issues
59 # Issues
60 map.permission :view_issues, {:projects => :roadmap,
60 map.permission :view_issues, {:projects => :roadmap,
61 :issues => [:index, :changes, :show, :context_menu],
61 :issues => [:index, :changes, :show],
62 :auto_complete => [:issues],
62 :auto_complete => [:issues],
63 :context_menus => [:issues],
63 :versions => [:show, :status_by],
64 :versions => [:show, :status_by],
64 :queries => :index,
65 :queries => :index,
65 :reports => [:issue_report, :issue_report_details]}
66 :reports => [:issue_report, :issue_report_details]}
66 map.permission :add_issues, {:issues => [:new, :create, :update_form]}
67 map.permission :add_issues, {:issues => [:new, :create, :update_form]}
67 map.permission :edit_issues, {:issues => [:edit, :update, :bulk_edit, :update_form], :journals => [:new]}
68 map.permission :edit_issues, {:issues => [:edit, :update, :bulk_edit, :update_form], :journals => [:new]}
68 map.permission :manage_issue_relations, {:issue_relations => [:new, :destroy]}
69 map.permission :manage_issue_relations, {:issue_relations => [:new, :destroy]}
69 map.permission :manage_subtasks, {}
70 map.permission :manage_subtasks, {}
70 map.permission :add_issue_notes, {:issues => [:edit, :update], :journals => [:new]}
71 map.permission :add_issue_notes, {:issues => [:edit, :update], :journals => [:new]}
71 map.permission :edit_issue_notes, {:journals => :edit}, :require => :loggedin
72 map.permission :edit_issue_notes, {:journals => :edit}, :require => :loggedin
72 map.permission :edit_own_issue_notes, {:journals => :edit}, :require => :loggedin
73 map.permission :edit_own_issue_notes, {:journals => :edit}, :require => :loggedin
73 map.permission :move_issues, {:issue_moves => [:new, :create]}, :require => :loggedin
74 map.permission :move_issues, {:issue_moves => [:new, :create]}, :require => :loggedin
74 map.permission :delete_issues, {:issues => :destroy}, :require => :member
75 map.permission :delete_issues, {:issues => :destroy}, :require => :member
75 # Queries
76 # Queries
76 map.permission :manage_public_queries, {:queries => [:new, :edit, :destroy]}, :require => :member
77 map.permission :manage_public_queries, {:queries => [:new, :edit, :destroy]}, :require => :member
77 map.permission :save_queries, {:queries => [:new, :edit, :destroy]}, :require => :loggedin
78 map.permission :save_queries, {:queries => [:new, :edit, :destroy]}, :require => :loggedin
78 # Gantt & calendar
79 # Gantt & calendar
79 map.permission :view_gantt, :gantts => :show
80 map.permission :view_gantt, :gantts => :show
80 map.permission :view_calendar, :calendars => :show
81 map.permission :view_calendar, :calendars => :show
81 # Watchers
82 # Watchers
82 map.permission :view_issue_watchers, {}
83 map.permission :view_issue_watchers, {}
83 map.permission :add_issue_watchers, {:watchers => :new}
84 map.permission :add_issue_watchers, {:watchers => :new}
84 map.permission :delete_issue_watchers, {:watchers => :destroy}
85 map.permission :delete_issue_watchers, {:watchers => :destroy}
85 end
86 end
86
87
87 map.project_module :time_tracking do |map|
88 map.project_module :time_tracking do |map|
88 map.permission :log_time, {:timelog => :edit}, :require => :loggedin
89 map.permission :log_time, {:timelog => :edit}, :require => :loggedin
89 map.permission :view_time_entries, :timelog => [:details, :report]
90 map.permission :view_time_entries, :timelog => [:details, :report]
90 map.permission :edit_time_entries, {:timelog => [:edit, :destroy]}, :require => :member
91 map.permission :edit_time_entries, {:timelog => [:edit, :destroy]}, :require => :member
91 map.permission :edit_own_time_entries, {:timelog => [:edit, :destroy]}, :require => :loggedin
92 map.permission :edit_own_time_entries, {:timelog => [:edit, :destroy]}, :require => :loggedin
92 map.permission :manage_project_activities, {:projects => [:save_activities, :reset_activities]}, :require => :member
93 map.permission :manage_project_activities, {:projects => [:save_activities, :reset_activities]}, :require => :member
93 end
94 end
94
95
95 map.project_module :news do |map|
96 map.project_module :news do |map|
96 map.permission :manage_news, {:news => [:new, :edit, :destroy, :destroy_comment]}, :require => :member
97 map.permission :manage_news, {:news => [:new, :edit, :destroy, :destroy_comment]}, :require => :member
97 map.permission :view_news, {:news => [:index, :show]}, :public => true
98 map.permission :view_news, {:news => [:index, :show]}, :public => true
98 map.permission :comment_news, {:news => :add_comment}
99 map.permission :comment_news, {:news => :add_comment}
99 end
100 end
100
101
101 map.project_module :documents do |map|
102 map.project_module :documents do |map|
102 map.permission :manage_documents, {:documents => [:new, :edit, :destroy, :add_attachment]}, :require => :loggedin
103 map.permission :manage_documents, {:documents => [:new, :edit, :destroy, :add_attachment]}, :require => :loggedin
103 map.permission :view_documents, :documents => [:index, :show, :download]
104 map.permission :view_documents, :documents => [:index, :show, :download]
104 end
105 end
105
106
106 map.project_module :files do |map|
107 map.project_module :files do |map|
107 map.permission :manage_files, {:projects => :add_file}, :require => :loggedin
108 map.permission :manage_files, {:projects => :add_file}, :require => :loggedin
108 map.permission :view_files, :projects => :list_files, :versions => :download
109 map.permission :view_files, :projects => :list_files, :versions => :download
109 end
110 end
110
111
111 map.project_module :wiki do |map|
112 map.project_module :wiki do |map|
112 map.permission :manage_wiki, {:wikis => [:edit, :destroy]}, :require => :member
113 map.permission :manage_wiki, {:wikis => [:edit, :destroy]}, :require => :member
113 map.permission :rename_wiki_pages, {:wiki => :rename}, :require => :member
114 map.permission :rename_wiki_pages, {:wiki => :rename}, :require => :member
114 map.permission :delete_wiki_pages, {:wiki => :destroy}, :require => :member
115 map.permission :delete_wiki_pages, {:wiki => :destroy}, :require => :member
115 map.permission :view_wiki_pages, :wiki => [:index, :special]
116 map.permission :view_wiki_pages, :wiki => [:index, :special]
116 map.permission :export_wiki_pages, {}
117 map.permission :export_wiki_pages, {}
117 map.permission :view_wiki_edits, :wiki => [:history, :diff, :annotate]
118 map.permission :view_wiki_edits, :wiki => [:history, :diff, :annotate]
118 map.permission :edit_wiki_pages, :wiki => [:edit, :preview, :add_attachment]
119 map.permission :edit_wiki_pages, :wiki => [:edit, :preview, :add_attachment]
119 map.permission :delete_wiki_pages_attachments, {}
120 map.permission :delete_wiki_pages_attachments, {}
120 map.permission :protect_wiki_pages, {:wiki => :protect}, :require => :member
121 map.permission :protect_wiki_pages, {:wiki => :protect}, :require => :member
121 end
122 end
122
123
123 map.project_module :repository do |map|
124 map.project_module :repository do |map|
124 map.permission :manage_repository, {:repositories => [:edit, :committers, :destroy]}, :require => :member
125 map.permission :manage_repository, {:repositories => [:edit, :committers, :destroy]}, :require => :member
125 map.permission :browse_repository, :repositories => [:show, :browse, :entry, :annotate, :changes, :diff, :stats, :graph]
126 map.permission :browse_repository, :repositories => [:show, :browse, :entry, :annotate, :changes, :diff, :stats, :graph]
126 map.permission :view_changesets, :repositories => [:show, :revisions, :revision]
127 map.permission :view_changesets, :repositories => [:show, :revisions, :revision]
127 map.permission :commit_access, {}
128 map.permission :commit_access, {}
128 end
129 end
129
130
130 map.project_module :boards do |map|
131 map.project_module :boards do |map|
131 map.permission :manage_boards, {:boards => [:new, :edit, :destroy]}, :require => :member
132 map.permission :manage_boards, {:boards => [:new, :edit, :destroy]}, :require => :member
132 map.permission :view_messages, {:boards => [:index, :show], :messages => [:show]}, :public => true
133 map.permission :view_messages, {:boards => [:index, :show], :messages => [:show]}, :public => true
133 map.permission :add_messages, {:messages => [:new, :reply, :quote]}
134 map.permission :add_messages, {:messages => [:new, :reply, :quote]}
134 map.permission :edit_messages, {:messages => :edit}, :require => :member
135 map.permission :edit_messages, {:messages => :edit}, :require => :member
135 map.permission :edit_own_messages, {:messages => :edit}, :require => :loggedin
136 map.permission :edit_own_messages, {:messages => :edit}, :require => :loggedin
136 map.permission :delete_messages, {:messages => :destroy}, :require => :member
137 map.permission :delete_messages, {:messages => :destroy}, :require => :member
137 map.permission :delete_own_messages, {:messages => :destroy}, :require => :loggedin
138 map.permission :delete_own_messages, {:messages => :destroy}, :require => :loggedin
138 end
139 end
139 end
140 end
140
141
141 Redmine::MenuManager.map :top_menu do |menu|
142 Redmine::MenuManager.map :top_menu do |menu|
142 menu.push :home, :home_path
143 menu.push :home, :home_path
143 menu.push :my_page, { :controller => 'my', :action => 'page' }, :if => Proc.new { User.current.logged? }
144 menu.push :my_page, { :controller => 'my', :action => 'page' }, :if => Proc.new { User.current.logged? }
144 menu.push :projects, { :controller => 'projects', :action => 'index' }, :caption => :label_project_plural
145 menu.push :projects, { :controller => 'projects', :action => 'index' }, :caption => :label_project_plural
145 menu.push :administration, { :controller => 'admin', :action => 'index' }, :if => Proc.new { User.current.admin? }, :last => true
146 menu.push :administration, { :controller => 'admin', :action => 'index' }, :if => Proc.new { User.current.admin? }, :last => true
146 menu.push :help, Redmine::Info.help_url, :last => true
147 menu.push :help, Redmine::Info.help_url, :last => true
147 end
148 end
148
149
149 Redmine::MenuManager.map :account_menu do |menu|
150 Redmine::MenuManager.map :account_menu do |menu|
150 menu.push :login, :signin_path, :if => Proc.new { !User.current.logged? }
151 menu.push :login, :signin_path, :if => Proc.new { !User.current.logged? }
151 menu.push :register, { :controller => 'account', :action => 'register' }, :if => Proc.new { !User.current.logged? && Setting.self_registration? }
152 menu.push :register, { :controller => 'account', :action => 'register' }, :if => Proc.new { !User.current.logged? && Setting.self_registration? }
152 menu.push :my_account, { :controller => 'my', :action => 'account' }, :if => Proc.new { User.current.logged? }
153 menu.push :my_account, { :controller => 'my', :action => 'account' }, :if => Proc.new { User.current.logged? }
153 menu.push :logout, :signout_path, :if => Proc.new { User.current.logged? }
154 menu.push :logout, :signout_path, :if => Proc.new { User.current.logged? }
154 end
155 end
155
156
156 Redmine::MenuManager.map :application_menu do |menu|
157 Redmine::MenuManager.map :application_menu do |menu|
157 # Empty
158 # Empty
158 end
159 end
159
160
160 Redmine::MenuManager.map :admin_menu do |menu|
161 Redmine::MenuManager.map :admin_menu do |menu|
161 menu.push :projects, {:controller => 'admin', :action => 'projects'}, :caption => :label_project_plural
162 menu.push :projects, {:controller => 'admin', :action => 'projects'}, :caption => :label_project_plural
162 menu.push :users, {:controller => 'users'}, :caption => :label_user_plural
163 menu.push :users, {:controller => 'users'}, :caption => :label_user_plural
163 menu.push :groups, {:controller => 'groups'}, :caption => :label_group_plural
164 menu.push :groups, {:controller => 'groups'}, :caption => :label_group_plural
164 menu.push :roles, {:controller => 'roles'}, :caption => :label_role_and_permissions
165 menu.push :roles, {:controller => 'roles'}, :caption => :label_role_and_permissions
165 menu.push :trackers, {:controller => 'trackers'}, :caption => :label_tracker_plural
166 menu.push :trackers, {:controller => 'trackers'}, :caption => :label_tracker_plural
166 menu.push :issue_statuses, {:controller => 'issue_statuses'}, :caption => :label_issue_status_plural,
167 menu.push :issue_statuses, {:controller => 'issue_statuses'}, :caption => :label_issue_status_plural,
167 :html => {:class => 'issue_statuses'}
168 :html => {:class => 'issue_statuses'}
168 menu.push :workflows, {:controller => 'workflows', :action => 'edit'}, :caption => :label_workflow
169 menu.push :workflows, {:controller => 'workflows', :action => 'edit'}, :caption => :label_workflow
169 menu.push :custom_fields, {:controller => 'custom_fields'}, :caption => :label_custom_field_plural,
170 menu.push :custom_fields, {:controller => 'custom_fields'}, :caption => :label_custom_field_plural,
170 :html => {:class => 'custom_fields'}
171 :html => {:class => 'custom_fields'}
171 menu.push :enumerations, {:controller => 'enumerations'}
172 menu.push :enumerations, {:controller => 'enumerations'}
172 menu.push :settings, {:controller => 'settings'}
173 menu.push :settings, {:controller => 'settings'}
173 menu.push :ldap_authentication, {:controller => 'ldap_auth_sources', :action => 'index'},
174 menu.push :ldap_authentication, {:controller => 'ldap_auth_sources', :action => 'index'},
174 :html => {:class => 'server_authentication'}
175 :html => {:class => 'server_authentication'}
175 menu.push :plugins, {:controller => 'admin', :action => 'plugins'}, :last => true
176 menu.push :plugins, {:controller => 'admin', :action => 'plugins'}, :last => true
176 menu.push :info, {:controller => 'admin', :action => 'info'}, :caption => :label_information_plural, :last => true
177 menu.push :info, {:controller => 'admin', :action => 'info'}, :caption => :label_information_plural, :last => true
177 end
178 end
178
179
179 Redmine::MenuManager.map :project_menu do |menu|
180 Redmine::MenuManager.map :project_menu do |menu|
180 menu.push :overview, { :controller => 'projects', :action => 'show' }
181 menu.push :overview, { :controller => 'projects', :action => 'show' }
181 menu.push :activity, { :controller => 'projects', :action => 'activity' }
182 menu.push :activity, { :controller => 'projects', :action => 'activity' }
182 menu.push :roadmap, { :controller => 'projects', :action => 'roadmap' },
183 menu.push :roadmap, { :controller => 'projects', :action => 'roadmap' },
183 :if => Proc.new { |p| p.shared_versions.any? }
184 :if => Proc.new { |p| p.shared_versions.any? }
184 menu.push :issues, { :controller => 'issues', :action => 'index' }, :param => :project_id, :caption => :label_issue_plural
185 menu.push :issues, { :controller => 'issues', :action => 'index' }, :param => :project_id, :caption => :label_issue_plural
185 menu.push :new_issue, { :controller => 'issues', :action => 'new' }, :param => :project_id, :caption => :label_issue_new,
186 menu.push :new_issue, { :controller => 'issues', :action => 'new' }, :param => :project_id, :caption => :label_issue_new,
186 :html => { :accesskey => Redmine::AccessKeys.key_for(:new_issue) }
187 :html => { :accesskey => Redmine::AccessKeys.key_for(:new_issue) }
187 menu.push :gantt, { :controller => 'gantts', :action => 'show' }, :param => :project_id, :caption => :label_gantt
188 menu.push :gantt, { :controller => 'gantts', :action => 'show' }, :param => :project_id, :caption => :label_gantt
188 menu.push :calendar, { :controller => 'calendars', :action => 'show' }, :param => :project_id, :caption => :label_calendar
189 menu.push :calendar, { :controller => 'calendars', :action => 'show' }, :param => :project_id, :caption => :label_calendar
189 menu.push :news, { :controller => 'news', :action => 'index' }, :param => :project_id, :caption => :label_news_plural
190 menu.push :news, { :controller => 'news', :action => 'index' }, :param => :project_id, :caption => :label_news_plural
190 menu.push :documents, { :controller => 'documents', :action => 'index' }, :param => :project_id, :caption => :label_document_plural
191 menu.push :documents, { :controller => 'documents', :action => 'index' }, :param => :project_id, :caption => :label_document_plural
191 menu.push :wiki, { :controller => 'wiki', :action => 'index', :page => nil },
192 menu.push :wiki, { :controller => 'wiki', :action => 'index', :page => nil },
192 :if => Proc.new { |p| p.wiki && !p.wiki.new_record? }
193 :if => Proc.new { |p| p.wiki && !p.wiki.new_record? }
193 menu.push :boards, { :controller => 'boards', :action => 'index', :id => nil }, :param => :project_id,
194 menu.push :boards, { :controller => 'boards', :action => 'index', :id => nil }, :param => :project_id,
194 :if => Proc.new { |p| p.boards.any? }, :caption => :label_board_plural
195 :if => Proc.new { |p| p.boards.any? }, :caption => :label_board_plural
195 menu.push :files, { :controller => 'projects', :action => 'list_files' }, :caption => :label_file_plural
196 menu.push :files, { :controller => 'projects', :action => 'list_files' }, :caption => :label_file_plural
196 menu.push :repository, { :controller => 'repositories', :action => 'show' },
197 menu.push :repository, { :controller => 'repositories', :action => 'show' },
197 :if => Proc.new { |p| p.repository && !p.repository.new_record? }
198 :if => Proc.new { |p| p.repository && !p.repository.new_record? }
198 menu.push :settings, { :controller => 'projects', :action => 'settings' }, :last => true
199 menu.push :settings, { :controller => 'projects', :action => 'settings' }, :last => true
199 end
200 end
200
201
201 Redmine::Activity.map do |activity|
202 Redmine::Activity.map do |activity|
202 activity.register :issues, :class_name => %w(Issue Journal)
203 activity.register :issues, :class_name => %w(Issue Journal)
203 activity.register :changesets
204 activity.register :changesets
204 activity.register :news
205 activity.register :news
205 activity.register :documents, :class_name => %w(Document Attachment)
206 activity.register :documents, :class_name => %w(Document Attachment)
206 activity.register :files, :class_name => 'Attachment'
207 activity.register :files, :class_name => 'Attachment'
207 activity.register :wiki_edits, :class_name => 'WikiContent::Version', :default => false
208 activity.register :wiki_edits, :class_name => 'WikiContent::Version', :default => false
208 activity.register :messages, :default => false
209 activity.register :messages, :default => false
209 activity.register :time_entries, :default => false
210 activity.register :time_entries, :default => false
210 end
211 end
211
212
212 Redmine::Search.map do |search|
213 Redmine::Search.map do |search|
213 search.register :issues
214 search.register :issues
214 search.register :news
215 search.register :news
215 search.register :documents
216 search.register :documents
216 search.register :changesets
217 search.register :changesets
217 search.register :wiki_pages
218 search.register :wiki_pages
218 search.register :messages
219 search.register :messages
219 search.register :projects
220 search.register :projects
220 end
221 end
221
222
222 Redmine::WikiFormatting.map do |format|
223 Redmine::WikiFormatting.map do |format|
223 format.register :textile, Redmine::WikiFormatting::Textile::Formatter, Redmine::WikiFormatting::Textile::Helper
224 format.register :textile, Redmine::WikiFormatting::Textile::Formatter, Redmine::WikiFormatting::Textile::Helper
224 end
225 end
@@ -1,1159 +1,1076
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2008 Jean-Philippe Lang
2 # Copyright (C) 2006-2008 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.dirname(__FILE__) + '/../test_helper'
18 require File.dirname(__FILE__) + '/../test_helper'
19 require 'issues_controller'
19 require 'issues_controller'
20
20
21 # Re-raise errors caught by the controller.
21 # Re-raise errors caught by the controller.
22 class IssuesController; def rescue_action(e) raise e end; end
22 class IssuesController; def rescue_action(e) raise e end; end
23
23
24 class IssuesControllerTest < ActionController::TestCase
24 class IssuesControllerTest < ActionController::TestCase
25 fixtures :projects,
25 fixtures :projects,
26 :users,
26 :users,
27 :roles,
27 :roles,
28 :members,
28 :members,
29 :member_roles,
29 :member_roles,
30 :issues,
30 :issues,
31 :issue_statuses,
31 :issue_statuses,
32 :versions,
32 :versions,
33 :trackers,
33 :trackers,
34 :projects_trackers,
34 :projects_trackers,
35 :issue_categories,
35 :issue_categories,
36 :enabled_modules,
36 :enabled_modules,
37 :enumerations,
37 :enumerations,
38 :attachments,
38 :attachments,
39 :workflows,
39 :workflows,
40 :custom_fields,
40 :custom_fields,
41 :custom_values,
41 :custom_values,
42 :custom_fields_projects,
42 :custom_fields_projects,
43 :custom_fields_trackers,
43 :custom_fields_trackers,
44 :time_entries,
44 :time_entries,
45 :journals,
45 :journals,
46 :journal_details,
46 :journal_details,
47 :queries
47 :queries
48
48
49 def setup
49 def setup
50 @controller = IssuesController.new
50 @controller = IssuesController.new
51 @request = ActionController::TestRequest.new
51 @request = ActionController::TestRequest.new
52 @response = ActionController::TestResponse.new
52 @response = ActionController::TestResponse.new
53 User.current = nil
53 User.current = nil
54 end
54 end
55
55
56 def test_index
56 def test_index
57 Setting.default_language = 'en'
57 Setting.default_language = 'en'
58
58
59 get :index
59 get :index
60 assert_response :success
60 assert_response :success
61 assert_template 'index.rhtml'
61 assert_template 'index.rhtml'
62 assert_not_nil assigns(:issues)
62 assert_not_nil assigns(:issues)
63 assert_nil assigns(:project)
63 assert_nil assigns(:project)
64 assert_tag :tag => 'a', :content => /Can't print recipes/
64 assert_tag :tag => 'a', :content => /Can't print recipes/
65 assert_tag :tag => 'a', :content => /Subproject issue/
65 assert_tag :tag => 'a', :content => /Subproject issue/
66 # private projects hidden
66 # private projects hidden
67 assert_no_tag :tag => 'a', :content => /Issue of a private subproject/
67 assert_no_tag :tag => 'a', :content => /Issue of a private subproject/
68 assert_no_tag :tag => 'a', :content => /Issue on project 2/
68 assert_no_tag :tag => 'a', :content => /Issue on project 2/
69 # project column
69 # project column
70 assert_tag :tag => 'th', :content => /Project/
70 assert_tag :tag => 'th', :content => /Project/
71 end
71 end
72
72
73 def test_index_should_not_list_issues_when_module_disabled
73 def test_index_should_not_list_issues_when_module_disabled
74 EnabledModule.delete_all("name = 'issue_tracking' AND project_id = 1")
74 EnabledModule.delete_all("name = 'issue_tracking' AND project_id = 1")
75 get :index
75 get :index
76 assert_response :success
76 assert_response :success
77 assert_template 'index.rhtml'
77 assert_template 'index.rhtml'
78 assert_not_nil assigns(:issues)
78 assert_not_nil assigns(:issues)
79 assert_nil assigns(:project)
79 assert_nil assigns(:project)
80 assert_no_tag :tag => 'a', :content => /Can't print recipes/
80 assert_no_tag :tag => 'a', :content => /Can't print recipes/
81 assert_tag :tag => 'a', :content => /Subproject issue/
81 assert_tag :tag => 'a', :content => /Subproject issue/
82 end
82 end
83
83
84 def test_index_should_not_list_issues_when_module_disabled
84 def test_index_should_not_list_issues_when_module_disabled
85 EnabledModule.delete_all("name = 'issue_tracking' AND project_id = 1")
85 EnabledModule.delete_all("name = 'issue_tracking' AND project_id = 1")
86 get :index
86 get :index
87 assert_response :success
87 assert_response :success
88 assert_template 'index.rhtml'
88 assert_template 'index.rhtml'
89 assert_not_nil assigns(:issues)
89 assert_not_nil assigns(:issues)
90 assert_nil assigns(:project)
90 assert_nil assigns(:project)
91 assert_no_tag :tag => 'a', :content => /Can't print recipes/
91 assert_no_tag :tag => 'a', :content => /Can't print recipes/
92 assert_tag :tag => 'a', :content => /Subproject issue/
92 assert_tag :tag => 'a', :content => /Subproject issue/
93 end
93 end
94
94
95 def test_index_with_project
95 def test_index_with_project
96 Setting.display_subprojects_issues = 0
96 Setting.display_subprojects_issues = 0
97 get :index, :project_id => 1
97 get :index, :project_id => 1
98 assert_response :success
98 assert_response :success
99 assert_template 'index.rhtml'
99 assert_template 'index.rhtml'
100 assert_not_nil assigns(:issues)
100 assert_not_nil assigns(:issues)
101 assert_tag :tag => 'a', :content => /Can't print recipes/
101 assert_tag :tag => 'a', :content => /Can't print recipes/
102 assert_no_tag :tag => 'a', :content => /Subproject issue/
102 assert_no_tag :tag => 'a', :content => /Subproject issue/
103 end
103 end
104
104
105 def test_index_with_project_and_subprojects
105 def test_index_with_project_and_subprojects
106 Setting.display_subprojects_issues = 1
106 Setting.display_subprojects_issues = 1
107 get :index, :project_id => 1
107 get :index, :project_id => 1
108 assert_response :success
108 assert_response :success
109 assert_template 'index.rhtml'
109 assert_template 'index.rhtml'
110 assert_not_nil assigns(:issues)
110 assert_not_nil assigns(:issues)
111 assert_tag :tag => 'a', :content => /Can't print recipes/
111 assert_tag :tag => 'a', :content => /Can't print recipes/
112 assert_tag :tag => 'a', :content => /Subproject issue/
112 assert_tag :tag => 'a', :content => /Subproject issue/
113 assert_no_tag :tag => 'a', :content => /Issue of a private subproject/
113 assert_no_tag :tag => 'a', :content => /Issue of a private subproject/
114 end
114 end
115
115
116 def test_index_with_project_and_subprojects_should_show_private_subprojects
116 def test_index_with_project_and_subprojects_should_show_private_subprojects
117 @request.session[:user_id] = 2
117 @request.session[:user_id] = 2
118 Setting.display_subprojects_issues = 1
118 Setting.display_subprojects_issues = 1
119 get :index, :project_id => 1
119 get :index, :project_id => 1
120 assert_response :success
120 assert_response :success
121 assert_template 'index.rhtml'
121 assert_template 'index.rhtml'
122 assert_not_nil assigns(:issues)
122 assert_not_nil assigns(:issues)
123 assert_tag :tag => 'a', :content => /Can't print recipes/
123 assert_tag :tag => 'a', :content => /Can't print recipes/
124 assert_tag :tag => 'a', :content => /Subproject issue/
124 assert_tag :tag => 'a', :content => /Subproject issue/
125 assert_tag :tag => 'a', :content => /Issue of a private subproject/
125 assert_tag :tag => 'a', :content => /Issue of a private subproject/
126 end
126 end
127
127
128 def test_index_with_project_and_filter
128 def test_index_with_project_and_filter
129 get :index, :project_id => 1, :set_filter => 1
129 get :index, :project_id => 1, :set_filter => 1
130 assert_response :success
130 assert_response :success
131 assert_template 'index.rhtml'
131 assert_template 'index.rhtml'
132 assert_not_nil assigns(:issues)
132 assert_not_nil assigns(:issues)
133 end
133 end
134
134
135 def test_index_with_query
135 def test_index_with_query
136 get :index, :project_id => 1, :query_id => 5
136 get :index, :project_id => 1, :query_id => 5
137 assert_response :success
137 assert_response :success
138 assert_template 'index.rhtml'
138 assert_template 'index.rhtml'
139 assert_not_nil assigns(:issues)
139 assert_not_nil assigns(:issues)
140 assert_nil assigns(:issue_count_by_group)
140 assert_nil assigns(:issue_count_by_group)
141 end
141 end
142
142
143 def test_index_with_query_grouped_by_tracker
143 def test_index_with_query_grouped_by_tracker
144 get :index, :project_id => 1, :query_id => 6
144 get :index, :project_id => 1, :query_id => 6
145 assert_response :success
145 assert_response :success
146 assert_template 'index.rhtml'
146 assert_template 'index.rhtml'
147 assert_not_nil assigns(:issues)
147 assert_not_nil assigns(:issues)
148 assert_not_nil assigns(:issue_count_by_group)
148 assert_not_nil assigns(:issue_count_by_group)
149 end
149 end
150
150
151 def test_index_with_query_grouped_by_list_custom_field
151 def test_index_with_query_grouped_by_list_custom_field
152 get :index, :project_id => 1, :query_id => 9
152 get :index, :project_id => 1, :query_id => 9
153 assert_response :success
153 assert_response :success
154 assert_template 'index.rhtml'
154 assert_template 'index.rhtml'
155 assert_not_nil assigns(:issues)
155 assert_not_nil assigns(:issues)
156 assert_not_nil assigns(:issue_count_by_group)
156 assert_not_nil assigns(:issue_count_by_group)
157 end
157 end
158
158
159 def test_index_sort_by_field_not_included_in_columns
159 def test_index_sort_by_field_not_included_in_columns
160 Setting.issue_list_default_columns = %w(subject author)
160 Setting.issue_list_default_columns = %w(subject author)
161 get :index, :sort => 'tracker'
161 get :index, :sort => 'tracker'
162 end
162 end
163
163
164 def test_index_csv_with_project
164 def test_index_csv_with_project
165 Setting.default_language = 'en'
165 Setting.default_language = 'en'
166
166
167 get :index, :format => 'csv'
167 get :index, :format => 'csv'
168 assert_response :success
168 assert_response :success
169 assert_not_nil assigns(:issues)
169 assert_not_nil assigns(:issues)
170 assert_equal 'text/csv', @response.content_type
170 assert_equal 'text/csv', @response.content_type
171 assert @response.body.starts_with?("#,")
171 assert @response.body.starts_with?("#,")
172
172
173 get :index, :project_id => 1, :format => 'csv'
173 get :index, :project_id => 1, :format => 'csv'
174 assert_response :success
174 assert_response :success
175 assert_not_nil assigns(:issues)
175 assert_not_nil assigns(:issues)
176 assert_equal 'text/csv', @response.content_type
176 assert_equal 'text/csv', @response.content_type
177 end
177 end
178
178
179 def test_index_pdf
179 def test_index_pdf
180 get :index, :format => 'pdf'
180 get :index, :format => 'pdf'
181 assert_response :success
181 assert_response :success
182 assert_not_nil assigns(:issues)
182 assert_not_nil assigns(:issues)
183 assert_equal 'application/pdf', @response.content_type
183 assert_equal 'application/pdf', @response.content_type
184
184
185 get :index, :project_id => 1, :format => 'pdf'
185 get :index, :project_id => 1, :format => 'pdf'
186 assert_response :success
186 assert_response :success
187 assert_not_nil assigns(:issues)
187 assert_not_nil assigns(:issues)
188 assert_equal 'application/pdf', @response.content_type
188 assert_equal 'application/pdf', @response.content_type
189
189
190 get :index, :project_id => 1, :query_id => 6, :format => 'pdf'
190 get :index, :project_id => 1, :query_id => 6, :format => 'pdf'
191 assert_response :success
191 assert_response :success
192 assert_not_nil assigns(:issues)
192 assert_not_nil assigns(:issues)
193 assert_equal 'application/pdf', @response.content_type
193 assert_equal 'application/pdf', @response.content_type
194 end
194 end
195
195
196 def test_index_pdf_with_query_grouped_by_list_custom_field
196 def test_index_pdf_with_query_grouped_by_list_custom_field
197 get :index, :project_id => 1, :query_id => 9, :format => 'pdf'
197 get :index, :project_id => 1, :query_id => 9, :format => 'pdf'
198 assert_response :success
198 assert_response :success
199 assert_not_nil assigns(:issues)
199 assert_not_nil assigns(:issues)
200 assert_not_nil assigns(:issue_count_by_group)
200 assert_not_nil assigns(:issue_count_by_group)
201 assert_equal 'application/pdf', @response.content_type
201 assert_equal 'application/pdf', @response.content_type
202 end
202 end
203
203
204 def test_index_sort
204 def test_index_sort
205 get :index, :sort => 'tracker,id:desc'
205 get :index, :sort => 'tracker,id:desc'
206 assert_response :success
206 assert_response :success
207
207
208 sort_params = @request.session['issues_index_sort']
208 sort_params = @request.session['issues_index_sort']
209 assert sort_params.is_a?(String)
209 assert sort_params.is_a?(String)
210 assert_equal 'tracker,id:desc', sort_params
210 assert_equal 'tracker,id:desc', sort_params
211
211
212 issues = assigns(:issues)
212 issues = assigns(:issues)
213 assert_not_nil issues
213 assert_not_nil issues
214 assert !issues.empty?
214 assert !issues.empty?
215 assert_equal issues.sort {|a,b| a.tracker == b.tracker ? b.id <=> a.id : a.tracker <=> b.tracker }.collect(&:id), issues.collect(&:id)
215 assert_equal issues.sort {|a,b| a.tracker == b.tracker ? b.id <=> a.id : a.tracker <=> b.tracker }.collect(&:id), issues.collect(&:id)
216 end
216 end
217
217
218 def test_index_with_columns
218 def test_index_with_columns
219 columns = ['tracker', 'subject', 'assigned_to']
219 columns = ['tracker', 'subject', 'assigned_to']
220 get :index, :set_filter => 1, :query => { 'column_names' => columns}
220 get :index, :set_filter => 1, :query => { 'column_names' => columns}
221 assert_response :success
221 assert_response :success
222
222
223 # query should use specified columns
223 # query should use specified columns
224 query = assigns(:query)
224 query = assigns(:query)
225 assert_kind_of Query, query
225 assert_kind_of Query, query
226 assert_equal columns, query.column_names.map(&:to_s)
226 assert_equal columns, query.column_names.map(&:to_s)
227
227
228 # columns should be stored in session
228 # columns should be stored in session
229 assert_kind_of Hash, session[:query]
229 assert_kind_of Hash, session[:query]
230 assert_kind_of Array, session[:query][:column_names]
230 assert_kind_of Array, session[:query][:column_names]
231 assert_equal columns, session[:query][:column_names].map(&:to_s)
231 assert_equal columns, session[:query][:column_names].map(&:to_s)
232 end
232 end
233
233
234 def test_changes
234 def test_changes
235 get :changes, :project_id => 1
235 get :changes, :project_id => 1
236 assert_response :success
236 assert_response :success
237 assert_not_nil assigns(:journals)
237 assert_not_nil assigns(:journals)
238 assert_equal 'application/atom+xml', @response.content_type
238 assert_equal 'application/atom+xml', @response.content_type
239 end
239 end
240
240
241 def test_show_by_anonymous
241 def test_show_by_anonymous
242 get :show, :id => 1
242 get :show, :id => 1
243 assert_response :success
243 assert_response :success
244 assert_template 'show.rhtml'
244 assert_template 'show.rhtml'
245 assert_not_nil assigns(:issue)
245 assert_not_nil assigns(:issue)
246 assert_equal Issue.find(1), assigns(:issue)
246 assert_equal Issue.find(1), assigns(:issue)
247
247
248 # anonymous role is allowed to add a note
248 # anonymous role is allowed to add a note
249 assert_tag :tag => 'form',
249 assert_tag :tag => 'form',
250 :descendant => { :tag => 'fieldset',
250 :descendant => { :tag => 'fieldset',
251 :child => { :tag => 'legend',
251 :child => { :tag => 'legend',
252 :content => /Notes/ } }
252 :content => /Notes/ } }
253 end
253 end
254
254
255 def test_show_by_manager
255 def test_show_by_manager
256 @request.session[:user_id] = 2
256 @request.session[:user_id] = 2
257 get :show, :id => 1
257 get :show, :id => 1
258 assert_response :success
258 assert_response :success
259
259
260 assert_tag :tag => 'form',
260 assert_tag :tag => 'form',
261 :descendant => { :tag => 'fieldset',
261 :descendant => { :tag => 'fieldset',
262 :child => { :tag => 'legend',
262 :child => { :tag => 'legend',
263 :content => /Change properties/ } },
263 :content => /Change properties/ } },
264 :descendant => { :tag => 'fieldset',
264 :descendant => { :tag => 'fieldset',
265 :child => { :tag => 'legend',
265 :child => { :tag => 'legend',
266 :content => /Log time/ } },
266 :content => /Log time/ } },
267 :descendant => { :tag => 'fieldset',
267 :descendant => { :tag => 'fieldset',
268 :child => { :tag => 'legend',
268 :child => { :tag => 'legend',
269 :content => /Notes/ } }
269 :content => /Notes/ } }
270 end
270 end
271
271
272 def test_show_should_deny_anonymous_access_without_permission
272 def test_show_should_deny_anonymous_access_without_permission
273 Role.anonymous.remove_permission!(:view_issues)
273 Role.anonymous.remove_permission!(:view_issues)
274 get :show, :id => 1
274 get :show, :id => 1
275 assert_response :redirect
275 assert_response :redirect
276 end
276 end
277
277
278 def test_show_should_deny_non_member_access_without_permission
278 def test_show_should_deny_non_member_access_without_permission
279 Role.non_member.remove_permission!(:view_issues)
279 Role.non_member.remove_permission!(:view_issues)
280 @request.session[:user_id] = 9
280 @request.session[:user_id] = 9
281 get :show, :id => 1
281 get :show, :id => 1
282 assert_response 403
282 assert_response 403
283 end
283 end
284
284
285 def test_show_should_deny_member_access_without_permission
285 def test_show_should_deny_member_access_without_permission
286 Role.find(1).remove_permission!(:view_issues)
286 Role.find(1).remove_permission!(:view_issues)
287 @request.session[:user_id] = 2
287 @request.session[:user_id] = 2
288 get :show, :id => 1
288 get :show, :id => 1
289 assert_response 403
289 assert_response 403
290 end
290 end
291
291
292 def test_show_should_not_disclose_relations_to_invisible_issues
292 def test_show_should_not_disclose_relations_to_invisible_issues
293 Setting.cross_project_issue_relations = '1'
293 Setting.cross_project_issue_relations = '1'
294 IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(2), :relation_type => 'relates')
294 IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(2), :relation_type => 'relates')
295 # Relation to a private project issue
295 # Relation to a private project issue
296 IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(4), :relation_type => 'relates')
296 IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(4), :relation_type => 'relates')
297
297
298 get :show, :id => 1
298 get :show, :id => 1
299 assert_response :success
299 assert_response :success
300
300
301 assert_tag :div, :attributes => { :id => 'relations' },
301 assert_tag :div, :attributes => { :id => 'relations' },
302 :descendant => { :tag => 'a', :content => /#2$/ }
302 :descendant => { :tag => 'a', :content => /#2$/ }
303 assert_no_tag :div, :attributes => { :id => 'relations' },
303 assert_no_tag :div, :attributes => { :id => 'relations' },
304 :descendant => { :tag => 'a', :content => /#4$/ }
304 :descendant => { :tag => 'a', :content => /#4$/ }
305 end
305 end
306
306
307 def test_show_atom
307 def test_show_atom
308 get :show, :id => 2, :format => 'atom'
308 get :show, :id => 2, :format => 'atom'
309 assert_response :success
309 assert_response :success
310 assert_template 'changes.rxml'
310 assert_template 'changes.rxml'
311 # Inline image
311 # Inline image
312 assert_select 'content', :text => Regexp.new(Regexp.quote('http://test.host/attachments/download/10'))
312 assert_select 'content', :text => Regexp.new(Regexp.quote('http://test.host/attachments/download/10'))
313 end
313 end
314
314
315 def test_show_export_to_pdf
315 def test_show_export_to_pdf
316 get :show, :id => 3, :format => 'pdf'
316 get :show, :id => 3, :format => 'pdf'
317 assert_response :success
317 assert_response :success
318 assert_equal 'application/pdf', @response.content_type
318 assert_equal 'application/pdf', @response.content_type
319 assert @response.body.starts_with?('%PDF')
319 assert @response.body.starts_with?('%PDF')
320 assert_not_nil assigns(:issue)
320 assert_not_nil assigns(:issue)
321 end
321 end
322
322
323 def test_get_new
323 def test_get_new
324 @request.session[:user_id] = 2
324 @request.session[:user_id] = 2
325 get :new, :project_id => 1, :tracker_id => 1
325 get :new, :project_id => 1, :tracker_id => 1
326 assert_response :success
326 assert_response :success
327 assert_template 'new'
327 assert_template 'new'
328
328
329 assert_tag :tag => 'input', :attributes => { :name => 'issue[custom_field_values][2]',
329 assert_tag :tag => 'input', :attributes => { :name => 'issue[custom_field_values][2]',
330 :value => 'Default string' }
330 :value => 'Default string' }
331 end
331 end
332
332
333 def test_get_new_without_tracker_id
333 def test_get_new_without_tracker_id
334 @request.session[:user_id] = 2
334 @request.session[:user_id] = 2
335 get :new, :project_id => 1
335 get :new, :project_id => 1
336 assert_response :success
336 assert_response :success
337 assert_template 'new'
337 assert_template 'new'
338
338
339 issue = assigns(:issue)
339 issue = assigns(:issue)
340 assert_not_nil issue
340 assert_not_nil issue
341 assert_equal Project.find(1).trackers.first, issue.tracker
341 assert_equal Project.find(1).trackers.first, issue.tracker
342 end
342 end
343
343
344 def test_get_new_with_no_default_status_should_display_an_error
344 def test_get_new_with_no_default_status_should_display_an_error
345 @request.session[:user_id] = 2
345 @request.session[:user_id] = 2
346 IssueStatus.delete_all
346 IssueStatus.delete_all
347
347
348 get :new, :project_id => 1
348 get :new, :project_id => 1
349 assert_response 500
349 assert_response 500
350 assert_not_nil flash[:error]
350 assert_not_nil flash[:error]
351 assert_tag :tag => 'div', :attributes => { :class => /error/ },
351 assert_tag :tag => 'div', :attributes => { :class => /error/ },
352 :content => /No default issue/
352 :content => /No default issue/
353 end
353 end
354
354
355 def test_get_new_with_no_tracker_should_display_an_error
355 def test_get_new_with_no_tracker_should_display_an_error
356 @request.session[:user_id] = 2
356 @request.session[:user_id] = 2
357 Tracker.delete_all
357 Tracker.delete_all
358
358
359 get :new, :project_id => 1
359 get :new, :project_id => 1
360 assert_response 500
360 assert_response 500
361 assert_not_nil flash[:error]
361 assert_not_nil flash[:error]
362 assert_tag :tag => 'div', :attributes => { :class => /error/ },
362 assert_tag :tag => 'div', :attributes => { :class => /error/ },
363 :content => /No tracker/
363 :content => /No tracker/
364 end
364 end
365
365
366 def test_update_new_form
366 def test_update_new_form
367 @request.session[:user_id] = 2
367 @request.session[:user_id] = 2
368 xhr :post, :update_form, :project_id => 1,
368 xhr :post, :update_form, :project_id => 1,
369 :issue => {:tracker_id => 2,
369 :issue => {:tracker_id => 2,
370 :subject => 'This is the test_new issue',
370 :subject => 'This is the test_new issue',
371 :description => 'This is the description',
371 :description => 'This is the description',
372 :priority_id => 5}
372 :priority_id => 5}
373 assert_response :success
373 assert_response :success
374 assert_template 'attributes'
374 assert_template 'attributes'
375
375
376 issue = assigns(:issue)
376 issue = assigns(:issue)
377 assert_kind_of Issue, issue
377 assert_kind_of Issue, issue
378 assert_equal 1, issue.project_id
378 assert_equal 1, issue.project_id
379 assert_equal 2, issue.tracker_id
379 assert_equal 2, issue.tracker_id
380 assert_equal 'This is the test_new issue', issue.subject
380 assert_equal 'This is the test_new issue', issue.subject
381 end
381 end
382
382
383 def test_post_create
383 def test_post_create
384 @request.session[:user_id] = 2
384 @request.session[:user_id] = 2
385 assert_difference 'Issue.count' do
385 assert_difference 'Issue.count' do
386 post :create, :project_id => 1,
386 post :create, :project_id => 1,
387 :issue => {:tracker_id => 3,
387 :issue => {:tracker_id => 3,
388 :status_id => 2,
388 :status_id => 2,
389 :subject => 'This is the test_new issue',
389 :subject => 'This is the test_new issue',
390 :description => 'This is the description',
390 :description => 'This is the description',
391 :priority_id => 5,
391 :priority_id => 5,
392 :estimated_hours => '',
392 :estimated_hours => '',
393 :custom_field_values => {'2' => 'Value for field 2'}}
393 :custom_field_values => {'2' => 'Value for field 2'}}
394 end
394 end
395 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
395 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
396
396
397 issue = Issue.find_by_subject('This is the test_new issue')
397 issue = Issue.find_by_subject('This is the test_new issue')
398 assert_not_nil issue
398 assert_not_nil issue
399 assert_equal 2, issue.author_id
399 assert_equal 2, issue.author_id
400 assert_equal 3, issue.tracker_id
400 assert_equal 3, issue.tracker_id
401 assert_equal 2, issue.status_id
401 assert_equal 2, issue.status_id
402 assert_nil issue.estimated_hours
402 assert_nil issue.estimated_hours
403 v = issue.custom_values.find(:first, :conditions => {:custom_field_id => 2})
403 v = issue.custom_values.find(:first, :conditions => {:custom_field_id => 2})
404 assert_not_nil v
404 assert_not_nil v
405 assert_equal 'Value for field 2', v.value
405 assert_equal 'Value for field 2', v.value
406 end
406 end
407
407
408 def test_post_create_and_continue
408 def test_post_create_and_continue
409 @request.session[:user_id] = 2
409 @request.session[:user_id] = 2
410 post :create, :project_id => 1,
410 post :create, :project_id => 1,
411 :issue => {:tracker_id => 3,
411 :issue => {:tracker_id => 3,
412 :subject => 'This is first issue',
412 :subject => 'This is first issue',
413 :priority_id => 5},
413 :priority_id => 5},
414 :continue => ''
414 :continue => ''
415 assert_redirected_to :controller => 'issues', :action => 'new', :issue => {:tracker_id => 3}
415 assert_redirected_to :controller => 'issues', :action => 'new', :issue => {:tracker_id => 3}
416 end
416 end
417
417
418 def test_post_create_without_custom_fields_param
418 def test_post_create_without_custom_fields_param
419 @request.session[:user_id] = 2
419 @request.session[:user_id] = 2
420 assert_difference 'Issue.count' do
420 assert_difference 'Issue.count' do
421 post :create, :project_id => 1,
421 post :create, :project_id => 1,
422 :issue => {:tracker_id => 1,
422 :issue => {:tracker_id => 1,
423 :subject => 'This is the test_new issue',
423 :subject => 'This is the test_new issue',
424 :description => 'This is the description',
424 :description => 'This is the description',
425 :priority_id => 5}
425 :priority_id => 5}
426 end
426 end
427 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
427 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
428 end
428 end
429
429
430 def test_post_create_with_required_custom_field_and_without_custom_fields_param
430 def test_post_create_with_required_custom_field_and_without_custom_fields_param
431 field = IssueCustomField.find_by_name('Database')
431 field = IssueCustomField.find_by_name('Database')
432 field.update_attribute(:is_required, true)
432 field.update_attribute(:is_required, true)
433
433
434 @request.session[:user_id] = 2
434 @request.session[:user_id] = 2
435 post :create, :project_id => 1,
435 post :create, :project_id => 1,
436 :issue => {:tracker_id => 1,
436 :issue => {:tracker_id => 1,
437 :subject => 'This is the test_new issue',
437 :subject => 'This is the test_new issue',
438 :description => 'This is the description',
438 :description => 'This is the description',
439 :priority_id => 5}
439 :priority_id => 5}
440 assert_response :success
440 assert_response :success
441 assert_template 'new'
441 assert_template 'new'
442 issue = assigns(:issue)
442 issue = assigns(:issue)
443 assert_not_nil issue
443 assert_not_nil issue
444 assert_equal I18n.translate('activerecord.errors.messages.invalid'), issue.errors.on(:custom_values)
444 assert_equal I18n.translate('activerecord.errors.messages.invalid'), issue.errors.on(:custom_values)
445 end
445 end
446
446
447 def test_post_create_with_watchers
447 def test_post_create_with_watchers
448 @request.session[:user_id] = 2
448 @request.session[:user_id] = 2
449 ActionMailer::Base.deliveries.clear
449 ActionMailer::Base.deliveries.clear
450
450
451 assert_difference 'Watcher.count', 2 do
451 assert_difference 'Watcher.count', 2 do
452 post :create, :project_id => 1,
452 post :create, :project_id => 1,
453 :issue => {:tracker_id => 1,
453 :issue => {:tracker_id => 1,
454 :subject => 'This is a new issue with watchers',
454 :subject => 'This is a new issue with watchers',
455 :description => 'This is the description',
455 :description => 'This is the description',
456 :priority_id => 5,
456 :priority_id => 5,
457 :watcher_user_ids => ['2', '3']}
457 :watcher_user_ids => ['2', '3']}
458 end
458 end
459 issue = Issue.find_by_subject('This is a new issue with watchers')
459 issue = Issue.find_by_subject('This is a new issue with watchers')
460 assert_not_nil issue
460 assert_not_nil issue
461 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue
461 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue
462
462
463 # Watchers added
463 # Watchers added
464 assert_equal [2, 3], issue.watcher_user_ids.sort
464 assert_equal [2, 3], issue.watcher_user_ids.sort
465 assert issue.watched_by?(User.find(3))
465 assert issue.watched_by?(User.find(3))
466 # Watchers notified
466 # Watchers notified
467 mail = ActionMailer::Base.deliveries.last
467 mail = ActionMailer::Base.deliveries.last
468 assert_kind_of TMail::Mail, mail
468 assert_kind_of TMail::Mail, mail
469 assert [mail.bcc, mail.cc].flatten.include?(User.find(3).mail)
469 assert [mail.bcc, mail.cc].flatten.include?(User.find(3).mail)
470 end
470 end
471
471
472 def test_post_create_subissue
472 def test_post_create_subissue
473 @request.session[:user_id] = 2
473 @request.session[:user_id] = 2
474
474
475 assert_difference 'Issue.count' do
475 assert_difference 'Issue.count' do
476 post :create, :project_id => 1,
476 post :create, :project_id => 1,
477 :issue => {:tracker_id => 1,
477 :issue => {:tracker_id => 1,
478 :subject => 'This is a child issue',
478 :subject => 'This is a child issue',
479 :parent_issue_id => 2}
479 :parent_issue_id => 2}
480 end
480 end
481 issue = Issue.find_by_subject('This is a child issue')
481 issue = Issue.find_by_subject('This is a child issue')
482 assert_not_nil issue
482 assert_not_nil issue
483 assert_equal Issue.find(2), issue.parent
483 assert_equal Issue.find(2), issue.parent
484 end
484 end
485
485
486 def test_post_create_should_send_a_notification
486 def test_post_create_should_send_a_notification
487 ActionMailer::Base.deliveries.clear
487 ActionMailer::Base.deliveries.clear
488 @request.session[:user_id] = 2
488 @request.session[:user_id] = 2
489 assert_difference 'Issue.count' do
489 assert_difference 'Issue.count' do
490 post :create, :project_id => 1,
490 post :create, :project_id => 1,
491 :issue => {:tracker_id => 3,
491 :issue => {:tracker_id => 3,
492 :subject => 'This is the test_new issue',
492 :subject => 'This is the test_new issue',
493 :description => 'This is the description',
493 :description => 'This is the description',
494 :priority_id => 5,
494 :priority_id => 5,
495 :estimated_hours => '',
495 :estimated_hours => '',
496 :custom_field_values => {'2' => 'Value for field 2'}}
496 :custom_field_values => {'2' => 'Value for field 2'}}
497 end
497 end
498 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
498 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
499
499
500 assert_equal 1, ActionMailer::Base.deliveries.size
500 assert_equal 1, ActionMailer::Base.deliveries.size
501 end
501 end
502
502
503 def test_post_create_should_preserve_fields_values_on_validation_failure
503 def test_post_create_should_preserve_fields_values_on_validation_failure
504 @request.session[:user_id] = 2
504 @request.session[:user_id] = 2
505 post :create, :project_id => 1,
505 post :create, :project_id => 1,
506 :issue => {:tracker_id => 1,
506 :issue => {:tracker_id => 1,
507 # empty subject
507 # empty subject
508 :subject => '',
508 :subject => '',
509 :description => 'This is a description',
509 :description => 'This is a description',
510 :priority_id => 6,
510 :priority_id => 6,
511 :custom_field_values => {'1' => 'Oracle', '2' => 'Value for field 2'}}
511 :custom_field_values => {'1' => 'Oracle', '2' => 'Value for field 2'}}
512 assert_response :success
512 assert_response :success
513 assert_template 'new'
513 assert_template 'new'
514
514
515 assert_tag :textarea, :attributes => { :name => 'issue[description]' },
515 assert_tag :textarea, :attributes => { :name => 'issue[description]' },
516 :content => 'This is a description'
516 :content => 'This is a description'
517 assert_tag :select, :attributes => { :name => 'issue[priority_id]' },
517 assert_tag :select, :attributes => { :name => 'issue[priority_id]' },
518 :child => { :tag => 'option', :attributes => { :selected => 'selected',
518 :child => { :tag => 'option', :attributes => { :selected => 'selected',
519 :value => '6' },
519 :value => '6' },
520 :content => 'High' }
520 :content => 'High' }
521 # Custom fields
521 # Custom fields
522 assert_tag :select, :attributes => { :name => 'issue[custom_field_values][1]' },
522 assert_tag :select, :attributes => { :name => 'issue[custom_field_values][1]' },
523 :child => { :tag => 'option', :attributes => { :selected => 'selected',
523 :child => { :tag => 'option', :attributes => { :selected => 'selected',
524 :value => 'Oracle' },
524 :value => 'Oracle' },
525 :content => 'Oracle' }
525 :content => 'Oracle' }
526 assert_tag :input, :attributes => { :name => 'issue[custom_field_values][2]',
526 assert_tag :input, :attributes => { :name => 'issue[custom_field_values][2]',
527 :value => 'Value for field 2'}
527 :value => 'Value for field 2'}
528 end
528 end
529
529
530 def test_post_create_should_ignore_non_safe_attributes
530 def test_post_create_should_ignore_non_safe_attributes
531 @request.session[:user_id] = 2
531 @request.session[:user_id] = 2
532 assert_nothing_raised do
532 assert_nothing_raised do
533 post :create, :project_id => 1, :issue => { :tracker => "A param can not be a Tracker" }
533 post :create, :project_id => 1, :issue => { :tracker => "A param can not be a Tracker" }
534 end
534 end
535 end
535 end
536
536
537 context "without workflow privilege" do
537 context "without workflow privilege" do
538 setup do
538 setup do
539 Workflow.delete_all(["role_id = ?", Role.anonymous.id])
539 Workflow.delete_all(["role_id = ?", Role.anonymous.id])
540 Role.anonymous.add_permission! :add_issues
540 Role.anonymous.add_permission! :add_issues
541 end
541 end
542
542
543 context "#new" do
543 context "#new" do
544 should "propose default status only" do
544 should "propose default status only" do
545 get :new, :project_id => 1
545 get :new, :project_id => 1
546 assert_response :success
546 assert_response :success
547 assert_template 'new'
547 assert_template 'new'
548 assert_tag :tag => 'select',
548 assert_tag :tag => 'select',
549 :attributes => {:name => 'issue[status_id]'},
549 :attributes => {:name => 'issue[status_id]'},
550 :children => {:count => 1},
550 :children => {:count => 1},
551 :child => {:tag => 'option', :attributes => {:value => IssueStatus.default.id.to_s}}
551 :child => {:tag => 'option', :attributes => {:value => IssueStatus.default.id.to_s}}
552 end
552 end
553
553
554 should "accept default status" do
554 should "accept default status" do
555 assert_difference 'Issue.count' do
555 assert_difference 'Issue.count' do
556 post :create, :project_id => 1,
556 post :create, :project_id => 1,
557 :issue => {:tracker_id => 1,
557 :issue => {:tracker_id => 1,
558 :subject => 'This is an issue',
558 :subject => 'This is an issue',
559 :status_id => 1}
559 :status_id => 1}
560 end
560 end
561 issue = Issue.last(:order => 'id')
561 issue = Issue.last(:order => 'id')
562 assert_equal IssueStatus.default, issue.status
562 assert_equal IssueStatus.default, issue.status
563 end
563 end
564
564
565 should "ignore unauthorized status" do
565 should "ignore unauthorized status" do
566 assert_difference 'Issue.count' do
566 assert_difference 'Issue.count' do
567 post :create, :project_id => 1,
567 post :create, :project_id => 1,
568 :issue => {:tracker_id => 1,
568 :issue => {:tracker_id => 1,
569 :subject => 'This is an issue',
569 :subject => 'This is an issue',
570 :status_id => 3}
570 :status_id => 3}
571 end
571 end
572 issue = Issue.last(:order => 'id')
572 issue = Issue.last(:order => 'id')
573 assert_equal IssueStatus.default, issue.status
573 assert_equal IssueStatus.default, issue.status
574 end
574 end
575 end
575 end
576 end
576 end
577
577
578 def test_copy_issue
578 def test_copy_issue
579 @request.session[:user_id] = 2
579 @request.session[:user_id] = 2
580 get :new, :project_id => 1, :copy_from => 1
580 get :new, :project_id => 1, :copy_from => 1
581 assert_template 'new'
581 assert_template 'new'
582 assert_not_nil assigns(:issue)
582 assert_not_nil assigns(:issue)
583 orig = Issue.find(1)
583 orig = Issue.find(1)
584 assert_equal orig.subject, assigns(:issue).subject
584 assert_equal orig.subject, assigns(:issue).subject
585 end
585 end
586
586
587 def test_get_edit
587 def test_get_edit
588 @request.session[:user_id] = 2
588 @request.session[:user_id] = 2
589 get :edit, :id => 1
589 get :edit, :id => 1
590 assert_response :success
590 assert_response :success
591 assert_template 'edit'
591 assert_template 'edit'
592 assert_not_nil assigns(:issue)
592 assert_not_nil assigns(:issue)
593 assert_equal Issue.find(1), assigns(:issue)
593 assert_equal Issue.find(1), assigns(:issue)
594 end
594 end
595
595
596 def test_get_edit_with_params
596 def test_get_edit_with_params
597 @request.session[:user_id] = 2
597 @request.session[:user_id] = 2
598 get :edit, :id => 1, :issue => { :status_id => 5, :priority_id => 7 }
598 get :edit, :id => 1, :issue => { :status_id => 5, :priority_id => 7 }
599 assert_response :success
599 assert_response :success
600 assert_template 'edit'
600 assert_template 'edit'
601
601
602 issue = assigns(:issue)
602 issue = assigns(:issue)
603 assert_not_nil issue
603 assert_not_nil issue
604
604
605 assert_equal 5, issue.status_id
605 assert_equal 5, issue.status_id
606 assert_tag :select, :attributes => { :name => 'issue[status_id]' },
606 assert_tag :select, :attributes => { :name => 'issue[status_id]' },
607 :child => { :tag => 'option',
607 :child => { :tag => 'option',
608 :content => 'Closed',
608 :content => 'Closed',
609 :attributes => { :selected => 'selected' } }
609 :attributes => { :selected => 'selected' } }
610
610
611 assert_equal 7, issue.priority_id
611 assert_equal 7, issue.priority_id
612 assert_tag :select, :attributes => { :name => 'issue[priority_id]' },
612 assert_tag :select, :attributes => { :name => 'issue[priority_id]' },
613 :child => { :tag => 'option',
613 :child => { :tag => 'option',
614 :content => 'Urgent',
614 :content => 'Urgent',
615 :attributes => { :selected => 'selected' } }
615 :attributes => { :selected => 'selected' } }
616 end
616 end
617
617
618 def test_update_edit_form
618 def test_update_edit_form
619 @request.session[:user_id] = 2
619 @request.session[:user_id] = 2
620 xhr :post, :update_form, :project_id => 1,
620 xhr :post, :update_form, :project_id => 1,
621 :id => 1,
621 :id => 1,
622 :issue => {:tracker_id => 2,
622 :issue => {:tracker_id => 2,
623 :subject => 'This is the test_new issue',
623 :subject => 'This is the test_new issue',
624 :description => 'This is the description',
624 :description => 'This is the description',
625 :priority_id => 5}
625 :priority_id => 5}
626 assert_response :success
626 assert_response :success
627 assert_template 'attributes'
627 assert_template 'attributes'
628
628
629 issue = assigns(:issue)
629 issue = assigns(:issue)
630 assert_kind_of Issue, issue
630 assert_kind_of Issue, issue
631 assert_equal 1, issue.id
631 assert_equal 1, issue.id
632 assert_equal 1, issue.project_id
632 assert_equal 1, issue.project_id
633 assert_equal 2, issue.tracker_id
633 assert_equal 2, issue.tracker_id
634 assert_equal 'This is the test_new issue', issue.subject
634 assert_equal 'This is the test_new issue', issue.subject
635 end
635 end
636
636
637 def test_update_using_invalid_http_verbs
637 def test_update_using_invalid_http_verbs
638 @request.session[:user_id] = 2
638 @request.session[:user_id] = 2
639 subject = 'Updated by an invalid http verb'
639 subject = 'Updated by an invalid http verb'
640
640
641 get :update, :id => 1, :issue => {:subject => subject}
641 get :update, :id => 1, :issue => {:subject => subject}
642 assert_not_equal subject, Issue.find(1).subject
642 assert_not_equal subject, Issue.find(1).subject
643
643
644 post :update, :id => 1, :issue => {:subject => subject}
644 post :update, :id => 1, :issue => {:subject => subject}
645 assert_not_equal subject, Issue.find(1).subject
645 assert_not_equal subject, Issue.find(1).subject
646
646
647 delete :update, :id => 1, :issue => {:subject => subject}
647 delete :update, :id => 1, :issue => {:subject => subject}
648 assert_not_equal subject, Issue.find(1).subject
648 assert_not_equal subject, Issue.find(1).subject
649 end
649 end
650
650
651 def test_put_update_without_custom_fields_param
651 def test_put_update_without_custom_fields_param
652 @request.session[:user_id] = 2
652 @request.session[:user_id] = 2
653 ActionMailer::Base.deliveries.clear
653 ActionMailer::Base.deliveries.clear
654
654
655 issue = Issue.find(1)
655 issue = Issue.find(1)
656 assert_equal '125', issue.custom_value_for(2).value
656 assert_equal '125', issue.custom_value_for(2).value
657 old_subject = issue.subject
657 old_subject = issue.subject
658 new_subject = 'Subject modified by IssuesControllerTest#test_post_edit'
658 new_subject = 'Subject modified by IssuesControllerTest#test_post_edit'
659
659
660 assert_difference('Journal.count') do
660 assert_difference('Journal.count') do
661 assert_difference('JournalDetail.count', 2) do
661 assert_difference('JournalDetail.count', 2) do
662 put :update, :id => 1, :issue => {:subject => new_subject,
662 put :update, :id => 1, :issue => {:subject => new_subject,
663 :priority_id => '6',
663 :priority_id => '6',
664 :category_id => '1' # no change
664 :category_id => '1' # no change
665 }
665 }
666 end
666 end
667 end
667 end
668 assert_redirected_to :action => 'show', :id => '1'
668 assert_redirected_to :action => 'show', :id => '1'
669 issue.reload
669 issue.reload
670 assert_equal new_subject, issue.subject
670 assert_equal new_subject, issue.subject
671 # Make sure custom fields were not cleared
671 # Make sure custom fields were not cleared
672 assert_equal '125', issue.custom_value_for(2).value
672 assert_equal '125', issue.custom_value_for(2).value
673
673
674 mail = ActionMailer::Base.deliveries.last
674 mail = ActionMailer::Base.deliveries.last
675 assert_kind_of TMail::Mail, mail
675 assert_kind_of TMail::Mail, mail
676 assert mail.subject.starts_with?("[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}]")
676 assert mail.subject.starts_with?("[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}]")
677 assert mail.body.include?("Subject changed from #{old_subject} to #{new_subject}")
677 assert mail.body.include?("Subject changed from #{old_subject} to #{new_subject}")
678 end
678 end
679
679
680 def test_put_update_with_custom_field_change
680 def test_put_update_with_custom_field_change
681 @request.session[:user_id] = 2
681 @request.session[:user_id] = 2
682 issue = Issue.find(1)
682 issue = Issue.find(1)
683 assert_equal '125', issue.custom_value_for(2).value
683 assert_equal '125', issue.custom_value_for(2).value
684
684
685 assert_difference('Journal.count') do
685 assert_difference('Journal.count') do
686 assert_difference('JournalDetail.count', 3) do
686 assert_difference('JournalDetail.count', 3) do
687 put :update, :id => 1, :issue => {:subject => 'Custom field change',
687 put :update, :id => 1, :issue => {:subject => 'Custom field change',
688 :priority_id => '6',
688 :priority_id => '6',
689 :category_id => '1', # no change
689 :category_id => '1', # no change
690 :custom_field_values => { '2' => 'New custom value' }
690 :custom_field_values => { '2' => 'New custom value' }
691 }
691 }
692 end
692 end
693 end
693 end
694 assert_redirected_to :action => 'show', :id => '1'
694 assert_redirected_to :action => 'show', :id => '1'
695 issue.reload
695 issue.reload
696 assert_equal 'New custom value', issue.custom_value_for(2).value
696 assert_equal 'New custom value', issue.custom_value_for(2).value
697
697
698 mail = ActionMailer::Base.deliveries.last
698 mail = ActionMailer::Base.deliveries.last
699 assert_kind_of TMail::Mail, mail
699 assert_kind_of TMail::Mail, mail
700 assert mail.body.include?("Searchable field changed from 125 to New custom value")
700 assert mail.body.include?("Searchable field changed from 125 to New custom value")
701 end
701 end
702
702
703 def test_put_update_with_status_and_assignee_change
703 def test_put_update_with_status_and_assignee_change
704 issue = Issue.find(1)
704 issue = Issue.find(1)
705 assert_equal 1, issue.status_id
705 assert_equal 1, issue.status_id
706 @request.session[:user_id] = 2
706 @request.session[:user_id] = 2
707 assert_difference('TimeEntry.count', 0) do
707 assert_difference('TimeEntry.count', 0) do
708 put :update,
708 put :update,
709 :id => 1,
709 :id => 1,
710 :issue => { :status_id => 2, :assigned_to_id => 3 },
710 :issue => { :status_id => 2, :assigned_to_id => 3 },
711 :notes => 'Assigned to dlopper',
711 :notes => 'Assigned to dlopper',
712 :time_entry => { :hours => '', :comments => '', :activity_id => TimeEntryActivity.first }
712 :time_entry => { :hours => '', :comments => '', :activity_id => TimeEntryActivity.first }
713 end
713 end
714 assert_redirected_to :action => 'show', :id => '1'
714 assert_redirected_to :action => 'show', :id => '1'
715 issue.reload
715 issue.reload
716 assert_equal 2, issue.status_id
716 assert_equal 2, issue.status_id
717 j = Journal.find(:first, :order => 'id DESC')
717 j = Journal.find(:first, :order => 'id DESC')
718 assert_equal 'Assigned to dlopper', j.notes
718 assert_equal 'Assigned to dlopper', j.notes
719 assert_equal 2, j.details.size
719 assert_equal 2, j.details.size
720
720
721 mail = ActionMailer::Base.deliveries.last
721 mail = ActionMailer::Base.deliveries.last
722 assert mail.body.include?("Status changed from New to Assigned")
722 assert mail.body.include?("Status changed from New to Assigned")
723 # subject should contain the new status
723 # subject should contain the new status
724 assert mail.subject.include?("(#{ IssueStatus.find(2).name })")
724 assert mail.subject.include?("(#{ IssueStatus.find(2).name })")
725 end
725 end
726
726
727 def test_put_update_with_note_only
727 def test_put_update_with_note_only
728 notes = 'Note added by IssuesControllerTest#test_update_with_note_only'
728 notes = 'Note added by IssuesControllerTest#test_update_with_note_only'
729 # anonymous user
729 # anonymous user
730 put :update,
730 put :update,
731 :id => 1,
731 :id => 1,
732 :notes => notes
732 :notes => notes
733 assert_redirected_to :action => 'show', :id => '1'
733 assert_redirected_to :action => 'show', :id => '1'
734 j = Journal.find(:first, :order => 'id DESC')
734 j = Journal.find(:first, :order => 'id DESC')
735 assert_equal notes, j.notes
735 assert_equal notes, j.notes
736 assert_equal 0, j.details.size
736 assert_equal 0, j.details.size
737 assert_equal User.anonymous, j.user
737 assert_equal User.anonymous, j.user
738
738
739 mail = ActionMailer::Base.deliveries.last
739 mail = ActionMailer::Base.deliveries.last
740 assert mail.body.include?(notes)
740 assert mail.body.include?(notes)
741 end
741 end
742
742
743 def test_put_update_with_note_and_spent_time
743 def test_put_update_with_note_and_spent_time
744 @request.session[:user_id] = 2
744 @request.session[:user_id] = 2
745 spent_hours_before = Issue.find(1).spent_hours
745 spent_hours_before = Issue.find(1).spent_hours
746 assert_difference('TimeEntry.count') do
746 assert_difference('TimeEntry.count') do
747 put :update,
747 put :update,
748 :id => 1,
748 :id => 1,
749 :notes => '2.5 hours added',
749 :notes => '2.5 hours added',
750 :time_entry => { :hours => '2.5', :comments => 'test_put_update_with_note_and_spent_time', :activity_id => TimeEntryActivity.first.id }
750 :time_entry => { :hours => '2.5', :comments => 'test_put_update_with_note_and_spent_time', :activity_id => TimeEntryActivity.first.id }
751 end
751 end
752 assert_redirected_to :action => 'show', :id => '1'
752 assert_redirected_to :action => 'show', :id => '1'
753
753
754 issue = Issue.find(1)
754 issue = Issue.find(1)
755
755
756 j = Journal.find(:first, :order => 'id DESC')
756 j = Journal.find(:first, :order => 'id DESC')
757 assert_equal '2.5 hours added', j.notes
757 assert_equal '2.5 hours added', j.notes
758 assert_equal 0, j.details.size
758 assert_equal 0, j.details.size
759
759
760 t = issue.time_entries.find_by_comments('test_put_update_with_note_and_spent_time')
760 t = issue.time_entries.find_by_comments('test_put_update_with_note_and_spent_time')
761 assert_not_nil t
761 assert_not_nil t
762 assert_equal 2.5, t.hours
762 assert_equal 2.5, t.hours
763 assert_equal spent_hours_before + 2.5, issue.spent_hours
763 assert_equal spent_hours_before + 2.5, issue.spent_hours
764 end
764 end
765
765
766 def test_put_update_with_attachment_only
766 def test_put_update_with_attachment_only
767 set_tmp_attachments_directory
767 set_tmp_attachments_directory
768
768
769 # Delete all fixtured journals, a race condition can occur causing the wrong
769 # Delete all fixtured journals, a race condition can occur causing the wrong
770 # journal to get fetched in the next find.
770 # journal to get fetched in the next find.
771 Journal.delete_all
771 Journal.delete_all
772
772
773 # anonymous user
773 # anonymous user
774 put :update,
774 put :update,
775 :id => 1,
775 :id => 1,
776 :notes => '',
776 :notes => '',
777 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}}
777 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}}
778 assert_redirected_to :action => 'show', :id => '1'
778 assert_redirected_to :action => 'show', :id => '1'
779 j = Issue.find(1).journals.find(:first, :order => 'id DESC')
779 j = Issue.find(1).journals.find(:first, :order => 'id DESC')
780 assert j.notes.blank?
780 assert j.notes.blank?
781 assert_equal 1, j.details.size
781 assert_equal 1, j.details.size
782 assert_equal 'testfile.txt', j.details.first.value
782 assert_equal 'testfile.txt', j.details.first.value
783 assert_equal User.anonymous, j.user
783 assert_equal User.anonymous, j.user
784
784
785 mail = ActionMailer::Base.deliveries.last
785 mail = ActionMailer::Base.deliveries.last
786 assert mail.body.include?('testfile.txt')
786 assert mail.body.include?('testfile.txt')
787 end
787 end
788
788
789 def test_put_update_with_attachment_that_fails_to_save
789 def test_put_update_with_attachment_that_fails_to_save
790 set_tmp_attachments_directory
790 set_tmp_attachments_directory
791
791
792 # Delete all fixtured journals, a race condition can occur causing the wrong
792 # Delete all fixtured journals, a race condition can occur causing the wrong
793 # journal to get fetched in the next find.
793 # journal to get fetched in the next find.
794 Journal.delete_all
794 Journal.delete_all
795
795
796 # Mock out the unsaved attachment
796 # Mock out the unsaved attachment
797 Attachment.any_instance.stubs(:create).returns(Attachment.new)
797 Attachment.any_instance.stubs(:create).returns(Attachment.new)
798
798
799 # anonymous user
799 # anonymous user
800 put :update,
800 put :update,
801 :id => 1,
801 :id => 1,
802 :notes => '',
802 :notes => '',
803 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}}
803 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}}
804 assert_redirected_to :action => 'show', :id => '1'
804 assert_redirected_to :action => 'show', :id => '1'
805 assert_equal '1 file(s) could not be saved.', flash[:warning]
805 assert_equal '1 file(s) could not be saved.', flash[:warning]
806
806
807 end if Object.const_defined?(:Mocha)
807 end if Object.const_defined?(:Mocha)
808
808
809 def test_put_update_with_no_change
809 def test_put_update_with_no_change
810 issue = Issue.find(1)
810 issue = Issue.find(1)
811 issue.journals.clear
811 issue.journals.clear
812 ActionMailer::Base.deliveries.clear
812 ActionMailer::Base.deliveries.clear
813
813
814 put :update,
814 put :update,
815 :id => 1,
815 :id => 1,
816 :notes => ''
816 :notes => ''
817 assert_redirected_to :action => 'show', :id => '1'
817 assert_redirected_to :action => 'show', :id => '1'
818
818
819 issue.reload
819 issue.reload
820 assert issue.journals.empty?
820 assert issue.journals.empty?
821 # No email should be sent
821 # No email should be sent
822 assert ActionMailer::Base.deliveries.empty?
822 assert ActionMailer::Base.deliveries.empty?
823 end
823 end
824
824
825 def test_put_update_should_send_a_notification
825 def test_put_update_should_send_a_notification
826 @request.session[:user_id] = 2
826 @request.session[:user_id] = 2
827 ActionMailer::Base.deliveries.clear
827 ActionMailer::Base.deliveries.clear
828 issue = Issue.find(1)
828 issue = Issue.find(1)
829 old_subject = issue.subject
829 old_subject = issue.subject
830 new_subject = 'Subject modified by IssuesControllerTest#test_post_edit'
830 new_subject = 'Subject modified by IssuesControllerTest#test_post_edit'
831
831
832 put :update, :id => 1, :issue => {:subject => new_subject,
832 put :update, :id => 1, :issue => {:subject => new_subject,
833 :priority_id => '6',
833 :priority_id => '6',
834 :category_id => '1' # no change
834 :category_id => '1' # no change
835 }
835 }
836 assert_equal 1, ActionMailer::Base.deliveries.size
836 assert_equal 1, ActionMailer::Base.deliveries.size
837 end
837 end
838
838
839 def test_put_update_with_invalid_spent_time
839 def test_put_update_with_invalid_spent_time
840 @request.session[:user_id] = 2
840 @request.session[:user_id] = 2
841 notes = 'Note added by IssuesControllerTest#test_post_edit_with_invalid_spent_time'
841 notes = 'Note added by IssuesControllerTest#test_post_edit_with_invalid_spent_time'
842
842
843 assert_no_difference('Journal.count') do
843 assert_no_difference('Journal.count') do
844 put :update,
844 put :update,
845 :id => 1,
845 :id => 1,
846 :notes => notes,
846 :notes => notes,
847 :time_entry => {"comments"=>"", "activity_id"=>"", "hours"=>"2z"}
847 :time_entry => {"comments"=>"", "activity_id"=>"", "hours"=>"2z"}
848 end
848 end
849 assert_response :success
849 assert_response :success
850 assert_template 'edit'
850 assert_template 'edit'
851
851
852 assert_tag :textarea, :attributes => { :name => 'notes' },
852 assert_tag :textarea, :attributes => { :name => 'notes' },
853 :content => notes
853 :content => notes
854 assert_tag :input, :attributes => { :name => 'time_entry[hours]', :value => "2z" }
854 assert_tag :input, :attributes => { :name => 'time_entry[hours]', :value => "2z" }
855 end
855 end
856
856
857 def test_put_update_should_allow_fixed_version_to_be_set_to_a_subproject
857 def test_put_update_should_allow_fixed_version_to_be_set_to_a_subproject
858 issue = Issue.find(2)
858 issue = Issue.find(2)
859 @request.session[:user_id] = 2
859 @request.session[:user_id] = 2
860
860
861 put :update,
861 put :update,
862 :id => issue.id,
862 :id => issue.id,
863 :issue => {
863 :issue => {
864 :fixed_version_id => 4
864 :fixed_version_id => 4
865 }
865 }
866
866
867 assert_response :redirect
867 assert_response :redirect
868 issue.reload
868 issue.reload
869 assert_equal 4, issue.fixed_version_id
869 assert_equal 4, issue.fixed_version_id
870 assert_not_equal issue.project_id, issue.fixed_version.project_id
870 assert_not_equal issue.project_id, issue.fixed_version.project_id
871 end
871 end
872
872
873 def test_put_update_should_redirect_back_using_the_back_url_parameter
873 def test_put_update_should_redirect_back_using_the_back_url_parameter
874 issue = Issue.find(2)
874 issue = Issue.find(2)
875 @request.session[:user_id] = 2
875 @request.session[:user_id] = 2
876
876
877 put :update,
877 put :update,
878 :id => issue.id,
878 :id => issue.id,
879 :issue => {
879 :issue => {
880 :fixed_version_id => 4
880 :fixed_version_id => 4
881 },
881 },
882 :back_url => '/issues'
882 :back_url => '/issues'
883
883
884 assert_response :redirect
884 assert_response :redirect
885 assert_redirected_to '/issues'
885 assert_redirected_to '/issues'
886 end
886 end
887
887
888 def test_put_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
888 def test_put_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
889 issue = Issue.find(2)
889 issue = Issue.find(2)
890 @request.session[:user_id] = 2
890 @request.session[:user_id] = 2
891
891
892 put :update,
892 put :update,
893 :id => issue.id,
893 :id => issue.id,
894 :issue => {
894 :issue => {
895 :fixed_version_id => 4
895 :fixed_version_id => 4
896 },
896 },
897 :back_url => 'http://google.com'
897 :back_url => 'http://google.com'
898
898
899 assert_response :redirect
899 assert_response :redirect
900 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue.id
900 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue.id
901 end
901 end
902
902
903 def test_get_bulk_edit
903 def test_get_bulk_edit
904 @request.session[:user_id] = 2
904 @request.session[:user_id] = 2
905 get :bulk_edit, :ids => [1, 2]
905 get :bulk_edit, :ids => [1, 2]
906 assert_response :success
906 assert_response :success
907 assert_template 'bulk_edit'
907 assert_template 'bulk_edit'
908
908
909 # Project specific custom field, date type
909 # Project specific custom field, date type
910 field = CustomField.find(9)
910 field = CustomField.find(9)
911 assert !field.is_for_all?
911 assert !field.is_for_all?
912 assert_equal 'date', field.field_format
912 assert_equal 'date', field.field_format
913 assert_tag :input, :attributes => {:name => 'issue[custom_field_values][9]'}
913 assert_tag :input, :attributes => {:name => 'issue[custom_field_values][9]'}
914
914
915 # System wide custom field
915 # System wide custom field
916 assert CustomField.find(1).is_for_all?
916 assert CustomField.find(1).is_for_all?
917 assert_tag :select, :attributes => {:name => 'issue[custom_field_values][1]'}
917 assert_tag :select, :attributes => {:name => 'issue[custom_field_values][1]'}
918 end
918 end
919
919
920 def test_bulk_edit
920 def test_bulk_edit
921 @request.session[:user_id] = 2
921 @request.session[:user_id] = 2
922 # update issues priority
922 # update issues priority
923 post :bulk_edit, :ids => [1, 2], :notes => 'Bulk editing',
923 post :bulk_edit, :ids => [1, 2], :notes => 'Bulk editing',
924 :issue => {:priority_id => 7,
924 :issue => {:priority_id => 7,
925 :assigned_to_id => '',
925 :assigned_to_id => '',
926 :custom_field_values => {'2' => ''}}
926 :custom_field_values => {'2' => ''}}
927
927
928 assert_response 302
928 assert_response 302
929 # check that the issues were updated
929 # check that the issues were updated
930 assert_equal [7, 7], Issue.find_all_by_id([1, 2]).collect {|i| i.priority.id}
930 assert_equal [7, 7], Issue.find_all_by_id([1, 2]).collect {|i| i.priority.id}
931
931
932 issue = Issue.find(1)
932 issue = Issue.find(1)
933 journal = issue.journals.find(:first, :order => 'created_on DESC')
933 journal = issue.journals.find(:first, :order => 'created_on DESC')
934 assert_equal '125', issue.custom_value_for(2).value
934 assert_equal '125', issue.custom_value_for(2).value
935 assert_equal 'Bulk editing', journal.notes
935 assert_equal 'Bulk editing', journal.notes
936 assert_equal 1, journal.details.size
936 assert_equal 1, journal.details.size
937 end
937 end
938
938
939 def test_bullk_edit_should_send_a_notification
939 def test_bullk_edit_should_send_a_notification
940 @request.session[:user_id] = 2
940 @request.session[:user_id] = 2
941 ActionMailer::Base.deliveries.clear
941 ActionMailer::Base.deliveries.clear
942 post(:bulk_edit,
942 post(:bulk_edit,
943 {
943 {
944 :ids => [1, 2],
944 :ids => [1, 2],
945 :notes => 'Bulk editing',
945 :notes => 'Bulk editing',
946 :issue => {
946 :issue => {
947 :priority_id => 7,
947 :priority_id => 7,
948 :assigned_to_id => '',
948 :assigned_to_id => '',
949 :custom_field_values => {'2' => ''}
949 :custom_field_values => {'2' => ''}
950 }
950 }
951 })
951 })
952
952
953 assert_response 302
953 assert_response 302
954 assert_equal 2, ActionMailer::Base.deliveries.size
954 assert_equal 2, ActionMailer::Base.deliveries.size
955 end
955 end
956
956
957 def test_bulk_edit_status
957 def test_bulk_edit_status
958 @request.session[:user_id] = 2
958 @request.session[:user_id] = 2
959 # update issues priority
959 # update issues priority
960 post :bulk_edit, :ids => [1, 2], :notes => 'Bulk editing status',
960 post :bulk_edit, :ids => [1, 2], :notes => 'Bulk editing status',
961 :issue => {:priority_id => '',
961 :issue => {:priority_id => '',
962 :assigned_to_id => '',
962 :assigned_to_id => '',
963 :status_id => '5'}
963 :status_id => '5'}
964
964
965 assert_response 302
965 assert_response 302
966 issue = Issue.find(1)
966 issue = Issue.find(1)
967 assert issue.closed?
967 assert issue.closed?
968 end
968 end
969
969
970 def test_bulk_edit_custom_field
970 def test_bulk_edit_custom_field
971 @request.session[:user_id] = 2
971 @request.session[:user_id] = 2
972 # update issues priority
972 # update issues priority
973 post :bulk_edit, :ids => [1, 2], :notes => 'Bulk editing custom field',
973 post :bulk_edit, :ids => [1, 2], :notes => 'Bulk editing custom field',
974 :issue => {:priority_id => '',
974 :issue => {:priority_id => '',
975 :assigned_to_id => '',
975 :assigned_to_id => '',
976 :custom_field_values => {'2' => '777'}}
976 :custom_field_values => {'2' => '777'}}
977
977
978 assert_response 302
978 assert_response 302
979
979
980 issue = Issue.find(1)
980 issue = Issue.find(1)
981 journal = issue.journals.find(:first, :order => 'created_on DESC')
981 journal = issue.journals.find(:first, :order => 'created_on DESC')
982 assert_equal '777', issue.custom_value_for(2).value
982 assert_equal '777', issue.custom_value_for(2).value
983 assert_equal 1, journal.details.size
983 assert_equal 1, journal.details.size
984 assert_equal '125', journal.details.first.old_value
984 assert_equal '125', journal.details.first.old_value
985 assert_equal '777', journal.details.first.value
985 assert_equal '777', journal.details.first.value
986 end
986 end
987
987
988 def test_bulk_unassign
988 def test_bulk_unassign
989 assert_not_nil Issue.find(2).assigned_to
989 assert_not_nil Issue.find(2).assigned_to
990 @request.session[:user_id] = 2
990 @request.session[:user_id] = 2
991 # unassign issues
991 # unassign issues
992 post :bulk_edit, :ids => [1, 2], :notes => 'Bulk unassigning', :issue => {:assigned_to_id => 'none'}
992 post :bulk_edit, :ids => [1, 2], :notes => 'Bulk unassigning', :issue => {:assigned_to_id => 'none'}
993 assert_response 302
993 assert_response 302
994 # check that the issues were updated
994 # check that the issues were updated
995 assert_nil Issue.find(2).assigned_to
995 assert_nil Issue.find(2).assigned_to
996 end
996 end
997
997
998 def test_post_bulk_edit_should_allow_fixed_version_to_be_set_to_a_subproject
998 def test_post_bulk_edit_should_allow_fixed_version_to_be_set_to_a_subproject
999 @request.session[:user_id] = 2
999 @request.session[:user_id] = 2
1000
1000
1001 post :bulk_edit, :ids => [1,2], :issue => {:fixed_version_id => 4}
1001 post :bulk_edit, :ids => [1,2], :issue => {:fixed_version_id => 4}
1002
1002
1003 assert_response :redirect
1003 assert_response :redirect
1004 issues = Issue.find([1,2])
1004 issues = Issue.find([1,2])
1005 issues.each do |issue|
1005 issues.each do |issue|
1006 assert_equal 4, issue.fixed_version_id
1006 assert_equal 4, issue.fixed_version_id
1007 assert_not_equal issue.project_id, issue.fixed_version.project_id
1007 assert_not_equal issue.project_id, issue.fixed_version.project_id
1008 end
1008 end
1009 end
1009 end
1010
1010
1011 def test_post_bulk_edit_should_redirect_back_using_the_back_url_parameter
1011 def test_post_bulk_edit_should_redirect_back_using_the_back_url_parameter
1012 @request.session[:user_id] = 2
1012 @request.session[:user_id] = 2
1013 post :bulk_edit, :ids => [1,2], :back_url => '/issues'
1013 post :bulk_edit, :ids => [1,2], :back_url => '/issues'
1014
1014
1015 assert_response :redirect
1015 assert_response :redirect
1016 assert_redirected_to '/issues'
1016 assert_redirected_to '/issues'
1017 end
1017 end
1018
1018
1019 def test_post_bulk_edit_should_not_redirect_back_using_the_back_url_parameter_off_the_host
1019 def test_post_bulk_edit_should_not_redirect_back_using_the_back_url_parameter_off_the_host
1020 @request.session[:user_id] = 2
1020 @request.session[:user_id] = 2
1021 post :bulk_edit, :ids => [1,2], :back_url => 'http://google.com'
1021 post :bulk_edit, :ids => [1,2], :back_url => 'http://google.com'
1022
1022
1023 assert_response :redirect
1023 assert_response :redirect
1024 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => Project.find(1).identifier
1024 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => Project.find(1).identifier
1025 end
1025 end
1026
1026
1027 def test_context_menu_one_issue
1028 @request.session[:user_id] = 2
1029 get :context_menu, :ids => [1]
1030 assert_response :success
1031 assert_template 'context_menu'
1032 assert_tag :tag => 'a', :content => 'Edit',
1033 :attributes => { :href => '/issues/1/edit',
1034 :class => 'icon-edit' }
1035 assert_tag :tag => 'a', :content => 'Closed',
1036 :attributes => { :href => '/issues/1/edit?issue%5Bstatus_id%5D=5',
1037 :class => '' }
1038 assert_tag :tag => 'a', :content => 'Immediate',
1039 :attributes => { :href => '/issues/bulk_edit?ids%5B%5D=1&amp;issue%5Bpriority_id%5D=8',
1040 :class => '' }
1041 # Versions
1042 assert_tag :tag => 'a', :content => '2.0',
1043 :attributes => { :href => '/issues/bulk_edit?ids%5B%5D=1&amp;issue%5Bfixed_version_id%5D=3',
1044 :class => '' }
1045 assert_tag :tag => 'a', :content => 'eCookbook Subproject 1 - 2.0',
1046 :attributes => { :href => '/issues/bulk_edit?ids%5B%5D=1&amp;issue%5Bfixed_version_id%5D=4',
1047 :class => '' }
1048
1049 assert_tag :tag => 'a', :content => 'Dave Lopper',
1050 :attributes => { :href => '/issues/bulk_edit?ids%5B%5D=1&amp;issue%5Bassigned_to_id%5D=3',
1051 :class => '' }
1052 assert_tag :tag => 'a', :content => 'Duplicate',
1053 :attributes => { :href => '/projects/ecookbook/issues/1/copy',
1054 :class => 'icon-duplicate' }
1055 assert_tag :tag => 'a', :content => 'Copy',
1056 :attributes => { :href => '/issues/move/new?copy_options%5Bcopy%5D=t&amp;ids%5B%5D=1',
1057 :class => 'icon-copy' }
1058 assert_tag :tag => 'a', :content => 'Move',
1059 :attributes => { :href => '/issues/move/new?ids%5B%5D=1',
1060 :class => 'icon-move' }
1061 assert_tag :tag => 'a', :content => 'Delete',
1062 :attributes => { :href => '/issues/destroy?ids%5B%5D=1',
1063 :class => 'icon-del' }
1064 end
1065
1066 def test_context_menu_one_issue_by_anonymous
1067 get :context_menu, :ids => [1]
1068 assert_response :success
1069 assert_template 'context_menu'
1070 assert_tag :tag => 'a', :content => 'Delete',
1071 :attributes => { :href => '#',
1072 :class => 'icon-del disabled' }
1073 end
1074
1075 def test_context_menu_multiple_issues_of_same_project
1076 @request.session[:user_id] = 2
1077 get :context_menu, :ids => [1, 2]
1078 assert_response :success
1079 assert_template 'context_menu'
1080 assert_tag :tag => 'a', :content => 'Edit',
1081 :attributes => { :href => '/issues/bulk_edit?ids%5B%5D=1&amp;ids%5B%5D=2',
1082 :class => 'icon-edit' }
1083 assert_tag :tag => 'a', :content => 'Immediate',
1084 :attributes => { :href => '/issues/bulk_edit?ids%5B%5D=1&amp;ids%5B%5D=2&amp;issue%5Bpriority_id%5D=8',
1085 :class => '' }
1086 assert_tag :tag => 'a', :content => 'Dave Lopper',
1087 :attributes => { :href => '/issues/bulk_edit?ids%5B%5D=1&amp;ids%5B%5D=2&amp;issue%5Bassigned_to_id%5D=3',
1088 :class => '' }
1089 assert_tag :tag => 'a', :content => 'Copy',
1090 :attributes => { :href => '/issues/move/new?copy_options%5Bcopy%5D=t&amp;ids%5B%5D=1&amp;ids%5B%5D=2',
1091 :class => 'icon-copy' }
1092 assert_tag :tag => 'a', :content => 'Move',
1093 :attributes => { :href => '/issues/move/new?ids%5B%5D=1&amp;ids%5B%5D=2',
1094 :class => 'icon-move' }
1095 assert_tag :tag => 'a', :content => 'Delete',
1096 :attributes => { :href => '/issues/destroy?ids%5B%5D=1&amp;ids%5B%5D=2',
1097 :class => 'icon-del' }
1098 end
1099
1100 def test_context_menu_multiple_issues_of_different_project
1101 @request.session[:user_id] = 2
1102 get :context_menu, :ids => [1, 2, 4]
1103 assert_response :success
1104 assert_template 'context_menu'
1105 assert_tag :tag => 'a', :content => 'Delete',
1106 :attributes => { :href => '#',
1107 :class => 'icon-del disabled' }
1108 end
1109
1110 def test_destroy_issue_with_no_time_entries
1027 def test_destroy_issue_with_no_time_entries
1111 assert_nil TimeEntry.find_by_issue_id(2)
1028 assert_nil TimeEntry.find_by_issue_id(2)
1112 @request.session[:user_id] = 2
1029 @request.session[:user_id] = 2
1113 post :destroy, :id => 2
1030 post :destroy, :id => 2
1114 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
1031 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
1115 assert_nil Issue.find_by_id(2)
1032 assert_nil Issue.find_by_id(2)
1116 end
1033 end
1117
1034
1118 def test_destroy_issues_with_time_entries
1035 def test_destroy_issues_with_time_entries
1119 @request.session[:user_id] = 2
1036 @request.session[:user_id] = 2
1120 post :destroy, :ids => [1, 3]
1037 post :destroy, :ids => [1, 3]
1121 assert_response :success
1038 assert_response :success
1122 assert_template 'destroy'
1039 assert_template 'destroy'
1123 assert_not_nil assigns(:hours)
1040 assert_not_nil assigns(:hours)
1124 assert Issue.find_by_id(1) && Issue.find_by_id(3)
1041 assert Issue.find_by_id(1) && Issue.find_by_id(3)
1125 end
1042 end
1126
1043
1127 def test_destroy_issues_and_destroy_time_entries
1044 def test_destroy_issues_and_destroy_time_entries
1128 @request.session[:user_id] = 2
1045 @request.session[:user_id] = 2
1129 post :destroy, :ids => [1, 3], :todo => 'destroy'
1046 post :destroy, :ids => [1, 3], :todo => 'destroy'
1130 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
1047 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
1131 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
1048 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
1132 assert_nil TimeEntry.find_by_id([1, 2])
1049 assert_nil TimeEntry.find_by_id([1, 2])
1133 end
1050 end
1134
1051
1135 def test_destroy_issues_and_assign_time_entries_to_project
1052 def test_destroy_issues_and_assign_time_entries_to_project
1136 @request.session[:user_id] = 2
1053 @request.session[:user_id] = 2
1137 post :destroy, :ids => [1, 3], :todo => 'nullify'
1054 post :destroy, :ids => [1, 3], :todo => 'nullify'
1138 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
1055 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
1139 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
1056 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
1140 assert_nil TimeEntry.find(1).issue_id
1057 assert_nil TimeEntry.find(1).issue_id
1141 assert_nil TimeEntry.find(2).issue_id
1058 assert_nil TimeEntry.find(2).issue_id
1142 end
1059 end
1143
1060
1144 def test_destroy_issues_and_reassign_time_entries_to_another_issue
1061 def test_destroy_issues_and_reassign_time_entries_to_another_issue
1145 @request.session[:user_id] = 2
1062 @request.session[:user_id] = 2
1146 post :destroy, :ids => [1, 3], :todo => 'reassign', :reassign_to_id => 2
1063 post :destroy, :ids => [1, 3], :todo => 'reassign', :reassign_to_id => 2
1147 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
1064 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
1148 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
1065 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
1149 assert_equal 2, TimeEntry.find(1).issue_id
1066 assert_equal 2, TimeEntry.find(1).issue_id
1150 assert_equal 2, TimeEntry.find(2).issue_id
1067 assert_equal 2, TimeEntry.find(2).issue_id
1151 end
1068 end
1152
1069
1153 def test_default_search_scope
1070 def test_default_search_scope
1154 get :index
1071 get :index
1155 assert_tag :div, :attributes => {:id => 'quick-search'},
1072 assert_tag :div, :attributes => {:id => 'quick-search'},
1156 :child => {:tag => 'form',
1073 :child => {:tag => 'form',
1157 :child => {:tag => 'input', :attributes => {:name => 'issues', :type => 'hidden', :value => '1'}}}
1074 :child => {:tag => 'input', :attributes => {:name => 'issues', :type => 'hidden', :value => '1'}}}
1158 end
1075 end
1159 end
1076 end
@@ -1,284 +1,286
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2010 Jean-Philippe Lang
2 # Copyright (C) 2006-2010 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.dirname(__FILE__)}/../test_helper"
18 require "#{File.dirname(__FILE__)}/../test_helper"
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 => 'projects', :action => 'activity', :id => nil
22 should_route :get, "/activity", :controller => 'projects', :action => 'activity', :id => nil
23 should_route :get, "/activity.atom", :controller => 'projects', :action => 'activity', :id => nil, :format => 'atom'
23 should_route :get, "/activity.atom", :controller => 'projects', :action => 'activity', :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/filename.ext", :controller => 'attachments', :action => 'show', :id => '1', :filename => 'filename.ext'
28 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'
29 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'
30 should_route :get, "/attachments/download/1/filename.ext", :controller => 'attachments', :action => 'download', :id => '1', :filename => 'filename.ext'
31 end
31 end
32
32
33 context "boards" do
33 context "boards" do
34 should_route :get, "/projects/world_domination/boards", :controller => 'boards', :action => 'index', :project_id => 'world_domination'
34 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'
35 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'
36 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'
37 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'
38 should_route :get, "/projects/world_domination/boards/44/edit", :controller => 'boards', :action => 'edit', :project_id => 'world_domination', :id => '44'
39
39
40 should_route :post, "/projects/world_domination/boards/new", :controller => 'boards', :action => 'new', :project_id => 'world_domination'
40 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'
41 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'
42 should_route :post, "/projects/world_domination/boards/44/destroy", :controller => 'boards', :action => 'destroy', :project_id => 'world_domination', :id => '44'
43
43
44 end
44 end
45
45
46 context "documents" do
46 context "documents" do
47 should_route :get, "/projects/567/documents", :controller => 'documents', :action => 'index', :project_id => '567'
47 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'
48 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'
49 should_route :get, "/documents/22", :controller => 'documents', :action => 'show', :id => '22'
50 should_route :get, "/documents/22/edit", :controller => 'documents', :action => 'edit', :id => '22'
50 should_route :get, "/documents/22/edit", :controller => 'documents', :action => 'edit', :id => '22'
51
51
52 should_route :post, "/projects/567/documents/new", :controller => 'documents', :action => 'new', :project_id => '567'
52 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'
53 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'
54 should_route :post, "/documents/567/destroy", :controller => 'documents', :action => 'destroy', :id => '567'
55 end
55 end
56
56
57 context "issues" do
57 context "issues" do
58 # REST actions
58 # REST actions
59 should_route :get, "/issues", :controller => 'issues', :action => 'index'
59 should_route :get, "/issues", :controller => 'issues', :action => 'index'
60 should_route :get, "/issues.pdf", :controller => 'issues', :action => 'index', :format => 'pdf'
60 should_route :get, "/issues.pdf", :controller => 'issues', :action => 'index', :format => 'pdf'
61 should_route :get, "/issues.atom", :controller => 'issues', :action => 'index', :format => 'atom'
61 should_route :get, "/issues.atom", :controller => 'issues', :action => 'index', :format => 'atom'
62 should_route :get, "/issues.xml", :controller => 'issues', :action => 'index', :format => 'xml'
62 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'
63 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'
64 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'
65 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'
66 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'
67 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'
68 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'
69 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'
70 should_route :get, "/issues/64.xml", :controller => 'issues', :action => 'show', :id => '64', :format => 'xml'
71
71
72 should_route :get, "/projects/23/issues/new", :controller => 'issues', :action => 'new', :project_id => '23'
72 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'
73 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'
74 should_route :post, "/issues.xml", :controller => 'issues', :action => 'create', :format => 'xml'
75
75
76 should_route :get, "/issues/64/edit", :controller => 'issues', :action => 'edit', :id => '64'
76 should_route :get, "/issues/64/edit", :controller => 'issues', :action => 'edit', :id => '64'
77 # TODO: Should use PUT
77 # TODO: Should use PUT
78 should_route :post, "/issues/64/edit", :controller => 'issues', :action => 'edit', :id => '64'
78 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'
79 should_route :put, "/issues/1.xml", :controller => 'issues', :action => 'update', :id => '1', :format => 'xml'
80
80
81 # TODO: Should use DELETE
81 # TODO: Should use DELETE
82 should_route :post, "/issues/64/destroy", :controller => 'issues', :action => 'destroy', :id => '64'
82 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'
83 should_route :delete, "/issues/1.xml", :controller => 'issues', :action => 'destroy', :id => '1', :format => 'xml'
84
84
85 # Extra actions
85 # Extra actions
86 should_route :get, "/projects/23/issues/64/copy", :controller => 'issues', :action => 'new', :project_id => '23', :copy_from => '64'
86 should_route :get, "/projects/23/issues/64/copy", :controller => 'issues', :action => 'new', :project_id => '23', :copy_from => '64'
87
87
88 should_route :get, "/issues/move/new", :controller => 'issue_moves', :action => 'new'
88 should_route :get, "/issues/move/new", :controller => 'issue_moves', :action => 'new'
89 should_route :post, "/issues/move", :controller => 'issue_moves', :action => 'create'
89 should_route :post, "/issues/move", :controller => 'issue_moves', :action => 'create'
90
90
91 should_route :post, "/issues/1/quoted", :controller => 'journals', :action => 'new', :id => '1'
91 should_route :post, "/issues/1/quoted", :controller => 'journals', :action => 'new', :id => '1'
92
92
93 should_route :get, "/issues/calendar", :controller => 'calendars', :action => 'show'
93 should_route :get, "/issues/calendar", :controller => 'calendars', :action => 'show'
94 should_route :post, "/issues/calendar", :controller => 'calendars', :action => 'show'
94 should_route :post, "/issues/calendar", :controller => 'calendars', :action => 'show'
95 should_route :get, "/projects/project-name/issues/calendar", :controller => 'calendars', :action => 'show', :project_id => 'project-name'
95 should_route :get, "/projects/project-name/issues/calendar", :controller => 'calendars', :action => 'show', :project_id => 'project-name'
96 should_route :post, "/projects/project-name/issues/calendar", :controller => 'calendars', :action => 'show', :project_id => 'project-name'
96 should_route :post, "/projects/project-name/issues/calendar", :controller => 'calendars', :action => 'show', :project_id => 'project-name'
97
97
98 should_route :get, "/issues/gantt", :controller => 'gantts', :action => 'show'
98 should_route :get, "/issues/gantt", :controller => 'gantts', :action => 'show'
99 should_route :post, "/issues/gantt", :controller => 'gantts', :action => 'show'
99 should_route :post, "/issues/gantt", :controller => 'gantts', :action => 'show'
100 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'
101 should_route :post, "/projects/project-name/issues/gantt", :controller => 'gantts', :action => 'show', :project_id => 'project-name'
101 should_route :post, "/projects/project-name/issues/gantt", :controller => 'gantts', :action => 'show', :project_id => 'project-name'
102
102
103 should_route :get, "/issues/auto_complete", :controller => 'auto_completes', :action => 'issues'
103 should_route :get, "/issues/auto_complete", :controller => 'auto_completes', :action => 'issues'
104
104
105 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'
106 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'
107 should_route :get, "/issues/context_menu", :controller => 'context_menus', :action => 'issues'
108 should_route :post, "/issues/context_menu", :controller => 'context_menus', :action => 'issues'
107 end
109 end
108
110
109 context "issue categories" do
111 context "issue categories" do
110 should_route :get, "/projects/test/issue_categories/new", :controller => 'issue_categories', :action => 'new', :project_id => 'test'
112 should_route :get, "/projects/test/issue_categories/new", :controller => 'issue_categories', :action => 'new', :project_id => 'test'
111
113
112 should_route :post, "/projects/test/issue_categories/new", :controller => 'issue_categories', :action => 'new', :project_id => 'test'
114 should_route :post, "/projects/test/issue_categories/new", :controller => 'issue_categories', :action => 'new', :project_id => 'test'
113 end
115 end
114
116
115 context "issue relations" do
117 context "issue relations" do
116 should_route :post, "/issues/1/relations", :controller => 'issue_relations', :action => 'new', :issue_id => '1'
118 should_route :post, "/issues/1/relations", :controller => 'issue_relations', :action => 'new', :issue_id => '1'
117 should_route :post, "/issues/1/relations/23/destroy", :controller => 'issue_relations', :action => 'destroy', :issue_id => '1', :id => '23'
119 should_route :post, "/issues/1/relations/23/destroy", :controller => 'issue_relations', :action => 'destroy', :issue_id => '1', :id => '23'
118 end
120 end
119
121
120 context "issue reports" do
122 context "issue reports" do
121 should_route :get, "/projects/567/issues/report", :controller => 'reports', :action => 'issue_report', :id => '567'
123 should_route :get, "/projects/567/issues/report", :controller => 'reports', :action => 'issue_report', :id => '567'
122 should_route :get, "/projects/567/issues/report/assigned_to", :controller => 'reports', :action => 'issue_report_details', :id => '567', :detail => 'assigned_to'
124 should_route :get, "/projects/567/issues/report/assigned_to", :controller => 'reports', :action => 'issue_report_details', :id => '567', :detail => 'assigned_to'
123 end
125 end
124
126
125 context "members" do
127 context "members" do
126 should_route :post, "/projects/5234/members/new", :controller => 'members', :action => 'new', :id => '5234'
128 should_route :post, "/projects/5234/members/new", :controller => 'members', :action => 'new', :id => '5234'
127 end
129 end
128
130
129 context "messages" do
131 context "messages" do
130 should_route :get, "/boards/22/topics/2", :controller => 'messages', :action => 'show', :id => '2', :board_id => '22'
132 should_route :get, "/boards/22/topics/2", :controller => 'messages', :action => 'show', :id => '2', :board_id => '22'
131 should_route :get, "/boards/lala/topics/new", :controller => 'messages', :action => 'new', :board_id => 'lala'
133 should_route :get, "/boards/lala/topics/new", :controller => 'messages', :action => 'new', :board_id => 'lala'
132 should_route :get, "/boards/lala/topics/22/edit", :controller => 'messages', :action => 'edit', :id => '22', :board_id => 'lala'
134 should_route :get, "/boards/lala/topics/22/edit", :controller => 'messages', :action => 'edit', :id => '22', :board_id => 'lala'
133
135
134 should_route :post, "/boards/lala/topics/new", :controller => 'messages', :action => 'new', :board_id => 'lala'
136 should_route :post, "/boards/lala/topics/new", :controller => 'messages', :action => 'new', :board_id => 'lala'
135 should_route :post, "/boards/lala/topics/22/edit", :controller => 'messages', :action => 'edit', :id => '22', :board_id => 'lala'
137 should_route :post, "/boards/lala/topics/22/edit", :controller => 'messages', :action => 'edit', :id => '22', :board_id => 'lala'
136 should_route :post, "/boards/22/topics/555/replies", :controller => 'messages', :action => 'reply', :id => '555', :board_id => '22'
138 should_route :post, "/boards/22/topics/555/replies", :controller => 'messages', :action => 'reply', :id => '555', :board_id => '22'
137 should_route :post, "/boards/22/topics/555/destroy", :controller => 'messages', :action => 'destroy', :id => '555', :board_id => '22'
139 should_route :post, "/boards/22/topics/555/destroy", :controller => 'messages', :action => 'destroy', :id => '555', :board_id => '22'
138 end
140 end
139
141
140 context "news" do
142 context "news" do
141 should_route :get, "/news", :controller => 'news', :action => 'index'
143 should_route :get, "/news", :controller => 'news', :action => 'index'
142 should_route :get, "/news.atom", :controller => 'news', :action => 'index', :format => 'atom'
144 should_route :get, "/news.atom", :controller => 'news', :action => 'index', :format => 'atom'
143 should_route :get, "/news.xml", :controller => 'news', :action => 'index', :format => 'xml'
145 should_route :get, "/news.xml", :controller => 'news', :action => 'index', :format => 'xml'
144 should_route :get, "/news.json", :controller => 'news', :action => 'index', :format => 'json'
146 should_route :get, "/news.json", :controller => 'news', :action => 'index', :format => 'json'
145 should_route :get, "/projects/567/news", :controller => 'news', :action => 'index', :project_id => '567'
147 should_route :get, "/projects/567/news", :controller => 'news', :action => 'index', :project_id => '567'
146 should_route :get, "/projects/567/news.atom", :controller => 'news', :action => 'index', :format => 'atom', :project_id => '567'
148 should_route :get, "/projects/567/news.atom", :controller => 'news', :action => 'index', :format => 'atom', :project_id => '567'
147 should_route :get, "/projects/567/news.xml", :controller => 'news', :action => 'index', :format => 'xml', :project_id => '567'
149 should_route :get, "/projects/567/news.xml", :controller => 'news', :action => 'index', :format => 'xml', :project_id => '567'
148 should_route :get, "/projects/567/news.json", :controller => 'news', :action => 'index', :format => 'json', :project_id => '567'
150 should_route :get, "/projects/567/news.json", :controller => 'news', :action => 'index', :format => 'json', :project_id => '567'
149 should_route :get, "/news/2", :controller => 'news', :action => 'show', :id => '2'
151 should_route :get, "/news/2", :controller => 'news', :action => 'show', :id => '2'
150 should_route :get, "/projects/567/news/new", :controller => 'news', :action => 'new', :project_id => '567'
152 should_route :get, "/projects/567/news/new", :controller => 'news', :action => 'new', :project_id => '567'
151 should_route :get, "/news/234", :controller => 'news', :action => 'show', :id => '234'
153 should_route :get, "/news/234", :controller => 'news', :action => 'show', :id => '234'
152
154
153 should_route :post, "/projects/567/news/new", :controller => 'news', :action => 'new', :project_id => '567'
155 should_route :post, "/projects/567/news/new", :controller => 'news', :action => 'new', :project_id => '567'
154 should_route :post, "/news/567/edit", :controller => 'news', :action => 'edit', :id => '567'
156 should_route :post, "/news/567/edit", :controller => 'news', :action => 'edit', :id => '567'
155 should_route :post, "/news/567/destroy", :controller => 'news', :action => 'destroy', :id => '567'
157 should_route :post, "/news/567/destroy", :controller => 'news', :action => 'destroy', :id => '567'
156 end
158 end
157
159
158 context "projects" do
160 context "projects" do
159 should_route :get, "/projects", :controller => 'projects', :action => 'index'
161 should_route :get, "/projects", :controller => 'projects', :action => 'index'
160 should_route :get, "/projects.atom", :controller => 'projects', :action => 'index', :format => 'atom'
162 should_route :get, "/projects.atom", :controller => 'projects', :action => 'index', :format => 'atom'
161 should_route :get, "/projects.xml", :controller => 'projects', :action => 'index', :format => 'xml'
163 should_route :get, "/projects.xml", :controller => 'projects', :action => 'index', :format => 'xml'
162 should_route :get, "/projects/new", :controller => 'projects', :action => 'add'
164 should_route :get, "/projects/new", :controller => 'projects', :action => 'add'
163 should_route :get, "/projects/test", :controller => 'projects', :action => 'show', :id => 'test'
165 should_route :get, "/projects/test", :controller => 'projects', :action => 'show', :id => 'test'
164 should_route :get, "/projects/1.xml", :controller => 'projects', :action => 'show', :id => '1', :format => 'xml'
166 should_route :get, "/projects/1.xml", :controller => 'projects', :action => 'show', :id => '1', :format => 'xml'
165 should_route :get, "/projects/4223/settings", :controller => 'projects', :action => 'settings', :id => '4223'
167 should_route :get, "/projects/4223/settings", :controller => 'projects', :action => 'settings', :id => '4223'
166 should_route :get, "/projects/4223/settings/members", :controller => 'projects', :action => 'settings', :id => '4223', :tab => 'members'
168 should_route :get, "/projects/4223/settings/members", :controller => 'projects', :action => 'settings', :id => '4223', :tab => 'members'
167 should_route :get, "/projects/567/destroy", :controller => 'projects', :action => 'destroy', :id => '567'
169 should_route :get, "/projects/567/destroy", :controller => 'projects', :action => 'destroy', :id => '567'
168 should_route :get, "/projects/33/files", :controller => 'projects', :action => 'list_files', :id => '33'
170 should_route :get, "/projects/33/files", :controller => 'projects', :action => 'list_files', :id => '33'
169 should_route :get, "/projects/33/files/new", :controller => 'projects', :action => 'add_file', :id => '33'
171 should_route :get, "/projects/33/files/new", :controller => 'projects', :action => 'add_file', :id => '33'
170 should_route :get, "/projects/33/roadmap", :controller => 'projects', :action => 'roadmap', :id => '33'
172 should_route :get, "/projects/33/roadmap", :controller => 'projects', :action => 'roadmap', :id => '33'
171 should_route :get, "/projects/33/activity", :controller => 'projects', :action => 'activity', :id => '33'
173 should_route :get, "/projects/33/activity", :controller => 'projects', :action => 'activity', :id => '33'
172 should_route :get, "/projects/33/activity.atom", :controller => 'projects', :action => 'activity', :id => '33', :format => 'atom'
174 should_route :get, "/projects/33/activity.atom", :controller => 'projects', :action => 'activity', :id => '33', :format => 'atom'
173
175
174 should_route :post, "/projects/new", :controller => 'projects', :action => 'add'
176 should_route :post, "/projects/new", :controller => 'projects', :action => 'add'
175 should_route :post, "/projects.xml", :controller => 'projects', :action => 'add', :format => 'xml'
177 should_route :post, "/projects.xml", :controller => 'projects', :action => 'add', :format => 'xml'
176 should_route :post, "/projects/4223/edit", :controller => 'projects', :action => 'edit', :id => '4223'
178 should_route :post, "/projects/4223/edit", :controller => 'projects', :action => 'edit', :id => '4223'
177 should_route :post, "/projects/64/destroy", :controller => 'projects', :action => 'destroy', :id => '64'
179 should_route :post, "/projects/64/destroy", :controller => 'projects', :action => 'destroy', :id => '64'
178 should_route :post, "/projects/33/files/new", :controller => 'projects', :action => 'add_file', :id => '33'
180 should_route :post, "/projects/33/files/new", :controller => 'projects', :action => 'add_file', :id => '33'
179 should_route :post, "/projects/64/archive", :controller => 'projects', :action => 'archive', :id => '64'
181 should_route :post, "/projects/64/archive", :controller => 'projects', :action => 'archive', :id => '64'
180 should_route :post, "/projects/64/unarchive", :controller => 'projects', :action => 'unarchive', :id => '64'
182 should_route :post, "/projects/64/unarchive", :controller => 'projects', :action => 'unarchive', :id => '64'
181 should_route :post, "/projects/64/activities/save", :controller => 'projects', :action => 'save_activities', :id => '64'
183 should_route :post, "/projects/64/activities/save", :controller => 'projects', :action => 'save_activities', :id => '64'
182
184
183 should_route :put, "/projects/1.xml", :controller => 'projects', :action => 'edit', :id => '1', :format => 'xml'
185 should_route :put, "/projects/1.xml", :controller => 'projects', :action => 'edit', :id => '1', :format => 'xml'
184
186
185 should_route :delete, "/projects/1.xml", :controller => 'projects', :action => 'destroy', :id => '1', :format => 'xml'
187 should_route :delete, "/projects/1.xml", :controller => 'projects', :action => 'destroy', :id => '1', :format => 'xml'
186 should_route :delete, "/projects/64/reset_activities", :controller => 'projects', :action => 'reset_activities', :id => '64'
188 should_route :delete, "/projects/64/reset_activities", :controller => 'projects', :action => 'reset_activities', :id => '64'
187 end
189 end
188
190
189 context "repositories" do
191 context "repositories" do
190 should_route :get, "/projects/redmine/repository", :controller => 'repositories', :action => 'show', :id => 'redmine'
192 should_route :get, "/projects/redmine/repository", :controller => 'repositories', :action => 'show', :id => 'redmine'
191 should_route :get, "/projects/redmine/repository/edit", :controller => 'repositories', :action => 'edit', :id => 'redmine'
193 should_route :get, "/projects/redmine/repository/edit", :controller => 'repositories', :action => 'edit', :id => 'redmine'
192 should_route :get, "/projects/redmine/repository/revisions", :controller => 'repositories', :action => 'revisions', :id => 'redmine'
194 should_route :get, "/projects/redmine/repository/revisions", :controller => 'repositories', :action => 'revisions', :id => 'redmine'
193 should_route :get, "/projects/redmine/repository/revisions.atom", :controller => 'repositories', :action => 'revisions', :id => 'redmine', :format => 'atom'
195 should_route :get, "/projects/redmine/repository/revisions.atom", :controller => 'repositories', :action => 'revisions', :id => 'redmine', :format => 'atom'
194 should_route :get, "/projects/redmine/repository/revisions/2457", :controller => 'repositories', :action => 'revision', :id => 'redmine', :rev => '2457'
196 should_route :get, "/projects/redmine/repository/revisions/2457", :controller => 'repositories', :action => 'revision', :id => 'redmine', :rev => '2457'
195 should_route :get, "/projects/redmine/repository/revisions/2457/diff", :controller => 'repositories', :action => 'diff', :id => 'redmine', :rev => '2457'
197 should_route :get, "/projects/redmine/repository/revisions/2457/diff", :controller => 'repositories', :action => 'diff', :id => 'redmine', :rev => '2457'
196 should_route :get, "/projects/redmine/repository/revisions/2457/diff.diff", :controller => 'repositories', :action => 'diff', :id => 'redmine', :rev => '2457', :format => 'diff'
198 should_route :get, "/projects/redmine/repository/revisions/2457/diff.diff", :controller => 'repositories', :action => 'diff', :id => 'redmine', :rev => '2457', :format => 'diff'
197 should_route :get, "/projects/redmine/repository/diff/path/to/file.c", :controller => 'repositories', :action => 'diff', :id => 'redmine', :path => %w[path to file.c]
199 should_route :get, "/projects/redmine/repository/diff/path/to/file.c", :controller => 'repositories', :action => 'diff', :id => 'redmine', :path => %w[path to file.c]
198 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'
200 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'
199 should_route :get, "/projects/redmine/repository/browse/path/to/file.c", :controller => 'repositories', :action => 'browse', :id => 'redmine', :path => %w[path to file.c]
201 should_route :get, "/projects/redmine/repository/browse/path/to/file.c", :controller => 'repositories', :action => 'browse', :id => 'redmine', :path => %w[path to file.c]
200 should_route :get, "/projects/redmine/repository/entry/path/to/file.c", :controller => 'repositories', :action => 'entry', :id => 'redmine', :path => %w[path to file.c]
202 should_route :get, "/projects/redmine/repository/entry/path/to/file.c", :controller => 'repositories', :action => 'entry', :id => 'redmine', :path => %w[path to file.c]
201 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'
203 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'
202 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'
204 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'
203 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'
205 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'
204 should_route :get, "/projects/redmine/repository/annotate/path/to/file.c", :controller => 'repositories', :action => 'annotate', :id => 'redmine', :path => %w[path to file.c]
206 should_route :get, "/projects/redmine/repository/annotate/path/to/file.c", :controller => 'repositories', :action => 'annotate', :id => 'redmine', :path => %w[path to file.c]
205 should_route :get, "/projects/redmine/repository/changes/path/to/file.c", :controller => 'repositories', :action => 'changes', :id => 'redmine', :path => %w[path to file.c]
207 should_route :get, "/projects/redmine/repository/changes/path/to/file.c", :controller => 'repositories', :action => 'changes', :id => 'redmine', :path => %w[path to file.c]
206 should_route :get, "/projects/redmine/repository/statistics", :controller => 'repositories', :action => 'stats', :id => 'redmine'
208 should_route :get, "/projects/redmine/repository/statistics", :controller => 'repositories', :action => 'stats', :id => 'redmine'
207
209
208
210
209 should_route :post, "/projects/redmine/repository/edit", :controller => 'repositories', :action => 'edit', :id => 'redmine'
211 should_route :post, "/projects/redmine/repository/edit", :controller => 'repositories', :action => 'edit', :id => 'redmine'
210 end
212 end
211
213
212 context "timelogs" do
214 context "timelogs" do
213 should_route :get, "/issues/567/time_entries/new", :controller => 'timelog', :action => 'edit', :issue_id => '567'
215 should_route :get, "/issues/567/time_entries/new", :controller => 'timelog', :action => 'edit', :issue_id => '567'
214 should_route :get, "/projects/ecookbook/time_entries/new", :controller => 'timelog', :action => 'edit', :project_id => 'ecookbook'
216 should_route :get, "/projects/ecookbook/time_entries/new", :controller => 'timelog', :action => 'edit', :project_id => 'ecookbook'
215 should_route :get, "/projects/ecookbook/issues/567/time_entries/new", :controller => 'timelog', :action => 'edit', :project_id => 'ecookbook', :issue_id => '567'
217 should_route :get, "/projects/ecookbook/issues/567/time_entries/new", :controller => 'timelog', :action => 'edit', :project_id => 'ecookbook', :issue_id => '567'
216 should_route :get, "/time_entries/22/edit", :controller => 'timelog', :action => 'edit', :id => '22'
218 should_route :get, "/time_entries/22/edit", :controller => 'timelog', :action => 'edit', :id => '22'
217 should_route :get, "/time_entries/report", :controller => 'timelog', :action => 'report'
219 should_route :get, "/time_entries/report", :controller => 'timelog', :action => 'report'
218 should_route :get, "/projects/567/time_entries/report", :controller => 'timelog', :action => 'report', :project_id => '567'
220 should_route :get, "/projects/567/time_entries/report", :controller => 'timelog', :action => 'report', :project_id => '567'
219 should_route :get, "/projects/567/time_entries/report.csv", :controller => 'timelog', :action => 'report', :project_id => '567', :format => 'csv'
221 should_route :get, "/projects/567/time_entries/report.csv", :controller => 'timelog', :action => 'report', :project_id => '567', :format => 'csv'
220 should_route :get, "/time_entries", :controller => 'timelog', :action => 'details'
222 should_route :get, "/time_entries", :controller => 'timelog', :action => 'details'
221 should_route :get, "/time_entries.csv", :controller => 'timelog', :action => 'details', :format => 'csv'
223 should_route :get, "/time_entries.csv", :controller => 'timelog', :action => 'details', :format => 'csv'
222 should_route :get, "/time_entries.atom", :controller => 'timelog', :action => 'details', :format => 'atom'
224 should_route :get, "/time_entries.atom", :controller => 'timelog', :action => 'details', :format => 'atom'
223 should_route :get, "/projects/567/time_entries", :controller => 'timelog', :action => 'details', :project_id => '567'
225 should_route :get, "/projects/567/time_entries", :controller => 'timelog', :action => 'details', :project_id => '567'
224 should_route :get, "/projects/567/time_entries.csv", :controller => 'timelog', :action => 'details', :project_id => '567', :format => 'csv'
226 should_route :get, "/projects/567/time_entries.csv", :controller => 'timelog', :action => 'details', :project_id => '567', :format => 'csv'
225 should_route :get, "/projects/567/time_entries.atom", :controller => 'timelog', :action => 'details', :project_id => '567', :format => 'atom'
227 should_route :get, "/projects/567/time_entries.atom", :controller => 'timelog', :action => 'details', :project_id => '567', :format => 'atom'
226 should_route :get, "/issues/234/time_entries", :controller => 'timelog', :action => 'details', :issue_id => '234'
228 should_route :get, "/issues/234/time_entries", :controller => 'timelog', :action => 'details', :issue_id => '234'
227 should_route :get, "/issues/234/time_entries.csv", :controller => 'timelog', :action => 'details', :issue_id => '234', :format => 'csv'
229 should_route :get, "/issues/234/time_entries.csv", :controller => 'timelog', :action => 'details', :issue_id => '234', :format => 'csv'
228 should_route :get, "/issues/234/time_entries.atom", :controller => 'timelog', :action => 'details', :issue_id => '234', :format => 'atom'
230 should_route :get, "/issues/234/time_entries.atom", :controller => 'timelog', :action => 'details', :issue_id => '234', :format => 'atom'
229 should_route :get, "/projects/ecookbook/issues/123/time_entries", :controller => 'timelog', :action => 'details', :project_id => 'ecookbook', :issue_id => '123'
231 should_route :get, "/projects/ecookbook/issues/123/time_entries", :controller => 'timelog', :action => 'details', :project_id => 'ecookbook', :issue_id => '123'
230
232
231 should_route :post, "/time_entries/55/destroy", :controller => 'timelog', :action => 'destroy', :id => '55'
233 should_route :post, "/time_entries/55/destroy", :controller => 'timelog', :action => 'destroy', :id => '55'
232 end
234 end
233
235
234 context "users" do
236 context "users" do
235 should_route :get, "/users", :controller => 'users', :action => 'index'
237 should_route :get, "/users", :controller => 'users', :action => 'index'
236 should_route :get, "/users/44", :controller => 'users', :action => 'show', :id => '44'
238 should_route :get, "/users/44", :controller => 'users', :action => 'show', :id => '44'
237 should_route :get, "/users/new", :controller => 'users', :action => 'add'
239 should_route :get, "/users/new", :controller => 'users', :action => 'add'
238 should_route :get, "/users/444/edit", :controller => 'users', :action => 'edit', :id => '444'
240 should_route :get, "/users/444/edit", :controller => 'users', :action => 'edit', :id => '444'
239 should_route :get, "/users/222/edit/membership", :controller => 'users', :action => 'edit', :id => '222', :tab => 'membership'
241 should_route :get, "/users/222/edit/membership", :controller => 'users', :action => 'edit', :id => '222', :tab => 'membership'
240
242
241 should_route :post, "/users/new", :controller => 'users', :action => 'add'
243 should_route :post, "/users/new", :controller => 'users', :action => 'add'
242 should_route :post, "/users/444/edit", :controller => 'users', :action => 'edit', :id => '444'
244 should_route :post, "/users/444/edit", :controller => 'users', :action => 'edit', :id => '444'
243 should_route :post, "/users/123/memberships", :controller => 'users', :action => 'edit_membership', :id => '123'
245 should_route :post, "/users/123/memberships", :controller => 'users', :action => 'edit_membership', :id => '123'
244 should_route :post, "/users/123/memberships/55", :controller => 'users', :action => 'edit_membership', :id => '123', :membership_id => '55'
246 should_route :post, "/users/123/memberships/55", :controller => 'users', :action => 'edit_membership', :id => '123', :membership_id => '55'
245 should_route :post, "/users/567/memberships/12/destroy", :controller => 'users', :action => 'destroy_membership', :id => '567', :membership_id => '12'
247 should_route :post, "/users/567/memberships/12/destroy", :controller => 'users', :action => 'destroy_membership', :id => '567', :membership_id => '12'
246 end
248 end
247
249
248 context "versions" do
250 context "versions" do
249 should_route :get, "/projects/foo/versions/new", :controller => 'versions', :action => 'new', :project_id => 'foo'
251 should_route :get, "/projects/foo/versions/new", :controller => 'versions', :action => 'new', :project_id => 'foo'
250
252
251 should_route :post, "/projects/foo/versions/new", :controller => 'versions', :action => 'new', :project_id => 'foo'
253 should_route :post, "/projects/foo/versions/new", :controller => 'versions', :action => 'new', :project_id => 'foo'
252 end
254 end
253
255
254 context "wiki (singular, project's pages)" do
256 context "wiki (singular, project's pages)" do
255 should_route :get, "/projects/567/wiki", :controller => 'wiki', :action => 'index', :id => '567'
257 should_route :get, "/projects/567/wiki", :controller => 'wiki', :action => 'index', :id => '567'
256 should_route :get, "/projects/567/wiki/lalala", :controller => 'wiki', :action => 'index', :id => '567', :page => 'lalala'
258 should_route :get, "/projects/567/wiki/lalala", :controller => 'wiki', :action => 'index', :id => '567', :page => 'lalala'
257 should_route :get, "/projects/567/wiki/my_page/edit", :controller => 'wiki', :action => 'edit', :id => '567', :page => 'my_page'
259 should_route :get, "/projects/567/wiki/my_page/edit", :controller => 'wiki', :action => 'edit', :id => '567', :page => 'my_page'
258 should_route :get, "/projects/1/wiki/CookBook_documentation/history", :controller => 'wiki', :action => 'history', :id => '1', :page => 'CookBook_documentation'
260 should_route :get, "/projects/1/wiki/CookBook_documentation/history", :controller => 'wiki', :action => 'history', :id => '1', :page => 'CookBook_documentation'
259 should_route :get, "/projects/1/wiki/CookBook_documentation/diff/2/vs/1", :controller => 'wiki', :action => 'diff', :id => '1', :page => 'CookBook_documentation', :version => '2', :version_from => '1'
261 should_route :get, "/projects/1/wiki/CookBook_documentation/diff/2/vs/1", :controller => 'wiki', :action => 'diff', :id => '1', :page => 'CookBook_documentation', :version => '2', :version_from => '1'
260 should_route :get, "/projects/1/wiki/CookBook_documentation/annotate/2", :controller => 'wiki', :action => 'annotate', :id => '1', :page => 'CookBook_documentation', :version => '2'
262 should_route :get, "/projects/1/wiki/CookBook_documentation/annotate/2", :controller => 'wiki', :action => 'annotate', :id => '1', :page => 'CookBook_documentation', :version => '2'
261 should_route :get, "/projects/22/wiki/ladida/rename", :controller => 'wiki', :action => 'rename', :id => '22', :page => 'ladida'
263 should_route :get, "/projects/22/wiki/ladida/rename", :controller => 'wiki', :action => 'rename', :id => '22', :page => 'ladida'
262 should_route :get, "/projects/567/wiki/page_index", :controller => 'wiki', :action => 'special', :id => '567', :page => 'page_index'
264 should_route :get, "/projects/567/wiki/page_index", :controller => 'wiki', :action => 'special', :id => '567', :page => 'page_index'
263 should_route :get, "/projects/567/wiki/Page_Index", :controller => 'wiki', :action => 'special', :id => '567', :page => 'Page_Index'
265 should_route :get, "/projects/567/wiki/Page_Index", :controller => 'wiki', :action => 'special', :id => '567', :page => 'Page_Index'
264 should_route :get, "/projects/567/wiki/date_index", :controller => 'wiki', :action => 'special', :id => '567', :page => 'date_index'
266 should_route :get, "/projects/567/wiki/date_index", :controller => 'wiki', :action => 'special', :id => '567', :page => 'date_index'
265 should_route :get, "/projects/567/wiki/export", :controller => 'wiki', :action => 'special', :id => '567', :page => 'export'
267 should_route :get, "/projects/567/wiki/export", :controller => 'wiki', :action => 'special', :id => '567', :page => 'export'
266
268
267 should_route :post, "/projects/567/wiki/my_page/edit", :controller => 'wiki', :action => 'edit', :id => '567', :page => 'my_page'
269 should_route :post, "/projects/567/wiki/my_page/edit", :controller => 'wiki', :action => 'edit', :id => '567', :page => 'my_page'
268 should_route :post, "/projects/567/wiki/CookBook_documentation/preview", :controller => 'wiki', :action => 'preview', :id => '567', :page => 'CookBook_documentation'
270 should_route :post, "/projects/567/wiki/CookBook_documentation/preview", :controller => 'wiki', :action => 'preview', :id => '567', :page => 'CookBook_documentation'
269 should_route :post, "/projects/22/wiki/ladida/rename", :controller => 'wiki', :action => 'rename', :id => '22', :page => 'ladida'
271 should_route :post, "/projects/22/wiki/ladida/rename", :controller => 'wiki', :action => 'rename', :id => '22', :page => 'ladida'
270 should_route :post, "/projects/22/wiki/ladida/destroy", :controller => 'wiki', :action => 'destroy', :id => '22', :page => 'ladida'
272 should_route :post, "/projects/22/wiki/ladida/destroy", :controller => 'wiki', :action => 'destroy', :id => '22', :page => 'ladida'
271 should_route :post, "/projects/22/wiki/ladida/protect", :controller => 'wiki', :action => 'protect', :id => '22', :page => 'ladida'
273 should_route :post, "/projects/22/wiki/ladida/protect", :controller => 'wiki', :action => 'protect', :id => '22', :page => 'ladida'
272 end
274 end
273
275
274 context "wikis (plural, admin setup)" do
276 context "wikis (plural, admin setup)" do
275 should_route :get, "/projects/ladida/wiki/destroy", :controller => 'wikis', :action => 'destroy', :id => 'ladida'
277 should_route :get, "/projects/ladida/wiki/destroy", :controller => 'wikis', :action => 'destroy', :id => 'ladida'
276
278
277 should_route :post, "/projects/ladida/wiki", :controller => 'wikis', :action => 'edit', :id => 'ladida'
279 should_route :post, "/projects/ladida/wiki", :controller => 'wikis', :action => 'edit', :id => 'ladida'
278 should_route :post, "/projects/ladida/wiki/destroy", :controller => 'wikis', :action => 'destroy', :id => 'ladida'
280 should_route :post, "/projects/ladida/wiki/destroy", :controller => 'wikis', :action => 'destroy', :id => 'ladida'
279 end
281 end
280
282
281 context "administration panel" do
283 context "administration panel" do
282 should_route :get, "/admin/projects", :controller => 'admin', :action => 'projects'
284 should_route :get, "/admin/projects", :controller => 'admin', :action => 'projects'
283 end
285 end
284 end
286 end
General Comments 0
You need to be logged in to leave comments. Login now