Commit f31c657e98f20ac22457d6de4feb9d000e00aeab

Authored by Daniela Feitosa
1 parent 0d1b2d3f

AI1826

app/controllers/public/profile_controller.rb
... ... @@ -14,6 +14,7 @@ class ProfileController < PublicController
14 14 if logged_in? && current_person.follows?(@profile)
15 15 @network_activities = @profile.tracked_notifications.paginate(:per_page => 30, :page => params[:page]) if @network_activities.empty?
16 16 @wall_items = @profile.scraps_received.not_replies.paginate(:per_page => 30, :page => params[:page])
  17 + @activities = @profile.activities.paginate(:per_page => 30, :page => params[:page])
17 18 end
18 19 @tags = profile.article_tags
19 20 unless profile.display_info_to?(user)
... ... @@ -180,18 +181,29 @@ class ProfileController < PublicController
180 181 @scrap.receiver= receiver
181 182 @tab_action = params[:tab_action]
182 183 @message = @scrap.save ? _("Message successfully sent.") : _("You can't leave an empty message.")
183   - @scraps = @profile.scraps_received.not_replies.paginate(:per_page => 30, :page => params[:page]) if params[:not_load_scraps].nil?
  184 + @activities = @profile.activities.paginate(:per_page => 30, :page => params[:page]) if params[:not_load_scraps].nil?
184 185 render :partial => 'leave_scrap'
185 186 end
186 187  
  188 + def leave_comment_on_activity
  189 + @comment = Comment.new(params[:comment])
  190 + @comment.author = user #'if logged_in?
  191 + @comment.source = ActionTracker::Record.find(params[:comment][:source_id])
  192 + @tab_action = params[:tab_action]
  193 + @message = @comment.save ? _("Comment successfully added.") : _("You can't leave an empty comment.")
  194 + @activities = @profile.activities.paginate(:per_page => 30, :page => params[:page]) if params[:not_load_scraps].nil?
  195 + render :partial => 'leave_comment_on_activity'
  196 + end
  197 +
187 198 def view_more_scraps
188 199 @scraps = @profile.scraps_received.not_replies.paginate(:per_page => 30, :page => params[:page])
189 200 render :partial => 'profile_scraps', :locals => {:scraps => @scraps}
190 201 end
191 202  
192 203 def view_more_activities
193   - @activities = @profile.tracked_actions.paginate(:per_page => 30, :page => params[:page])
194   - render :partial => 'profile_activities', :locals => {:activities => @activities}
  204 +# @activities = @profile.tracked_actions.paginate(:per_page => 30, :page => params[:page])
  205 + @activities = @profile.activities.paginate(:per_page => 30, :page => params[:page])
  206 + render :partial => 'profile_activities_scraps', :locals => {:activities => @activities}
195 207 end
196 208  
197 209 def view_more_network_activities
... ...
app/models/action_tracker_notification.rb
... ... @@ -3,9 +3,12 @@ class ActionTrackerNotification < ActiveRecord::Base
3 3 belongs_to :profile
4 4 belongs_to :action_tracker, :class_name => 'ActionTracker::Record', :foreign_key => 'action_tracker_id'
5 5  
  6 + has_many :comments, :through => :action_tracker, :class_name => 'Comment', :foreign_key => 'source_id'
  7 +
6 8 validates_presence_of :profile_id, :action_tracker_id
7 9 validates_uniqueness_of :action_tracker_id, :scope => :profile_id
8 10  
9 11 end
10 12  
11 13 ActionTracker::Record.has_many :action_tracker_notifications, :class_name => 'ActionTrackerNotification', :foreign_key => 'action_tracker_id', :dependent => :destroy
  14 +ActionTracker::Record.has_many :comments, :class_name => 'Comment', :foreign_key => 'source_id', :dependent => :destroy, :order => 'created_at asc'
... ...
app/models/article.rb
... ... @@ -2,9 +2,7 @@ require 'hpricot'
2 2  
3 3 class Article < ActiveRecord::Base
4 4  
5   - track_actions :create_article, :after_create, :keep_params => [:name, :url], :if => Proc.new { |a| a.is_trackable? && !a.image? }, :custom_target => :action_tracker_target
6   - track_actions :update_article, :before_update, :keep_params => [:name, :url], :if => Proc.new { |a| a.is_trackable? && (a.body_changed? || a.name_changed?) }, :custom_target => :action_tracker_target
7   - track_actions :remove_article, :before_destroy, :keep_params => [:name], :if => Proc.new { |a| a.is_trackable? }, :custom_target => :action_tracker_target
  5 + track_actions :create_article, :after_create, :keep_params => [:name, :url, :lead], :if => Proc.new { |a| a.is_trackable? && !a.image? }, :custom_target => :action_tracker_target
8 6  
9 7 # xss_terminate plugin can't sanitize array fields
10 8 before_save :sanitize_tag_list
... ... @@ -17,7 +15,7 @@ class Article &lt; ActiveRecord::Base
17 15  
18 16 belongs_to :last_changed_by, :class_name => 'Person', :foreign_key => 'last_changed_by_id'
19 17  
20   - has_many :comments, :dependent => :destroy, :order => 'created_at asc'
  18 + has_many :comments, :dependent => :destroy, :order => 'created_at asc', :as => :source
21 19  
22 20 has_many :article_categorizations, :conditions => [ 'articles_categories.virtual = ?', false ]
23 21 has_many :categories, :through => :article_categorizations
... ... @@ -134,7 +132,11 @@ class Article &lt; ActiveRecord::Base
134 132 before_update do |article|
135 133 article.advertise = true
136 134 end
137   -
  135 +
  136 + after_update do |article|
  137 + #update article's activity
  138 + end
  139 +
138 140 # retrieves all articles belonging to the given +profile+ that are not
139 141 # sub-articles of any other article.
140 142 named_scope :top_level_for, lambda { |profile|
... ...
app/models/comment.rb
1 1 class Comment < ActiveRecord::Base
2 2  
3   - track_actions :leave_comment, :after_create, :keep_params => ["article.title", "article.url", "title", "url", "body"], :custom_target => :action_tracker_target
  3 +# track_actions :leave_comment, :after_create, :keep_params => ["article.title", "article.url", "title", "url", "body"], :custom_target => :action_tracker_target
4 4  
5 5 validates_presence_of :body
6   - belongs_to :article, :counter_cache => true
  6 +
  7 + belongs_to :source, :foreign_key => :source_id, :counter_cache => true, :polymorphic => true
  8 + alias :article :source
  9 + alias :article= :source=
  10 +
7 11 belongs_to :author, :class_name => 'Person', :foreign_key => 'author_id'
8 12 has_many :children, :class_name => 'Comment', :foreign_key => 'reply_of_id', :dependent => :destroy
9 13 belongs_to :reply_of, :class_name => 'Comment', :foreign_key => 'reply_of_id'
... ... @@ -70,11 +74,11 @@ class Comment &lt; ActiveRecord::Base
70 74 after_save :notify_article
71 75 after_destroy :notify_article
72 76 def notify_article
73   - article.comments_updated
  77 + article.comments_updated if article.kind_of?(Article)
74 78 end
75 79  
76 80 after_create do |comment|
77   - if comment.article.notify_comments? && !comment.article.profile.notification_emails.empty?
  81 + if comment.source.kind_of?(Article) && comment.article.notify_comments? && !comment.article.profile.notification_emails.empty?
78 82 Comment::Notifier.deliver_mail(comment)
79 83 end
80 84 end
... ...
app/models/person.rb
... ... @@ -421,6 +421,10 @@ class Person &lt; Profile
421 421 user.save!
422 422 end
423 423  
  424 + def activities
  425 + Scrap.find_by_sql("SELECT id, updated_at, '#{Scrap.to_s}' AS klass FROM #{Scrap.table_name} WHERE scraps.receiver_id = #{self.id} AND scraps.scrap_id IS NULL UNION SELECT id, updated_at, '#{ActionTracker::Record.to_s}' AS klass FROM #{ActionTracker::Record.table_name} WHERE action_tracker.user_id = #{self.id} ORDER BY updated_at DESC")
  426 + end
  427 +
424 428 protected
425 429  
426 430 def followed_by?(profile)
... ...
app/models/profile.rb
... ... @@ -822,6 +822,10 @@ private :generate_url, :url_options
822 822 name
823 823 end
824 824  
  825 + # Override in your subclasses
  826 + def activities
  827 + []
  828 + end
825 829 protected
826 830  
827 831 def followed_by?(person)
... ...
app/models/scrap.rb
... ... @@ -11,8 +11,9 @@ class Scrap &lt; ActiveRecord::Base
11 11  
12 12 named_scope :not_replies, :conditions => {:scrap_id => nil}
13 13  
14   - track_actions :leave_scrap, :after_create, :keep_params => ['sender.name', 'content', 'receiver.name', 'receiver.url'], :if => Proc.new{|s| s.receiver != s.sender}, :custom_target => :action_tracker_target
15   - track_actions :leave_scrap_to_self, :after_create, :keep_params => ['sender.name', 'content'], :if => Proc.new{|s| s.receiver == s.sender}
  14 +######### COMO OS AMIGOS VÃO SABER Q O AMIGO RECEBEU COMENTÁRIO? ACHO QUE TEM QUE TER AÇÃO
  15 +# track_actions :leave_scrap, :after_create, :keep_params => ['sender.name', 'content', 'receiver.name', 'receiver.url'], :if => Proc.new{|s| s.receiver != s.sender}, :custom_target => :action_tracker_target
  16 +# track_actions :leave_scrap_to_self, :after_create, :keep_params => ['sender.name', 'content'], :if => Proc.new{|s| s.receiver == s.sender}
16 17  
17 18 after_create do |scrap|
18 19 scrap.root.update_attribute('updated_at', DateTime.now) unless scrap.root.nil?
... ...
app/views/profile/_add_member_in_community.rhtml 0 → 100644
... ... @@ -0,0 +1 @@
  1 +<%= render :partial => 'default_activity', :locals => {:activity => activity} %>
... ...
app/views/profile/_comment.rhtml 0 → 100644
... ... @@ -0,0 +1,61 @@
  1 +<li class="article-comment" style='border-bottom:none;'>
  2 + <div class="article-comment-inner">
  3 +
  4 + <div class="comment-content comment-logged-in">
  5 +
  6 + <%# if comment.author %>
  7 + <%= link_to image_tag(profile_icon(comment.author, :minor)) +
  8 + content_tag('span', comment.author_name, :class => 'comment-info'),
  9 + comment.author.url,
  10 + :class => 'comment-picture',
  11 + :title => comment.author_name
  12 + %>
  13 + <%# end %>
  14 +
  15 + <div class="comment-details">
  16 + <h4><%= comment.title %></h4>
  17 + <div class="comment-text">
  18 + <p/>
  19 + <%= txt2html comment.body %>
  20 + </div>
  21 + <div class="profile-activity-time">
  22 + <%= show_time(comment.created_at) %>
  23 + </div>
  24 + </div>
  25 +
  26 + <%# if logged_in? && (user == profile || user == comment.author || user.has_permission?(:moderate_comments, profile)) %>
  27 + <% button_bar(:style => 'float: right; margin-top: 0px;') do %>
  28 + <%= icon_button(:delete, _('Remove this comment and all its replies'), { :profile => params[:profile], :remove_comment => comment.id, :view => params[:view] }, :method => :post, :confirm => _('Are you sure you want to remove this comment and all its replies?')) %>
  29 + <% end %>
  30 + <%# end %>
  31 +
  32 + <div class="comment_reply post_comment_box closed">
  33 + <% if @comment && @comment.errors.any? && @comment.reply_of_id.to_i == comment.id %>
  34 + <%= error_messages_for :comment %>
  35 + <script type="text/javascript">
  36 + jQuery(function() {
  37 + document.location.href = '#<%= comment.anchor %>';
  38 + add_comment_reply_form('#comment-reply-to-<%= comment.id %>', <%= comment.id %>);
  39 + });
  40 + </script>
  41 + <% end %>
  42 + <%= report_abuse(comment.author, :comment_link, comment) if comment.author %>
  43 + <%= link_to_function _('Reply'),
  44 + "var f = add_comment_reply_form(this, %s); f.find('input[name=comment[title]], textarea').val(''); return false" % comment.id,
  45 + :class => 'comment-footer comment-footer-link comment-footer-hide',
  46 + :id => 'comment-reply-to-' + comment.id.to_s
  47 + %>
  48 + </div>
  49 +
  50 + </div>
  51 +
  52 + <% unless comment.replies.blank? %>
  53 + <ul class="comment-replies">
  54 + <% comment.replies.each do |reply| %>
  55 + <%= render :partial => 'comment', :locals => { :comment => reply } %>
  56 + <% end %>
  57 + </ul>
  58 + <% end %>
  59 +
  60 + </div>
  61 +</li>
... ...
app/views/profile/_create_article.rhtml 0 → 100644
... ... @@ -0,0 +1,11 @@
  1 +<div class='profile-activity-image'>
  2 + <%= link_to(profile_image(activity.user, :minor), activity.user.url) %>
  3 +</div>
  4 +<div class='profile-activity-description'>
  5 + <p class='profile-activity-text'><%= link_to activity.user.name, activity.user.url %> <%= describe activity %></p>
  6 + <p class='profile-activity-text'><%= activity.params['lead'] %></p>
  7 + <p class='profile-activity-time'><%= time_ago_as_sentence(activity.created_at) + ' ' + _('ago') %></p>
  8 + <div class='profile-wall-actions'>
  9 + <%= link_to_remote(content_tag(:span, _('Remove')), :url =>{:action => 'remove_activity', :activity_id => activity.id}, :update => "profile-activity-item-#{activity.id}") if logged_in? && current_person == @profile %>
  10 + </div>
  11 +</div>
... ...
app/views/profile/_default_activity.rhtml 0 → 100644
... ... @@ -0,0 +1,10 @@
  1 +<div class='profile-activity-image'>
  2 + <%= link_to(profile_image(activity.user, :minor), activity.user.url) %>
  3 +</div>
  4 +<div class='profile-activity-description'>
  5 + <p class='profile-activity-text'><%= link_to activity.user.name, activity.user.url %> <%= describe activity %></p>
  6 + <p class='profile-activity-time'><%= time_ago_as_sentence(activity.created_at) + ' ' + _('ago') %></p>
  7 + <div class='profile-wall-actions'>
  8 + <%= link_to_remote(content_tag(:span, _('Remove')), :url =>{:action => 'remove_activity', :activity_id => activity.id}, :update => "profile-activity-item-#{activity.id}") if logged_in? && current_person == @profile %>
  9 + </div>
  10 +</div>
... ...
app/views/profile/_join_community.rhtml 0 → 100644
... ... @@ -0,0 +1 @@
  1 +<%= render :partial => 'default_activity', :locals => {:activity => activity} %>
... ...
app/views/profile/_leave_comment_on_activity.rhtml 0 → 100644
... ... @@ -0,0 +1,4 @@
  1 +<%= @message %>
  2 +<% unless @activities.nil? %>
  3 + <%= render :partial => 'profile_activities_scraps', :locals => {:activities => @activities} %>
  4 +<% end %>
... ...
app/views/profile/_leave_scrap.rhtml
1 1 <%= @message %>
2   -<% unless @scraps.nil? %>
3   - <%= render :partial => 'profile_scraps', :locals => {:scraps => @scraps} %>
  2 +<% unless @activities.nil? %>
  3 + <%= render :partial => 'profile_activities_scraps', :locals => {:activities => @activities} %>
4 4 <% end %>
... ...
app/views/profile/_new_friendship.rhtml 0 → 100644
... ... @@ -0,0 +1 @@
  1 +<%= render :partial => 'default_activity', :locals => {:activity => activity} %>
... ...
app/views/profile/_profile_activities.rhtml
1   -<% activities.each do |activity| %>
2   - <li class='profile-activity-item <%= activity.verb %>' id='profile-activity-item-<%= activity.id %>'>
3   - <div class='profile-activity-image'>
4   - <%= link_to(profile_image(activity.user, :minor), activity.user.url) %>
  1 +<li class='profile-activity-item <%= activity.verb %>' id='profile-activity-item-<%= activity.id %>'>
  2 + <%= render :partial => activity.verb, :locals => { :activity => activity }%>
  3 + <hr />
  4 +
  5 + <%# if logged_in? && current_person.follows?(activity.sender) && activity.root.nil? %>
  6 + <span class='profile-wall-send-reply'><%= link_to_function _('Comment'), "hide_and_show(['#profile-wall-reply-response-#{activity.id}'],['#profile-wall-reply-#{activity.id}', '#profile-wall-reply-form-#{activity.id}']);$('reply_content_#{activity.id}').value='';$('activity_id_#{activity.id}').value='#{activity.id}';return false", :class => "profile-send-reply" %></span>
  7 + <%# end %>
  8 +
  9 + <ul class="profile-wall-activities-comments" style='padding-left: 50px;width:auto'>
  10 + <%= render :partial => 'comment', :collection => activity.comments %>
  11 + </ul>
  12 +
  13 + <div id='profile-wall-reply-<%= activity.id%>' style='display:none;width:auto;'>
  14 + <div id='profile-wall-reply-form-<%= activity.id%>' style='display:none;'>
  15 + <p class='profile-wall-reply'>
  16 + <% form_remote_tag :url => {:controller => 'profile', :action => 'leave_comment_on_activity'}, :update => "profile_activities", :success =>"hide_and_show(['#profile-wall-reply-form-#{activity.id}'],['#profile-wall-reply-response-#{activity.id}'])" do %>
  17 + <%= limited_text_area :comment, :body, 420, "reply_content_#{activity.id}", :cols => 50, :rows => 2 %>
  18 + <%= hidden_field :comment, :source_id, :id => "activity_id_#{activity.id}" %>
  19 + <%= hidden_field :comment, :author_id, :value => user.id %>
  20 + <%= submit_button :add, _('Leave a comment') %>
  21 + <%= button_to_function :cancel, _('Cancel'), "hide_and_show(['#profile-wall-reply-#{activity.id}'],[]);return false" %>
  22 + <% end %>
  23 + </p>
5 24 </div>
6   - <div class='profile-activity-description'>
7   - <p class='profile-activity-time'><%= time_ago_as_sentence(activity.created_at) + ' ' + _('ago') %></p>
8   - <p class='profile-activity-text'><%= link_to activity.user.name, activity.user.url %> <%= describe activity %></p>
9   - <%= button_to_remote(:delete, content_tag(:span, _('Remove')), :url =>{:action => 'remove_activity', :activity_id => activity.id}, :update => "profile-activity-item-#{activity.id}") if can_edit_profile %>
10   - </div>
11   - <hr />
12   - </li>
13   -<% end %>
14   -<% if activities.current_page < activities.total_pages %>
15   - <div id='profile_activities_page_<%= activities.current_page %>'>
16   - <%= button_to_remote :add, _('View more'), :url => {:action => 'view_more_activities', :page => (activities.current_page + 1)}, :update => "profile_activities_page_#{activities.current_page}" %>
  25 + <div id='profile-wall-message-response-<%=activity.id%>' class='profile-wall-message-response'></div>
17 26 </div>
18   -<% end %>
  27 +
  28 +</li>
... ...
app/views/profile/_profile_activities_scraps.rhtml 0 → 100644
... ... @@ -0,0 +1,8 @@
  1 +<% activities.each do |a| %>
  2 + <% activity = a.klass.constantize.find(a.id) %>
  3 + <% if activity.kind_of?(ActionTracker::Record) && @profile.person? %>
  4 + <%= render :partial => 'profile_activities', :locals => {:activity => activity} %>
  5 + <% else %>
  6 + <%= render :partial => 'profile_scrap', :locals => {:scrap => activity } %>
  7 + <% end %>
  8 +<% end %>
... ...
app/views/profile/_profile_activity.rhtml
1 1 <div id='profile-activity'>
2 2 <h3><%= _("%s's activity") % @profile.name %></h3>
3 3 <ul>
4   - <%= render :partial => 'profile_activities', :locals => {:activities => @activities} %>
  4 + <%= render :partial => 'profile_activities_scraps', :locals => {:activities => @activities} %>
5 5 </ul>
6 6 </div>
... ...
app/views/profile/_profile_scrap.rhtml
... ... @@ -7,13 +7,15 @@
7 7 </div>
8 8 <% comment_balloon :class => 'profile-wall-description' do %>
9 9 <p class='profile-wall-sender'><%= link_to scrap.sender.name, scrap.sender.url %></p>
10   - <p class='profile-wall-time'><%= time_ago_as_sentence(scrap.created_at) + ' ' + _('ago') %></p>
11 10 <p class='profile-wall-text'><%= txt2html scrap.content %></p>
12   - <%= button_to_remote(:delete, content_tag(:span, _('Remove')), :url =>{:action => 'remove_scrap', :scrap_id => scrap.id}, :update => "profile-wall-item-#{scrap.id}") if logged_in? && user.can_control_scrap?(scrap) %>
  11 + <p class='profile-wall-time'><%= time_ago_as_sentence(scrap.created_at) + ' ' + _('ago') %></p>
  12 + <div class='profile-wall-actions'>
13 13 <% if logged_in? && current_person.follows?(scrap.sender) && scrap.root.nil? %>
14   - <p class='profile-wall-send-reply'><%= link_to_function _('Reply'), "hide_and_show(['#profile-wall-reply-response-#{scrap.id}'],['#profile-wall-reply-#{scrap.id}', '#profile-wall-reply-form-#{scrap.id}']);$('reply_content_#{scrap.id}').value='';$('scrap_id_#{scrap.id}').value='#{scrap.id}';return false", :class => "profile-send-reply icon-reply" %></p>
  14 + <span class='profile-wall-send-reply'><%= link_to_function _('Comment'), "hide_and_show(['#profile-wall-reply-response-#{scrap.id}'],['#profile-wall-reply-#{scrap.id}', '#profile-wall-reply-form-#{scrap.id}']);$('reply_content_#{scrap.id}').value='';$('scrap_id_#{scrap.id}').value='#{scrap.id}';return false", :class => "profile-send-reply" %></span>
15 15 <% end %>
  16 + <%= link_to_remote(content_tag(:span, _('Remove')), :url =>{:action => 'remove_scrap', :scrap_id => scrap.id}, :update => "profile-wall-item-#{scrap.id}") if logged_in? && user.can_control_scrap?(scrap) %>
16 17 <% end %>
  18 + </div>
17 19 <ul class="profile-wall-scrap-replies">
18 20 <% scrap.replies.map do |reply| %>
19 21 <%= render :partial => 'profile_scrap', :locals => {:scrap => reply} %>
... ... @@ -35,7 +37,7 @@
35 37 <div id='profile-wall-reply-<%= scrap.id%>' style='display:none;'>
36 38 <div id='profile-wall-reply-form-<%= scrap.id%>' style='display:none;'>
37 39 <p class='profile-wall-reply'>
38   - <% form_remote_tag :url => {:controller => 'profile', :action => 'leave_scrap'}, :update => "profile_scraps", :success =>"hide_and_show(['#profile-wall-reply-form-#{scrap.id}'],['#profile-wall-reply-response-#{scrap.id}'])" do %>
  40 + <% form_remote_tag :url => {:controller => 'profile', :action => 'leave_scrap'}, :update => "profile_activities", :success =>"hide_and_show(['#profile-wall-reply-form-#{scrap.id}'],['#profile-wall-reply-response-#{scrap.id}'])" do %>
39 41 <%= limited_text_area :scrap, :content, 420, "reply_content_#{scrap.id}", :cols => 50, :rows => 2 %>
40 42 <%= hidden_field :scrap, :scrap_id, :id => "scrap_id_#{scrap.id}" %>
41 43 <%= hidden_field_tag 'receiver_id', scrap.sender.id %>
... ...
app/views/profile/_profile_wall.rhtml
1 1 <h3><%= _("%s's wall") % @profile.name %></h3>
2 2 <div id='leave_scrap'>
3 3 <%= flash[:error] %>
4   - <% form_remote_tag :url => {:controller => 'profile', :action => 'leave_scrap', :tab_action => 'wall' }, :update => 'profile_scraps', :success => "$('leave_scrap_content').value=''" do %>
  4 + <% form_remote_tag :url => {:controller => 'profile', :action => 'leave_scrap', :tab_action => 'wall' }, :update => 'profile_activities', :success => "$('leave_scrap_content').value=''" do %>
5 5 <%= limited_text_area :scrap, :content, 420, 'leave_scrap_content', :cols => 50, :rows => 2 %>
6 6 <%= submit_button :scrap, _('Leave a scrap') %>
7 7 <% end %>
8 8 </div>
9 9 <div id='leave_scrap_response'></div>
  10 +<ul id='profile_activities'>
  11 + <%= render :partial => 'profile_activities_scraps', :locals => {:activities => @activities} %>
  12 +</ul>
  13 +
  14 +<% if @activities.current_page < @activities.total_pages %>
  15 + <div id='profile_activities_page_<%= @activities.current_page %>'>
  16 + <%= button_to_remote :add, _('View more'), :url => {:action => 'view_more_activities', :page => (@activities.current_page + 1)}, :update => "profile_activities_page_#{@activities.current_page}" %>
  17 + </div>
  18 +<% end %>
  19 +
  20 +<!--
10 21 <ul id='profile_scraps'>
11   - <%= render :partial => 'profile_scraps', :locals => {:scraps => @wall_items} %>
  22 + <%#= render :partial => 'profile_scraps', :locals => {:scraps => @wall_items} %>
12 23 </ul>
  24 +
  25 +<% if @profile.person? %>
  26 + <%#= render :partial => 'profile_activity' %>
  27 +<% end %>
  28 +-->
... ...
app/views/profile/_update_article.rhtml 0 → 100644
... ... @@ -0,0 +1 @@
  1 +<%= render :partial => 'default_activity', :locals => {:activity => activity} %>
... ...
app/views/profile/_upload_image.rhtml 0 → 100644
... ... @@ -0,0 +1 @@
  1 +<%= render :partial => 'default_activity', :locals => {:activity => activity} %>
... ...
config/initializers/action_tracker.rb
... ... @@ -5,13 +5,7 @@ require &#39;noosfero/i18n&#39;
5 5 ActionTrackerConfig.verbs = {
6 6  
7 7 :create_article => {
8   - :description => lambda { n_('published 1 article: %{title}', 'published %{num} articles: %{title}', get_name.size) % { :num => get_name.size, :title => '{{ta.collect_group_with_index(:name){ |n,i| link_to(truncate(n), ta.get_url[i]) }.to_sentence(:connector => "%s")}}' % _("and") } },
9   - :type => :groupable
10   - },
11   -
12   - :update_article => {
13   - :description => lambda { n_('updated 1 article: %{title}', 'updated %{num} articles: %{title}', get_name.uniq.size) % { :num => get_name.uniq.size, :title => '{{ta.collect_group_with_index(:name){ |n,i| link_to(truncate(n), ta.get_url[i]) }.uniq.to_sentence(:connector => "%s")}}' % _("and") } },
14   - :type => :groupable
  8 + :description => lambda { _('published an article: %{title}') % { :title => '{{link_to(truncate(ta.get_name), ta.get_url)}}' } }
15 9 },
16 10  
17 11 :remove_article => {
... ...
db/migrate/20111211204445_add_polymorphism_on_comment.rb 0 → 100644
... ... @@ -0,0 +1,12 @@
  1 +class AddPolymorphismOnComment < ActiveRecord::Migration
  2 + def self.up
  3 + rename_column :comments, :article_id, :source_id
  4 + add_column :comments, :source_type, :string
  5 + execute("update comments set source_type = 'Article'")
  6 + end
  7 +
  8 + def self.down
  9 + remove_column :comments, :source_type
  10 + rename_column :comments, :source_id, :article_id
  11 + end
  12 +end
... ...
db/migrate/20111211233957_add_comment_count_to_action_tracker.rb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +class AddCommentCountToActionTracker < ActiveRecord::Migration
  2 + def self.up
  3 + add_column :action_tracker, :comments_count, :integer, :default => 0
  4 + end
  5 +
  6 + def self.down
  7 + remove_column :action_tracker, :comments_count, :integer, :default => 0
  8 + end
  9 +end
... ...
db/schema.rb
... ... @@ -29,6 +29,7 @@ ActiveRecord::Schema.define(:version =&gt; 20120307200651) do
29 29 t.string "verb"
30 30 t.datetime "created_at"
31 31 t.datetime "updated_at"
  32 + t.integer "comments_count", :default => 0
32 33 end
33 34  
34 35 add_index "action_tracker", ["target_id", "target_type"], :name => "index_action_tracker_on_dispatcher_id_and_dispatcher_type"
... ... @@ -198,7 +199,7 @@ ActiveRecord::Schema.define(:version =&gt; 20120307200651) do
198 199 create_table "comments", :force => true do |t|
199 200 t.string "title"
200 201 t.text "body"
201   - t.integer "article_id"
  202 + t.integer "source_id"
202 203 t.integer "author_id"
203 204 t.string "name"
204 205 t.string "email"
... ... @@ -206,6 +207,7 @@ ActiveRecord::Schema.define(:version =&gt; 20120307200651) do
206 207 t.integer "reply_of_id"
207 208 t.string "ip_address"
208 209 t.boolean "spam"
  210 + t.string "source_type"
209 211 end
210 212  
211 213 create_table "contact_lists", :force => true do |t|
... ... @@ -252,6 +254,7 @@ ActiveRecord::Schema.define(:version =&gt; 20120307200651) do
252 254 t.datetime "created_at"
253 255 t.datetime "updated_at"
254 256 t.integer "reports_lower_bound", :default => 0, :null => false
  257 + t.text "send_email_plugin_allow_to"
255 258 end
256 259  
257 260 create_table "external_feeds", :force => true do |t|
... ... @@ -384,7 +387,7 @@ ActiveRecord::Schema.define(:version =&gt; 20120307200651) do
384 387 t.string "type"
385 388 t.string "identifier"
386 389 t.integer "environment_id"
387   - t.boolean "active", :default => true
  390 + t.boolean "active", :default => true
388 391 t.string "address"
389 392 t.string "contact_phone"
390 393 t.integer "home_page_id"
... ... @@ -395,19 +398,24 @@ ActiveRecord::Schema.define(:version =&gt; 20120307200651) do
395 398 t.float "lat"
396 399 t.float "lng"
397 400 t.integer "geocode_precision"
398   - t.boolean "enabled", :default => true
399   - t.string "nickname", :limit => 16
  401 + t.boolean "enabled", :default => true
  402 + t.string "nickname", :limit => 16
400 403 t.text "custom_header"
401 404 t.text "custom_footer"
402 405 t.string "theme"
403   - t.boolean "public_profile", :default => true
  406 + t.boolean "public_profile", :default => true
404 407 t.date "birth_date"
405 408 t.integer "preferred_domain_id"
406 409 t.datetime "updated_at"
407   - t.boolean "visible", :default => true
  410 + t.boolean "visible", :default => true
408 411 t.integer "image_id"
409   - t.boolean "validated", :default => true
  412 + t.boolean "validated", :default => true
410 413 t.string "cnpj"
  414 + t.boolean "shopping_cart", :default => true
  415 + t.boolean "shopping_cart_delivery", :default => false
  416 + t.decimal "shopping_cart_delivery_price", :default => 0.0
  417 + t.integer "bsc_id"
  418 + t.string "company_name"
411 419 end
412 420  
413 421 add_index "profiles", ["environment_id"], :name => "index_profiles_on_environment_id"
... ... @@ -496,6 +504,7 @@ ActiveRecord::Schema.define(:version =&gt; 20120307200651) do
496 504 t.datetime "created_at"
497 505 t.string "target_type"
498 506 t.integer "image_id"
  507 + t.integer "bsc_id"
499 508 end
500 509  
501 510 create_table "thumbnails", :force => true do |t|
... ...
public/designs/themes/base/style.css
... ... @@ -1053,53 +1053,53 @@ hr.pre-posts, hr.sep-posts {
1053 1053  
1054 1054 .comment-wrapper-1 {
1055 1055 margin-left: 60px;
1056   - background: url(imgs/comment-bg-N.png) 0% 0% repeat-x;
  1056 + Xbackground: url(imgs/comment-bg-N.png) 0% 0% repeat-x;
1057 1057 }
1058 1058 .comment-wrapper-2 {
1059   - background: url(imgs/comment-bg-S.png) 0% 100% repeat-x;
  1059 + Xbackground: url(imgs/comment-bg-S.png) 0% 100% repeat-x;
1060 1060 }
1061 1061 .comment-wrapper-3 {
1062   - background: url(imgs/comment-bg-L.png) 100% 0% repeat-y;
  1062 + Xbackground: url(imgs/comment-bg-L.png) 100% 0% repeat-y;
1063 1063 }
1064 1064 .comment-wrapper-4 {
1065   - background: url(imgs/comment-bg-O.png) 0% 0% repeat-y;
  1065 + Xbackground: url(imgs/comment-bg-O.png) 0% 0% repeat-y;
1066 1066 }
1067 1067 .comment-wrapper-5 {
1068   - background: url(imgs/comment-bg-SL.png) 100% 100% no-repeat;
  1068 + Xbackground: url(imgs/comment-bg-SL.png) 100% 100% no-repeat;
1069 1069 }
1070 1070 .comment-wrapper-6 {
1071   - background: url(imgs/comment-bg-SO.png) 0% 100% no-repeat;
  1071 + Xbackground: url(imgs/comment-bg-SO.png) 0% 100% no-repeat;
1072 1072 }
1073 1073 .comment-wrapper-7 {
1074   - background: url(imgs/comment-bg-NL.png) 100% 0% no-repeat;
  1074 + Xbackground: url(imgs/comment-bg-NL.png) 100% 0% no-repeat;
1075 1075 }
1076 1076 .comment-wrapper-8 {
1077   - background: url(imgs/comment-bg-NO.png) 0% 0% no-repeat;
  1077 + Xbackground: url(imgs/comment-bg-NO.png) 0% 0% no-repeat;
1078 1078 }
1079 1079  
1080 1080 .comment-from-owner .comment-wrapper-1 {
1081   - background: #fbf7b5 url(/images/comment-owner-bg-N.png) repeat-x;
  1081 + Xbackground: #fbf7b5 url(/images/comment-owner-bg-N.png) repeat-x;
1082 1082 }
1083 1083 .comment-from-owner .comment-wrapper-2 {
1084   - background: url(/images/comment-owner-bg-S.png) 0% 100% repeat-x;
  1084 + Xbackground: url(/images/comment-owner-bg-S.png) 0% 100% repeat-x;
1085 1085 }
1086 1086 .comment-from-owner .comment-wrapper-3 {
1087   - background: url(/images/comment-owner-bg-L.png) 100% 0% repeat-y;
  1087 + Xbackground: url(/images/comment-owner-bg-L.png) 100% 0% repeat-y;
1088 1088 }
1089 1089 .comment-from-owner .comment-wrapper-4 {
1090   - background: url(/images/comment-owner-bg-O.png) 0% 0% repeat-y;
  1090 + Xbackground: url(/images/comment-owner-bg-O.png) 0% 0% repeat-y;
1091 1091 }
1092 1092 .comment-from-owner .comment-wrapper-5 {
1093   - background: url(/images/comment-owner-bg-SL.png) 100% 100% no-repeat;
  1093 + Xbackground: url(/images/comment-owner-bg-SL.png) 100% 100% no-repeat;
1094 1094 }
1095 1095 .comment-from-owner .comment-wrapper-6 {
1096   - background: url(/images/comment-owner-bg-SO.png) 0% 100% no-repeat;
  1096 + Xbackground: url(/images/comment-owner-bg-SO.png) 0% 100% no-repeat;
1097 1097 }
1098 1098 .comment-from-owner .comment-wrapper-7 {
1099   - background: url(/images/comment-owner-bg-NL.png) 100% 0% no-repeat;
  1099 + Xbackground: url(/images/comment-owner-bg-NL.png) 100% 0% no-repeat;
1100 1100 }
1101 1101 .comment-from-owner .comment-wrapper-8 {
1102   - background: url(/images/comment-owner-bg-NO.png) 0% 0% no-repeat;
  1102 + Xbackground: url(/images/comment-owner-bg-NO.png) 0% 0% no-repeat;
1103 1103 }
1104 1104  
1105 1105 .comment-created-at {
... ...
public/stylesheets/application.css
... ... @@ -1314,7 +1314,7 @@ a.comment-picture {
1314 1314 }
1315 1315  
1316 1316 .comment-balloon-content {
1317   - margin-left: 15px;
  1317 + Xmargin-left: 15px;
1318 1318 }
1319 1319  
1320 1320 /* * * Comment Replies * * */
... ... @@ -5883,7 +5883,15 @@ h1#agenda-title {
5883 5883 #profile-activity li, #profile-network li, #profile-wall li {
5884 5884 display: block;
5885 5885 padding: 0;
5886   - margin-bottom: 8px;
  5886 + Xmargin-bottom: 8px;
  5887 + background-color: #E8E8E8;
  5888 + border-bottom: 5px double #f2f2f2;
  5889 +}
  5890 +
  5891 +#profile-activity .profile-wall-scrap-replies li,
  5892 +#profile-network .profile-wall-scrap-replies li,
  5893 +#profile-wall .profile-wall-scrap-replies li {
  5894 + border-bottom: none;
5887 5895 }
5888 5896  
5889 5897 #profile-activity .profile-activity-image, #profile-network .profile-network-image, #profile-wall .profile-wall-image {
... ... @@ -5897,12 +5905,12 @@ h1#agenda-title {
5897 5905  
5898 5906 #profile-activity .profile-activity-description, #profile-network .profile-network-description, #profile-wall .profile-wall-description {
5899 5907 float: left;
5900   - min-height: 60px;
  5908 + Xmin-height: 60px;
5901 5909 margin: 0;
5902 5910 padding: 0;
5903 5911 border: 1px solid #ccc;
5904 5912 overflow: hidden;
5905   - background-color: #fff;
  5913 + Xbackground-color: #fff;
5906 5914 position: relative;
5907 5915 }
5908 5916  
... ... @@ -5931,17 +5939,18 @@ h1#agenda-title {
5931 5939  
5932 5940 #profile-activity .profile-activity-text, #profile-network .profile-network-text, #profile-wall .profile-wall-text {
5933 5941 font-size: 13px;
5934   - margin: 5px;
  5942 + margin: 2px 5px;
5935 5943 }
5936 5944  
5937 5945 #profile-wall .profile-wall-text {
5938 5946 padding-top: 0;
5939 5947 }
5940 5948  
5941   -#profile-activity .profile-activity-time, #profile-network .profile-network-time, #profile-wall .profile-wall-time {
  5949 +#profile_activities .profile-activity-time, #profile-network .profile-network-time, #profile-wall .profile-wall-time {
