Index: app/models/message.rb =================================================================== --- app/models/message.rb (revision 5352) +++ app/models/message.rb (working copy) @@ -36,14 +36,19 @@ :author_key => :author_id acts_as_watchable - attr_protected :locked, :sticky + attr_protected :locked, :sticky, :is_private validates_presence_of :board, :subject, :content validates_length_of :subject, :maximum => 255 after_create :add_author_as_watcher def visible?(user=User.current) - !user.nil? && user.allowed_to?(:view_messages, project) + # Check private conditions first + if is_private? + !user.nil? && user.allowed_to?(:view_private_messages, project) + else + !user.nil? && user.allowed_to?(:view_messages, project) + end end def validate_on_create @@ -78,10 +83,19 @@ sticky == 1 end + def is_private=(arg) + write_attribute :is_private , (arg == true || arg.to_s == '1' ? 1 : 0) + end + + def is_private? + is_private == 1 + end + def project board.project end + # @TODO probably should check private message perms here? def editable_by?(usr) usr && usr.logged? && (usr.allowed_to?(:edit_messages, project) || (self.author == usr && usr.allowed_to?(:edit_own_messages, project))) end Index: app/models/board.rb =================================================================== --- app/models/board.rb (revision 5352) +++ app/models/board.rb (working copy) @@ -19,22 +19,53 @@ belongs_to :project has_many :topics, :class_name => 'Message', :conditions => "#{Message.table_name}.parent_id IS NULL", :order => "#{Message.table_name}.created_on DESC" has_many :messages, :dependent => :destroy, :order => "#{Message.table_name}.created_on DESC" - belongs_to :last_message, :class_name => 'Message', :foreign_key => :last_message_id + + # Should messages be restricted by privacy settings? + conditions = "#{Message.table_name}.is_private IN (0, " + (User.current.allowed_to?(:view_private_messages, @project) ? "1" : "0") + ")" + has_one :last_message, + :class_name => 'Message', + :conditions => "#{Message.table_name}.parent_id IS NULL AND #{conditions}", + :order => "#{Message.table_name}.created_on DESC" + acts_as_list :scope => :project_id acts_as_watchable - + validates_presence_of :name, :description validates_length_of :name, :maximum => 30 validates_length_of :description, :maximum => 255 def visible?(user=User.current) + # We do not check for private messages here because view_private_messages + # should be a sub-permission of view_messages !user.nil? && user.allowed_to?(:view_messages, project) end def to_s name end - + + # Ensures the message count reflects the topics the user has rights to see + def permissioned_topics_count! + if User.current.allowed_to?(:view_private_messages, project) + conditions = "#{Message.table_name}.is_private IN (0, 1)" + else + conditions = "#{Message.table_name}.is_private = 0"; + end + permissioned_topics = messages.find :all, :conditions => "board_id=#{id} AND #{Message.table_name}.parent_id IS NULL AND #{conditions}" + return permissioned_topics.count + end + + # Ensures the message count reflects the messages the user has rights to see + def permissioned_messages_count! + if User.current.allowed_to?(:view_private_messages, project) + conditions = "#{Message.table_name}.is_private IN (0, 1)" + else + conditions = "#{Message.table_name}.is_private = 0"; + end + permissioned_messages = messages.find :all, :conditions => "board_id=#{id} AND #{conditions}" + return permissioned_messages.count + end + def reset_counters! self.class.reset_counters!(id) end @@ -47,4 +78,4 @@ " last_message_id = (SELECT MAX(id) FROM #{Message.table_name} WHERE board_id=#{board_id})", ["id = ?", board_id]) end -end +end \ No newline at end of file Index: app/controllers/messages_controller.rb =================================================================== --- app/controllers/messages_controller.rb (revision 5352) +++ app/controllers/messages_controller.rb (working copy) @@ -33,13 +33,17 @@ # Show a topic and its replies def show + return render_403 if !@message.visible? + page = params[:page] # Find the page of the requested reply if params[:r] && page.nil? offset = @topic.children.count(:conditions => ["#{Message.table_name}.id < ?", params[:r].to_i]) page = 1 + offset / REPLIES_PER_PAGE end - + + # We are not concerned about privacy here because the reply of a private + # message will be private as well @reply_count = @topic.children.count @reply_pages = Paginator.new self, @reply_count, REPLIES_PER_PAGE, page @replies = @topic.children.find(:all, :include => [:author, :attachments, {:board => :project}], @@ -59,6 +63,7 @@ if params[:message] && User.current.allowed_to?(:edit_messages, @project) @message.locked = params[:message]['locked'] @message.sticky = params[:message]['sticky'] + @message.is_private = params[:message]['is_private'] end if request.post? && @message.save call_hook(:controller_messages_new_after_save, { :params => params, :message => @message}) @@ -73,6 +78,8 @@ @reply = Message.new(params[:reply]) @reply.author = User.current @reply.board = @board + # Inherit privacy settings from original post + @reply.is_private = @topic.is_private @topic.children << @reply if !@reply.new_record? call_hook(:controller_messages_reply_after_save, { :params => params, :message => @reply}) @@ -88,6 +95,7 @@ if params[:message] @message.locked = params[:message]['locked'] @message.sticky = params[:message]['sticky'] + @message.is_private = params[:message]['is_private'] end if request.post? && @message.update_attributes(params[:message]) attachments = Attachment.attach_files(@message, params[:attachments]) Index: app/controllers/boards_controller.rb =================================================================== --- app/controllers/boards_controller.rb (revision 5352) +++ app/controllers/boards_controller.rb (working copy) @@ -37,6 +37,14 @@ end def show + + # Can the user see private messages? + if User.current.allowed_to?(:view_private_messages, @board.project) + conditions = "#{Message.table_name}.is_private IN (0, 1)" + else + conditions = "#{Message.table_name}.is_private = 0"; + end + respond_to do |format| format.html { sort_init 'updated_on', 'desc' @@ -49,7 +57,8 @@ @topics = @board.topics.find :all, :order => ["#{Message.table_name}.sticky DESC", sort_clause].compact.join(', '), :include => [:author, {:last_reply => :author}], :limit => @topic_pages.items_per_page, - :offset => @topic_pages.current.offset + :offset => @topic_pages.current.offset, + :conditions => [conditions] @message = Message.new render :action => 'show', :layout => !request.xhr? } Index: app/views/messages/show.rhtml =================================================================== --- app/views/messages/show.rhtml (revision 5352) +++ app/views/messages/show.rhtml (working copy) @@ -8,7 +8,9 @@ <%= 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) %> -