##// END OF EJS Templates
Add a permission to remove issue watchers (#2450)....
Jean-Philippe Lang -
r2863:97b4e754787d
parent child
Show More
@@ -1,70 +1,82
1 1 # redMine - project management software
2 2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 class WatchersController < ApplicationController
19 19 before_filter :find_project
20 20 before_filter :require_login, :check_project_privacy, :only => [:watch, :unwatch]
21 before_filter :authorize, :only => :new
21 before_filter :authorize, :only => [:new, :destroy]
22 22
23 23 verify :method => :post,
24 24 :only => [ :watch, :unwatch ],
25 25 :render => { :nothing => true, :status => :method_not_allowed }
26 26
27 27 def watch
28 28 set_watcher(User.current, true)
29 29 end
30 30
31 31 def unwatch
32 32 set_watcher(User.current, false)
33 33 end
34 34
35 35 def new
36 36 @watcher = Watcher.new(params[:watcher])
37 37 @watcher.watchable = @watched
38 38 @watcher.save if request.post?
39 39 respond_to do |format|
40 40 format.html { redirect_to :back }
41 41 format.js do
42 42 render :update do |page|
43 43 page.replace_html 'watchers', :partial => 'watchers/watchers', :locals => {:watched => @watched}
44 44 end
45 45 end
46 46 end
47 47 rescue ::ActionController::RedirectBackError
48 48 render :text => 'Watcher added.', :layout => true
49 49 end
50 50
51 def destroy
52 @watched.set_watcher(User.find(params[:user_id]), false) if request.post?
53 respond_to do |format|
54 format.html { redirect_to :back }
55 format.js do
56 render :update do |page|
57 page.replace_html 'watchers', :partial => 'watchers/watchers', :locals => {:watched => @watched}
58 end
59 end
60 end
61 end
62
51 63 private
52 64 def find_project
53 65 klass = Object.const_get(params[:object_type].camelcase)
54 66 return false unless klass.respond_to?('watched_by')
55 67 @watched = klass.find(params[:object_id])
56 68 @project = @watched.project
57 69 rescue
58 70 render_404
59 71 end
60 72
61 73 def set_watcher(user, watching)
62 74 @watched.set_watcher(user, watching)
63 75 respond_to do |format|
64 76 format.html { redirect_to :back }
65 77 format.js { render(:update) {|page| page.replace_html 'watcher', watcher_link(@watched, user)} }
66 78 end
67 79 rescue ::ActionController::RedirectBackError
68 80 render :text => (watching ? 'Watcher added.' : 'Watcher removed.'), :layout => true
69 81 end
70 82 end
@@ -1,41 +1,56
1 1 # redMine - project management software
2 2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 module WatchersHelper
19 19 def watcher_tag(object, user)
20 20 content_tag("span", watcher_link(object, user), :id => 'watcher')
21 21 end
22 22
23 23 def watcher_link(object, user)
24 24 return '' unless user && user.logged? && object.respond_to?('watched_by?')
25 25 watched = object.watched_by?(user)
26 26 url = {:controller => 'watchers',
27 27 :action => (watched ? 'unwatch' : 'watch'),
28 28 :object_type => object.class.to_s.underscore,
29 29 :object_id => object.id}
30 30 link_to_remote((watched ? l(:button_unwatch) : l(:button_watch)),
31 31 {:url => url},
32 32 :href => url_for(url),
33 33 :class => (watched ? 'icon icon-fav' : 'icon icon-fav-off'))
34 34
35 35 end
36 36
37 37 # Returns a comma separated list of users watching the given object
38 38 def watchers_list(object)
39 object.watcher_users.collect {|u| content_tag('span', link_to_user(u), :class => 'user') }.join(",\n")
39 remove_allowed = User.current.allowed_to?("delete_#{object.class.name.underscore}_watchers".to_sym, object.project)
40 object.watcher_users.collect do |user|
41 s = content_tag('span', link_to_user(user), :class => 'user')
42 if remove_allowed
43 url = {:controller => 'watchers',
44 :action => 'destroy',
45 :object_type => object.class.to_s.underscore,
46 :object_id => object.id,
47 :user_id => user}
48 s += ' ' + link_to_remote(image_tag('delete.png'),
49 {:url => url},
50 :href => url_for(url),
51 :style => "vertical-align: middle")
52 end
53 s
54 end.join(",\n")
40 55 end
41 56 end
@@ -1,166 +1,167
1 1 require 'redmine/access_control'
2 2 require 'redmine/menu_manager'
3 3 require 'redmine/activity'
4 4 require 'redmine/mime_type'
5 5 require 'redmine/core_ext'
6 6 require 'redmine/themes'
7 7 require 'redmine/hook'
8 8 require 'redmine/plugin'
9 9 require 'redmine/wiki_formatting'
10 10
11 11 begin
12 12 require_library_or_gem 'RMagick' unless Object.const_defined?(:Magick)
13 13 rescue LoadError
14 14 # RMagick is not available
15 15 end
16 16
17 17 REDMINE_SUPPORTED_SCM = %w( Subversion Darcs Mercurial Cvs Bazaar Git Filesystem )
18 18
19 19 # Permissions
20 20 Redmine::AccessControl.map do |map|
21 21 map.permission :view_project, {:projects => [:show, :activity]}, :public => true
22 22 map.permission :search_project, {:search => :index}, :public => true
23 23 map.permission :add_project, {:projects => :add}, :require => :loggedin
24 24 map.permission :edit_project, {:projects => [:settings, :edit]}, :require => :member
25 25 map.permission :select_project_modules, {:projects => :modules}, :require => :member
26 26 map.permission :manage_members, {:projects => :settings, :members => [:new, :edit, :destroy, :autocomplete_for_member]}, :require => :member
27 27 map.permission :manage_versions, {:projects => [:settings, :add_version], :versions => [:edit, :destroy]}, :require => :member
28 28
29 29 map.project_module :issue_tracking do |map|
30 30 # Issue categories
31 31 map.permission :manage_categories, {:projects => [:settings, :add_issue_category], :issue_categories => [:edit, :destroy]}, :require => :member
32 32 # Issues
33 33 map.permission :view_issues, {:projects => [:changelog, :roadmap],
34 34 :issues => [:index, :changes, :show, :context_menu],
35 35 :versions => [:show, :status_by],
36 36 :queries => :index,
37 37 :reports => :issue_report}, :public => true
38 38 map.permission :add_issues, {:issues => :new}
39 39 map.permission :edit_issues, {:issues => [:edit, :reply, :bulk_edit]}
40 40 map.permission :manage_issue_relations, {:issue_relations => [:new, :destroy]}
41 41 map.permission :add_issue_notes, {:issues => [:edit, :reply]}
42 42 map.permission :edit_issue_notes, {:journals => :edit}, :require => :loggedin
43 43 map.permission :edit_own_issue_notes, {:journals => :edit}, :require => :loggedin
44 44 map.permission :move_issues, {:issues => :move}, :require => :loggedin
45 45 map.permission :delete_issues, {:issues => :destroy}, :require => :member
46 46 # Queries
47 47 map.permission :manage_public_queries, {:queries => [:new, :edit, :destroy]}, :require => :member
48 48 map.permission :save_queries, {:queries => [:new, :edit, :destroy]}, :require => :loggedin
49 49 # Gantt & calendar
50 50 map.permission :view_gantt, :issues => :gantt
51 51 map.permission :view_calendar, :issues => :calendar
52 52 # Watchers
53 53 map.permission :view_issue_watchers, {}
54 54 map.permission :add_issue_watchers, {:watchers => :new}
55 map.permission :delete_issue_watchers, {:watchers => :destroy}
55 56 end
56 57
57 58 map.project_module :time_tracking do |map|
58 59 map.permission :log_time, {:timelog => :edit}, :require => :loggedin
59 60 map.permission :view_time_entries, :timelog => [:details, :report]
60 61 map.permission :edit_time_entries, {:timelog => [:edit, :destroy]}, :require => :member
61 62 map.permission :edit_own_time_entries, {:timelog => [:edit, :destroy]}, :require => :loggedin
62 63 map.permission :manage_project_activities, {:projects => [:save_activities, :reset_activities]}, :require => :member
63 64 end
64 65
65 66 map.project_module :news do |map|
66 67 map.permission :manage_news, {:news => [:new, :edit, :destroy, :destroy_comment]}, :require => :member
67 68 map.permission :view_news, {:news => [:index, :show]}, :public => true
68 69 map.permission :comment_news, {:news => :add_comment}
69 70 end
70 71
71 72 map.project_module :documents do |map|
72 73 map.permission :manage_documents, {:documents => [:new, :edit, :destroy, :add_attachment]}, :require => :loggedin
73 74 map.permission :view_documents, :documents => [:index, :show, :download]
74 75 end
75 76
76 77 map.project_module :files do |map|
77 78 map.permission :manage_files, {:projects => :add_file}, :require => :loggedin
78 79 map.permission :view_files, :projects => :list_files, :versions => :download
79 80 end
80 81
81 82 map.project_module :wiki do |map|
82 83 map.permission :manage_wiki, {:wikis => [:edit, :destroy]}, :require => :member
83 84 map.permission :rename_wiki_pages, {:wiki => :rename}, :require => :member
84 85 map.permission :delete_wiki_pages, {:wiki => :destroy}, :require => :member
85 86 map.permission :view_wiki_pages, :wiki => [:index, :special]
86 87 map.permission :view_wiki_edits, :wiki => [:history, :diff, :annotate]
87 88 map.permission :edit_wiki_pages, :wiki => [:edit, :preview, :add_attachment]
88 89 map.permission :delete_wiki_pages_attachments, {}
89 90 map.permission :protect_wiki_pages, {:wiki => :protect}, :require => :member
90 91 end
91 92
92 93 map.project_module :repository do |map|
93 94 map.permission :manage_repository, {:repositories => [:edit, :committers, :destroy]}, :require => :member
94 95 map.permission :browse_repository, :repositories => [:show, :browse, :entry, :annotate, :changes, :diff, :stats, :graph]
95 96 map.permission :view_changesets, :repositories => [:show, :revisions, :revision]
96 97 map.permission :commit_access, {}
97 98 end
98 99
99 100 map.project_module :boards do |map|
100 101 map.permission :manage_boards, {:boards => [:new, :edit, :destroy]}, :require => :member
101 102 map.permission :view_messages, {:boards => [:index, :show], :messages => [:show]}, :public => true
102 103 map.permission :add_messages, {:messages => [:new, :reply, :quote]}
103 104 map.permission :edit_messages, {:messages => :edit}, :require => :member
104 105 map.permission :edit_own_messages, {:messages => :edit}, :require => :loggedin
105 106 map.permission :delete_messages, {:messages => :destroy}, :require => :member
106 107 map.permission :delete_own_messages, {:messages => :destroy}, :require => :loggedin
107 108 end
108 109 end
109 110
110 111 Redmine::MenuManager.map :top_menu do |menu|
111 112 menu.push :home, :home_path
112 113 menu.push :my_page, { :controller => 'my', :action => 'page' }, :if => Proc.new { User.current.logged? }
113 114 menu.push :projects, { :controller => 'projects', :action => 'index' }, :caption => :label_project_plural
114 115 menu.push :administration, { :controller => 'admin', :action => 'index' }, :if => Proc.new { User.current.admin? }, :last => true
115 116 menu.push :help, Redmine::Info.help_url, :last => true
116 117 end
117 118
118 119 Redmine::MenuManager.map :account_menu do |menu|
119 120 menu.push :login, :signin_path, :if => Proc.new { !User.current.logged? }
120 121 menu.push :register, { :controller => 'account', :action => 'register' }, :if => Proc.new { !User.current.logged? && Setting.self_registration? }
121 122 menu.push :my_account, { :controller => 'my', :action => 'account' }, :if => Proc.new { User.current.logged? }
122 123 menu.push :logout, :signout_path, :if => Proc.new { User.current.logged? }
123 124 end
124 125
125 126 Redmine::MenuManager.map :application_menu do |menu|
126 127 # Empty
127 128 end
128 129
129 130 Redmine::MenuManager.map :admin_menu do |menu|
130 131 # Empty
131 132 end
132 133
133 134 Redmine::MenuManager.map :project_menu do |menu|
134 135 menu.push :overview, { :controller => 'projects', :action => 'show' }
135 136 menu.push :activity, { :controller => 'projects', :action => 'activity' }
136 137 menu.push :roadmap, { :controller => 'projects', :action => 'roadmap' },
137 138 :if => Proc.new { |p| p.versions.any? }
138 139 menu.push :issues, { :controller => 'issues', :action => 'index' }, :param => :project_id, :caption => :label_issue_plural
139 140 menu.push :new_issue, { :controller => 'issues', :action => 'new' }, :param => :project_id, :caption => :label_issue_new,
140 141 :html => { :accesskey => Redmine::AccessKeys.key_for(:new_issue) }
141 142 menu.push :news, { :controller => 'news', :action => 'index' }, :param => :project_id, :caption => :label_news_plural
142 143 menu.push :documents, { :controller => 'documents', :action => 'index' }, :param => :project_id, :caption => :label_document_plural
143 144 menu.push :wiki, { :controller => 'wiki', :action => 'index', :page => nil },
144 145 :if => Proc.new { |p| p.wiki && !p.wiki.new_record? }
145 146 menu.push :boards, { :controller => 'boards', :action => 'index', :id => nil }, :param => :project_id,
146 147 :if => Proc.new { |p| p.boards.any? }, :caption => :label_board_plural
147 148 menu.push :files, { :controller => 'projects', :action => 'list_files' }, :caption => :label_attachment_plural
148 149 menu.push :repository, { :controller => 'repositories', :action => 'show' },
149 150 :if => Proc.new { |p| p.repository && !p.repository.new_record? }
150 151 menu.push :settings, { :controller => 'projects', :action => 'settings' }, :last => true
151 152 end
152 153
153 154 Redmine::Activity.map do |activity|
154 155 activity.register :issues, :class_name => %w(Issue Journal)
155 156 activity.register :changesets
156 157 activity.register :news
157 158 activity.register :documents, :class_name => %w(Document Attachment)
158 159 activity.register :files, :class_name => 'Attachment'
159 160 activity.register :wiki_edits, :class_name => 'WikiContent::Version', :default => false
160 161 activity.register :messages, :default => false
161 162 activity.register :time_entries, :default => false
162 163 end
163 164
164 165 Redmine::WikiFormatting.map do |format|
165 166 format.register :textile, Redmine::WikiFormatting::Textile::Formatter, Redmine::WikiFormatting::Textile::Helper
166 167 end
@@ -1,178 +1,179
1 1 ---
2 2 roles_001:
3 3 name: Manager
4 4 id: 1
5 5 builtin: 0
6 6 permissions: |
7 7 ---
8 8 - :add_project
9 9 - :edit_project
10 10 - :manage_members
11 11 - :manage_versions
12 12 - :manage_categories
13 13 - :add_issues
14 14 - :edit_issues
15 15 - :manage_issue_relations
16 16 - :add_issue_notes
17 17 - :move_issues
18 18 - :delete_issues
19 19 - :view_issue_watchers
20 20 - :add_issue_watchers
21 - :delete_issue_watchers
21 22 - :manage_public_queries
22 23 - :save_queries
23 24 - :view_gantt
24 25 - :view_calendar
25 26 - :log_time
26 27 - :view_time_entries
27 28 - :edit_time_entries
28 29 - :delete_time_entries
29 30 - :manage_news
30 31 - :comment_news
31 32 - :view_documents
32 33 - :manage_documents
33 34 - :view_wiki_pages
34 35 - :view_wiki_edits
35 36 - :edit_wiki_pages
36 37 - :delete_wiki_pages_attachments
37 38 - :protect_wiki_pages
38 39 - :delete_wiki_pages
39 40 - :rename_wiki_pages
40 41 - :add_messages
41 42 - :edit_messages
42 43 - :delete_messages
43 44 - :manage_boards
44 45 - :view_files
45 46 - :manage_files
46 47 - :browse_repository
47 48 - :manage_repository
48 49 - :view_changesets
49 50 - :manage_project_activities
50 51
51 52 position: 1
52 53 roles_002:
53 54 name: Developer
54 55 id: 2
55 56 builtin: 0
56 57 permissions: |
57 58 ---
58 59 - :edit_project
59 60 - :manage_members
60 61 - :manage_versions
61 62 - :manage_categories
62 63 - :add_issues
63 64 - :edit_issues
64 65 - :manage_issue_relations
65 66 - :add_issue_notes
66 67 - :move_issues
67 68 - :delete_issues
68 69 - :view_issue_watchers
69 70 - :save_queries
70 71 - :view_gantt
71 72 - :view_calendar
72 73 - :log_time
73 74 - :view_time_entries
74 75 - :edit_own_time_entries
75 76 - :manage_news
76 77 - :comment_news
77 78 - :view_documents
78 79 - :manage_documents
79 80 - :view_wiki_pages
80 81 - :view_wiki_edits
81 82 - :edit_wiki_pages
82 83 - :protect_wiki_pages
83 84 - :delete_wiki_pages
84 85 - :add_messages
85 86 - :edit_own_messages
86 87 - :delete_own_messages
87 88 - :manage_boards
88 89 - :view_files
89 90 - :manage_files
90 91 - :browse_repository
91 92 - :view_changesets
92 93
93 94 position: 2
94 95 roles_003:
95 96 name: Reporter
96 97 id: 3
97 98 builtin: 0
98 99 permissions: |
99 100 ---
100 101 - :edit_project
101 102 - :manage_members
102 103 - :manage_versions
103 104 - :manage_categories
104 105 - :add_issues
105 106 - :edit_issues
106 107 - :manage_issue_relations
107 108 - :add_issue_notes
108 109 - :move_issues
109 110 - :view_issue_watchers
110 111 - :save_queries
111 112 - :view_gantt
112 113 - :view_calendar
113 114 - :log_time
114 115 - :view_time_entries
115 116 - :manage_news
116 117 - :comment_news
117 118 - :view_documents
118 119 - :manage_documents
119 120 - :view_wiki_pages
120 121 - :view_wiki_edits
121 122 - :edit_wiki_pages
122 123 - :delete_wiki_pages
123 124 - :add_messages
124 125 - :manage_boards
125 126 - :view_files
126 127 - :manage_files
127 128 - :browse_repository
128 129 - :view_changesets
129 130
130 131 position: 3
131 132 roles_004:
132 133 name: Non member
133 134 id: 4
134 135 builtin: 1
135 136 permissions: |
136 137 ---
137 138 - :add_issues
138 139 - :edit_issues
139 140 - :manage_issue_relations
140 141 - :add_issue_notes
141 142 - :move_issues
142 143 - :save_queries
143 144 - :view_gantt
144 145 - :view_calendar
145 146 - :log_time
146 147 - :view_time_entries
147 148 - :comment_news
148 149 - :view_documents
149 150 - :manage_documents
150 151 - :view_wiki_pages
151 152 - :view_wiki_edits
152 153 - :edit_wiki_pages
153 154 - :add_messages
154 155 - :view_files
155 156 - :manage_files
156 157 - :browse_repository
157 158 - :view_changesets
158 159
159 160 position: 4
160 161 roles_005:
161 162 name: Anonymous
162 163 id: 5
163 164 builtin: 2
164 165 permissions: |
165 166 ---
166 167 - :add_issue_notes
167 168 - :view_gantt
168 169 - :view_calendar
169 170 - :view_time_entries
170 171 - :view_documents
171 172 - :view_wiki_pages
172 173 - :view_wiki_edits
173 174 - :view_files
174 175 - :browse_repository
175 176 - :view_changesets
176 177
177 178 position: 5
178 179
@@ -1,70 +1,80
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2008 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require File.dirname(__FILE__) + '/../test_helper'
19 19 require 'watchers_controller'
20 20
21 21 # Re-raise errors caught by the controller.
22 22 class WatchersController; def rescue_action(e) raise e end; end
23 23
24 24 class WatchersControllerTest < ActionController::TestCase
25 25 fixtures :projects, :users, :roles, :members, :member_roles, :enabled_modules,
26 26 :issues, :trackers, :projects_trackers, :issue_statuses, :enumerations, :watchers
27 27
28 28 def setup
29 29 @controller = WatchersController.new
30 30 @request = ActionController::TestRequest.new
31 31 @response = ActionController::TestResponse.new
32 32 User.current = nil
33 33 end
34 34
35 35 def test_get_watch_should_be_invalid
36 36 @request.session[:user_id] = 3
37 37 get :watch, :object_type => 'issue', :object_id => '1'
38 38 assert_response 405
39 39 end
40 40
41 41 def test_watch
42 42 @request.session[:user_id] = 3
43 43 assert_difference('Watcher.count') do
44 44 xhr :post, :watch, :object_type => 'issue', :object_id => '1'
45 45 assert_response :success
46 46 assert_select_rjs :replace_html, 'watcher'
47 47 end
48 48 assert Issue.find(1).watched_by?(User.find(3))
49 49 end
50 50
51 51 def test_unwatch
52 52 @request.session[:user_id] = 3
53 53 assert_difference('Watcher.count', -1) do
54 54 xhr :post, :unwatch, :object_type => 'issue', :object_id => '2'
55 55 assert_response :success
56 56 assert_select_rjs :replace_html, 'watcher'
57 57 end
58 58 assert !Issue.find(1).watched_by?(User.find(3))
59 59 end
60 60
61 61 def test_new_watcher
62 62 @request.session[:user_id] = 2
63 63 assert_difference('Watcher.count') do
64 64 xhr :post, :new, :object_type => 'issue', :object_id => '2', :watcher => {:user_id => '4'}
65 65 assert_response :success
66 66 assert_select_rjs :replace_html, 'watchers'
67 67 end
68 68 assert Issue.find(2).watched_by?(User.find(4))
69 69 end
70
71 def test_remove_watcher
72 @request.session[:user_id] = 2
73 assert_difference('Watcher.count', -1) do
74 xhr :post, :destroy, :object_type => 'issue', :object_id => '2', :user_id => '3'
75 assert_response :success
76 assert_select_rjs :replace_html, 'watchers'
77 end
78 assert !Issue.find(2).watched_by?(User.find(3))
79 end
70 80 end
General Comments 0
You need to be logged in to leave comments. Login now