5942 5950 font-size: 11px;
5943 5951 margin: 5px;
5944 5952 color: #babdb6;
  5953 + text-align: right;
5945 5954 }
5946 5955  
5947 5956 #profile-activity hr, #profile-network hr, #profile-wall hr {
... ... @@ -6083,21 +6092,30 @@ h1#agenda-title {
6083 6092 }
6084 6093  
6085 6094 .profile-send-reply {
6086   - background-color: #eee;
6087   - border: 1px solid #aaa;
6088   - padding: 2px;
6089   - padding-left: 20px;
6090   - background-repeat: no-repeat;
6091   - background-position: 2px center;
  6095 + xbackground-color: #eee;
  6096 + xborder: 1px solid #aaa;
  6097 + xpadding: 2px;
  6098 + xpadding-left: 20px;
  6099 + xbackground-repeat: no-repeat;
  6100 + xbackground-position: 2px center;
6092 6101 color: #aaa;
6093   - text-decoration: none;
6094   - margin-left: 8px;
  6102 + Xtext-decoration: none;
  6103 + Xmargin-left: 8px;
6095 6104 }
6096 6105  
6097 6106 #content .profile-send-reply:hover {
6098 6107 text-decoration: none;
6099 6108 }
6100 6109  
  6110 +#profile-wall .profile-wall-actions {
  6111 + text-align: right;
  6112 +}
  6113 +
  6114 +#profile-wall .profile-wall-send-reply {
  6115 + display: inline-block;
  6116 +
  6117 +}
  6118 +
