Commit a332e0a4 authored by Jean-Philippe Lang's avatar Jean-Philippe Lang

Adds permissions for viewing the watcher list and adding new watchers on the…

Adds permissions for viewing the watcher list and adding new watchers on the issue detail view (#398).

git-svn-id: http://redmine.rubyforge.org/svn/trunk@1712 e93f8b46-1217-0410-a6f0-8f06a7374b81
parent 6034067d
......@@ -17,30 +17,38 @@
class WatchersController < ApplicationController
layout 'base'
before_filter :require_login, :find_project, :check_project_privacy
before_filter :find_project
before_filter :require_login, :check_project_privacy, :only => [:watch, :unwatch]
before_filter :authorize, :only => :new
def add
user = User.current
@watched.add_watcher(user)
respond_to do |format|
format.html { redirect_to :back }
format.js { render(:update) {|page| page.replace_html 'watcher', watcher_link(@watched, user)} }
end
rescue RedirectBackError
render :text => 'Watcher added.', :layout => true
verify :method => :post,
:only => [ :watch, :unwatch ],
:render => { :nothing => true, :status => :method_not_allowed }
def watch
set_watcher(User.current, true)
end
def unwatch
set_watcher(User.current, false)
end
def remove
user = User.current
@watched.remove_watcher(user)
def new
@watcher = Watcher.new(params[:watcher])
@watcher.watchable = @watched
@watcher.save if request.post?
respond_to do |format|
format.html { redirect_to :back }
format.js { render(:update) {|page| page.replace_html 'watcher', watcher_link(@watched, user)} }
format.js do
render :update do |page|
page.replace_html 'watchers', :partial => 'watchers/watchers', :locals => {:watched => @watched}
end
end
end
rescue RedirectBackError
render :text => 'Watcher removed.', :layout => true
rescue ::ActionController::RedirectBackError
render :text => 'Watcher added.', :layout => true
end
private
def find_project
klass = Object.const_get(params[:object_type].camelcase)
......@@ -50,4 +58,14 @@ private
rescue
render_404
end
def set_watcher(user, watching)
@watched.set_watcher(user, watching)
respond_to do |format|
format.html { redirect_to :back }
format.js { render(:update) {|page| page.replace_html 'watcher', watcher_link(@watched, user)} }
end
rescue ::ActionController::RedirectBackError
render :text => (watching ? 'Watcher added.' : 'Watcher removed.'), :layout => true
end
end
......@@ -24,7 +24,7 @@ module WatchersHelper
return '' unless user && user.logged? && object.respond_to?('watched_by?')
watched = object.watched_by?(user)
url = {:controller => 'watchers',
:action => (watched ? 'remove' : 'add'),
:action => (watched ? 'unwatch' : 'watch'),
:object_type => object.class.to_s.underscore,
:object_id => object.id}
link_to_remote((watched ? l(:button_unwatch) : l(:button_watch)),
......@@ -33,4 +33,9 @@ module WatchersHelper
:class => (watched ? 'icon icon-fav' : 'icon icon-fav-off'))
end
# Returns a comma separated list of users watching the given object
def watchers_list(object)
object.watcher_users.collect {|u| content_tag('span', link_to_user(u), :class => 'user') }.join(",\n")
end
end
......@@ -19,5 +19,12 @@ class Watcher < ActiveRecord::Base
belongs_to :watchable, :polymorphic => true
belongs_to :user
validates_presence_of :user
validates_uniqueness_of :user_id, :scope => [:watchable_type, :watchable_id]
protected
def validate
errors.add :user_id, :activerecord_error_invalid unless user.nil? || user.active?
end
end
......@@ -78,6 +78,14 @@ end %>
</div>
<% end %>
<% if User.current.allowed_to?(:add_issue_watchers, @project) ||
(@issue.watchers.any? && User.current.allowed_to?(:view_issue_watchers, @project)) %>
<hr />
<div id="watchers">
<%= render :partial => 'watchers/watchers', :locals => {:watched => @issue} %>
</div>
<% end %>
</div>
<% if @issue.changesets.any? && User.current.allowed_to?(:view_changesets, @project) %>
......
<div class="contextual">
<%= link_to_remote l(:button_add),
:url => {:controller => 'watchers',
:action => 'new',
:object_type => watched.class.name.underscore,
:object_id => watched} if User.current.allowed_to?(:add_issue_watchers, @project) %>
</div>
<p><strong><%= l(:label_issue_watchers) %></strong></p>
<%= watchers_list(watched) %>
<% unless @watcher.nil? %>
<% remote_form_for(:watcher, @watcher,
:url => {:controller => 'watchers',
:action => 'new',
:object_type => watched.class.name.underscore,
:object_id => watched},
:method => :post,
:html => {:id => 'new-watcher-form'}) do |f| %>
<p><%= f.select :user_id, (watched.addable_watcher_users.collect {|m| [m.name, m.id]}), :prompt => true %>
<%= submit_tag l(:button_add) %>
<%= toggle_link l(:button_cancel), 'new-watcher-form'%></p>
<% end %>
<% end %>
......@@ -633,3 +633,4 @@ setting_mail_handler_api_enabled: Enable WS for incoming emails
setting_mail_handler_api_key: API key
text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nConfigure your SMTP server in config/email.yml and restart the application to enable them."
field_parent_title: Parent page
label_issue_watchers: Watchers
......@@ -638,3 +638,4 @@ setting_mail_handler_api_enabled: Enable WS for incoming emails
setting_mail_handler_api_key: API key
text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nConfigure your SMTP server in config/email.yml and restart the application to enable them."
field_parent_title: Parent page
label_issue_watchers: Watchers
......@@ -635,3 +635,4 @@ setting_mail_handler_api_enabled: Enable WS for incoming emails
setting_mail_handler_api_key: API key
text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nConfigure your SMTP server in config/email.yml and restart the application to enable them."
field_parent_title: Parent page
label_issue_watchers: Watchers
......@@ -634,3 +634,4 @@ setting_mail_handler_api_enabled: Enable WS for incoming emails
setting_mail_handler_api_key: API key
text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nConfigure your SMTP server in config/email.yml and restart the application to enable them."
field_parent_title: Parent page
label_issue_watchers: Watchers
......@@ -521,6 +521,7 @@ label_reverse_chronological_order: In reverse chronological order
label_planning: Planning
label_incoming_emails: Incoming emails
label_generate_key: Generate a key
label_issue_watchers: Watchers
button_login: Login
button_submit: Submit
......
......@@ -636,3 +636,4 @@ setting_mail_handler_api_enabled: Enable WS for incoming emails
setting_mail_handler_api_key: API key
text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nConfigure your SMTP server in config/email.yml and restart the application to enable them."
field_parent_title: Parent page
label_issue_watchers: Watchers
......@@ -633,3 +633,4 @@ setting_mail_handler_api_enabled: Enable WS for incoming emails
setting_mail_handler_api_key: API key
text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nConfigure your SMTP server in config/email.yml and restart the application to enable them."
field_parent_title: Parent page
label_issue_watchers: Watchers
......@@ -521,6 +521,7 @@ label_reverse_chronological_order: Dans l'ordre chronologique inverse
label_planning: Planning
label_incoming_emails: Emails entrants
label_generate_key: Générer une clé
label_issue_watchers: Utilisateurs surveillant cette demande
button_login: Connexion
button_submit: Soumettre
......
......@@ -633,3 +633,4 @@ setting_mail_handler_api_enabled: Enable WS for incoming emails
setting_mail_handler_api_key: API key
text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nConfigure your SMTP server in config/email.yml and restart the application to enable them."
field_parent_title: Parent page
label_issue_watchers: Watchers
......@@ -634,3 +634,4 @@ setting_mail_handler_api_enabled: Web Service engedélyezése a beérkezett leve
setting_mail_handler_api_key: API kulcs
text_email_delivery_not_configured: "Az E-mail küldés nincs konfigurálva, és az értesítések ki vannak kapcsolva.\nÁllítsd be az SMTP szervert a config/email.yml fájlban és indítsd újra az alkalmazást, hogy érvénybe lépjen."
field_parent_title: Parent page
label_issue_watchers: Watchers
......@@ -633,3 +633,4 @@ setting_mail_handler_api_enabled: Abilita WS per le e-mail in arrivo
setting_mail_handler_api_key: chiave API
text_email_delivery_not_configured: "La consegna via e-mail non è configurata e le notifiche sono disabilitate.\nConfigura il tuo server SMTP in config/email.yml e riavvia l'applicazione per abilitarle."
field_parent_title: Parent page
label_issue_watchers: Watchers
......@@ -634,3 +634,4 @@ setting_mail_handler_api_enabled: Enable WS for incoming emails
setting_mail_handler_api_key: API key
text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nConfigure your SMTP server in config/email.yml and restart the application to enable them."
field_parent_title: Parent page
label_issue_watchers: Watchers
......@@ -633,3 +633,4 @@ setting_mail_handler_api_enabled: Enable WS for incoming emails
setting_mail_handler_api_key: API key
text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nConfigure your SMTP server in config/email.yml and restart the application to enable them."
field_parent_title: Parent page
label_issue_watchers: Watchers
......@@ -636,3 +636,4 @@ setting_mail_handler_api_key: API raktas
text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nConfigure your SMTP server in config/email.yml and restart the application to enable them."
field_parent_title: Parent page
label_issue_watchers: Watchers
......@@ -634,3 +634,4 @@ setting_mail_handler_api_enabled: Enable WS for incoming emails
setting_mail_handler_api_key: API key
text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nConfigure your SMTP server in config/email.yml and restart the application to enable them."
field_parent_title: Parent page
label_issue_watchers: Watchers
......@@ -634,3 +634,4 @@ setting_mail_handler_api_enabled: Enable WS for incoming emails
setting_mail_handler_api_key: API key
text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nConfigure your SMTP server in config/email.yml and restart the application to enable them."
field_parent_title: Parent page
label_issue_watchers: Watchers
......@@ -633,3 +633,4 @@ setting_mail_handler_api_enabled: Enable WS for incoming emails
setting_mail_handler_api_key: API key
text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nConfigure your SMTP server in config/email.yml and restart the application to enable them."
field_parent_title: Parent page
label_issue_watchers: Watchers
......@@ -633,3 +633,4 @@ setting_mail_handler_api_enabled: Enable WS for incoming emails
setting_mail_handler_api_key: API key
text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nConfigure your SMTP server in config/email.yml and restart the application to enable them."
field_parent_title: Parent page
label_issue_watchers: Watchers
......@@ -633,3 +633,4 @@ setting_mail_handler_api_enabled: Enable WS for incoming emails
setting_mail_handler_api_key: API key
text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nConfigure your SMTP server in config/email.yml and restart the application to enable them."
field_parent_title: Parent page
label_issue_watchers: Watchers
......@@ -633,3 +633,4 @@ setting_mail_handler_api_enabled: Enable WS for incoming emails
setting_mail_handler_api_key: API key
text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nConfigure your SMTP server in config/email.yml and restart the application to enable them."
field_parent_title: Parent page
label_issue_watchers: Watchers
......@@ -637,3 +637,4 @@ setting_mail_handler_api_enabled: Включить веб-сервис для в
setting_mail_handler_api_key: API ключ
text_email_delivery_not_configured: "Параметры работы с почтовым сервером не настроены и функция уведомления по email не активна.\nНастроить параметры для вашего SMTP сервера вы можете в файле config/email.yml. Для применения изменений перезапустите приложение."
field_parent_title: Parent page
label_issue_watchers: Watchers
......@@ -634,3 +634,4 @@ setting_mail_handler_api_enabled: Enable WS for incoming emails
setting_mail_handler_api_key: API key
text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nConfigure your SMTP server in config/email.yml and restart the application to enable them."
field_parent_title: Parent page
label_issue_watchers: Watchers
......@@ -634,3 +634,4 @@ setting_mail_handler_api_enabled: Enable WS for incoming emails
setting_mail_handler_api_key: API key
text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nConfigure your SMTP server in config/email.yml and restart the application to enable them."
field_parent_title: Parent page
label_issue_watchers: Watchers
......@@ -636,3 +636,4 @@ setting_mail_handler_api_enabled: Enable WS for incoming emails
setting_mail_handler_api_key: API key
text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nConfigure your SMTP server in config/email.yml and restart the application to enable them."
field_parent_title: Parent page
label_issue_watchers: Watchers
......@@ -635,3 +635,4 @@ setting_mail_handler_api_enabled: Enable WS for incoming emails
setting_mail_handler_api_key: API key
text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nConfigure your SMTP server in config/email.yml and restart the application to enable them."
field_parent_title: Parent page
label_issue_watchers: Watchers
......@@ -634,3 +634,4 @@ enumeration_issue_priorities: 項目優先權
enumeration_doc_categories: 文件分類
enumeration_activities: 活動 (時間追蹤)
field_parent_title: Parent page
label_issue_watchers: Watchers
......@@ -634,3 +634,4 @@ enumeration_doc_categories: 文档类别
enumeration_activities: 活动(时间跟踪)
text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nConfigure your SMTP server in config/email.yml and restart the application to enable them."
field_parent_title: Parent page
label_issue_watchers: Watchers
......@@ -46,6 +46,9 @@ Redmine::AccessControl.map do |map|
# Gantt & calendar
map.permission :view_gantt, :projects => :gantt
map.permission :view_calendar, :projects => :calendar
# Watchers
map.permission :view_issue_watchers, {}
map.permission :add_issue_watchers, {:watchers => :new}
end
map.project_module :time_tracking do |map|
......
......@@ -15,6 +15,8 @@ roles_001:
- :add_issue_notes
- :move_issues
- :delete_issues
- :view_issue_watchers
- :add_issue_watchers
- :manage_public_queries
- :save_queries
- :view_gantt
......@@ -58,6 +60,7 @@ roles_002:
- :add_issue_notes
- :move_issues
- :delete_issues
- :view_issue_watchers
- :save_queries
- :view_gantt
- :view_calendar
......@@ -95,6 +98,7 @@ roles_003:
- :manage_issue_relations
- :add_issue_notes
- :move_issues
- :view_issue_watchers
- :save_queries
- :view_gantt
- :view_calendar
......
---
watchers_001:
watchable_type: Issue
watchable_id: 2
user_id: 3
\ No newline at end of file
# Redmine - project management software
# Copyright (C) 2006-2008 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.dirname(__FILE__) + '/../test_helper'
require 'watchers_controller'
# Re-raise errors caught by the controller.
class WatchersController; def rescue_action(e) raise e end; end
class WatchersControllerTest < Test::Unit::TestCase
fixtures :projects, :users, :roles, :members, :enabled_modules,
:issues, :trackers, :projects_trackers, :issue_statuses, :enumerations, :watchers
def setup
@controller = WatchersController.new
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
User.current = nil
end
def test_get_watch_should_be_invalid
@request.session[:user_id] = 3
get :watch, :object_type => 'issue', :object_id => '1'
assert_response 405
end
def test_watch
@request.session[:user_id] = 3
assert_difference('Watcher.count') do
xhr :post, :watch, :object_type => 'issue', :object_id => '1'
assert_response :success
assert_select_rjs :replace_html, 'watcher'
end
assert Issue.find(1).watched_by?(User.find(3))
end
def test_unwatch
@request.session[:user_id] = 3
assert_difference('Watcher.count', -1) do
xhr :post, :unwatch, :object_type => 'issue', :object_id => '2'
assert_response :success
assert_select_rjs :replace_html, 'watcher'
end
assert !Issue.find(1).watched_by?(User.find(3))
end
def test_new_watcher
@request.session[:user_id] = 2
assert_difference('Watcher.count') do
xhr :post, :new, :object_type => 'issue', :object_id => '2', :watcher => {:user_id => '4'}
assert_response :success
assert_select_rjs :replace_html, 'watchers'
end
assert Issue.find(2).watched_by?(User.find(4))
end
end
......@@ -13,6 +13,7 @@ module Redmine
class_eval do
has_many :watchers, :as => :watchable, :dependent => :delete_all
has_many :watcher_users, :through => :watchers, :source => :user
end
end
end
......@@ -22,25 +23,40 @@ module Redmine
base.extend ClassMethods
end
# Returns an array of users that are proposed as watchers
def addable_watcher_users
self.project.users.sort - self.watcher_users
end
# Adds user as a watcher
def add_watcher(user)
self.watchers << Watcher.new(:user => user)
end
# Removes user from the watchers list
def remove_watcher(user)
return nil unless user && user.is_a?(User)
Watcher.delete_all "watchable_type = '#{self.class}' AND watchable_id = #{self.id} AND user_id = #{user.id}"
end
# Adds/removes watcher
def set_watcher(user, watching=true)
watching ? add_watcher(user) : remove_watcher(user)
end
# Returns if object is watched by user
def watched_by?(user)
!self.watchers.find(:first,
:conditions => ["#{Watcher.table_name}.user_id = ?", user.id]).nil?
end
# Returns an array of watchers' email addresses
def watcher_recipients
self.watchers.collect { |w| w.user.mail if w.user.active? }.compact
end
module ClassMethods
# Returns the objects that are watched by user
def watched_by(user)
find(:all,
:include => :watchers,
......@@ -50,4 +66,4 @@ module Redmine
end
end
end
end
\ No newline at end of file
end
......@@ -138,8 +138,8 @@ module ActionView #:nodoc:
def add_options(option_tags, options, value = nil)
option_tags = "<option value=\"\"></option>\n" + option_tags if options[:include_blank]
if value.blank? && options[:prompt]
("<option value=\"\">#{options[:prompt].kind_of?(String) ? options[:prompt] : l(:actionview_instancetag_blank_option)}</option>\n") + option_tags
if options[:prompt]
("<option value=\"\">--- #{options[:prompt].kind_of?(String) ? options[:prompt] : l(:actionview_instancetag_blank_option)} ---</option>\n") + option_tags
else
option_tags
end
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment