Feature #7555 ยป private_messages.patch
app/models/message.rb (working copy) | ||
---|---|---|
36 | 36 |
:author_key => :author_id |
37 | 37 |
acts_as_watchable |
38 | 38 |
|
39 |
attr_protected :locked, :sticky |
|
39 |
attr_protected :locked, :sticky, :is_private
|
|
40 | 40 |
validates_presence_of :board, :subject, :content |
41 | 41 |
validates_length_of :subject, :maximum => 255 |
42 | 42 |
|
43 | 43 |
after_create :add_author_as_watcher |
44 | 44 |
|
45 | 45 |
def visible?(user=User.current) |
46 |
!user.nil? && user.allowed_to?(:view_messages, project) |
|
46 |
# Check private conditions first |
|
47 |
if is_private? |
|
48 |
!user.nil? && user.allowed_to?(:view_private_messages, project) |
|
49 |
else |
|
50 |
!user.nil? && user.allowed_to?(:view_messages, project) |
|
51 |
end |
|
47 | 52 |
end |
48 | 53 |
|
49 | 54 |
def validate_on_create |
... | ... | |
78 | 83 |
sticky == 1 |
79 | 84 |
end |
80 | 85 |
|
86 |
def is_private=(arg) |
|
87 |
write_attribute :is_private , (arg == true || arg.to_s == '1' ? 1 : 0) |
|
88 |
end |
|
89 | ||
90 |
def is_private? |
|
91 |
is_private == 1 |
|
92 |
end |
|
93 | ||
81 | 94 |
def project |
82 | 95 |
board.project |
83 | 96 |
end |
84 | 97 | |
98 |
# @TODO probably should check private message perms here? |
|
85 | 99 |
def editable_by?(usr) |
86 | 100 |
usr && usr.logged? && (usr.allowed_to?(:edit_messages, project) || (self.author == usr && usr.allowed_to?(:edit_own_messages, project))) |
87 | 101 |
end |
app/models/board.rb (working copy) | ||
---|---|---|
19 | 19 |
belongs_to :project |
20 | 20 |
has_many :topics, :class_name => 'Message', :conditions => "#{Message.table_name}.parent_id IS NULL", :order => "#{Message.table_name}.created_on DESC" |
21 | 21 |
has_many :messages, :dependent => :destroy, :order => "#{Message.table_name}.created_on DESC" |
22 |
belongs_to :last_message, :class_name => 'Message', :foreign_key => :last_message_id |
|
22 | ||
23 |
# Should messages be restricted by privacy settings? |
|
24 |
conditions = "#{Message.table_name}.is_private IN (0, " + (User.current.allowed_to?(:view_private_messages, @project) ? "1" : "0") + ")" |
|
25 |
has_one :last_message, |
|
26 |
:class_name => 'Message', |
|
27 |
:conditions => "#{Message.table_name}.parent_id IS NULL AND #{conditions}", |
|
28 |
:order => "#{Message.table_name}.created_on DESC" |
|
29 | ||
23 | 30 |
acts_as_list :scope => :project_id |
24 | 31 |
acts_as_watchable |
25 |
|
|
32 | ||
26 | 33 |
validates_presence_of :name, :description |
27 | 34 |
validates_length_of :name, :maximum => 30 |
28 | 35 |
validates_length_of :description, :maximum => 255 |
29 | 36 |
|
30 | 37 |
def visible?(user=User.current) |
38 |
# We do not check for private messages here because view_private_messages |
|
39 |
# should be a sub-permission of view_messages |
|
31 | 40 |
!user.nil? && user.allowed_to?(:view_messages, project) |
32 | 41 |
end |
33 | 42 |
|
34 | 43 |
def to_s |
35 | 44 |
name |
36 | 45 |
end |
37 |
|
|
46 | ||
47 |
# Ensures the message count reflects the topics the user has rights to see |
|
48 |
def permissioned_topics_count! |
|
49 |
if User.current.allowed_to?(:view_private_messages, project) |
|
50 |
conditions = "#{Message.table_name}.is_private IN (0, 1)" |
|
51 |
else |
|
52 |
conditions = "#{Message.table_name}.is_private = 0"; |
|
53 |
end |
|
54 |
permissioned_topics = messages.find :all, :conditions => "board_id=#{id} AND #{Message.table_name}.parent_id IS NULL AND #{conditions}" |
|
55 |
return permissioned_topics.count |
|
56 |
end |
|
57 | ||
58 |
# Ensures the message count reflects the messages the user has rights to see |
|
59 |
def permissioned_messages_count! |
|
60 |
if User.current.allowed_to?(:view_private_messages, project) |
|
61 |
conditions = "#{Message.table_name}.is_private IN (0, 1)" |
|
62 |
else |
|
63 |
conditions = "#{Message.table_name}.is_private = 0"; |
|
64 |
end |
|
65 |
permissioned_messages = messages.find :all, :conditions => "board_id=#{id} AND #{conditions}" |
|
66 |
return permissioned_messages.count |
|
67 |
end |
|
68 | ||
38 | 69 |
def reset_counters! |
39 | 70 |
self.class.reset_counters!(id) |
40 | 71 |
end |
... | ... | |
47 | 78 |
" last_message_id = (SELECT MAX(id) FROM #{Message.table_name} WHERE board_id=#{board_id})", |
48 | 79 |
["id = ?", board_id]) |
49 | 80 |
end |
50 |
end |
|
81 |
end |
app/controllers/messages_controller.rb (working copy) | ||
---|---|---|
33 | 33 |
|
34 | 34 |
# Show a topic and its replies |
35 | 35 |
def show |
36 |
return render_403 if !@message.visible? |
|
37 |
|
|
36 | 38 |
page = params[:page] |
37 | 39 |
# Find the page of the requested reply |
38 | 40 |
if params[:r] && page.nil? |
39 | 41 |
offset = @topic.children.count(:conditions => ["#{Message.table_name}.id < ?", params[:r].to_i]) |
40 | 42 |
page = 1 + offset / REPLIES_PER_PAGE |
41 | 43 |
end |
42 |
|
|
44 | ||
45 |
# We are not concerned about privacy here because the reply of a private |
|
46 |
# message will be private as well |
|
43 | 47 |
@reply_count = @topic.children.count |
44 | 48 |
@reply_pages = Paginator.new self, @reply_count, REPLIES_PER_PAGE, page |
45 | 49 |
@replies = @topic.children.find(:all, :include => [:author, :attachments, {:board => :project}], |
... | ... | |
59 | 63 |
if params[:message] && User.current.allowed_to?(:edit_messages, @project) |
60 | 64 |
@message.locked = params[:message]['locked'] |
61 | 65 |
@message.sticky = params[:message]['sticky'] |
66 |
@message.is_private = params[:message]['is_private'] |
|
62 | 67 |
end |
63 | 68 |
if request.post? && @message.save |
64 | 69 |
call_hook(:controller_messages_new_after_save, { :params => params, :message => @message}) |
... | ... | |
73 | 78 |
@reply = Message.new(params[:reply]) |
74 | 79 |
@reply.author = User.current |
75 | 80 |
@reply.board = @board |
81 |
# Inherit privacy settings from original post |
|
82 |
@reply.is_private = @topic.is_private |
|
76 | 83 |
@topic.children << @reply |
77 | 84 |
if !@reply.new_record? |
78 | 85 |
call_hook(:controller_messages_reply_after_save, { :params => params, :message => @reply}) |
... | ... | |
88 | 95 |
if params[:message] |
89 | 96 |
@message.locked = params[:message]['locked'] |
90 | 97 |
@message.sticky = params[:message]['sticky'] |
98 |
@message.is_private = params[:message]['is_private'] |
|
91 | 99 |
end |
92 | 100 |
if request.post? && @message.update_attributes(params[:message]) |
93 | 101 |
attachments = Attachment.attach_files(@message, params[:attachments]) |
app/controllers/boards_controller.rb (working copy) | ||
---|---|---|
37 | 37 |
end |
38 | 38 | |
39 | 39 |
def show |
40 | ||
41 |
# Can the user see private messages? |
|
42 |
if User.current.allowed_to?(:view_private_messages, @board.project) |
|
43 |
conditions = "#{Message.table_name}.is_private IN (0, 1)" |
|
44 |
else |
|
45 |
conditions = "#{Message.table_name}.is_private = 0"; |
|
46 |
end |
|
47 | ||
40 | 48 |
respond_to do |format| |
41 | 49 |
format.html { |
42 | 50 |
sort_init 'updated_on', 'desc' |
... | ... | |
49 | 57 |
@topics = @board.topics.find :all, :order => ["#{Message.table_name}.sticky DESC", sort_clause].compact.join(', '), |
50 | 58 |
:include => [:author, {:last_reply => :author}], |
51 | 59 |
:limit => @topic_pages.items_per_page, |
52 |
:offset => @topic_pages.current.offset |
|
60 |
:offset => @topic_pages.current.offset, |
|
61 |
:conditions => [conditions] |
|
53 | 62 |
@message = Message.new |
54 | 63 |
render :action => 'show', :layout => !request.xhr? |
55 | 64 |
} |
app/views/messages/show.rhtml (working copy) | ||
---|---|---|
8 | 8 |
<%= link_to(l(:button_delete), {:action => 'destroy', :id => @topic}, :method => :post, :confirm => l(:text_are_you_sure), :class => 'icon icon-del') if @message.destroyable_by?(User.current) %> |
9 | 9 |
</div> |
10 | 10 | |
11 |
<h2><%= avatar(@topic.author, :size => "24") %><%=h @topic.subject %></h2> |
|
11 |
<h2><%= avatar(@topic.author, :size => "24") %><%=h @topic.subject %> |
|
12 |
<% if @message.is_private? %><span class="private-message"><%= l(:text_message_is_private) %></span><% end %> |
|
13 |
</h2> |
|
12 | 14 | |
13 | 15 |
<div class="message"> |
14 | 16 |
<p><span class="author"><%= authoring @topic.created_on, @topic.author %></span></p> |
app/views/messages/_form.rhtml (working copy) | ||
---|---|---|
9 | 9 |
<% if !replying && User.current.allowed_to?(:edit_messages, @project) %> |
10 | 10 |
<label><%= f.check_box :sticky %><%= l(:label_board_sticky) %></label> |
11 | 11 |
<label><%= f.check_box :locked %><%= l(:label_board_locked) %></label> |
12 |
<label><%= f.check_box :is_private %><%= l(:label_message_private) %></label> |
|
12 | 13 |
<% end %> |
13 | 14 |
</p> |
14 | 15 |
app/views/boards/show.rhtml (working copy) | ||
---|---|---|
42 | 42 |
<tbody> |
43 | 43 |
<% @topics.each do |topic| %> |
44 | 44 |
<tr class="message <%= cycle 'odd', 'even' %> <%= topic.sticky? ? 'sticky' : '' %> <%= topic.locked? ? 'locked' : '' %>"> |
45 |
<td class="subject"><%= link_to h(topic.subject), { :controller => 'messages', :action => 'show', :board_id => @board, :id => topic } %></td> |
|
45 |
<td class="subject"><%= link_to h(topic.subject), { :controller => 'messages', :action => 'show', :board_id => @board, :id => topic } %> |
|
46 |
<% if topic.is_private? %><span class="private-message"><%= l(:label_board_message_is_private) %></span><% end %> |
|
47 |
</td> |
|
46 | 48 |
<td class="author" align="center"><%= topic.author %></td> |
47 | 49 |
<td class="created_on" align="center"><%= format_time(topic.created_on) %></td> |
48 | 50 |
<td class="replies" align="center"><%= topic.replies_count %></td> |
app/views/boards/index.rhtml (working copy) | ||
---|---|---|
14 | 14 |
<%= link_to h(board.name), {:action => 'show', :id => board}, :class => "board" %><br /> |
15 | 15 |
<%=h board.description %> |
16 | 16 |
</td> |
17 |
<td align="center"><%= board.topics_count %></td>
|
|
18 |
<td align="center"><%= board.messages_count %></td>
|
|
17 |
<td align="center"><%= board.permissioned_topics_count! %></td>
|
|
18 |
<td align="center"><%= board.permissioned_messages_count! %></td>
|
|
19 | 19 |
<td> |
20 | 20 |
<small> |
21 | 21 |
<% if board.last_message %> |
22 | 22 |
<%= authoring board.last_message.created_on, board.last_message.author %><br /> |
23 |
<%= link_to_message board.last_message %>
|
|
24 |
<% end %> |
|
23 |
<%= link_to_message board.last_message %> |
|
24 |
<% end %>
|
|
25 | 25 |
</small> |
26 | 26 |
</td> |
27 | 27 |
</tr> |
db/migrate/20110405_add_message_private.rb (revision 0) | ||
---|---|---|
1 |
class AddMessagePrivate < ActiveRecord::Migration |
|
2 |
def self.up |
|
3 |
add_column :messages, :is_private, :integer, :default => 0 |
|
4 |
end |
|
5 | ||
6 |
def self.down |
|
7 |
remove_column :messages, :is_private |
|
8 |
end |
|
9 |
end |
config/locales/en.yml (working copy) | ||
---|---|---|
793 | 793 |
label_project_copy_notifications: Send email notifications during the project copy |
794 | 794 |
label_principal_search: "Search for user or group:" |
795 | 795 |
label_user_search: "Search for user:" |
796 |
|
|
796 |
label_message_private: "Private post" |
|
797 |
label_board_message_is_private: "(Private post)" |
|
798 | ||
797 | 799 |
button_login: Login |
798 | 800 |
button_submit: Submit |
799 | 801 |
button_save: Save |
... | ... | |
908 | 910 |
text_own_membership_delete_confirmation: "You are about to remove some or all of your permissions and may no longer be able to edit this project after that.\nAre you sure you want to continue?" |
909 | 911 |
text_zoom_in: Zoom in |
910 | 912 |
text_zoom_out: Zoom out |
913 |
text_message_is_private: "(Private message)" |
|
911 | 914 |
|
912 | 915 |
default_role_manager: Manager |
913 | 916 |
default_role_developer: Developer |
... | ... | |
935 | 938 |
enumeration_doc_categories: Document categories |
936 | 939 |
enumeration_activities: Activities (time tracking) |
937 | 940 |
enumeration_system_activity: System Activity |
938 |
lib/redmine.rb (working copy) | ||
---|---|---|
129 | 129 |
map.project_module :boards do |map| |
130 | 130 |
map.permission :manage_boards, {:boards => [:new, :edit, :destroy]}, :require => :member |
131 | 131 |
map.permission :view_messages, {:boards => [:index, :show], :messages => [:show]}, :public => true |
132 |
map.permission :view_private_messages, {:boards => [:index, :show], :messages => [:show]}, :public => false |
|
132 | 133 |
map.permission :add_messages, {:messages => [:new, :reply, :quote]} |
133 | 134 |
map.permission :edit_messages, {:messages => :edit}, :require => :member |
134 | 135 |
map.permission :edit_own_messages, {:messages => :edit}, :require => :loggedin |