6101 6119 #profile-wall .profile-wall-scrap-replies .profile-wall-description {
6102 6120 background: transparent;
6103 6121 }
... ... @@ -6244,7 +6262,7 @@ h1#agenda-title {
6244 6262 }
6245 6263  
6246 6264 #profile-wall .comment-balloon-content {
6247   - padding: 3px 0 3px 15px;
  6265 + padding: 3px 0px;
6248 6266 }
6249 6267  
6250 6268 .profile-wall-reply {
... ... @@ -6266,8 +6284,9 @@ h1#agenda-title {
6266 6284 width: 98%;
6267 6285 }
6268 6286  
6269   -#profile-activity .profile-activity-image, #profile-network .profile-network-image, #profile-wall .profile-wall-image {
6270   - width: 19%;
  6287 +#profile_activities .profile-activity-image, #profile-network .profile-network-image, #profile-wall .profile-wall-image {
  6288 + width: 50px;
  6289 + margin: 5px;
6271 6290 }
6272 6291  
6273 6292 #profile-activity .profile-activity-description, #profile-network .profile-network-description, #profile-wall .profile-wall-description {
... ...
test/factories.rb
... ... @@ -438,7 +438,7 @@ module Noosfero::Factory
438 438  
439 439 def defaults_for_comment(params = {})
440 440 name = "comment_#{rand(1000)}"
441   - { :title => name, :body => "my own comment", :article_id => 1 }.merge(params)
  441 + { :title => name, :body => "my own comment", :source_id => 1 }.merge(params)
