]> source.dussan.org Git - redmine.git/commitdiff
Adds watch/unwatch functionality at forum topic level (#1912).
authorJean-Philippe Lang <jp_lang@yahoo.fr>
Fri, 19 Sep 2008 15:32:52 +0000 (15:32 +0000)
committerJean-Philippe Lang <jp_lang@yahoo.fr>
Fri, 19 Sep 2008 15:32:52 +0000 (15:32 +0000)
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

app/controllers/messages_controller.rb
app/models/message.rb
app/models/message_observer.rb
app/views/messages/show.rhtml
db/migrate/098_set_topic_authors_as_watchers.rb [new file with mode: 0644]
test/fixtures/watchers.yml
test/unit/message_test.rb

index 554279d21261d6708263c98c04c458424518d795..79b4b616a99cec34eedc7c1eecbafd37fd532c42 100644 (file)
@@ -24,7 +24,7 @@ class MessagesController < ApplicationController
   verify :method => :post, :only => [ :reply, :destroy ], :redirect_to => { :action => :show }
   verify :xhr => true, :only => :quote
 
-  
+  helper :watchers
   helper :attachments
   include AttachmentsHelper   
 
index 80df7a33a84304fd3e616d580d669ced6b9780d6..f1cb2d0baa312a701acb203b4e637246d1eb5f32 100644 (file)
@@ -33,11 +33,14 @@ class Message < ActiveRecord::Base
                                                                                                                                        {:id => o.parent_id, :anchor => "message-#{o.id}"})}
 
   acts_as_activity_provider :find_options => {:include => [{:board => :project}, :author]}
+  acts_as_watchable
     
   attr_protected :locked, :sticky
   validates_presence_of :subject, :content
   validates_length_of :subject, :maximum => 255
   
+  after_create :add_author_as_watcher
+  
   def validate_on_create
     # Can not reply to a locked topic
     errors.add_to_base 'Topic is locked' if root.locked? && self != root
@@ -68,4 +71,10 @@ class Message < ActiveRecord::Base
   def project
     board.project
   end
+  
+  private
+  
+  def add_author_as_watcher
+    Watcher.create(:watchable => self.root, :user => author)
+  end
 end
index 0439881725a9594849b21c132d6221fd0e4951bf..d37b5381343011d8c5b73f8bbec711b09cf41be8 100644 (file)
@@ -17,8 +17,9 @@
 
 class MessageObserver < ActiveRecord::Observer
   def after_create(message)
-    # send notification to the authors of the thread
-    recipients = ([message.root] + message.root.children).collect {|m| m.author.mail if m.author && m.author.active?}
+    recipients = []
+    # send notification to the topic watchers
+    recipients += message.root.watcher_recipients
     # send notification to the board watchers
     recipients += message.board.watcher_recipients
     # send notification to project members who want to be notified
index c24be7a213bf381ce9d474419ba84528d110d0cf..31696d56dfde0a6123da884c6f1df86bb7ec3681 100644 (file)
@@ -2,6 +2,7 @@
                link_to(h(@board.name), {:controller => 'boards', :action => 'show', :project_id => @project, :id => @board}) %>
 
 <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_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' %>
diff --git a/db/migrate/098_set_topic_authors_as_watchers.rb b/db/migrate/098_set_topic_authors_as_watchers.rb
new file mode 100644 (file)
index 0000000..5bc41fb
--- /dev/null
@@ -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
index a8c4829557c3d26830e835ed23df38b3c1d31b7a..6c8cdfb5e59ea8748a7390488430ffdc0371aa93 100644 (file)
@@ -3,4 +3,8 @@ watchers_001:
   watchable_type: Issue
   watchable_id: 2
   user_id: 3
+watchers_002: 
+  watchable_type: Message
+  watchable_id: 1
+  user_id: 1
   
\ No newline at end of file
index 82ed3fe1372b474dabd6a980a56730ca7e5c6e8e..6e8e8fb26ab6a5143196ad3be4d085c93e7cfd67 100644 (file)
@@ -1,7 +1,7 @@
 require File.dirname(__FILE__) + '/../test_helper'
 
 class MessageTest < Test::Unit::TestCase
-  fixtures :projects, :boards, :messages
+  fixtures :projects, :boards, :messages, :users, :watchers
 
   def setup
     @board = Board.find(1)
@@ -20,6 +20,8 @@ class MessageTest < Test::Unit::TestCase
     # messages count incremented
     assert_equal messages_count+1, @board[:messages_count]
     assert_equal message, @board.last_message
+    # author should be watching the message
+    assert message.watched_by?(@user)
   end
   
   def test_reply
@@ -28,7 +30,8 @@ class MessageTest < Test::Unit::TestCase
     @message = Message.find(1)
     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
     @board.reload
     # same topics count
@@ -40,13 +43,18 @@ class MessageTest < Test::Unit::TestCase
     # replies count incremented
     assert_equal replies_count+1, @message[:replies_count]
     assert_equal reply, @message.last_reply
+    # author should be watching the message
+    assert @message.watched_by?(reply_author)
   end
   
   def test_destroy_topic
     message = Message.find(1)
     board = message.board
     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
     
     # Replies deleted
@@ -54,6 +62,7 @@ class MessageTest < Test::Unit::TestCase
     # Checks counters
     assert_equal topics_count - 1, board.topics_count
     assert_equal messages_count - 3, board.messages_count
+    # Watchers removed
   end
   
   def test_destroy_reply