Project

General

Profile

Feature #7555 ยป private_messages.patch

support for private messages - arthur me, 2011-04-07 16:42

View differences:

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
    (1-1/1)