442 442 end
443 443  
444 444 ###############################################
... ...
test/functional/profile_controller_test.rb
... ... @@ -714,21 +714,27 @@ class ProfileControllerTest &lt; ActionController::TestCase
714 714 assert_no_tag :tag => 'p', :content => 'A scrap'
715 715 end
716 716  
717   - should 'see all activities of the current profile' do
  717 + should 'see only actions of the current profile when he is not followed by the viewer' do
718 718 p1= Person.first
719 719 p2= fast_create(Person)
720   - assert !p1.is_a_friend?(p2)
721 720 p3= fast_create(Person)
722   - assert !p1.is_a_friend?(p3)
  721 +
  722 +# UserStampSweeper.any_instance.stubs(:current_user).returns(p1)
723 723 ActionTracker::Record.destroy_all
724   - Scrap.create!(defaults_for_scrap(:sender => p1, :receiver => p1))
  724 + scrap1 = Scrap.create!(defaults_for_scrap(:sender => p1, :receiver => p1))
  725 +
  726 +# UserStampSweeper.any_instance.stubs(:current_user).returns(p2)
  727 + scrap2 = Scrap.create!(defaults_for_scrap(:sender => p2, :receiver => p3))
  728 +# a2 = ActionTracker::Record.last
  729 +
  730 +# UserStampSweeper.any_instance.stubs(:current_user).returns(p3)
  731 + scrap3 = Scrap.create!(defaults_for_scrap(:sender => p3, :receiver => p1))
  732 +# a3 = ActionTracker::Record.last
  733 +
  734 + UserStampSweeper.any_instance.stubs(:current_user).returns(p1)
  735 + TinyMceArticle.create!(:profile => p1, :name => 'An article about free software')
