@@ -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&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&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&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&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&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&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&ids%5B%5D=2&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&ids%5B%5D=2&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&ids%5B%5D=1&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&ids%5B%5D=2', | |||
|
73 | :class => 'icon-move' } | |||
|
74 | assert_tag :tag => 'a', :content => 'Delete', | |||
|
75 | :attributes => { :href => '/issues/destroy?ids%5B%5D=1&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 |
@@ -22,7 +22,7 class IssuesController < ApplicationController | |||||
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 |
|
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] | |
@@ -257,35 +257,6 class IssuesController < ApplicationController | |||||
257 | format.json { head :ok } |
|
257 | format.json { head :ok } | |
258 | end |
|
258 | end | |
259 | end |
|
259 | end | |
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 |
|
260 | |||
290 | def update_form |
|
261 | def update_form | |
291 | if params[:id].blank? |
|
262 | if params[:id].blank? |
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 |
@@ -81,4 +81,4 | |||||
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 |
|
84 | <%= context_menu issues_context_menu_path %> |
@@ -130,4 +130,4 | |||||
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('#{ |
|
133 | <%= javascript_tag "new ContextMenu('#{issues_context_menu_path}')" %> |
@@ -107,6 +107,7 ActionController::Routing::Routes.draw do |map| | |||||
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| |
@@ -58,8 +58,9 Redmine::AccessControl.map do |map| | |||||
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 |
|
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]} |
@@ -1024,89 +1024,6 class IssuesControllerTest < ActionController::TestCase | |||||
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&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&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&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&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&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&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&ids%5B%5D=2&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&ids%5B%5D=2&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&ids%5B%5D=1&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&ids%5B%5D=2', |
|
|||
1094 | :class => 'icon-move' } |
|
|||
1095 | assert_tag :tag => 'a', :content => 'Delete', |
|
|||
1096 | :attributes => { :href => '/issues/destroy?ids%5B%5D=1&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 |
@@ -104,6 +104,8 class RoutingTest < ActionController::IntegrationTest | |||||
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 |
General Comments 0
You need to be logged in to leave comments.
Login now