Adds watch/unwatch functionality at forum topic level (#1912).
Users who create/reply a topic are automatically added as watchers but are now able to unwatch the topic. git-svn-id: http://redmine.rubyforge.org/svn/trunk@1878 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
parent
9e7bce6a94
commit
16e09bfd77
|
@ -24,7 +24,7 @@ class MessagesController < ApplicationController
|
||||||
verify :method => :post, :only => [ :reply, :destroy ], :redirect_to => { :action => :show }
|
verify :method => :post, :only => [ :reply, :destroy ], :redirect_to => { :action => :show }
|
||||||
verify :xhr => true, :only => :quote
|
verify :xhr => true, :only => :quote
|
||||||
|
|
||||||
|
helper :watchers
|
||||||
helper :attachments
|
helper :attachments
|
||||||
include AttachmentsHelper
|
include AttachmentsHelper
|
||||||
|
|
||||||
|
|
|
@ -33,11 +33,14 @@ class Message < ActiveRecord::Base
|
||||||
{:id => o.parent_id, :anchor => "message-#{o.id}"})}
|
{:id => o.parent_id, :anchor => "message-#{o.id}"})}
|
||||||
|
|
||||||
acts_as_activity_provider :find_options => {:include => [{:board => :project}, :author]}
|
acts_as_activity_provider :find_options => {:include => [{:board => :project}, :author]}
|
||||||
|
acts_as_watchable
|
||||||
|
|
||||||
attr_protected :locked, :sticky
|
attr_protected :locked, :sticky
|
||||||
validates_presence_of :subject, :content
|
validates_presence_of :subject, :content
|
||||||
validates_length_of :subject, :maximum => 255
|
validates_length_of :subject, :maximum => 255
|
||||||
|
|
||||||
|
after_create :add_author_as_watcher
|
||||||
|
|
||||||
def validate_on_create
|
def validate_on_create
|
||||||
# Can not reply to a locked topic
|
# Can not reply to a locked topic
|
||||||
errors.add_to_base 'Topic is locked' if root.locked? && self != root
|
errors.add_to_base 'Topic is locked' if root.locked? && self != root
|
||||||
|
@ -68,4 +71,10 @@ class Message < ActiveRecord::Base
|
||||||
def project
|
def project
|
||||||
board.project
|
board.project
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def add_author_as_watcher
|
||||||
|
Watcher.create(:watchable => self.root, :user => author)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -17,8 +17,9 @@
|
||||||
|
|
||||||
class MessageObserver < ActiveRecord::Observer
|
class MessageObserver < ActiveRecord::Observer
|
||||||
def after_create(message)
|
def after_create(message)
|
||||||
# send notification to the authors of the thread
|
recipients = []
|
||||||
recipients = ([message.root] + message.root.children).collect {|m| m.author.mail if m.author && m.author.active?}
|
# send notification to the topic watchers
|
||||||
|
recipients += message.root.watcher_recipients
|
||||||
# send notification to the board watchers
|
# send notification to the board watchers
|
||||||
recipients += message.board.watcher_recipients
|
recipients += message.board.watcher_recipients
|
||||||
# send notification to project members who want to be notified
|
# send notification to project members who want to be notified
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
link_to(h(@board.name), {:controller => 'boards', :action => 'show', :project_id => @project, :id => @board}) %>
|
link_to(h(@board.name), {:controller => 'boards', :action => 'show', :project_id => @project, :id => @board}) %>
|
||||||
|
|
||||||
<div class="contextual">
|
<div class="contextual">
|
||||||
|
<%= watcher_tag(@topic, User.current) %>
|
||||||
<%= link_to_remote_if_authorized l(:button_quote), { :url => {:action => 'quote', :id => @topic} }, :class => 'icon icon-comment' %>
|
<%= link_to_remote_if_authorized l(:button_quote), { :url => {:action => 'quote', :id => @topic} }, :class => 'icon icon-comment' %>
|
||||||
<%= link_to_if_authorized l(:button_edit), {:action => 'edit', :id => @topic}, :class => 'icon icon-edit' %>
|
<%= link_to_if_authorized l(:button_edit), {:action => 'edit', :id => @topic}, :class => 'icon icon-edit' %>
|
||||||
<%= link_to_if_authorized l(:button_delete), {:action => 'destroy', :id => @topic}, :method => :post, :confirm => l(:text_are_you_sure), :class => 'icon icon-del' %>
|
<%= link_to_if_authorized l(:button_delete), {:action => 'destroy', :id => @topic}, :method => :post, :confirm => l(:text_are_you_sure), :class => 'icon icon-del' %>
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
class SetTopicAuthorsAsWatchers < ActiveRecord::Migration
|
||||||
|
def self.up
|
||||||
|
# Sets active users who created/replied a topic as watchers of the topic
|
||||||
|
# so that the new watch functionality at topic level doesn't affect notifications behaviour
|
||||||
|
Message.connection.execute("INSERT INTO watchers (watchable_type, watchable_id, user_id)" +
|
||||||
|
" SELECT DISTINCT 'Message', COALESCE(messages.parent_id, messages.id), messages.author_id FROM messages, users" +
|
||||||
|
" WHERE messages.author_id = users.id AND users.status = 1")
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.down
|
||||||
|
# Removes all message watchers
|
||||||
|
Watcher.delete_all("watchable_type = 'Message'")
|
||||||
|
end
|
||||||
|
end
|
|
@ -3,4 +3,8 @@ watchers_001:
|
||||||
watchable_type: Issue
|
watchable_type: Issue
|
||||||
watchable_id: 2
|
watchable_id: 2
|
||||||
user_id: 3
|
user_id: 3
|
||||||
|
watchers_002:
|
||||||
|
watchable_type: Message
|
||||||
|
watchable_id: 1
|
||||||
|
user_id: 1
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
require File.dirname(__FILE__) + '/../test_helper'
|
require File.dirname(__FILE__) + '/../test_helper'
|
||||||
|
|
||||||
class MessageTest < Test::Unit::TestCase
|
class MessageTest < Test::Unit::TestCase
|
||||||
fixtures :projects, :boards, :messages
|
fixtures :projects, :boards, :messages, :users, :watchers
|
||||||
|
|
||||||
def setup
|
def setup
|
||||||
@board = Board.find(1)
|
@board = Board.find(1)
|
||||||
|
@ -20,6 +20,8 @@ class MessageTest < Test::Unit::TestCase
|
||||||
# messages count incremented
|
# messages count incremented
|
||||||
assert_equal messages_count+1, @board[:messages_count]
|
assert_equal messages_count+1, @board[:messages_count]
|
||||||
assert_equal message, @board.last_message
|
assert_equal message, @board.last_message
|
||||||
|
# author should be watching the message
|
||||||
|
assert message.watched_by?(@user)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_reply
|
def test_reply
|
||||||
|
@ -28,7 +30,8 @@ class MessageTest < Test::Unit::TestCase
|
||||||
@message = Message.find(1)
|
@message = Message.find(1)
|
||||||
replies_count = @message.replies_count
|
replies_count = @message.replies_count
|
||||||
|
|
||||||
reply = Message.new(:board => @board, :subject => 'Test reply', :content => 'Test reply content', :parent => @message, :author => @user)
|
reply_author = User.find(2)
|
||||||
|
reply = Message.new(:board => @board, :subject => 'Test reply', :content => 'Test reply content', :parent => @message, :author => reply_author)
|
||||||
assert reply.save
|
assert reply.save
|
||||||
@board.reload
|
@board.reload
|
||||||
# same topics count
|
# same topics count
|
||||||
|
@ -40,13 +43,18 @@ class MessageTest < Test::Unit::TestCase
|
||||||
# replies count incremented
|
# replies count incremented
|
||||||
assert_equal replies_count+1, @message[:replies_count]
|
assert_equal replies_count+1, @message[:replies_count]
|
||||||
assert_equal reply, @message.last_reply
|
assert_equal reply, @message.last_reply
|
||||||
|
# author should be watching the message
|
||||||
|
assert @message.watched_by?(reply_author)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_destroy_topic
|
def test_destroy_topic
|
||||||
message = Message.find(1)
|
message = Message.find(1)
|
||||||
board = message.board
|
board = message.board
|
||||||
topics_count, messages_count = board.topics_count, board.messages_count
|
topics_count, messages_count = board.topics_count, board.messages_count
|
||||||
assert message.destroy
|
|
||||||
|
assert_difference('Watcher.count', -1) do
|
||||||
|
assert message.destroy
|
||||||
|
end
|
||||||
board.reload
|
board.reload
|
||||||
|
|
||||||
# Replies deleted
|
# Replies deleted
|
||||||
|
@ -54,6 +62,7 @@ class MessageTest < Test::Unit::TestCase
|
||||||
# Checks counters
|
# Checks counters
|
||||||
assert_equal topics_count - 1, board.topics_count
|
assert_equal topics_count - 1, board.topics_count
|
||||||
assert_equal messages_count - 3, board.messages_count
|
assert_equal messages_count - 3, board.messages_count
|
||||||
|
# Watchers removed
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_destroy_reply
|
def test_destroy_reply
|
||||||
|
|
Loading…
Reference in New Issue