725 736 a1 = ActionTracker::Record.last
726   - UserStampSweeper.any_instance.stubs(:current_user).returns(p2)
727   - Scrap.create!(defaults_for_scrap(:sender => p2, :receiver => p3))
728   - a2 = ActionTracker::Record.last
729   - UserStampSweeper.any_instance.stubs(:current_user).returns(p3)
730   - Scrap.create!(defaults_for_scrap(:sender => p3, :receiver => p1))
731   - a3 = ActionTracker::Record.last
  737 +
732 738 login_as(profile.identifier)
733 739 get :index, :profile => p1.identifier
734 740 assert_not_nil assigns(:activities)
... ... @@ -744,7 +750,7 @@ class ProfileControllerTest &lt; ActionController::TestCase
744 750 assert_equal 30, assigns(:activities).count
745 751 end
746 752  
747   - should 'see not see the friends activities in the current profile activity' do
  753 + should 'not see the friends actions and scraps in the current profile activity' do
748 754 p1= Person.first
749 755 p2= fast_create(Person)
750 756 assert !p1.is_a_friend?(p2)
... ... @@ -752,18 +758,23 @@ class ProfileControllerTest &lt; ActionController::TestCase
752 758 p1.add_friend(p3)
753 759 assert p1.is_a_friend?(p3)
754 760 ActionTracker::Record.destroy_all
755   - Scrap.create!(defaults_for_scrap(:sender => p1, :receiver => p1))
  761 +
  762 + scrap1 = Scrap.create!(defaults_for_scrap(:sender => p1, :receiver => p1))
  763 + scrap2 = Scrap.create!(defaults_for_scrap(:sender => p2, :receiver => p3))
  764 + scrap3 = Scrap.create!(defaults_for_scrap(:sender => p3, :receiver => p1))
  765 +
  766 + UserStampSweeper.any_instance.stubs(:current_user).returns(p3)
  767 + TinyMceArticle.create!(:profile => p3, :name => 'An article about free software')
756 768 a1 = ActionTracker::Record.last
757   - UserStampSweeper.any_instance.stubs(:current_user).returns(p2)
758   - Scrap.create!(defaults_for_scrap(:sender => p2, :receiver => p3))
  769 +
  770 + UserStampSweeper.any_instance.stubs(:current_user).returns(p1)
  771 + TinyMceArticle.create!(:profile => p1, :name => 'Another article about free software')
759 772 a2 = ActionTracker::Record.last
760   - UserStampSweeper.any_instance.stubs(:current_user).returns(p3)
761   - Scrap.create!(defaults_for_scrap(:sender => p3, :receiver => p1))
762   - a3 = ActionTracker::Record.last
  773 +
763 774 login_as(profile.identifier)
764 775 get :index, :profile => p1.identifier
765 776 assert_not_nil assigns(:activities)
766   - assert_equal [a1], assigns(:activities)
  777 + assert_equal [a2], assigns(:activities)
