@@ -0,0 +1,14 | |||||
|
1 | class SetTopicAuthorsAsWatchers < ActiveRecord::Migration | |||
|
2 | def self.up | |||
|
3 | # Sets active users who created/replied a topic as watchers of the topic | |||
|
4 | # so that the new watch functionality at topic level doesn't affect notifications behaviour | |||
|
5 | Message.connection.execute("INSERT INTO watchers (watchable_type, watchable_id, user_id)" + | |||
|
6 | " SELECT DISTINCT 'Message', COALESCE(messages.parent_id, messages.id), messages.author_id FROM messages, users" + | |||
|
7 | " WHERE messages.author_id = users.id AND users.status = 1") | |||
|
8 | end | |||
|
9 | ||||
|
10 | def self.down | |||
|
11 | # Removes all message watchers | |||
|
12 | Watcher.delete_all("watchable_type = 'Message'") | |||
|
13 | end | |||
|
14 | end |
@@ -24,7 +24,7 class MessagesController < ApplicationController | |||||
24 | verify :method => :post, :only => [ :reply, :destroy ], :redirect_to => { :action => :show } |
|
24 | verify :method => :post, :only => [ :reply, :destroy ], :redirect_to => { :action => :show } | |
25 | verify :xhr => true, :only => :quote |
|
25 | verify :xhr => true, :only => :quote | |
26 |
|
26 | |||
27 |
|
27 | helper :watchers | ||
28 | helper :attachments |
|
28 | helper :attachments | |
29 | include AttachmentsHelper |
|
29 | include AttachmentsHelper | |
30 |
|
30 |
@@ -33,11 +33,14 class Message < ActiveRecord::Base | |||||
33 | {:id => o.parent_id, :anchor => "message-#{o.id}"})} |
|
33 | {:id => o.parent_id, :anchor => "message-#{o.id}"})} | |
34 |
|
34 | |||
35 | acts_as_activity_provider :find_options => {:include => [{:board => :project}, :author]} |
|
35 | acts_as_activity_provider :find_options => {:include => [{:board => :project}, :author]} | |
|
36 | acts_as_watchable | |||
36 |
|
37 | |||
37 | attr_protected :locked, :sticky |
|
38 | attr_protected :locked, :sticky | |
38 | validates_presence_of :subject, :content |
|
39 | validates_presence_of :subject, :content | |
39 | validates_length_of :subject, :maximum => 255 |
|
40 | validates_length_of :subject, :maximum => 255 | |
40 |
|
41 | |||
|
42 | after_create :add_author_as_watcher | |||
|
43 | ||||
41 | def validate_on_create |
|
44 | def validate_on_create | |
42 | # Can not reply to a locked topic |
|
45 | # Can not reply to a locked topic | |
43 | errors.add_to_base 'Topic is locked' if root.locked? && self != root |
|
46 | errors.add_to_base 'Topic is locked' if root.locked? && self != root | |
@@ -68,4 +71,10 class Message < ActiveRecord::Base | |||||
68 | def project |
|
71 | def project | |
69 | board.project |
|
72 | board.project | |
70 | end |
|
73 | end | |
|
74 | ||||
|
75 | private | |||
|
76 | ||||
|
77 | def add_author_as_watcher | |||
|
78 | Watcher.create(:watchable => self.root, :user => author) | |||
|
79 | end | |||
71 | end |
|
80 | end |
@@ -17,8 +17,9 | |||||
17 |
|
17 | |||
18 | class MessageObserver < ActiveRecord::Observer |
|
18 | class MessageObserver < ActiveRecord::Observer | |
19 | def after_create(message) |
|
19 | def after_create(message) | |
20 | # send notification to the authors of the thread |
|
20 | recipients = [] | |
21 | recipients = ([message.root] + message.root.children).collect {|m| m.author.mail if m.author && m.author.active?} |
|
21 | # send notification to the topic watchers | |
|
22 | recipients += message.root.watcher_recipients | |||
22 | # send notification to the board watchers |
|
23 | # send notification to the board watchers | |
23 | recipients += message.board.watcher_recipients |
|
24 | recipients += message.board.watcher_recipients | |
24 | # send notification to project members who want to be notified |
|
25 | # send notification to project members who want to be notified |
@@ -2,6 +2,7 | |||||
2 | link_to(h(@board.name), {:controller => 'boards', :action => 'show', :project_id => @project, :id => @board}) %> |
|
2 | link_to(h(@board.name), {:controller => 'boards', :action => 'show', :project_id => @project, :id => @board}) %> | |
3 |
|
3 | |||
4 | <div class="contextual"> |
|
4 | <div class="contextual"> | |
|
5 | <%= watcher_tag(@topic, User.current) %> | |||
5 | <%= link_to_remote_if_authorized l(:button_quote), { :url => {:action => 'quote', :id => @topic} }, :class => 'icon icon-comment' %> |
|
6 | <%= link_to_remote_if_authorized l(:button_quote), { :url => {:action => 'quote', :id => @topic} }, :class => 'icon icon-comment' %> | |
6 | <%= link_to_if_authorized l(:button_edit), {:action => 'edit', :id => @topic}, :class => 'icon icon-edit' %> |
|
7 | <%= link_to_if_authorized l(:button_edit), {:action => 'edit', :id => @topic}, :class => 'icon icon-edit' %> | |
7 | <%= link_to_if_authorized l(:button_delete), {:action => 'destroy', :id => @topic}, :method => :post, :confirm => l(:text_are_you_sure), :class => 'icon icon-del' %> |
|
8 | <%= link_to_if_authorized l(:button_delete), {:action => 'destroy', :id => @topic}, :method => :post, :confirm => l(:text_are_you_sure), :class => 'icon icon-del' %> |
@@ -3,4 +3,8 watchers_001: | |||||
3 | watchable_type: Issue |
|
3 | watchable_type: Issue | |
4 | watchable_id: 2 |
|
4 | watchable_id: 2 | |
5 | user_id: 3 |
|
5 | user_id: 3 | |
|
6 | watchers_002: | |||
|
7 | watchable_type: Message | |||
|
8 | watchable_id: 1 | |||
|
9 | user_id: 1 | |||
6 | No newline at end of file |
|
10 |
@@ -1,7 +1,7 | |||||
1 | require File.dirname(__FILE__) + '/../test_helper' |
|
1 | require File.dirname(__FILE__) + '/../test_helper' | |
2 |
|
2 | |||
3 | class MessageTest < Test::Unit::TestCase |
|
3 | class MessageTest < Test::Unit::TestCase | |
4 | fixtures :projects, :boards, :messages |
|
4 | fixtures :projects, :boards, :messages, :users, :watchers | |
5 |
|
5 | |||
6 | def setup |
|
6 | def setup | |
7 | @board = Board.find(1) |
|
7 | @board = Board.find(1) | |
@@ -20,6 +20,8 class MessageTest < Test::Unit::TestCase | |||||
20 | # messages count incremented |
|
20 | # messages count incremented | |
21 | assert_equal messages_count+1, @board[:messages_count] |
|
21 | assert_equal messages_count+1, @board[:messages_count] | |
22 | assert_equal message, @board.last_message |
|
22 | assert_equal message, @board.last_message | |
|
23 | # author should be watching the message | |||
|
24 | assert message.watched_by?(@user) | |||
23 | end |
|
25 | end | |
24 |
|
26 | |||
25 | def test_reply |
|
27 | def test_reply | |
@@ -28,7 +30,8 class MessageTest < Test::Unit::TestCase | |||||
28 | @message = Message.find(1) |
|
30 | @message = Message.find(1) | |
29 | replies_count = @message.replies_count |
|
31 | replies_count = @message.replies_count | |
30 |
|
32 | |||
31 | reply = Message.new(:board => @board, :subject => 'Test reply', :content => 'Test reply content', :parent => @message, :author => @user) |
|
33 | reply_author = User.find(2) | |
|
34 | reply = Message.new(:board => @board, :subject => 'Test reply', :content => 'Test reply content', :parent => @message, :author => reply_author) | |||
32 | assert reply.save |
|
35 | assert reply.save | |
33 | @board.reload |
|
36 | @board.reload | |
34 | # same topics count |
|
37 | # same topics count | |
@@ -40,13 +43,18 class MessageTest < Test::Unit::TestCase | |||||
40 | # replies count incremented |
|
43 | # replies count incremented | |
41 | assert_equal replies_count+1, @message[:replies_count] |
|
44 | assert_equal replies_count+1, @message[:replies_count] | |
42 | assert_equal reply, @message.last_reply |
|
45 | assert_equal reply, @message.last_reply | |
|
46 | # author should be watching the message | |||
|
47 | assert @message.watched_by?(reply_author) | |||
43 | end |
|
48 | end | |
44 |
|
49 | |||
45 | def test_destroy_topic |
|
50 | def test_destroy_topic | |
46 | message = Message.find(1) |
|
51 | message = Message.find(1) | |
47 | board = message.board |
|
52 | board = message.board | |
48 | topics_count, messages_count = board.topics_count, board.messages_count |
|
53 | topics_count, messages_count = board.topics_count, board.messages_count | |
49 | assert message.destroy |
|
54 | ||
|
55 | assert_difference('Watcher.count', -1) do | |||
|
56 | assert message.destroy | |||
|
57 | end | |||
50 | board.reload |
|
58 | board.reload | |
51 |
|
59 | |||
52 | # Replies deleted |
|
60 | # Replies deleted | |
@@ -54,6 +62,7 class MessageTest < Test::Unit::TestCase | |||||
54 | # Checks counters |
|
62 | # Checks counters | |
55 | assert_equal topics_count - 1, board.topics_count |
|
63 | assert_equal topics_count - 1, board.topics_count | |
56 | assert_equal messages_count - 3, board.messages_count |
|
64 | assert_equal messages_count - 3, board.messages_count | |
|
65 | # Watchers removed | |||
57 | end |
|
66 | end | |
58 |
|
67 | |||
59 | def test_destroy_reply |
|
68 | def test_destroy_reply |
General Comments 0
You need to be logged in to leave comments.
Login now