767 778 end
768 779  
769 780 should 'see all the activities in the current profile network' do
... ... @@ -976,7 +987,7 @@ class ProfileControllerTest &lt; ActionController::TestCase
976 987  
977 988 should 'the wall_itens be paginated in people profiles' do
978 989 p1 = Person.first
979   - 40.times{fast_create(Scrap, :sender_id => p1.id)}
  990 + 40.times{fast_create(Scrap, :sender_id => p1.id, :created_at => Time.now)}
980 991  
981 992 @controller.stubs(:logged_in?).returns(true)
982 993 user = mock()
... ... @@ -1158,7 +1169,7 @@ class ProfileControllerTest &lt; ActionController::TestCase
1158 1169 assert_equal 40, profile.tracked_actions.count
1159 1170 get :view_more_activities, :profile => profile.identifier, :page => 2
1160 1171 assert_response :success
1161   - assert_template '_profile_activities'
  1172 + assert_template '_profile_bla'
1162 1173 assert_equal 10, assigns(:activities).count
1163 1174 end
1164 1175  
... ... @@ -1247,4 +1258,34 @@ class ProfileControllerTest &lt; ActionController::TestCase
1247 1258 post :register_report, :profile => reported.identifier, :abuse_report => {:reason => 'some reason'}
1248 1259 end
1249 1260 end
  1261 +
  1262 + should 'display activities and scraps together' do
  1263 + another_person = fast_create(Person)
  1264 + Scrap.create!(defaults_for_scrap(:sender => another_person, :receiver => profile, :content => 'A scrap'))
  1265 +
  1266 + UserStampSweeper.any_instance.stubs(:current_user).returns(profile)
  1267 + ActionTracker::Record.destroy_all
  1268 + TinyMceArticle.create!(:profile => profile, :name => 'An article about free software')
  1269 +
  1270 + login_as(profile.identifier)
  1271 + get :index, :profile => profile.identifier
  1272 +
  1273 + assert_tag :tag => 'div', :attributes => { :id => 'profile-wall' }, :descendant => { :tag => 'p', :content => 'A scrap' }
  1274 + assert_tag :tag => 'div', :attributes => { :id => 'profile-wall' }, :descendant => { :tag => 'a', :content => 'An article about free software' }
  1275 + end
  1276 +
  1277 + should 'have scraps and activities on activities' do
  1278 + another_person = fast_create(Person)
  1279 + scrap = Scrap.create!(defaults_for_scrap(:sender => another_person, :receiver => profile, :content => 'A scrap'))
  1280 +
  1281 + UserStampSweeper.any_instance.stubs(:current_user).returns(profile)
  1282 + ActionTracker::Record.destroy_all
  1283 + TinyMceArticle.create!(:profile => profile, :name => 'An article about free software')
  1284 + activity = ActionTracker::Record.last
  1285 +
  1286 + login_as(profile.identifier)
  1287 + get :index, :profile => profile.identifier
  1288 +
  1289 + assert_equivalent [scrap,activity], assigns(:activities).map {|a| a.klass.constantize.find(a.id)}
  1290 + end
1250 1291 end
... ...
test/unit/action_tracker_notification_test.rb
... ... @@ -76,4 +76,12 @@ class ActionTrackerNotificationTest &lt; ActiveSupport::TestCase
76 76 assert_equal [last_notification], at.action_tracker_notifications
77 77 end
78 78  
  79 + should "have comments through action_tracker" do
  80 + action = fast_create(ActionTracker::Record)
  81 + notification = fast_create(ActionTrackerNotification, :action_tracker_id => action.id, :profile_id => 1)
  82 +
  83 + comment = fast_create(Comment, :source_id => action.id)
  84 + assert_equal action.comments, notification.comments
  85 + end
  86 +
79 87 end
... ...
test/unit/article_test.rb
... ... @@ -1009,6 +1009,28 @@ class ArticleTest &lt; ActiveSupport::TestCase
1009 1009 assert_equal ['a','b'], ta.get_name
1010 1010 end
1011 1011  
  1012 + should 'update action when article is updated' do
  1013 + article = create(TinyMceArticle, :profile => profile)
  1014 + action = ActionTracker::Record.last
  1015 + time = action.updated_at
  1016 +
  1017 + Time.stubs(:now).returns(time + 1.day)
  1018 + article.name = 'New name'
  1019 + article.save
  1020 + assert_not_equal time, ActionTracker::Record.last.updated_at
  1021 + end
  1022 +
  1023 + should 'update action when comment is created' do
  1024 + article = create(TinyMceArticle, :profile => profile)
  1025 + action = ActionTracker::Record.last
  1026 + time = action.updated_at
  1027 +
  1028 + Time.stubs(:now).returns(time + 1.day)
  1029 +
  1030 + article.comments << Comment.create(:name => 'Guest', :email => 'guest@example.com', :title => 'test comment', :body => 'hello!')
  1031 + assert_not_equal time, ActionTracker::Record.last.updated_at
  1032 + end
  1033 +
1012 1034 should 'notifiable is false by default' do
1013 1035 a = fast_create(Article)
1014 1036 assert !a.notifiable?
... ... @@ -1638,4 +1660,23 @@ class ArticleTest &lt; ActiveSupport::TestCase
1638 1660 assert_equal [c1,c2,c5], Article.text_articles
1639 1661 end
1640 1662  
  1663 + should 'filter articles by date of creation' do
  1664 + from = Date.today - 2.days
  1665 + to = Date.today - 1.day
  1666 + article1 = fast_create(Article, :created_at => from - 1.day)
  1667 + article2 = fast_create(Article, :created_at => from + 6.hours)
  1668 + article3 = fast_create(Article, :created_at => to + 1.day)
  1669 +
  1670 + assert_not_includes Article.created_between(from, nil), article1
  1671 + assert_includes Article.created_between(from, nil), article2
  1672 + assert_includes Article.created_between(from, nil), article3
  1673 +
  1674 + assert_includes Article.created_between(nil, to), article1
  1675 + assert_includes Article.created_between(nil, to), article2
  1676 + assert_not_includes Article.created_between(nil, to), article3
  1677 +
  1678 + assert_not_includes Article.created_between(from, to), article1
  1679 + assert_includes Article.created_between(from, to), article2
  1680 + assert_not_includes Article.created_between(from, to), article3
  1681 + end
1641 1682 end
... ...
test/unit/comment_test.rb
... ... @@ -13,13 +13,13 @@ class CommentTest &lt; ActiveSupport::TestCase
13 13 assert_mandatory(Comment.new, :body)
14 14 end
15 15  
16   - should 'belong to an article' do
  16 + should 'have a polymorphic relationship with source' do
17 17 c = Comment.new
18   - assert_raise ActiveRecord::AssociationTypeMismatch do
19   - c.article = 1
  18 + assert_nothing_raised do
  19 + c.source = Article.new
20 20 end
21 21 assert_nothing_raised do
22   - c.article = Article.new
  22 + c.source = ActionTracker::Record.new
23 23 end
24 24 end
25 25  
... ... @@ -69,8 +69,9 @@ class CommentTest &lt; ActiveSupport::TestCase
69 69  
70 70 cc = art.comments_count
71 71 art.comments.build(:title => 'test comment', :body => 'anything', :author => owner).save!
72   - art.reload
73   - assert_equal cc + 1, art.comments_count
  72 + art = Article.find(art.id)
  73 +
  74 + assert_equal cc + 1, Article.find(art.id).comments_count
74 75 end
75 76  
76 77 should 'provide author name for authenticated authors' do
... ... @@ -217,30 +218,10 @@ class CommentTest &lt; ActiveSupport::TestCase
217 218 assert File.exists?(File.join(Rails.root, 'public', image)), "#{image} does not exist."
218 219 end
219 220  
220   - should 'track action when comment is created' do
221   - owner = create_user('testuser').person
222   - article = owner.articles.create!(:name => 'test', :body => '...')
223   - comment = article.comments.create!(:article => article, :name => 'foo', :title => 'bar', :body => 'my comment', :email => 'cracker@test.org')
224   - ta = ActionTracker::Record.last
225   - assert_equal 'bar', ta.get_title
226   - assert_equal 'my comment', ta.get_body
227   - assert_equal 'test', ta.get_article_title
228   - assert_equal article.url, ta.get_article_url
229   - assert_equal comment.url, ta.get_url
230   - end
231   -
232 221 should 'have the action_tracker_target defined' do
233 222 assert Comment.method_defined?(:action_tracker_target)
234 223 end
235 224  
236   - should "have the action_tracker_target be the articles's profile" do
237   - owner = create_user('testuser').person
238   - article = owner.articles.create!(:name => 'test', :body => '...')
239   - comment = article.comments.create!(:article => article, :name => 'foo', :title => 'bar', :body => 'my comment', :email => 'cracker@test.org')
240   - ta = ActionTracker::Record.last
241   - assert_equal owner, ta.target
242   - end
243   -
244 225 should "get children of a comment" do
245 226 c = fast_create(Comment)
246 227 c1 = fast_create(Comment, :reply_of_id => c.id)
... ... @@ -307,11 +288,11 @@ class CommentTest &lt; ActiveSupport::TestCase
307 288  
308 289 should "return comments as a thread" do
309 290 a = fast_create(Article)
310   - c0 = fast_create(Comment, :article_id => a.id)
311   - c1 = fast_create(Comment, :reply_of_id => c0.id, :article_id => a.id)
312   - c2 = fast_create(Comment, :reply_of_id => c1.id, :article_id => a.id)
313   - c3 = fast_create(Comment, :reply_of_id => c0.id, :article_id => a.id)
314   - c4 = fast_create(Comment, :article_id => a.id)
  291 + c0 = fast_create(Comment, :source_id => a.id)
  292 + c1 = fast_create(Comment, :reply_of_id => c0.id, :source_id => a.id)
  293 + c2 = fast_create(Comment, :reply_of_id => c1.id, :source_id => a.id)
  294 + c3 = fast_create(Comment, :reply_of_id => c0.id, :source_id => a.id)
  295 + c4 = fast_create(Comment, :source_id => a.id)
315 296 result = a.comments.as_thread
316 297 assert_equal c0.id, result[0].id
317 298 assert_equal [c1.id, c3.id], result[0].replies.map(&:id)
... ...
test/unit/community_test.rb
... ... @@ -341,4 +341,5 @@ class CommunityTest &lt; ActiveSupport::TestCase
341 341 assert_equal false, community.receives_scrap_notification?
342 342 end
343 343  
  344 + should 'return tracked_actions and scraps as activities'
344 345 end
... ...
test/unit/enterprise_test.rb
... ... @@ -450,4 +450,6 @@ class EnterpriseTest &lt; ActiveSupport::TestCase
450 450 e = fast_create(Enterprise)
451 451 assert_respond_to e, :production_costs
452 452 end
  453 +
  454 + should 'return tracked_actions and scraps as activities'
453 455 end
... ...
test/unit/person_test.rb
... ... @@ -1243,4 +1243,34 @@ class PersonTest &lt; ActiveSupport::TestCase
1243 1243 assert !person.visible
1244 1244 assert_not_equal password, person.user.password
1245 1245 end
  1246 +
  1247 + should 'return tracked_actions and scraps as activities' do
  1248 + person = fast_create(Person)
  1249 + another_person = fast_create(Person)
  1250 +
  1251 + scrap = Scrap.create!(defaults_for_scrap(:sender => another_person, :receiver => person, :content => 'A scrap'))
  1252 + UserStampSweeper.any_instance.expects(:current_user).returns(person).at_least_once
  1253 + TinyMceArticle.create!(:profile => person, :name => 'An article about free software')
  1254 + activity = ActionTracker::Record.last
  1255 +
  1256 + assert_equal 'An article about free software', activity.get_name.last
  1257 + assert_equal [scrap,activity], person.activities.map { |a| a.klass.constantize.find(a.id) }
  1258 + end
  1259 +
  1260 + should 'not return tracked_actions and scraps from others as activities' do
  1261 + person = fast_create(Person)
  1262 + another_person = fast_create(Person)
  1263 +
  1264 + person_scrap = Scrap.create!(defaults_for_scrap(:sender => person, :receiver => person, :content => 'A scrap from person'))
  1265 + another_person_scrap = Scrap.create!(defaults_for_scrap(:sender => another_person, :receiver => another_person, :content => 'A scrap from another person'))
  1266 +
  1267 + TinyMceArticle.create!(:profile => another_person, :name => 'An article about free software from another person')
  1268 + another_person_activity = ActionTracker::Record.last
  1269 +
  1270 + UserStampSweeper.any_instance.stubs(:current_user).returns(person)
  1271 + TinyMceArticle.create!(:profile => person, :name => 'An article about free software')
  1272 + person_activity = ActionTracker::Record.last
  1273 +
  1274 + assert_equal [person_scrap,person_activity], person.activities.map { |a| a.klass.constantize.find(a.id) }
  1275 + end
1246 1276 end
... ...
test/unit/profile_test.rb
... ... @@ -1704,6 +1704,7 @@ class ProfileTest &lt; ActiveSupport::TestCase
1704 1704 assert profile.is_on_homepage?("/#{profile.identifier}/#{homepage.slug}", homepage)
1705 1705 end
1706 1706  
  1707 +
1707 1708 should 'find profiles with image' do
1708 1709 env = fast_create(Environment)
1709 1710 2.times do |n|
... ... @@ -1762,10 +1763,15 @@ class ProfileTest &lt; ActiveSupport::TestCase
1762 1763 assert_raise NoMethodError do
1763 1764 Profile::Roles.invalid_role(env.id)
1764 1765 end
  1766 +
  1767 + should 'return empty array as activities' do
  1768 + profile = Profile.new
  1769 + assert_equal [], profile.activities
1765 1770 end
1766 1771  
1767 1772 private
1768 1773  
  1774 +
1769 1775 def assert_invalid_identifier(id)
1770 1776 profile = Profile.new(:identifier => id)
1771 1777 assert !profile.valid?
... ...
vendor/plugins/active_record_counter_cache_on_polymorphic_association/init.rb 0 → 100644
... ... @@ -0,0 +1,32 @@
  1 +# monkey patch to fix ActiveRecord bug
  2 +#
  3 +# https://rails.lighthouseapp.com/projects/8994/tickets/2452-counter_cache-not-updated-when-an-item-updates-its-polymorphic-owner
  4 +
  5 +ActiveRecord::Associations::ClassMethods.module_eval do
  6 +
  7 + def replace(record)
  8 + counter_cache_name = @reflection.counter_cache_column
  9 + if record.nil?
  10 + if counter_cache_name && !@owner.new_record?
  11 + record.class.base_class.decrement_counter(counter_cache_name, @owner[@reflection.primary_key_name]) if @owner[@reflection.primary_key_name]
  12 + end
  13 + @target = @owner[@reflection.primary_key_name] = @owner[@reflection.options[:foreign_type]] = nil
  14 + else
  15 + @target = (AssociationProxy === record ? record.target : record)
  16 +
  17 + if counter_cache_name && !@owner.new_record?
  18 + record.class.base_class.increment_counter(counter_cache_name, record.id)
  19 + record.class.base_class.decrement_counter(counter_cache_name, @owner[@reflection.primary_key_name]) if @owner[@reflection.primary_key_name]
  20 + end
  21 +
  22 + @owner[@reflection.primary_key_name] = record.id
  23 + @owner[@reflection.options[:foreign_type]] = record.class.base_class.name.to_s
  24 +
  25 + @updated = true
  26 + end
  27 +
  28 + loaded
  29 + record
  30 + end
  31 +
  32 +end
... ...