Commit 75524307b8962414354c692e19a677611fb4852c

Authored by Daniela Feitosa
2 parents 91bf3f94 ba6034cc

Merging AI1826 with master

Conflicts:
	app/models/article.rb
	app/models/profile.rb
	app/models/uploaded_file.rb
	public/javascripts/application.js
	public/stylesheets/application.css
	test/unit/article_test.rb
	test/unit/category_finder_test.rb
	test/unit/enterprise_test.rb
Showing 86 changed files with 1672 additions and 772 deletions   Show diff stats
app/controllers/public/profile_controller.rb
... ... @@ -3,17 +3,15 @@ class ProfileController < PublicController
3 3 needs_profile
4 4 before_filter :check_access_to_profile, :except => [:join, :join_not_logged, :index, :add]
5 5 before_filter :store_location, :only => [:join, :join_not_logged, :report_abuse]
6   - before_filter :login_required, :only => [:add, :join, :join_not_logged, :leave, :unblock, :leave_scrap, :remove_scrap, :remove_activity, :view_more_scraps, :view_more_activities, :view_more_network_activities, :report_abuse, :register_report]
  6 + before_filter :login_required, :only => [:add, :join, :join_not_logged, :leave, :unblock, :leave_scrap, :remove_scrap, :remove_activity, :view_more_activities, :view_more_network_activities, :report_abuse, :register_report, :leave_comment_on_activity]
7 7  
8 8 helper TagsHelper
9 9  
10 10 def index
11   - @activities = @profile.tracked_actions.paginate(:per_page => 30, :page => params[:page])
12   - @wall_items = []
13   - @network_activities = !@profile.is_a?(Person) ? @profile.tracked_notifications.paginate(:per_page => 30, :page => params[:page]) : []
  11 + @network_activities = !@profile.is_a?(Person) ? @profile.tracked_notifications.visible.paginate(:per_page => 15, :page => params[:page]) : []
14 12 if logged_in? && current_person.follows?(@profile)
15   - @network_activities = @profile.tracked_notifications.paginate(:per_page => 30, :page => params[:page]) if @network_activities.empty?
16   - @wall_items = @profile.scraps_received.not_replies.paginate(:per_page => 30, :page => params[:page])
  13 + @network_activities = @profile.tracked_notifications.visible.paginate(:per_page => 15, :page => params[:page]) if @network_activities.empty?
  14 + @activities = @profile.activities.paginate(:per_page => 15, :page => params[:page])
17 15 end
18 16 @tags = profile.article_tags
19 17 unless profile.display_info_to?(user)
... ... @@ -180,22 +178,33 @@ class ProfileController < PublicController
180 178 @scrap.receiver= receiver
181 179 @tab_action = params[:tab_action]
182 180 @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   - render :partial => 'leave_scrap'
  181 + activities = @profile.activities.paginate(:per_page => 15, :page => params[:page]) if params[:not_load_scraps].nil?
  182 + render :partial => 'profile_activities_list', :locals => {:activities => activities}
185 183 end
186 184  
187   - def view_more_scraps
188   - @scraps = @profile.scraps_received.not_replies.paginate(:per_page => 30, :page => params[:page])
189   - render :partial => 'profile_scraps', :locals => {:scraps => @scraps}
  185 + def leave_comment_on_activity
  186 + @comment = Comment.new(params[:comment])
  187 + @comment.author = user
  188 + @activity = ActionTracker::Record.find(params[:source_id])
  189 + @comment.source_type, @comment.source_id = (@activity.target_type == 'Article' ? ['Article', @activity.target_id] : [@activity.class.to_s, @activity.id])
  190 + @tab_action = params[:tab_action]
  191 + @message = @comment.save ? _("Comment successfully added.") : _("You can't leave an empty comment.")
  192 + if @tab_action == 'wall'
  193 + activities = @profile.activities.paginate(:per_page => 15, :page => params[:page]) if params[:not_load_scraps].nil?
  194 + render :partial => 'profile_activities_list', :locals => {:activities => activities}
  195 + else
  196 + network_activities = @profile.tracked_notifications.visible.paginate(:per_page => 15, :page => params[:page])
  197 + render :partial => 'profile_network_activities', :locals => {:network_activities => network_activities}
  198 + end
190 199 end
191 200  
192 201 def view_more_activities
193   - @activities = @profile.tracked_actions.paginate(:per_page => 30, :page => params[:page])
194   - render :partial => 'profile_activities', :locals => {:activities => @activities}
  202 + @activities = @profile.activities.paginate(:per_page => 10, :page => params[:page])
  203 + render :partial => 'profile_activities_list', :locals => {:activities => @activities}
195 204 end
196 205  
197 206 def view_more_network_activities
198   - @activities = @profile.tracked_notifications.paginate(:per_page => 30, :page => params[:page])
  207 + @activities = @profile.tracked_notifications.paginate(:per_page => 10, :page => params[:page])
199 208 render :partial => 'profile_network_activities', :locals => {:network_activities => @activities}
200 209 end
201 210  
... ... @@ -213,7 +222,11 @@ class ProfileController < PublicController
213 222 begin
214 223 raise if !can_edit_profile
215 224 activity = ActionTracker::Record.find(params[:activity_id])
216   - activity.destroy
  225 + if params[:only_hide]
  226 + activity.update_attribute(:visible, false)
  227 + else
  228 + activity.destroy
  229 + end
217 230 render :text => _('Activity successfully removed.')
218 231 rescue
219 232 render :text => _('You could not remove this activity')
... ... @@ -285,6 +298,16 @@ class ProfileController < PublicController
285 298 end
286 299 end
287 300  
  301 + def remove_comment
  302 + #FIXME Check whether these permissions are enough
  303 + @comment = Comment.find(params[:comment_id])
  304 + if (user == @comment.author || user == profile || user.has_permission?(:moderate_comments, profile))
  305 + @comment.destroy
  306 + session[:notice] = _('Comment successfully deleted')
  307 + end
  308 + redirect_to :action => :index
  309 + end
  310 +
288 311 protected
289 312  
290 313 def check_access_to_profile
... ...
app/helpers/application_helper.rb
... ... @@ -1218,15 +1218,12 @@ module ApplicationHelper
1218 1218 else _('1 minute')
1219 1219 end
1220 1220  
1221   - when 2..44 then _('%{distance} minutes') % { :distance => distance_in_minutes }
1222   - when 45..89 then _('about 1 hour')
1223   - when 90..1439 then _('about %{distance} hours') % { :distance => (distance_in_minutes.to_f / 60.0).round }
1224   - when 1440..2879 then _('1 day')
1225   - when 2880..43199 then _('%{distance} days') % { :distance => (distance_in_minutes / 1440).round }
1226   - when 43200..86399 then _('about 1 month')
1227   - when 86400..525599 then _('%{distance} months') % { :distance => (distance_in_minutes / 43200).round }
1228   - when 525600..1051199 then _('about 1 year')
1229   - else _('over %{distance} years') % { :distance => (distance_in_minutes / 525600).round }
  1221 + when 2..44 then _('%{distance} minutes ago') % { :distance => distance_in_minutes }
  1222 + when 45..89 then _('about 1 hour ago')
  1223 + when 90..1439 then _('about %{distance} hours ago') % { :distance => (distance_in_minutes.to_f / 60.0).round }
  1224 + when 1440..2879 then _('1 day ago')
  1225 + when 2880..10079 then _('%{distance} days ago') % { :distance => (distance_in_minutes / 1440).round }
  1226 + else show_time(from_time)
1230 1227 end
1231 1228 end
1232 1229  
... ...
app/helpers/forum_helper.rb
... ... @@ -42,9 +42,9 @@ module ForumHelper
42 42 def last_topic_update(article)
43 43 info = article.info_from_last_update
44 44 if info[:author_url]
45   - time_ago_as_sentence(info[:date]) + ' ' + _('ago') + ' ' + _('by') + ' ' + link_to(info[:author_name], info[:author_url])
  45 + time_ago_as_sentence(info[:date]) + ' ' + _('by') + ' ' + link_to(info[:author_name], info[:author_url])
46 46 else
47   - time_ago_as_sentence(info[:date]) + ' ' + _('ago') + ' ' + _('by') + ' ' + info[:author_name]
  47 + time_ago_as_sentence(info[:date]) + ' ' + _('by') + ' ' + info[:author_name]
48 48 end
49 49 end
50 50  
... ...
app/models/action_tracker_notification.rb
... ... @@ -3,6 +3,8 @@ 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  
... ...
app/models/article.rb
... ... @@ -8,9 +8,7 @@ class Article < ActiveRecord::Base
8 8 _('Content')
9 9 end
10 10  
11   - track_actions :create_article, :after_create, :keep_params => [:name, :url], :if => Proc.new { |a| a.is_trackable? && !a.image? }, :custom_target => :action_tracker_target
12   - 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
13   - track_actions :remove_article, :before_destroy, :keep_params => [:name], :if => Proc.new { |a| a.is_trackable? }, :custom_target => :action_tracker_target
  11 + track_actions :create_article, :after_create, :keep_params => [:name, :url, :lead, :first_image], :if => Proc.new { |a| a.is_trackable? && !a.image? }
14 12  
15 13 # xss_terminate plugin can't sanitize array fields
16 14 before_save :sanitize_tag_list
... ... @@ -23,7 +21,7 @@ class Article < ActiveRecord::Base
23 21  
24 22 belongs_to :last_changed_by, :class_name => 'Person', :foreign_key => 'last_changed_by_id'
25 23  
26   - has_many :comments, :dependent => :destroy, :order => 'created_at asc'
  24 + has_many :comments, :class_name => 'Comment', :foreign_key => 'source_id', :dependent => :destroy, :order => 'created_at asc'
27 25  
28 26 has_many :article_categorizations, :conditions => [ 'articles_categories.virtual = ?', false ]
29 27 has_many :categories, :through => :article_categorizations
... ... @@ -74,7 +72,7 @@ class Article < ActiveRecord::Base
74 72 validate :translation_must_have_language
75 73  
76 74 def is_trackable?
77   - self.published? && self.notifiable? && self.advertise?
  75 + self.published? && self.notifiable? && self.advertise? && self.profile.public_profile
78 76 end
79 77  
80 78 def external_link=(link)
... ... @@ -147,7 +145,7 @@ class Article < ActiveRecord::Base
147 145 before_update do |article|
148 146 article.advertise = true
149 147 end
150   -
  148 +
151 149 # retrieves all articles belonging to the given +profile+ that are not
152 150 # sub-articles of any other article.
153 151 named_scope :top_level_for, lambda { |profile|
... ... @@ -597,6 +595,21 @@ class Article < ActiveRecord::Base
597 595 _('Created at: ')
598 596 end
599 597  
  598 + def activity
  599 + ActionTracker::Record.find_by_target_type_and_target_id 'Article', self.id
  600 + end
  601 +
  602 + def create_activity
  603 + if is_trackable? && !image?
  604 + save_action_for_verb 'create_article', [:name, :url, :lead, :first_image], Proc.new{}, :author
  605 + end
  606 + end
  607 +
  608 + def first_image
  609 + img = Hpricot(self.lead.to_s).search('img[@src]').first || Hpricot(self.body.to_s).search('img').first
  610 + img.nil? ? '' : img.attributes['src']
  611 + end
  612 +
600 613 private
601 614  
602 615 # FIXME: workaround for development env.
... ...
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
4   -
5 3 validates_presence_of :body
6   - belongs_to :article, :counter_cache => true
  4 +
  5 + belongs_to :source, :counter_cache => true, :polymorphic => true
  6 + alias :article :source
  7 + alias :article= :source=
  8 +
7 9 belongs_to :author, :class_name => 'Person', :foreign_key => 'author_id'
8 10 has_many :children, :class_name => 'Comment', :foreign_key => 'reply_of_id', :dependent => :destroy
9 11 belongs_to :reply_of, :class_name => 'Comment', :foreign_key => 'reply_of_id'
... ... @@ -70,13 +72,25 @@ class Comment &lt; ActiveRecord::Base
70 72 after_save :notify_article
71 73 after_destroy :notify_article
72 74 def notify_article
73   - article.comments_updated
  75 + article.comments_updated if article.kind_of?(Article)
74 76 end
75 77  
76 78 after_create do |comment|
77   - if comment.article.notify_comments? && !comment.article.profile.notification_emails.empty?
  79 + if comment.source.kind_of?(Article) && comment.article.notify_comments? && !comment.article.profile.notification_emails.empty?
78 80 Comment::Notifier.deliver_mail(comment)
79 81 end
  82 +
  83 + if comment.source.kind_of?(Article)
  84 + comment.article.create_activity if comment.article.activity.nil?
  85 + if comment.article.activity
  86 + comment.article.activity.increment!(:comments_count)
  87 + comment.article.activity.update_attribute(:visible, true)
  88 + end
  89 + end
  90 + end
  91 +
  92 + after_destroy do |comment|
  93 + comment.article.activity.decrement!(:comments_count) if comment.source.kind_of?(Article) && comment.article.activity
80 94 end
81 95  
82 96 def replies
... ...
app/models/community.rb
... ... @@ -87,4 +87,8 @@ class Community &lt; Organization
87 87 {:title => __('Community Info and settings'), :icon => 'edit-profile-group'}
88 88 end
89 89  
  90 + def activities
  91 + 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.target_id = #{self.id} UNION SELECT at.id, at.updated_at, '#{ActionTracker::Record.to_s}' AS klass FROM #{ActionTracker::Record.table_name} at INNER JOIN articles a ON at.target_id = a.id WHERE a.profile_id = #{self.id} AND at.target_type = 'Article' ORDER BY updated_at DESC")
  92 + end
  93 +
90 94 end
... ...
app/models/enterprise.rb
... ... @@ -180,4 +180,8 @@ class Enterprise &lt; Organization
180 180 true
181 181 end
182 182  
  183 + def activities
  184 + Scrap.find_by_sql("SELECT id, updated_at, 'Scrap' AS klass FROM scraps WHERE scraps.receiver_id = #{self.id} AND scraps.scrap_id IS NULL UNION SELECT id, updated_at, 'ActionTracker::Record' AS klass FROM action_tracker WHERE action_tracker.target_id = #{self.id} UNION SELECT action_tracker.id, action_tracker.updated_at, 'ActionTracker::Record' AS klass FROM action_tracker INNER JOIN articles ON action_tracker.target_id = articles.id WHERE articles.profile_id = #{self.id} AND action_tracker.target_type = 'Article' ORDER BY action_tracker.updated_at DESC")
  185 + end
  186 +
183 187 end
... ...
app/models/event.rb
... ... @@ -124,6 +124,10 @@ class Event &lt; Article
124 124 true
125 125 end
126 126  
  127 + def notifiable?
  128 + true
  129 + end
  130 +
127 131 include Noosfero::TranslatableContent
128 132 include MaybeAddHttp
129 133  
... ...
app/models/external_feed.rb
... ... @@ -14,6 +14,7 @@ class ExternalFeed &lt; ActiveRecord::Base
14 14 article = TinyMceArticle.new(:name => title, :profile => blog.profile, :body => content, :published_at => date, :source => link, :profile => blog.profile, :parent => blog)
15 15 unless blog.children.exists?(:slug => article.slug)
16 16 article.save!
  17 + article.delay.create_activity
17 18 end
18 19 end
19 20  
... ...
app/models/forum.rb
... ... @@ -28,4 +28,14 @@ class Forum &lt; Folder
28 28 def self.icon_name(article = nil)
29 29 'forum'
30 30 end
  31 +
  32 + def notifiable?
  33 + true
  34 + end
  35 +
  36 + def first_paragraph
  37 + return '' if body.blank?
  38 + paragraphs = Hpricot(body).search('p')
  39 + paragraphs.empty? ? '' : paragraphs.first.to_html
  40 + end
31 41 end
... ...
app/models/image.rb
... ... @@ -13,7 +13,7 @@ class Image &lt; ActiveRecord::Base
13 13 :thumbnails => { :big => '150x150',
14 14 :thumb => '100x100',
15 15 :portrait => '64x64',
16   - :minor => '50x50',
  16 + :minor => '50x50>',
17 17 :icon => '20x20!' },
18 18 :max_size => 5.megabytes # remember to update validate message below
19 19  
... ...
app/models/person.rb
... ... @@ -442,6 +442,10 @@ class Person &lt; Profile
442 442 user.save!
443 443 end
444 444  
  445 + def activities
  446 + 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")
  447 + end
  448 +
445 449 protected
446 450  
447 451 def followed_by?(profile)
... ...
app/models/profile.rb
... ... @@ -840,6 +840,11 @@ private :generate_url, :url_options
840 840 name
841 841 end
842 842  
  843 + # Override in your subclasses
  844 + def activities
  845 + []
  846 + end
  847 +
843 848 private
844 849 def self.f_categories_label_proc(environment)
845 850 ids = environment.top_level_category_as_facet_ids
... ...
app/models/scrap.rb
... ... @@ -12,6 +12,7 @@ class Scrap &lt; ActiveRecord::Base
12 12 named_scope :not_replies, :conditions => {:scrap_id => nil}
13 13  
14 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 +
15 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|
... ...
app/models/uploaded_file.rb
... ... @@ -8,7 +8,7 @@ class UploadedFile &lt; Article
8 8 _('File')
9 9 end
10 10  
11   - track_actions :upload_image, :after_create, :keep_params => ["view_url", "thumbnail_path", "parent.url", "parent.name"], :if => Proc.new { |a| a.published? && a.image? && !a.parent.nil? && a.parent.gallery? }
  11 + track_actions :upload_image, :after_create, :keep_params => ["view_url", "thumbnail_path", "parent.url", "parent.name"], :if => Proc.new { |a| a.published? && a.image? && !a.parent.nil? && a.parent.gallery? }, :custom_target => :action_tracker_target
12 12  
13 13 include ShortFilename
14 14  
... ... @@ -29,7 +29,7 @@ class UploadedFile &lt; Article
29 29 end
30 30  
31 31 def thumbnail_path
32   - self.image? ? self.full_filename(:thumb).gsub(File.join(RAILS_ROOT, 'public'), '') : nil
  32 + self.image? ? self.full_filename(:display).gsub(File.join(RAILS_ROOT, 'public'), '') : nil
33 33 end
34 34  
35 35 def display_title
... ... @@ -144,4 +144,9 @@ class UploadedFile &lt; Article
144 144 def uploaded_file?
145 145 true
146 146 end
  147 +
  148 + def action_tracker_target
  149 + self
  150 + end
  151 +
147 152 end
... ...
app/views/profile/_add_member_in_community.rhtml 0 → 100644
... ... @@ -0,0 +1 @@
  1 +<%= render :partial => 'default_activity', :locals => { :activity => activity, :tab_action => tab_action } %>
... ...
app/views/profile/_comment.rhtml 0 → 100644
... ... @@ -0,0 +1,67 @@
  1 +<% Comment %>
  2 +<% Profile %>
  3 +<% Person %>
  4 +
  5 +<li class="article-comment" style='border-bottom:none;'>
  6 + <div class="article-comment-inner">
  7 +
  8 + <div class="comment-content comment-logged-in">
  9 +
  10 + <% if comment.author %>
  11 + <%= link_to image_tag(profile_icon(comment.author, :minor)),
  12 + Person.find(comment.author_id).url,
  13 + :class => 'comment-picture',
  14 + :title => comment.author_name
  15 + %>
  16 + <% end %>
  17 +
  18 + <div class="comment-details">
  19 + <div class="comment-text">
  20 + <%= link_to(comment.author_name, comment.author.url) %>
  21 + <% unless comment.title.blank? %>
  22 + <span class="comment-title"><%= comment.title %></span><br/>
  23 + <% end %>
  24 + <%= txt2html comment.body %>
  25 + </div>
  26 + <div class="profile-activity-time">
  27 + <%= time_ago_as_sentence(comment.created_at) %>
  28 + </div>
  29 + </div>
  30 +
  31 + <% if logged_in? && (user == profile || user == comment.author || user.has_permission?(:moderate_comments, profile)) %>
  32 + <% button_bar(:style => 'float: right; margin-top: 0px;') do %>
  33 + <%= icon_button(:delete, _('Remove'), { :action => :remove_comment, :comment_id => comment.id }, :method => :get, :confirm => _('Are you sure you want to remove this comment and all its replies?')) %>
  34 + <% end %>
  35 + <% end %>
  36 + <br style="clear: both;" />
  37 +
  38 + <div class="comment_reply post_comment_box closed">
  39 + <% if @comment && @comment.errors.any? && @comment.reply_of_id.to_i == comment.id %>
  40 + <%= error_messages_for :comment %>
  41 + <script type="text/javascript">
  42 + jQuery(function() {
  43 + document.location.href = '#<%= comment.anchor %>';
  44 + add_comment_reply_form('#comment-reply-to-<%= comment.id %>', <%= comment.id %>);
  45 + });
  46 + </script>
  47 + <% end %>
  48 + <%= report_abuse(comment.author, :comment_link, comment) if comment.author %>
  49 + <%= link_to_function _('Reply'),
  50 + "var f = add_comment_reply_form(this, %s); f.find('input[name=comment[title]], textarea').val(''); return false" % comment.id,
  51 + :class => 'comment-footer comment-footer-link comment-footer-hide',
  52 + :id => 'comment-reply-to-' + comment.id.to_s
  53 + %>
  54 + </div>
  55 +
  56 + </div>
  57 +
  58 + <% unless comment.replies.blank? %>
  59 + <ul class="comment-replies">
  60 + <% comment.replies.each do |reply| %>
  61 + <%= render :partial => 'comment', :locals => { :comment => reply } %>
  62 + <% end %>
  63 + </ul>
  64 + <% end %>
  65 +
  66 + </div>
  67 +</li>
... ...
app/views/profile/_create_article.rhtml 0 → 100644
... ... @@ -0,0 +1,22 @@
  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 profile-activity-article-<%= activity.target.class.icon_name %>'>
  5 + <p class='profile-activity-text'>
  6 + <%= link_to activity.user.short_name(20), activity.user.url %>
  7 + <%= _("on community %s") % link_to(activity.target.profile.short_name(20), activity.target.profile.url) if activity.target.profile.is_a?(Community) %>
  8 + </p>
  9 + <div class='profile-activity-lead'>
  10 + <div class='article-name'><%= link_to(activity.params['name'], activity.params['url']) %></div>
  11 + <span title='<%= activity.target.class.short_description %>' class='profile-activity-icon icon-new icon-new<%= activity.target.class.icon_name %>'></span>
  12 + <%= image_tag(activity.params['first_image']) unless activity.params['first_image'].blank? %><%= strip_tags(truncate(activity.params['lead'], :length => 1000, :ommision => '...')).gsub(/(\xA0|\xC2|\s)+/, ' ').gsub(/^\s+/, '') %> <small><%= link_to(_('See more'), activity.params['url']) unless activity.get_lead.blank? %></small>
  13 + </div>
  14 + <%= content_tag(:p, link_to(_('See complete forum'), activity.get_url), :class => 'see-forum') if activity.target.is_a?(Forum) %>
  15 + <p class='profile-activity-time'><%= time_ago_as_sentence(activity.created_at) %></p>
  16 + <div class='profile-wall-actions'>
  17 + <%= link_to s_('profile|Comment'), '#', { :class => 'focus-on-comment'} %>
  18 + <%= link_to_remote(content_tag(:span, _('Remove')), :url =>{:action => 'remove_activity', :activity_id => activity.id, :only_hide => true}, :confirm => _('Are you sure?'), :update => "profile-activity-item-#{activity.id}") if logged_in? && current_person == @profile %>
  19 + </div>
  20 +</div>
  21 +
  22 +<%= render :partial => 'profile_comments', :locals => { :activity => activity, :tab_action => tab_action } %>
... ...
app/views/profile/_default_activity.rhtml 0 → 100644
... ... @@ -0,0 +1,13 @@
  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) %></p>
  7 + <div class='profile-wall-actions'>
  8 + <%= link_to s_('profile|Comment'), '#', { :class => 'focus-on-comment'} %>
  9 + <%= link_to_remote(content_tag(:span, _('Remove')), :confirm => _('Are you sure?'), :url =>{:action => 'remove_activity', :activity_id => activity.id}, :update => "profile-activity-item-#{activity.id}") if logged_in? && current_person == @profile %>
  10 + </div>
  11 +</div>
  12 +
  13 +<%= render :partial => 'profile_comments', :locals => { :activity => activity, :tab_action => tab_action } %>
... ...
app/views/profile/_join_community.rhtml 0 → 120000
... ... @@ -0,0 +1 @@
  1 +_add_member_in_community.rhtml
0 2 \ No newline at end of file
... ...
app/views/profile/_leave_comment_on_activity.rhtml 0 → 100644
... ... @@ -0,0 +1 @@
  1 +NÃO É PRA APARECER
... ...
app/views/profile/_leave_scrap.rhtml
1   -<%= @message %>
2   -<% unless @scraps.nil? %>
3   - <%= render :partial => 'profile_scraps', :locals => {:scraps => @scraps} %>
4   -<% end %>
  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) %></p>
  7 + <div class='profile-wall-actions'>
  8 + <%= link_to_remote(content_tag(:span, _('Remove')), :confirm => _('Are you sure?'), :url =>{:action => 'remove_activity', :activity_id => activity.id}, :update => "profile-activity-item-#{activity.id}") if logged_in? && current_person == @profile %>
  9 + </div>
  10 +</div>
  11 +
  12 +<br/>
... ...
app/views/profile/_leave_scrap_to_self.rhtml 0 → 120000
... ... @@ -0,0 +1 @@
  1 +_leave_scrap.rhtml
0 2 \ No newline at end of file
... ...
app/views/profile/_new_friendship.rhtml 0 → 120000
... ... @@ -0,0 +1 @@
  1 +_add_member_in_community.rhtml
0 2 \ No newline at end of file
... ...
app/views/profile/_profile.rhtml
1   -<tr>
2   - <td colspan='2'>
  1 +NÃO DEVE APARECER
3 2  
4   - <% plugins_tabs = @plugins.dispatch(:profile_tabs).
5   - map { |tab| {:title => tab[:title], :id => tab[:id], :content => instance_eval(&tab[:content]), :start => tab[:title]} }%>
6   -
7   - <% tabs = plugins_tabs.select { |tab| tab[:start] } %>
8   -
9   - <% if logged_in? && current_person.follows?(@profile) %>
10   - <% tabs << {:title => _('Wall'), :id => 'profile-wall', :content => (render :partial => 'profile_wall')} %>
11   - <% end %>
12   -
13   - <% if @profile.organization? %>
14   - <% tabs << {:title => _('What\'s new'), :id => 'profile-network', :content => (render :partial => 'profile_network')} %>
15   - <% tabs << {:title => _('Profile'), :id => 'organization-profile', :content => (render :partial => 'organization_profile')} %>
16   - <% elsif @profile.person? %>
17   - <% if logged_in? && current_person.follows?(@profile) %>
18   - <% tabs << {:title => _('Network'), :id => 'profile-network', :content => (render :partial => 'profile_network')} %>
19   - <% end %>
20   -
21   - <% tabs << {:title => _('Activity'), :id => 'profile-activity', :content => (render :partial => 'profile_activity')} %>
22   - <% tabs << {:title => _('Profile'), :id => 'person-profile', :content => (render :partial => 'person_profile')} %>
23   - <% end %>
24   -
25   - <% tabs += plugins_tabs.select { |tab| !tab[:start] } %>
26   -
27   - <%= render_tabs(tabs) %>
28   -
29   - </td>
30   -</tr>
... ...
app/views/profile/_profile_activities.rhtml
... ... @@ -1,18 +0,0 @@
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) %>
5   - </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}" %>
17   - </div>
18   -<% end %>
app/views/profile/_profile_activities_list.rhtml 0 → 100644
... ... @@ -0,0 +1,16 @@
  1 +<% unless activities.nil? %>
  2 + <% activities.each do |a| %>
  3 + <% activity = a.klass.constantize.find(a.id) %>
  4 + <% if activity.kind_of?(ActionTracker::Record) %>
  5 + <%= render :partial => 'profile_activity', :locals => { :activity => activity, :tab_action => 'wall' } if activity.visible? %>
  6 + <% else %>
  7 + <%= render :partial => 'profile_scrap', :locals => {:scrap => activity } %>
  8 + <% end %>
  9 + <% end %>
  10 +<% end %>
  11 +
  12 +<% if activities.current_page < activities.total_pages %>
  13 + <div id='profile_activities_page_<%= activities.current_page %>'>
  14 + <%= button_to_remote :add, _('View more'), :url => {:action => 'view_more_activities', :page => (activities.current_page + 1)}, :update => "profile_activities_page_#{activities.current_page}" %>
  15 + </div>
  16 +<% end %>
... ...
app/views/profile/_profile_activities_scraps.rhtml 0 → 100644
... ... @@ -0,0 +1,2 @@
  1 +NÂO DEVE APARECER!!
  2 +
... ...
app/views/profile/_profile_activity.rhtml
1   -<div id='profile-activity'>
2   - <h3><%= _("%s's activity") % @profile.name %></h3>
3   - <ul>
4   - <%= render :partial => 'profile_activities', :locals => {:activities => @activities} %>
5   - </ul>
6   -</div>
  1 +<li class='profile-activity-item <%= activity.verb %>' id='profile-activity-item-<%= activity.id %>'>
  2 + <%= render :partial => activity.verb, :locals => { :activity => activity, :tab_action => tab_action }%>
  3 + <hr />
  4 +</li>
... ...
app/views/profile/_profile_comment_form.rhtml 0 → 100644
... ... @@ -0,0 +1,20 @@
  1 +<div id='profile-wall-reply-<%= activity.id%>'>
  2 + <div id='profile-wall-reply-form-<%= activity.id%>'>
  3 + <p class='profile-wall-reply'>
  4 + <% update_area = tab_action == 'wall' ? 'profile_activities' : 'network-activities' %>
  5 + <% form_remote_tag :url => {:controller => 'profile', :action => 'leave_comment_on_activity', :tab_action => tab_action}, :html => { :class => 'profile-wall-reply-form', 'data-update' => update_area } do %>
  6 + <%= text_area :comment, :body, {:id => "reply_content_#{activity.id}",
  7 + :cols => 50,
  8 + :rows => 1,
  9 + :class => 'submit-with-keypress',
  10 + :title => _('Leave your comment'),
  11 + :onfocus => ('if(this.value==this.title){this.value="";this.style.color="#000"};this.style.backgroundImage="url(' + profile_icon(current_person, :icon, false) + ')"' if logged_in?),
  12 + :onblur => ('if(this.value==""){this.value=this.title;this.style.color="#ccc"};this.style.backgroundImage="none"' if logged_in?),
  13 + :value => _('Leave your comment'),
  14 + :style => 'color: #ccc' } %>
  15 + <%= hidden_field_tag :source_id, activity.id, :id => "activity_id_#{activity.id}" %>
  16 + <% end %>
  17 + </p>
  18 + </div>
  19 + <div id='profile-wall-message-response-<%=activity.id%>' class='profile-wall-message-response'></div>
  20 +</div>
... ...
app/views/profile/_profile_comments.rhtml 0 → 100644
... ... @@ -0,0 +1,13 @@
  1 +<hr />
  2 +
  3 +<% if activity.comments_count > 2 %>
  4 + <div class='view-all-comments icon-chat'>
  5 + <%= link_to(_("View all %s comments") % activity.comments_count, '#') %>
  6 + </div>
  7 +<% end %>
  8 +
  9 +<ul class="profile-wall-activities-comments" style="<%= 'display:none;' if (activity.comments_count > 2) %>" >
  10 + <%= render :partial => 'comment', :collection => activity.comments_as_thread %>
  11 +</ul>
  12 +
  13 +<%= render :partial => 'profile_comment_form', :locals => { :activity => activity, :tab_action => tab_action } %>
... ...
app/views/profile/_profile_network.rhtml
1 1 <h3><%= _("%s's network activity") % @profile.name %></h3>
2   -<ul>
  2 +<ul id='network-activities' class='profile-activities'>
3 3 <%= render :partial => 'profile_network_activities', :locals => {:network_activities => @network_activities} %>
4 4 </ul>
... ...
app/views/profile/_profile_network_activities.rhtml
1   - <% network_activities.each do |activity| %>
2   - <li class='profile-network-item <%= activity.verb %>' id='profile-network-item-<%= activity.id %>'>
3   - <div class='profile-network-image'>
4   - <%= link_to(profile_image(activity.user, :minor), activity.user.url) %>
5   - <% if logged_in? && current_person.follows?(activity.user) && current_person != activity.user %>
6   - <p class='profile-network-send-message'><%= link_to_function _('Scrap'), "hide_and_show(['#profile-network-message-response-#{activity.id}'],['#profile-network-message-#{activity.id}', '#profile-network-form-#{activity.id}']);$('content_#{activity.id}').value='';return false", :class => "profile-send-message", :title => _("Send a message to %s") % activity.user.name %></p>
7   - <% end %>
8   - </div>
9   - <div class='profile-network-description'>
10   - <p class='profile-network-time'><%= time_ago_as_sentence(activity.created_at) + ' ' + _('ago') %></p>
11   - <p class='profile-network-text'><%= link_to activity.user.name, activity.user.url %> <%= describe activity %></p>
12   - <%= button_to_remote(:delete, content_tag(:span, _('Remove')), :url =>{:action => 'remove_notification', :activity_id => activity.id}, :update => "profile-network-item-#{activity.id}") if can_edit_profile %>
13   - <p class='profile-network-where'><%= _('In community %s') % link_to(activity.target.name, activity.target.url) if !profile.is_a?(Community) && activity.target.is_a?(Community) %></p>
14   - </div>
15   - <div id='profile-network-message-<%= activity.id%>' style='display:none;'>
16   - <div id='profile-network-form-<%= activity.id%>' style='display:none;'>
17   - <p class='profile-network-message'>
18   - <% form_remote_tag :url => {:controller => 'profile', :action => 'leave_scrap', :not_load_scraps => true}, :update => "profile-network-message-response-#{activity.id}", :success =>"hide_and_show(['#profile-network-form-#{activity.id}'],['#profile-network-message-response-#{activity.id}'])" do %>
19   - <%= limited_text_area :scrap, :content, 420, "content_#{activity.id}", :cols => 50, :rows => 2 %>
20   - <%= hidden_field_tag 'receiver_id', activity.user.id %>
21   - <%= submit_button :add, _('Leave a message') %>
22   - <%= button_to_function :cancel, _('Cancel'), "hide_and_show(['#profile-network-message-#{activity.id}'],[]);return false" %>
23   - <% end %>
24   - </p>
25   - </div>
26   - <div id='profile-network-message-response-<%=activity.id%>' class='profile-network-message-response'></div>
27   - </div>
28   - <hr />
29   - </li>
30   - <% end %>
  1 +<% network_activities.each do |activity| %>
  2 + <%= render :partial => 'profile_activity', :locals => { :activity => activity, :tab_action => 'network' } if activity.visible? %>
  3 +<% end %>
31 4 <% if network_activities.current_page < network_activities.total_pages %>
32 5 <div id='profile_network_activities_page_<%= network_activities.current_page %>'>
33 6 <%= button_to_remote :add, _('View more'), :url => {:action => 'view_more_network_activities', :page => (network_activities.current_page + 1)}, :update => "profile_network_activities_page_#{network_activities.current_page}" %>
... ...
app/views/profile/_profile_scrap.rhtml
1   -<li class='profile-wall-item' id='profile-wall-item-<%= scrap.id %>'>
2   - <div class='profile-wall-image'>
  1 +<li class='profile-activity-item' id='profile-activity-item-<%= scrap.id %>'>
  2 + <div class='profile-activity-image'>
3 3 <%= link_to(profile_image(scrap.sender, :minor), scrap.sender.url) %>
4   - <% if logged_in? && current_person.follows?(scrap.sender) && current_person != scrap.sender %>
5   - <p class='profile-wall-send-message'><%= link_to_function _('Scrap'), "hide_and_show(['#profile-wall-message-response-#{scrap.id}'],['#profile-wall-message-#{scrap.id}', '#profile-wall-form-#{scrap.id}']);$('content_#{scrap.id}').value='';return false", :class => "profile-send-message", :title => _("Send a message to %s") % scrap.sender.name %></p>
6   - <% end %>
7 4 </div>
8   - <% comment_balloon :class => 'profile-wall-description' do %>
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   - <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) %>
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>
  5 + <div class='profile-activity-description'>
  6 + <p class='profile-activity-sender'><%= link_to scrap.sender.name, scrap.sender.url %></p>
  7 + <p class='profile-activity-text'><%= txt2html scrap.content %></p>
  8 + <p class='profile-activity-time'><%= time_ago_as_sentence(scrap.created_at) %></p>
  9 + <div class='profile-wall-actions'>
  10 + <% if logged_in? && current_person.follows?(scrap.sender) %>
  11 + <span class='profile-activity-send-reply'>
  12 + <%= link_to_function s_('profile|Comment'), "hide_and_show(['#profile-wall-message-response-#{scrap.id}'],['#profile-wall-reply-#{scrap.id}', '#profile-wall-reply-form-#{scrap.id}']);$('reply_content_#{scrap.id}').value='';$('reply_content_#{scrap.id}').focus();return false", :class => "profile-send-reply" %>
  13 + </span>
15 14 <% end %>
  15 + <%= link_to_remote(content_tag(:span, _('Remove')), :confirm => _('Are you sure?'), :url =>{:action => 'remove_scrap', :scrap_id => scrap.id}, :update => "profile-activity-item-#{scrap.id}") if logged_in? && user.can_control_scrap?(scrap) %>
  16 + </div>
  17 + </div>
  18 +
  19 + <% if scrap.replies.count > 2 %>
  20 + <div class='view-all-comments icon-chat'>
  21 + <%= link_to(_("View all %s comments") % scrap.replies.count, '#') %>
  22 + </div>
16 23 <% end %>
17   - <ul class="profile-wall-scrap-replies">
  24 +
  25 + <ul class="profile-wall-activities-comments scrap-replies" style="width: auto; <%= 'display:none;' if (scrap.replies.count > 2) %>" >
18 26 <% scrap.replies.map do |reply| %>
19 27 <%= render :partial => 'profile_scrap', :locals => {:scrap => reply} %>
20 28 <% end %>
21 29 </ul>
22   - <div id='profile-wall-message-<%= scrap.id%>' style='display:none;'>
23   - <div id='profile-wall-form-<%= scrap.id%>' style='display:none;'>
24   - <p class='profile-wall-message'>
25   - <% form_remote_tag :url => {:controller => 'profile', :action => 'leave_scrap', :not_load_scraps => true}, :update => "profile-wall-message-response-#{scrap.id}", :success =>"hide_and_show(['#profile-wall-form-#{scrap.id}'],['#profile-wall-message-response-#{scrap.id}'])" do %>
26   - <%= limited_text_area :scrap, :content, 420, "content_#{scrap.id}", :cols => 50, :rows => 2 %>
27   - <%= hidden_field_tag 'receiver_id', scrap.sender.id %>
28   - <%= submit_button :add, _('Leave a scrap') %>
29   - <%= button_to_function :cancel, _('Cancel'), "hide_and_show(['#profile-wall-message-#{scrap.id}'],[]);return false" %>
30   - <% end %>
31   - </p>
32   - </div>
33   - <div id='profile-wall-message-response-<%=scrap.id%>' class='profile-wall-message-response'></div>
34   - </div>
35   - <div id='profile-wall-reply-<%= scrap.id%>' style='display:none;'>
36   - <div id='profile-wall-reply-form-<%= scrap.id%>' style='display:none;'>
37   - <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 %>
39   - <%= limited_text_area :scrap, :content, 420, "reply_content_#{scrap.id}", :cols => 50, :rows => 2 %>
40   - <%= hidden_field :scrap, :scrap_id, :id => "scrap_id_#{scrap.id}" %>
41   - <%= hidden_field_tag 'receiver_id', scrap.sender.id %>
42   - <%= submit_button :add, _('Leave a scrap') %>
43   - <%= button_to_function :cancel, _('Cancel'), "hide_and_show(['#profile-wall-reply-#{scrap.id}'],[]);return false" %>
44   - <% end %>
45   - </p>
46   - </div>
47   - <div id='profile-wall-message-response-<%=scrap.id%>' class='profile-wall-message-response'></div>
48   - </div>
  30 + <%= render :partial => 'profile_scrap_reply_form', :locals => { :scrap => scrap } %>
49 31 <hr />
50 32 </li>
... ...
app/views/profile/_profile_scrap_reply_form.rhtml 0 → 100644
... ... @@ -0,0 +1,20 @@
  1 +<div id='profile-wall-reply-<%= scrap.id%>' style='display:none'>
  2 + <div id='profile-wall-reply-form-<%= scrap.id%>' style='display:none'>
  3 + <p class='profile-wall-reply'>
  4 + <% form_remote_tag :url => {:controller => 'profile', :action => 'leave_scrap'}, :update => "profile_activities", :html => { :class => 'profile-wall-reply-form'} do %>
  5 + <%= text_area :scrap, :content, { :id => "reply_content_#{scrap.id}",
  6 + :cols => 50,
  7 + :rows => 1,
  8 + :class => 'submit-with-keypress',
  9 + :title => _('Leave your comment'),
  10 + :onfocus => ('if(this.value==this.title){this.value="";this.style.color="#000"};this.style.backgroundImage="url(' + profile_icon(current_person, :icon, false) + ')"' if logged_in?),
  11 + :onblur => ('if(this.value==""){this.value=this.title;this.style.color="#ccc"};this.style.backgroundImage="none"' if logged_in?),
  12 + :value => _('Leave your comment')
  13 + } %>
  14 + <%= hidden_field_tag 'scrap[scrap_id]', scrap.id %>
  15 + <%= hidden_field_tag 'receiver_id', scrap.sender.id %>
  16 + <% end %>
  17 + </p>
  18 + </div>
  19 + <div id='profile-wall-message-response-<%=scrap.id%>' class='profile-wall-message-response'></div>
  20 +</div>
... ...
app/views/profile/_profile_scraps.rhtml
1   -<% scraps.map do |scrap| %>
2   - <%= render :partial => 'profile_scrap', :locals => {:scrap => scrap} %>
3   -<% end %>
4   -<% if scraps.current_page < scraps.total_pages %>
5   - <div id='profile_scraps_page_<%= scraps.current_page %>'>
6   - <%= button_to_remote :add, _('View more'), :url => {:action => 'view_more_scraps', :page => (scraps.current_page + 1)}, :update => "profile_scraps_page_#{scraps.current_page}" %>
7   - </div>
8   -<% end %>
  1 +NÃO DEVE APARECER
... ...
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   - <%= submit_button :scrap, _('Leave a scrap') %>
  6 + <%= submit_button :new, _('Share') %>
7 7 <% end %>
8 8 </div>
9 9 <div id='leave_scrap_response'></div>
10   -<ul id='profile_scraps'>
11   - <%= render :partial => 'profile_scraps', :locals => {:scraps => @wall_items} %>
  10 +<ul id='profile_activities' class='profile-activities'>
  11 + <%= render :partial => 'profile_activities_list', :locals => {:activities => @activities} %>
12 12 </ul>
... ...
app/views/profile/_update_article.rhtml 0 → 100644
... ... @@ -0,0 +1 @@
  1 +NAO É PRA APARECER
... ...
app/views/profile/_upload_image.rhtml 0 → 100644
... ... @@ -0,0 +1,20 @@
  1 +<div class="activity-gallery-images-count-<%= activity.get_view_url.size %>">
  2 + <div class='profile-activity-image'>
  3 + <%= link_to(profile_image(activity.user, :minor), activity.user.url) %>
  4 + </div>
  5 + <div class='profile-activity-description'>
  6 + <p class='profile-activity-text'><%= link_to activity.user.name, activity.user.url %> <%= describe activity %></p>
  7 + <p class='profile-activity-time'><%= time_ago_as_sentence(activity.created_at) %></p>
  8 + <div class='profile-wall-actions'>
  9 + <%= link_to(s_('profile|Comment'), '#', { :class => 'focus-on-comment'}) unless activity.get_view_url.size == 1 %>
  10 + <%= link_to_remote(content_tag(:span, _('Remove')), :confirm => _('Are you sure?'), :url =>{:action => 'remove_activity', :activity_id => activity.id}, :update => "profile-activity-item-#{activity.id}") if logged_in? && current_person == @profile %>
  11 + </div>
  12 + </div>
  13 +</div>
  14 +<div title='<%= activity.target.class.short_description %>' class='profile-activity-icon icon-new icon-newgallery'></div>
  15 +
  16 +<% if activity.get_view_url.size == 1 %>
  17 + <%= render :partial => 'profile_comments', :locals => { :activity => activity, :tab_action => tab_action } %>
  18 +<% end %>
  19 +
  20 +<br/>
... ...
app/views/profile/index.rhtml
... ... @@ -17,6 +17,31 @@
17 17  
18 18 <% if @profile.public? || (logged_in? && current_person.follows?(@profile)) %>
19 19 <table class='profile'>
20   - <%= render :partial => 'profile' %>
  20 + <tr>
  21 + <td colspan='2'>
  22 + <% plugins_tabs = @plugins.dispatch(:profile_tabs).
  23 + map { |tab| {:title => tab[:title], :id => tab[:id], :content => instance_eval(&tab[:content]), :start => tab[:title]} }%>
  24 +
  25 + <% tabs = plugins_tabs.select { |tab| tab[:start] } %>
  26 +
  27 + <% if @profile.organization? %>
  28 + <% tabs << {:title => _('Profile'), :id => 'organization-profile', :content => (render :partial => 'organization_profile')} %>
  29 + <% if logged_in? && current_person.follows?(@profile) %>
  30 + <% tabs << {:title => _('Wall'), :id => 'profile-wall', :content => (render :partial => 'profile_wall')} %>
  31 + <% end %>
  32 + <% tabs << {:title => _('What\'s new'), :id => 'profile-network', :content => (render :partial => 'profile_network')} %>
  33 + <% elsif @profile.person? %>
  34 + <% tabs << {:title => _('Profile'), :id => 'person-profile', :content => (render :partial => 'person_profile')} %>
  35 + <% if logged_in? && current_person.follows?(@profile) %>
  36 + <% tabs << {:title => _('Wall'), :id => 'profile-wall', :content => (render :partial => 'profile_wall')} %>
  37 + <% tabs << {:title => _('Network'), :id => 'profile-network', :content => (render :partial => 'profile_network')} %>
  38 + <% end %>
  39 + <% end %>
  40 +
  41 + <% tabs += plugins_tabs.select { |tab| !tab[:start] } %>
  42 +
  43 + <%= render_tabs(tabs) %>
  44 + </td>
  45 + </tr>
21 46 </table>
22 47 <% end %>
... ...
app/views/tasks/_abuse_complaint_accept_details.rhtml
... ... @@ -2,7 +2,7 @@
2 2 <% task.abuse_reports.each do |abuse_report| %>
3 3 <div>
4 4 <strong style="word-wrap: break-word; display: block; padding-right: 40px">"<%= abuse_report.reason %>"</strong> <br />
5   - <i><%= _('Reported by %{reporter} %{time}.') % {:reporter => abuse_report.reporter.name, :time => time_ago_as_sentence(abuse_report.created_at) + ' ' + _('ago')}%></i> <br />
  5 + <i><%= _('Reported by %{reporter} %{time}.') % {:reporter => abuse_report.reporter.name, :time => time_ago_as_sentence(abuse_report.created_at) }%></i> <br />
6 6 <% if !abuse_report.content.blank? %>
7 7 <button class="display-abuse-report-details" data-report="<%=abuse_report.id%>"><%=_('View details')%></button>
8 8 <div style='display: none' id=<%= 'abuse-report-details-'+abuse_report.id.to_s %> class="abuse-report-details">
... ...
config/initializers/action_tracker.rb
... ... @@ -5,18 +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
15   - },
16   -
17   - :remove_article => {
18   - :description => lambda { n_('removed 1 article: %{title}', 'removed %{num} articles: %{title}', get_name.size) % { :num => get_name.size, :title => '{{ta.get_name.collect{ |n| truncate(n) }.to_sentence(:connector => "%s")}}' % _("and") } },
19   - :type => :groupable
  8 + :description => lambda { _('published an article: %{title}') % { :title => '{{link_to(truncate(ta.get_name), ta.get_url)}}' } }
20 9 },
21 10  
22 11 :new_friendship => {
... ... @@ -33,24 +22,11 @@ ActionTrackerConfig.verbs = {
33 22 :description => lambda { _('has joined the community.') },
34 23 },
35 24  
36   - :remove_member_in_community => {
37   - :description => lambda { _('has left the community.') },
38   - },
39   -
40   - :leave_community => {
41   - :description => lambda { n_('has left 1 community:<br />%{name}', 'has left %{num} communities:<br />%{name}', get_resource_name.size) % { :num => get_resource_name.size, :name => '{{ta.collect_group_with_index(:resource_name){ |n,i| link_to(image_tag(ta.get_resource_profile_custom_icon[i] || default_or_themed_icon("/images/icons-app/community-icon.png")), ta.get_resource_url[i], :title => n)}.join}}' } },
42   - :type => :groupable
43   - },
44   -
45 25 :upload_image => {
46   - :description => lambda { n_('uploaded 1 image:<br />%{thumbnails}<br />%{details}', 'uploaded %{num} images:<br />%{thumbnails}<br />%{details}', get_view_url.size) % { :num => get_view_url.size, :thumbnails => '{{ta.collect_group_with_index(:thumbnail_path){ |t,i| content_tag(:span, link_to(image_tag(t), ta.get_view_url[i]))}.last(3).join}}', :details => '{{unique_with_count(ta.collect_group_with_index(:parent_name){ |n,i| link_to(n, ta.get_parent_url[i])}, "%s").join("<br />")}}' % _("in the gallery") } },
  26 + :description => lambda { n_('uploaded 1 image<br />%{thumbnails}<br style="clear: both;" />', 'uploaded %{num} images<br />%{thumbnails}<br style="clear: both;" />', get_view_url.size) % { :num => get_view_url.size, :thumbnails => '{{ta.collect_group_with_index(:thumbnail_path){ |t,i| content_tag(:span, link_to(image_tag(t), ta.get_view_url[i]))}.last(3).join}}' } },
47 27 :type => :groupable
48 28 },
49 29  
50   - :leave_comment => {
51   - :description => lambda { _('has left a comment entitled "%{title}" on the article %{article}: <br /> "%{comment}" (%{read})') % { :title => "{{truncate(ta.get_title)}}", :article => "{{link_to(truncate(ta.get_article_title), ta.get_article_url)}}", :comment => "{{truncate(ta.get_body, 50)}}", :read => '{{link_to("%s", ta.get_url)}}' % _("read") } }
52   - },
53   -
54 30 :leave_scrap => {
55 31 :description => lambda { _('sent a message to %{receiver}: <br /> "%{message}"') % { :receiver => "{{link_to(ta.get_receiver_name, ta.get_receiver_url)}}", :message => "{{auto_link_urls(ta.get_content)}}" } }
56 32 },
... ...
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
  8 + end
  9 +end
... ...
db/migrate/20111228202739_remove_useless_tracked_actions.rb 0 → 100644
... ... @@ -0,0 +1,17 @@
  1 +class RemoveUselessTrackedActions < ActiveRecord::Migration
  2 + def self.up
  3 + select_all("SELECT id FROM action_tracker").each do |tracker|
  4 + verbs = ['update_article', 'remove_article', 'leave_comment', 'leave_community', 'remove_member_in_community']
  5 + activity = ActionTracker::Record.find_by_id(tracker['id'])
  6 + if activity
  7 + if (activity.updated_at.to_time < Time.now.months_ago(3)) || verbs.include?(activity.verb)
  8 + activity.destroy
  9 + end
  10 + end
  11 + end
  12 + end
  13 +
  14 + def self.down
  15 + say "this migration can't be reverted"
  16 + end
  17 +end
... ...
db/migrate/20120228154642_add_visibility_to_action_tracker.rb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +class AddVisibilityToActionTracker < ActiveRecord::Migration
  2 + def self.up
  3 + add_column :action_tracker, :visible, :boolean, :default => true
  4 + end
  5 +
  6 + def self.down
  7 + remove_column :action_tracker, :visible, :boolean
  8 + end
  9 +end
... ...
db/migrate/20120228202739_adapt_create_articles_activity.rb 0 → 100644
... ... @@ -0,0 +1,24 @@
  1 +class AdaptCreateArticlesActivity < ActiveRecord::Migration
  2 +
  3 + # Removing 'create_article' activities that grouped articles.
  4 + # Creating new activities only to recent articles (not grouping)
  5 + def self.up
  6 + select_all("SELECT id FROM action_tracker WHERE verb = 'create_article'").each do |tracker|
  7 + activity = ActionTracker::Record.find_by_id(tracker['id'])
  8 + if activity
  9 + activity.destroy
  10 + end
  11 + end
  12 +
  13 + select_all("SELECT id FROM articles").each do |art|
  14 + article = Article.find(art['id'])
  15 + if article && article.created_at >= 8.days.ago && article.author && article.author.kind_of?(Person)
  16 + article.create_activity
  17 + end
  18 + end
  19 + end
  20 +
  21 + def self.down
  22 + say "this migration can't be reverted"
  23 + end
  24 +end
... ...
db/schema.rb
... ... @@ -29,6 +29,8 @@ ActiveRecord::Schema.define(:version =&gt; 20120411132751) 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
  33 + t.boolean "visible", :default => true
32 34 end
33 35  
34 36 add_index "action_tracker", ["target_id", "target_type"], :name => "index_action_tracker_on_dispatcher_id_and_dispatcher_type"
... ... @@ -200,7 +202,7 @@ ActiveRecord::Schema.define(:version =&gt; 20120411132751) do
200 202 create_table "comments", :force => true do |t|
201 203 t.string "title"
202 204 t.text "body"
203   - t.integer "article_id"
  205 + t.integer "source_id"
204 206 t.integer "author_id"
205 207 t.string "name"
206 208 t.string "email"
... ... @@ -208,6 +210,7 @@ ActiveRecord::Schema.define(:version =&gt; 20120411132751) do
208 210 t.integer "reply_of_id"
209 211 t.string "ip_address"
210 212 t.boolean "spam"
  213 + t.string "source_type"
211 214 end
212 215  
213 216 create_table "contact_lists", :force => true do |t|
... ...
lib/notify_activity_to_profiles_job.rb
1 1 class NotifyActivityToProfilesJob < Struct.new(:tracked_action_id)
2 2 NOTIFY_ONLY_COMMUNITY = [
3   - 'add_member_in_community',
4   - 'remove_member_in_community',
  3 + 'add_member_in_community'
5 4 ]
6 5  
7 6 NOT_NOTIFY_COMMUNITY = [
8   - 'join_community',
9   - 'leave_community',
  7 + 'join_community'
10 8 ]
11 9 def perform
12 10 return unless ActionTracker::Record.exists?(tracked_action_id)
... ... @@ -17,14 +15,23 @@ class NotifyActivityToProfilesJob &lt; Struct.new(:tracked_action_id)
17 15 return
18 16 end
19 17  
  18 + # Notify the user
20 19 ActionTrackerNotification.create(:profile_id => tracked_action.user.id, :action_tracker_id => tracked_action.id)
21 20  
  21 + # Notify all friends
22 22 ActionTrackerNotification.connection.execute("insert into action_tracker_notifications(profile_id, action_tracker_id) select f.friend_id, #{tracked_action.id} from friendships as f where person_id=#{tracked_action.user.id} and f.friend_id not in (select atn.profile_id from action_tracker_notifications as atn where atn.action_tracker_id = #{tracked_action.id})")
23 23  
24 24 if target.is_a?(Community)
25   - ActionTrackerNotification.connection.execute("insert into action_tracker_notifications(profile_id, action_tracker_id) select distinct profiles.id, #{tracked_action.id} from role_assignments, profiles where profiles.type = 'Person' and profiles.id = role_assignments.accessor_id and profiles.id != #{tracked_action.user.id} and role_assignments.resource_type = 'Profile' and role_assignments.resource_id = #{target.id}")
26   -
27 25 ActionTrackerNotification.create(:profile_id => target.id, :action_tracker_id => tracked_action.id) unless NOT_NOTIFY_COMMUNITY.include?(tracked_action.verb)
  26 +
  27 + ActionTrackerNotification.connection.execute("insert into action_tracker_notifications(profile_id, action_tracker_id) select distinct profiles.id, #{tracked_action.id} from role_assignments, profiles where profiles.type = 'Person' and profiles.id = role_assignments.accessor_id and profiles.id != #{tracked_action.user.id} and profiles.id not in (select atn.profile_id from action_tracker_notifications as atn where atn.action_tracker_id = #{tracked_action.id}) and role_assignments.resource_type = 'Profile' and role_assignments.resource_id = #{target.id}")
  28 + end
  29 +
  30 + if target.is_a?(Article) && target.profile.is_a?(Community)
  31 + ActionTrackerNotification.create(:profile_id => target.profile.id, :action_tracker_id => tracked_action.id) unless NOT_NOTIFY_COMMUNITY.include?(tracked_action.verb)
  32 +
  33 + ActionTrackerNotification.connection.execute("insert into action_tracker_notifications(profile_id, action_tracker_id) select distinct profiles.id, #{tracked_action.id} from role_assignments, profiles where profiles.type = 'Person' and profiles.id = role_assignments.accessor_id and profiles.id != #{tracked_action.user.id} and profiles.id not in (select atn.profile_id from action_tracker_notifications as atn where atn.action_tracker_id = #{tracked_action.id}) and role_assignments.resource_type = 'Profile' and role_assignments.resource_id = #{target.profile.id}")
28 34 end
  35 +
29 36 end
30 37 end
... ...
public/designs/icons/tango/style.css
... ... @@ -91,7 +91,7 @@
91 91 .icon-lock { background-image: url(Tango/16x16/actions/lock.png) }
92 92 .icon-chat { background-image: url(Tango/16x16/apps/internet-group-chat.png); background-repeat: no-repeat }
93 93 .icon-reply { background-image: url(Tango/16x16/actions/mail-reply-sender.png) }
94   -.icon-newforum { background-image: url(Tango/16x16/apps/system-users.png) }
  94 +.icon-newforum { background-image: url(Tango/16x16/apps/internet-group-chat.png) }
95 95 .icon-forum { background-image: url(Tango/16x16/apps/system-users.png) }
96 96 .icon-gallery { background-image: url(Tango/16x16/mimetypes/image-x-generic.png) }
97 97 .icon-newgallery { background-image: url(Tango/16x16/mimetypes/image-x-generic.png) }
... ...
public/designs/templates/default/stylesheets/style.css
... ... @@ -24,3 +24,9 @@
24 24 #profile-wall ul {
25 25 width: 460px;
26 26 }
  27 +#profile-activity ul.comment-replies,
  28 +#profile-network ul.comment-replies,
  29 +#profile-wall ul.comment-replies {
  30 + width: auto;
  31 +}
  32 +
... ...
public/designs/templates/leftbar/stylesheets/style.css
... ... @@ -23,3 +23,48 @@
23 23 #profile-wall ul {
24 24 width: 620px;
25 25 }
  26 +
  27 +.profile-activity-lead {
  28 + width: 534px;
  29 +}
  30 +
  31 +#profile-wall textarea {
  32 + width: 534px;
  33 +}
  34 +
  35 +#profile-wall #leave_scrap textarea {
  36 + width: 640px;
  37 +}
  38 +
  39 +#profile-wall li textarea {
  40 + width: 548px;
  41 +}
  42 +
  43 +.profile-activity-article-forum .profile-activity-lead {
  44 + background: url(/images/forum-activity-bg-onecol.png);
  45 + width: 489px;
  46 +}
  47 +
  48 +#profile-wall li.profile-activity-item.upload_image span,
  49 +#profile-wall li.profile-activity-item.upload_image span img,
  50 +#profile-wall li.profile-activity-item.upload_image span a,
  51 +#profile-network li.profile-activity-item.upload_image span,
  52 +#profile-network li.profile-activity-item.upload_image span img,
  53 +#profile-network li.profile-activity-item.upload_image span a {
  54 + width: 178px;
  55 + height: 144px;
  56 +}
  57 +
  58 +#profile-wall li.profile-activity-item.upload_image .activity-gallery-images-count-1 span,
  59 +#profile-wall li.profile-activity-item.upload_image .activity-gallery-images-count-1 span a img,
  60 +#profile-wall li.profile-activity-item.upload_image .activity-gallery-images-count-1 span a,
  61 +#profile-network li.profile-activity-item.upload_image .activity-gallery-images-count-1 span,
  62 +#profile-network li.profile-activity-item.upload_image .activity-gallery-images-count-1 span a img,
  63 +#profile-network li.profile-activity-item.upload_image .activity-gallery-images-count-1 span a {
  64 + max-width: 540px;
  65 +}
  66 +
  67 +#profile-wall li.profile-activity-item.upload_image .activity-gallery-images-count-1 span a,
  68 +#profile-network li.profile-activity-item.upload_image .activity-gallery-images-count-1 span a {
  69 + background-image: url(/images/gallery-image-activity-border-big-onecol.png);
  70 +}
... ...
public/designs/templates/rightbar/stylesheets/style.css
... ... @@ -23,3 +23,43 @@
23 23 #profile-wall ul {
24 24 width: 620px;
25 25 }
  26 +
  27 +.profile-activity-lead {
  28 + width: 534px;
  29 +}
  30 +
  31 +#profile-wall textarea {
  32 + width: 534px;
  33 +}
  34 +
  35 +#profile-wall #leave_scrap textarea {
  36 + width: 640px;
  37 +}
  38 +
  39 +#profile-wall li textarea {
  40 + width: 548px;
  41 +}
  42 +
  43 +.profile-activity-article-forum .profile-activity-lead {
  44 + background: url(/images/forum-activity-bg-onecol.png);
  45 + width: 489px;
  46 +}
  47 +
  48 +#profile-wall li.profile-activity-item.upload_image span,
  49 +#profile-wall li.profile-activity-item.upload_image span img,
  50 +#profile-wall li.profile-activity-item.upload_image span a,
  51 +#profile-network li.profile-activity-item.upload_image span,
  52 +#profile-network li.profile-activity-item.upload_image span img,
  53 +#profile-network li.profile-activity-item.upload_image span a {
  54 + width: 178px;
  55 + height: 144px;
  56 +}
  57 +
  58 +#profile-wall li.profile-activity-item.upload_image .activity-gallery-images-count-1 span,
  59 +#profile-wall li.profile-activity-item.upload_image .activity-gallery-images-count-1 span a img,
  60 +#profile-wall li.profile-activity-item.upload_image .activity-gallery-images-count-1 span a,
  61 +#profile-network li.profile-activity-item.upload_image .activity-gallery-images-count-1 span,
  62 +#profile-network li.profile-activity-item.upload_image .activity-gallery-images-count-1 span a img,
  63 +#profile-network li.profile-activity-item.upload_image .activity-gallery-images-count-1 span a {
  64 + max-width: 540px;
  65 +}
... ...
public/images/forum-activity-bg-onecol.png 0 → 100644

1.73 KB

public/images/forum-activity-bg.png 0 → 100644

1.72 KB

public/images/forum-activity-icon.png 0 → 100644

477 Bytes

public/images/gallery-image-activity-border-big-onecol.png 0 → 100644

2.21 KB

public/images/gallery-image-activity-border-big.png 0 → 100644

1.32 KB

public/images/gallery-image-activity-border-onecol.png 0 → 100644

1.44 KB

public/images/gallery-image-activity-border.png 0 → 100644

1.01 KB

public/javascripts/application.js
... ... @@ -711,6 +711,41 @@ Array.min = function(array) {
711 711 return Math.min.apply(Math, array);
712 712 };
713 713  
  714 +jQuery(function($){
  715 + $('.submit-with-keypress').live('keydown', function(e) {
  716 + field = this;
  717 + if (e.keyCode == 13) {
  718 + e.preventDefault();
  719 + var form = $(field).closest("form");
  720 + $.ajax({
  721 + url: form.attr("action"),
  722 + data: form.serialize(),
  723 + beforeSend: function() {
  724 + loading_for_button($(field));
  725 + },
  726 + success: function(data) {
  727 + var update = form.attr('data-update');
  728 + $('#'+update).html(data);
  729 + $(field).val($(field).attr('title'));
  730 + }
  731 + });
  732 + return false;
  733 + }
  734 + });
  735 +
  736 + $('.view-all-comments').live('click', function(e) {
  737 + var link = this;
  738 + $(link).parent().find('.profile-wall-activities-comments').show();
  739 + $(link).hide();
  740 + return false;
  741 + });
  742 + $('.focus-on-comment').live('click', function(e) {
  743 + var link = this;
  744 + $(link).parents('.profile-activity-item').find('textarea').focus();
  745 + return false;
  746 + });
  747 +});
  748 +
714 749 /**
715 750 * @author Remy Sharp
716 751 * @url http://remysharp.com/2007/01/25/jquery-tutorial-text-box-hints/
... ...
public/stylesheets/application.css
... ... @@ -240,6 +240,13 @@ td.field-name {
240 240 text-align: left;
241 241 vertical-align: top;
242 242 }
  243 +
  244 +table.profile .ui-tabs .ui-tabs-panel {
  245 + border-left: 0;
  246 + border-right: 0;
  247 + border-bottom: 0;
  248 +}
  249 +
243 250 table.profile th {
244 251 border-bottom: 2px solid #eeeeec;
245 252 padding: 10px 0px 0px 0px;
... ... @@ -1034,6 +1041,11 @@ a.comment-picture {
1034 1041 .comment-logged-out .comment-text {
1035 1042 color: #888;
1036 1043 }
  1044 +
  1045 +.comment-title {
  1046 + font-size: 12px;
  1047 + font-weight: bold;
  1048 +}
1037 1049 .comment-created-at {
1038 1050 padding-right: 9px;
1039 1051 }
... ... @@ -1205,7 +1217,9 @@ a.comment-picture {
1205 1217 -webkit-border-radius: 5px;
1206 1218 border-radius: 5px;
1207 1219 }
1208   -.comment-replies .article-comment-inner {
  1220 +
  1221 +.comment-replies .article-comment-inner,
  1222 +.scrap-replies {
1209 1223 border: 1px solid #fff;
1210 1224 padding: 0;
1211 1225 -moz-border-radius: 4px;
... ... @@ -4651,8 +4665,187 @@ h1#agenda-title {
4651 4665 }
4652 4666 #profile-activity li, #profile-network li, #profile-wall li {
4653 4667 display: block;
4654   - padding: 0;
4655   - margin-bottom: 8px;
  4668 + padding: 3px;
  4669 + margin-bottom: 3px;
  4670 + background-color: #fff;
  4671 + border-bottom: 1px solid #e8e8e8;
  4672 + position: relative;
  4673 +}
  4674 +
  4675 +#profile-activity li, #profile-network li, #profile-wall li {
  4676 +}
  4677 +
  4678 +.profile-activity-lead img {
  4679 + width: 124px;
  4680 + float: left;
  4681 + margin-right: 5px;
  4682 +}
  4683 +
  4684 +.profile-activity-lead {
  4685 + width: 370px;
  4686 + display: inline-block;
  4687 + text-align: left;
  4688 + margin: 5px 0;
  4689 +}
  4690 +
  4691 +.profile-activity-lead .article-name {
  4692 + font-weight: bold;
  4693 + margin-bottom: 5px;
  4694 +}
  4695 +
  4696 +.profile-activity-article-forum .profile-activity-lead {
  4697 + height: 50px;
  4698 + width: 297px;
  4699 + padding-left: 60px;
  4700 + float: none;
  4701 + overflow: hidden;
  4702 + background: transparent url(/images/forum-activity-bg.png) left center no-repeat;
  4703 +}
  4704 +
  4705 +.profile-activity-article-forum .see-forum {
  4706 + text-align: right;
  4707 +}
  4708 +
  4709 +.profile-activity-article-forum .see-forum a {
  4710 + background: transparent url(/images/forum-activity-icon.png) left center no-repeat;
  4711 + padding-left: 30px;
  4712 + font-weight: bold;
  4713 + color: #dadada !important;
  4714 + text-decoration: none;
  4715 + font-size: 11px;
  4716 +}
  4717 +
  4718 +.profile-activity-article-forum .profile-activity-lead b {
  4719 + font-weight: normal;
  4720 +}
  4721 +
  4722 +#profile-activity li a, #profile-network li a, #profile-wall li a,
  4723 +#profile-wall .profile-wall-send-reply {
  4724 + color: #333;
  4725 +}
  4726 +
  4727 +#profile-activity li a, #profile-network li a, #profile-wall li a {
  4728 + font-weight: bold;
  4729 + text-decoration: none;
  4730 +}
  4731 +
  4732 +#profile-activity li a:hover, #profile-network li a:hover, #profile-wall li a:hover {
  4733 + text-decoration: underline;
  4734 +}
  4735 +
  4736 +.profile-activity-text {
  4737 + margin: 0;
  4738 + color: #000;
  4739 +}
  4740 +
  4741 +#profile-wall li.profile-activity-item.upload_image span,
  4742 +#profile-wall li.profile-activity-item.upload_image span a,
  4743 +#profile-network li.profile-activity-item.upload_image span,
  4744 +#profile-network li.profile-activity-item.upload_image span a {
  4745 + width: 110px;
  4746 + height: 100px;
  4747 + display: block;
  4748 + overflow: hidden;
  4749 + position: absolute;
  4750 +}
  4751 +
  4752 +#profile-wall li.profile-activity-item.upload_image span a img,
  4753 +#profile-network li.profile-activity-item.upload_image span a img {
  4754 + width: 110px;
  4755 + height: 100px;
  4756 +}
  4757 +
  4758 +#profile-wall li.profile-activity-item.upload_image .activity-gallery-images-count-1 span,
  4759 +#profile-wall li.profile-activity-item.upload_image .activity-gallery-images-count-1 span a,
  4760 +#profile-wall li.profile-activity-item.upload_image .activity-gallery-images-count-1 span a img,
  4761 +#profile-network li.profile-activity-item.upload_image .activity-gallery-images-count-1 span,
  4762 +#profile-network li.profile-activity-item.upload_image .activity-gallery-images-count-1 span a img {
  4763 + width: auto;
  4764 + max-width: 383px;
  4765 + height: auto;
  4766 +}
  4767 +
  4768 +#profile-wall li.profile-activity-item.upload_image span img,
  4769 +#profile-network li.profile-activity-item.upload_image span img {
  4770 + display: block;
  4771 +}
  4772 +
  4773 +#profile-wall li.profile-activity-item.upload_image span,
  4774 +#profile-network li.profile-activity-item.upload_image span {
  4775 + position: relative;
  4776 + display: inline-block;
  4777 + margin: 5px 0px 0px 5px;
  4778 +}
  4779 +
  4780 +#profile-wall li.profile-activity-item.upload_image .profile-activity-text span,
  4781 +#profile-network li.profile-activity-item.upload_image .profile-activity-text span {
  4782 + border: 4px solid #D2D2D2;
  4783 + border-radius: 4px;
  4784 + -webkit-border-radius: 4px;
  4785 + -moz-border-radius: 4px;
  4786 +}
  4787 +
  4788 +#profile-wall li.profile-activity-item.upload_image span a,
  4789 +#profile-network li.profile-activity-item.upload_image span a {
  4790 + text-indent: -5000em;
  4791 +}
  4792 +
  4793 +#profile-wall li.profile-activity-item.upload_image .activity-gallery-images-count-1 span a,
  4794 +#profile-network li.profile-activity-item.upload_image .activity-gallery-images-count-1 span a {
  4795 + position: relative;
  4796 +}
  4797 +
  4798 +#profile-wall li.profile-activity-item.upload_image .article-comment span,
  4799 +#profile-wall li.profile-activity-item.upload_image .profile-wall-actions span,
  4800 +#profile-network li.profile-activity-item.upload_image .article-comment span,
  4801 +#profile-network li.profile-activity-item.upload_image .profile-wall-actions span {
  4802 + display: inline;
  4803 + position: static;
  4804 + margin: 0;
  4805 + float: none;
  4806 + width: auto;
  4807 + height: auto;
  4808 + font-weight: normal;
  4809 +}
  4810 +
  4811 +#profile-wall li.profile-activity-item ul.profile-wall-activities-comments,
  4812 +#profile-network li.profile-activity-item ul.profile-wall-activities-comments {
  4813 + margin-top: 0;
  4814 +}
  4815 +
  4816 +#profile-wall li.profile-activity-item.upload_image .profile-activity-text,
  4817 +#profile-network li.profile-activity-item.upload_image .profile-activity-text,
  4818 +#profile-network li.profile-activity-item ul.profile-wall-activities-comments {
  4819 + padding-left: 50px;
  4820 +}
  4821 +
  4822 +#profile-wall li.profile-activity-item.join_community .profile-activity-text a img,
  4823 +#profile-wall li.profile-activity-item.new_friendship .profile-activity-text a img,
  4824 +#profile-network li.profile-activity-item.join_community .profile-activity-text a img,
  4825 +#profile-network li.profile-activity-item.new_friendship .profile-activity-text a img {
  4826 + margin: 5px 5px 0 0;
  4827 + padding: 1px;
  4828 + border: 1px solid #ccc;
  4829 +}
  4830 +
  4831 +#profile-wall li.profile-activity-item.create_article,
  4832 +#profile-netowrk li.profile-activity-item.create_article {
  4833 + position: relative;
  4834 +}
  4835 +
  4836 +.profile-activity-icon {
  4837 + width: 16px;
  4838 + height: 16px;
  4839 + display: inline-block;
  4840 + position: absolute;
  4841 + top: 0px;
  4842 + right: 0px;
  4843 +}
  4844 +
  4845 +#profile-activity .profile-wall-scrap-replies li,
  4846 +#profile-network .profile-wall-scrap-replies li,
  4847 +#profile-wall .profile-wall-scrap-replies li {
  4848 + border-bottom: none;
4656 4849 }
4657 4850 #profile-activity .profile-activity-image, #profile-network .profile-network-image, #profile-wall .profile-wall-image {
4658 4851 float: left;
... ... @@ -4664,12 +4857,12 @@ h1#agenda-title {
4664 4857 }
4665 4858 #profile-activity .profile-activity-description, #profile-network .profile-network-description, #profile-wall .profile-wall-description {
4666 4859 float: left;
4667   - min-height: 60px;
  4860 + Xmin-height: 60px;
4668 4861 margin: 0;
4669 4862 padding: 0;
4670 4863 border: 1px solid #ccc;
4671 4864 overflow: hidden;
4672   - background-color: #fff;
  4865 + Xbackground-color: #fff;
4673 4866 position: relative;
4674 4867 }
4675 4868 #profile-wall .profile-wall-description {
... ... @@ -4678,7 +4871,10 @@ h1#agenda-title {
4678 4871 #profile-activity .profile-activity-description .icon-delete span, #profile-network .profile-network-description .icon-delete span, #profile-wall .profile-wall-description .icon-delete span {
4679 4872 display: none;
4680 4873 }
4681   -#profile-activity .profile-activity-description .icon-delete, #profile-network .profile-network-description .icon-delete, #profile-wall .profile-wall-description .icon-delete {
  4874 +
  4875 +#profile-activity .profile-activity-description .icon-delete,
  4876 +#profile-network .profile-activity-description .icon-delete,
  4877 +#profile-wall .profile-wall-description .icon-delete {
4682 4878 position: absolute;
4683 4879 top: 4px;
4684 4880 right: 4px;
... ... @@ -4688,21 +4884,55 @@ h1#agenda-title {
4688 4884 -webkit-border-radius: 3px;
4689 4885 -moz-border-radius: 3px;
4690 4886 }
4691   -#profile-activity .profile-activity-text, #profile-network .profile-network-text, #profile-wall .profile-wall-text {
  4887 +
  4888 +#profile-activity .profile-activity-text,
  4889 +#profile-network .profile-activity-text,
  4890 +#profile-wall .profile-wall-text {
4692 4891 font-size: 13px;
4693   - margin: 5px;
  4892 + margin: 2px 5px;
4694 4893 }
4695 4894 #profile-wall .profile-wall-text {
4696 4895 padding-top: 0;
4697 4896 }
4698   -#profile-activity .profile-activity-time, #profile-network .profile-network-time, #profile-wall .profile-wall-time {
  4897 +
  4898 +.profile-activities .profile-activity-time,
  4899 +#profile-network .profile-activity-time,
  4900 +#profile-wall .profile-wall-time {
4699 4901 font-size: 11px;
4700 4902 margin: 5px;
4701 4903 color: #babdb6;
  4904 + text-align: right;
  4905 +}
  4906 +
  4907 +#profile-wall .profile-wall-send-reply,
  4908 +.profile-activities .profile-activity-time,
  4909 +#profile-network .profile-activity-time,
  4910 +#profile-wall .profile-wall-time,
  4911 +.profile-wall-actions a {
  4912 + display: block;
  4913 + float: right;
  4914 + font-size: 10px;
  4915 + margin: 2px 0 3px 10px;
  4916 + color: #ccc;
  4917 + padding: 0;
  4918 +}
  4919 +
  4920 +#profile-wall li .profile-wall-actions a,
  4921 +#profile-activity li .profile-wall-actions a,
  4922 +#profile-network li .profile-wall-actions a,
  4923 +#profile-wall .profile-wall-send-reply a {
  4924 + text-decoration: none;
  4925 + color: #333;
  4926 + font-weight: normal;
  4927 +}
  4928 +
  4929 +#profile-wall li .profile-wall-actions a:hover,
  4930 +#profile-network li .profile-wall-actions a:hover,
  4931 +#profile-wall .profile-wall-send-reply a:hover {
  4932 + text-decoration: underline;
4702 4933 }
4703 4934 #profile-activity hr, #profile-network hr, #profile-wall hr {
4704   - clear: both;
4705   - border: 0;
  4935 + display: none;
4706 4936 }
4707 4937 #profile-activity .profile-activity-send-message, #profile-network .profile-network-send-message, #profile-wall .profile-wall-send-message {
4708 4938 font-size: 10px;
... ... @@ -4762,9 +4992,13 @@ h1#agenda-title {
4762 4992 }
4763 4993 .profile-wall-sender, .profile-wall-time, .profile-wall-description, .profile-activity-sender, .profile-activity-time, .profile-activity-description, .profile-network-sender, .profile-network-time, .profile-network-description {
4764 4994 padding-left: 5px;
  4995 + margin: 5px;
4765 4996 }
4766   -.profile-network-sender, .profile-wall-sender {
4767   - margin: 2px 0;
  4997 +
  4998 +.profile-network-sender,
  4999 +.profile-activity-sender,
  5000 +.profile-wall-sender {
  5001 + margin: 0;
4768 5002 }
4769 5003 #profile-activity .profile-activity-time, #profile-network .profile-network-time, #profile-wall .profile-wall-time {
4770 5004 margin: 0;
... ... @@ -4775,7 +5009,16 @@ h1#agenda-title {
4775 5009 padding: 2px;
4776 5010 overflow: hidden;
4777 5011 }
4778   -.profile-network-message, .profile-wall-message {
  5012 +
  5013 +#profile-network li textarea:focus,
  5014 +#profile-wall li textarea:focus {
  5015 + background-position: left center;
  5016 + background-repeat: no-repeat;
  5017 + text-indent: 28px;
  5018 +}
  5019 +
  5020 +.profile-network-message,
  5021 +.profile-wall-message {
4779 5022 margin: 0;
4780 5023 }
4781 5024 .limited-text-area p {
... ... @@ -4801,19 +5044,24 @@ h1#agenda-title {
4801 5044 overflow: hidden;
4802 5045 }
4803 5046 .profile-send-reply {
4804   - background-color: #eee;
4805   - border: 1px solid #aaa;
4806   - padding: 2px;
4807   - padding-left: 20px;
4808   - background-repeat: no-repeat;
4809   - background-position: 2px center;
  5047 + xbackground-color: #eee;
  5048 + xborder: 1px solid #aaa;
  5049 + xpadding: 2px;
  5050 + xpadding-left: 20px;
  5051 + xbackground-repeat: no-repeat;
  5052 + xbackground-position: 2px center;
4810 5053 color: #aaa;
4811   - text-decoration: none;
4812   - margin-left: 8px;
  5054 + Xtext-decoration: none;
  5055 + Xmargin-left: 8px;
4813 5056 }
4814 5057 #content .profile-send-reply:hover {
4815 5058 text-decoration: none;
4816 5059 }
  5060 +
  5061 +#profile-wall .profile-wall-actions {
  5062 + text-align: right;
  5063 +}
  5064 +
4817 5065 #profile-wall .profile-wall-scrap-replies .profile-wall-description {
4818 5066 background: transparent;
4819 5067 }
... ... @@ -4826,6 +5074,105 @@ h1#agenda-title {
4826 5074 .limited-text-area div.fieldWithErrors {
4827 5075 background: transparent;
4828 5076 }
  5077 +
  5078 +#profile-wall ul.profile-wall-activities-comments,
  5079 +#profile-network ul.profile-wall-activities-comments {
  5080 + margin-top: 35px;
  5081 + padding-left: 50px;
  5082 + width: auto;
  5083 +}
  5084 +
  5085 +#profile-wall ul.profile-wall-activities-comments ul,
  5086 +#profile-network ul.profile-wall-activities-comments ul {
  5087 + padding-left: 0px;
  5088 +}
  5089 +
  5090 +#profile-wall .profile-wall-activities-comments li,
  5091 +#profile-network .profile-wall-activities-comments li {
  5092 + background: #f0f0f1;
  5093 + border-bottom: 1px solid #d2d2d2 !important;
  5094 + border-top: 1px solid #fff;
  5095 + margin-bottom: 0;
  5096 +}
  5097 +
  5098 +#profile-wall .profile-wall-activities-comments img,
  5099 +#profile-network .profile-wall-activities-comments img {
  5100 + max-width: 50px;
  5101 + max-height: 50px;
  5102 +}
  5103 +
  5104 +#profile-wall .profile-wall-activities-comments .comment_reply,
  5105 +#profile-wall .profile-wall-activities-comments h4,
  5106 +#profile-network .profile-wall-activities-comments .comment_reply,
  5107 +#profile-network .profile-wall-activities-comments h4 {
  5108 + display: none;
  5109 +}
  5110 +
  5111 +#profile-wall .profile-wall-activities-comments .comment-picture,
  5112 +#profile-network .profile-wall-activities-comments .comment-picture {
  5113 + width: 50px;
  5114 + text-align: center;
  5115 +}
  5116 +
  5117 +#profile-wall .profile-wall-activities-comments .comment-text p,
  5118 +#profile-network .profile-wall-activities-comments .comment-text p {
  5119 + margin: 0;
  5120 +}
  5121 +
  5122 +#profile-wall .profile-wall-activities-comments .profile-activity-time,
  5123 +#profile-network .profile-wall-activities-comments .profile-activity-time {
  5124 + clear: both;
  5125 +}
  5126 +
  5127 +#profile-wall .profile-wall-activities-comments .comment-details,
  5128 +#profile-network .profile-wall-activities-comments .comment-details {
  5129 + padding: 0;
  5130 +}
  5131 +
  5132 +#profile-wall .profile-wall-activities-comments .article-comment .button-bar,
  5133 +#profile-network .profile-wall-activities-comments .article-comment .button-bar {
  5134 + float: right;
  5135 + padding: 0;
  5136 + text-align: right;
  5137 + position: static;
  5138 + clear: none;
  5139 + display: none;
  5140 +}
  5141 +
  5142 +#profile-wall .profile-wall-activities-comments .article-comment:hover .button-bar,
  5143 +#profile-network .profile-wall-activities-comments .article-comment:hover .button-bar {
  5144 + display: block;
  5145 +}
  5146 +
  5147 +#profile-wall .profile-wall-activities-comments .article-comment .button-bar a.button,
  5148 +#profile-network .profile-wall-activities-comments .article-comment .button-bar a.button {
  5149 + background: transparent;
  5150 + border: 0;
  5151 + height: auto;
  5152 + line-height: auto;
  5153 + color: #333;
  5154 + text-decoration: none;
  5155 + font-size: 10px;
  5156 + padding: 0;
  5157 + margin: 0;
  5158 + display: inline;
  5159 + position: static;
  5160 + float: none;
  5161 + font-weight: normal;
  5162 +}
  5163 +
  5164 +#profile-wall .profile-wall-activities-comments .article-comment .button-bar a.button:hover,
  5165 +#profile-network .profile-wall-activities-comments .article-comment .button-bar a.button:hover {
  5166 + text-decoration: underline;
  5167 +}
  5168 +
  5169 +#profile-wall .profile-wall-activities-comments .article-comment .button-bar .button span,
  5170 +#profile-network .profile-wall-activities-comments .article-comment .button-bar .button span {
  5171 + display: inline;
  5172 + position: static;
  5173 + display: inline;
  5174 +}
  5175 +
4829 5176 /* friends online {{{ */
4830 5177  
4831 5178 #chat-online-users {
... ... @@ -4948,15 +5295,36 @@ h1#agenda-title {
4948 5295 margin-left: 0;
4949 5296 }
4950 5297 #profile-wall .comment-balloon-content {
4951   - padding: 3px 0 3px 15px;
  5298 + padding: 3px 0px;
4952 5299 }
4953 5300 .profile-wall-reply {
4954 5301 margin: 0;
4955 5302 }
  5303 +
  5304 +.profile-wall-reply-form {
  5305 + display: block;
  5306 + background: #f0f0f1;
  5307 + border-bottom: 1px solid #d2d2d2;
  5308 + border-top: 1px solid #fff;
  5309 + margin-left: 50px;
  5310 + padding: 0 5px;
  5311 +}
  5312 +
  5313 +.scrap-replies .profile-wall-reply-form {
  5314 + margin-left: 0px;
  5315 +}
  5316 +
4956 5317 .profile-wall-scrap-replies {
4957 5318 float: right;
4958 5319 margin-right: 2px;
4959 5320 }
  5321 +
  5322 +.view-all-comments {
  5323 + clear: both;
  5324 + margin-left: 50px;
  5325 + padding-left: 20px;
  5326 +}
  5327 +
4960 5328 /* Profile activity relative dimensions */
4961 5329  
4962 5330 #leave_scrap {
... ... @@ -4965,15 +5333,37 @@ h1#agenda-title {
4965 5333 #leave_scrap textarea {
4966 5334 width: 98%;
4967 5335 }
4968   -#profile-activity .profile-activity-image, #profile-network .profile-network-image, #profile-wall .profile-wall-image {
4969   - width: 19%;
  5336 +
  5337 +.profile-activities .profile-activity-image,
  5338 +#profile-network .profile-activity-image,
  5339 +#profile-wall .profile-wall-image {
  5340 + width: 50px;
  5341 + margin: 5px;
  5342 + float: left;
4970 5343 }
4971   -#profile-activity .profile-activity-description, #profile-network .profile-network-description, #profile-wall .profile-wall-description {
4972   - width: 80%;
  5344 +
  5345 +#profile-activity .profile-activity-description,
  5346 +#profile-network .profile-activity-description,
  5347 +#profile-wall .profile-wall-description {
4973 5348 word-wrap: break-word;
4974 5349 }
4975   -#profile-wall .profile-wall-scrap-replies textarea, #profile-network textarea, #profile-wall textarea {
4976   - width: 99%;
  5350 +
  5351 +#profile-wall textarea {
  5352 + width: 375px;
  5353 +}
  5354 +
  5355 +#profile-wall li textarea {
  5356 + width: 388px;
  5357 +}
  5358 +
  5359 +#profile-wall .profile-wall-scrap-replies textarea,
  5360 +#profile-network textarea, #profile-wall textarea,
  5361 +#profile-wall li .profile-wall-reply-form textarea {
  5362 + width: 98%;
  5363 +}
  5364 +
  5365 +#profile-wall #leave_scrap textarea {
  5366 + width: 442px;
4977 5367 }
4978 5368 .profile-wall-scrap-replies {
4979 5369 width: 100%;
... ...
test/factories.rb
... ... @@ -374,7 +374,7 @@ module Noosfero::Factory
374 374 ###############################################
375 375  
376 376 def defaults_for_scrap(params = {})
377   - { :content => 'soment content ', :sender_id => 1, :receiver_id => 1, :created_at => DateTime.now }.merge(params)
  377 + { :content => 'some content ', :sender_id => 1, :receiver_id => 1, :created_at => DateTime.now }.merge(params)
378 378 end
379 379  
380 380 ###############################################
... ... @@ -442,7 +442,7 @@ module Noosfero::Factory
442 442  
443 443 def defaults_for_comment(params = {})
444 444 name = "comment_#{rand(1000)}"
445   - { :title => name, :body => "my own comment", :article_id => 1 }.merge(params)
  445 + { :title => name, :body => "my own comment", :source_id => 1 }.merge(params)
446 446 end
447 447  
448 448 ###############################################
... ...
test/functional/profile_controller_test.rb
... ... @@ -714,25 +714,23 @@ 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
718   - p1= Person.first
  717 + should 'not display activities of the current profile when he is not followed by the viewer' do
  718 + p1= fast_create(Person)
719 719 p2= fast_create(Person)
720   - assert !p1.is_a_friend?(p2)
721   - p3= fast_create(Person)
722   - assert !p1.is_a_friend?(p3)
723   - ActionTracker::Record.destroy_all
724   - Scrap.create!(defaults_for_scrap(:sender => p1, :receiver => p1))
725   - a1 = ActionTracker::Record.last
  720 +
  721 + UserStampSweeper.any_instance.stubs(:current_user).returns(p1)
  722 + scrap1 = Scrap.create!(defaults_for_scrap(:sender => p1, :receiver => p2))
  723 +
726 724 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
  725 + scrap2 = Scrap.create!(defaults_for_scrap(:sender => p2, :receiver => p1))
  726 +
  727 + UserStampSweeper.any_instance.stubs(:current_user).returns(p1)
  728 + TinyMceArticle.create!(:profile => p1, :name => 'An article about free software')
  729 + a1 = ActionTracker::Record.last
  730 +
732 731 login_as(profile.identifier)
733 732 get :index, :profile => p1.identifier
734   - assert_not_nil assigns(:activities)
735   - assert_equal [a1], assigns(:activities)
  733 + assert_nil assigns(:activities)
736 734 end
737 735  
738 736 should 'see the activities_items paginated' do
... ... @@ -744,26 +742,27 @@ class ProfileControllerTest &lt; ActionController::TestCase
744 742 assert_equal 30, assigns(:activities).count
745 743 end
746 744  
747   - should 'see not see the friends activities in the current profile activity' do
748   - p1= Person.first
  745 + should 'not see the friends activities in the current profile' do
749 746 p2= fast_create(Person)
750   - assert !p1.is_a_friend?(p2)
  747 + assert !profile.is_a_friend?(p2)
751 748 p3= fast_create(Person)
752   - p1.add_friend(p3)
753   - assert p1.is_a_friend?(p3)
  749 + p3.add_friend(profile)
  750 + assert p3.is_a_friend?(profile)
754 751 ActionTracker::Record.destroy_all
755   - Scrap.create!(defaults_for_scrap(:sender => p1, :receiver => p1))
756   - a1 = ActionTracker::Record.last
757   - UserStampSweeper.any_instance.stubs(:current_user).returns(p2)
758   - Scrap.create!(defaults_for_scrap(:sender => p2, :receiver => p3))
759   - a2 = ActionTracker::Record.last
  752 +
  753 + scrap1 = Scrap.create!(defaults_for_scrap(:sender => p2, :receiver => p3))
  754 + scrap2 = Scrap.create!(defaults_for_scrap(:sender => p2, :receiver => profile))
  755 +
760 756 UserStampSweeper.any_instance.stubs(:current_user).returns(p3)
761   - Scrap.create!(defaults_for_scrap(:sender => p3, :receiver => p1))
762   - a3 = ActionTracker::Record.last
  757 + article1 = TinyMceArticle.create!(:profile => p3, :name => 'An article about free software')
  758 +
  759 + UserStampSweeper.any_instance.stubs(:current_user).returns(p2)
  760 + article2 = TinyMceArticle.create!(:profile => p2, :name => 'Another article about free software')
  761 +
763 762 login_as(profile.identifier)
764   - get :index, :profile => p1.identifier
  763 + get :index, :profile => p3.identifier
765 764 assert_not_nil assigns(:activities)
766   - assert_equal [a1], assigns(:activities)
  765 + assert_equivalent [scrap1, article1.activity], assigns(:activities).map { |a| a.klass.constantize.find(a.id) }
767 766 end
768 767  
769 768 should 'see all the activities in the current profile network' do
... ... @@ -931,13 +930,29 @@ class ProfileControllerTest &lt; ActionController::TestCase
931 930 assert_template 'index'
932 931 end
933 932  
934   - should 'have wall_itens defined' do
935   - p1= ActionTracker::Record.current_user_from_model
  933 + should 'not have activities defined if not logged in' do
  934 + p1= fast_create(Person)
  935 + get :index, :profile => p1.identifier
  936 + assert_nil assigns(:actvities)
  937 + end
  938 +
  939 + should 'not have activities defined if logged in but is not following profile' do
  940 + login_as(profile.identifier)
  941 + p1= fast_create(Person)
936 942 get :index, :profile => p1.identifier
937   - assert_equal [], assigns(:wall_items)
  943 + assert_nil assigns(:activities)
938 944 end
939 945  
940   - should 'the wall_itens be the received scraps in people profile' do
  946 + should 'have activities defined if logged in and is following profile' do
  947 + login_as(profile.identifier)
  948 + p1= fast_create(Person)
  949 + p1.add_friend(profile)
  950 + ActionTracker::Record.destroy_all
  951 + get :index, :profile => p1.identifier
  952 + assert_equal [], assigns(:activities)
  953 + end
  954 +
  955 + should 'the activities be the received scraps in people profile' do
941 956 p1 = ActionTracker::Record.current_user_from_model
942 957 p2 = fast_create(Person)
943 958 p3 = fast_create(Person)
... ... @@ -952,10 +967,10 @@ class ProfileControllerTest &lt; ActionController::TestCase
952 967 @controller.stubs(:current_user).returns(user)
953 968 Person.any_instance.stubs(:follows?).returns(true)
954 969 get :index, :profile => p1.identifier
955   - assert_equal [s2,s3], assigns(:wall_items)
  970 + assert_equal [s2,s3], assigns(:activities)
956 971 end
957 972  
958   - should 'the wall_itens be the received scraps in community profile' do
  973 + should 'the activities be the received scraps in community profile' do
959 974 c = fast_create(Community)
960 975 p1 = fast_create(Person)
961 976 p2 = fast_create(Person)
... ... @@ -971,12 +986,12 @@ class ProfileControllerTest &lt; ActionController::TestCase
971 986 @controller.stubs(:current_user).returns(user)
972 987 Person.any_instance.stubs(:follows?).returns(true)
973 988 get :index, :profile => c.identifier
974   - assert_equal [s2,s3], assigns(:wall_items)
  989 + assert_equal [s2,s3], assigns(:activities)
975 990 end
976 991  
977   - should 'the wall_itens be paginated in people profiles' do
  992 + should 'the activities be paginated in people profiles' do
978 993 p1 = Person.first
979   - 40.times{fast_create(Scrap, :sender_id => p1.id)}
  994 + 40.times{fast_create(Scrap, :sender_id => p1.id, :created_at => Time.now)}
980 995  
981 996 @controller.stubs(:logged_in?).returns(true)
982 997 user = mock()
... ... @@ -986,10 +1001,10 @@ class ProfileControllerTest &lt; ActionController::TestCase
986 1001 Person.any_instance.stubs(:follows?).returns(true)
987 1002 assert_equal 40, p1.scraps_received.not_replies.count
988 1003 get :index, :profile => p1.identifier
989   - assert_equal 30, assigns(:wall_items).count
  1004 + assert_equal 30, assigns(:activities).count
990 1005 end
991 1006  
992   - should 'the wall_itens be paginated in community profiles' do
  1007 + should 'the activities be paginated in community profiles' do
993 1008 p1 = Person.first
994 1009 c = fast_create(Community)
995 1010 40.times{fast_create(Scrap, :receiver_id => c.id)}
... ... @@ -1002,7 +1017,7 @@ class ProfileControllerTest &lt; ActionController::TestCase
1002 1017 Person.any_instance.stubs(:follows?).returns(true)
1003 1018 assert_equal 40, c.scraps_received.not_replies.count
1004 1019 get :index, :profile => c.identifier
1005   - assert_equal 30, assigns(:wall_items).count
  1020 + assert_equal 30, assigns(:activities).count
1006 1021 end
1007 1022  
1008 1023 should "the owner of activity could remove it" do
... ... @@ -1072,17 +1087,17 @@ class ProfileControllerTest &lt; ActionController::TestCase
1072 1087 end
1073 1088 end
1074 1089  
1075   - should "not show the scrap button on network activity if the user don't follow the user" do
  1090 + should "not show the network activity if the viewer don't follow the profile" do
1076 1091 login_as(profile.identifier)
1077 1092 person = fast_create(Person)
1078 1093 at = fast_create(ActionTracker::Record, :user_id => person.id)
1079 1094 atn = fast_create(ActionTrackerNotification, :profile_id => profile.id, :action_tracker_id => at.id)
1080   - get :index, :profile => profile.identifier
1081   - assert_no_tag :tag => 'p', :attributes => {:class => 'profile-network-send-message'}
  1095 + get :index, :profile => person.identifier
  1096 + assert_no_tag :tag => 'div', :attributes => {:id => 'profile-network'}
1082 1097  
1083 1098 person.add_friend(profile)
1084   - get :index, :profile => profile.identifier
1085   - assert_tag :tag => 'p', :attributes => {:class => 'profile-network-send-message'}
  1099 + get :index, :profile => person.identifier
  1100 + assert_tag :tag => 'div', :attributes => {:id => 'profile-network'}
1086 1101 end
1087 1102  
1088 1103 should "not show the scrap button on network activity if the user is himself" do
... ... @@ -1093,16 +1108,16 @@ class ProfileControllerTest &lt; ActionController::TestCase
1093 1108 assert_no_tag :tag => 'p', :attributes => {:class => 'profile-network-send-message'}
1094 1109 end
1095 1110  
1096   - should "not show the scrap button on wall activity if the user don't follow the user" do
  1111 + should "not show the scrap area on wall if the user don't follow the user" do
1097 1112 login_as(profile.identifier)
1098 1113 person = fast_create(Person)
1099 1114 scrap = fast_create(Scrap, :sender_id => person.id, :receiver_id => profile.id)
1100   - get :index, :profile => profile.identifier
1101   - assert_no_tag :tag => 'p', :attributes => {:class => 'profile-wall-send-message'}
  1115 + get :index, :profile => person.identifier
  1116 + assert_no_tag :tag => 'div', :attributes => {:id => 'leave_scrap'}, :descendant => { :tag => 'input', :attributes => {:value => 'Share'} }
1102 1117  
1103 1118 person.add_friend(profile)
1104   - get :index, :profile => profile.identifier
1105   - assert_tag :tag => 'p', :attributes => {:class => 'profile-wall-send-message'}
  1119 + get :index, :profile => person.identifier
  1120 + assert_tag :tag => 'div', :attributes => {:id => 'leave_scrap'}, :descendant => { :tag => 'input', :attributes => {:value => 'Share'} }
1106 1121 end
1107 1122  
1108 1123 should "not show the scrap button on wall activity if the user is himself" do
... ... @@ -1158,7 +1173,7 @@ class ProfileControllerTest &lt; ActionController::TestCase
1158 1173 assert_equal 40, profile.tracked_actions.count
1159 1174 get :view_more_activities, :profile => profile.identifier, :page => 2
1160 1175 assert_response :success
1161   - assert_template '_profile_activities'
  1176 + assert_template '_profile_activities_list'
1162 1177 assert_equal 10, assigns(:activities).count
1163 1178 end
1164 1179  
... ... @@ -1247,4 +1262,70 @@ class ProfileControllerTest &lt; ActionController::TestCase
1247 1262 post :register_report, :profile => reported.identifier, :abuse_report => {:reason => 'some reason'}
1248 1263 end
1249 1264 end
  1265 +
  1266 + should 'display activities and scraps together' do
  1267 + another_person = fast_create(Person)
  1268 + Scrap.create!(defaults_for_scrap(:sender => another_person, :receiver => profile, :content => 'A scrap'))
  1269 +
  1270 + UserStampSweeper.any_instance.stubs(:current_user).returns(profile)
  1271 + ActionTracker::Record.destroy_all
  1272 + TinyMceArticle.create!(:profile => profile, :name => 'An article about free software')
  1273 +
  1274 + login_as(profile.identifier)
  1275 + get :index, :profile => profile.identifier
  1276 +
  1277 + assert_tag :tag => 'p', :content => 'A scrap', :attributes => { :class => 'profile-activity-text'}
  1278 + assert_tag :tag => 'div', :attributes => { :class => 'profile-activity-lead' }, :descendant => { :tag => 'a', :content => 'An article about free software' }
  1279 + end
  1280 +
  1281 + should 'have scraps and activities on activities' do
  1282 + another_person = fast_create(Person)
  1283 + scrap = Scrap.create!(defaults_for_scrap(:sender => another_person, :receiver => profile, :content => 'A scrap'))
  1284 +
  1285 + UserStampSweeper.any_instance.stubs(:current_user).returns(profile)
  1286 + ActionTracker::Record.destroy_all
  1287 + TinyMceArticle.create!(:profile => profile, :name => 'An article about free software')
  1288 + activity = ActionTracker::Record.last
  1289 +
  1290 + login_as(profile.identifier)
  1291 + get :index, :profile => profile.identifier
  1292 +
  1293 + assert_equivalent [scrap,activity], assigns(:activities).map {|a| a.klass.constantize.find(a.id)}
  1294 + end
  1295 +
  1296 + should "be logged in to leave comment on an activity" do
  1297 + article = TinyMceArticle.create!(:profile => profile, :name => 'An article about free software')
  1298 + activity = ActionTracker::Record.last
  1299 + count = activity.comments.count
  1300 +
  1301 + post :leave_comment_on_activity, :profile => profile.identifier, :comment => {:body => 'something', :source_id => activity.id}
  1302 + assert_equal count, activity.comments.count
  1303 + assert_redirected_to :controller => 'account', :action => 'login'
  1304 + end
  1305 +
  1306 + should "leave a comment in own activity" do
  1307 + login_as(profile.identifier)
  1308 + TinyMceArticle.create!(:profile => profile, :name => 'An article about free software')
  1309 + activity = ActionTracker::Record.last
  1310 + count = activity.comments.count
  1311 +
  1312 + assert_equal 0, count
  1313 + post :leave_comment_on_activity, :profile => profile.identifier, :comment => {:body => 'something'}, :source_id => activity.id
  1314 + assert_equal count + 1, ActionTracker::Record.find(activity.id).comments_count
  1315 + assert_response :success
  1316 + assert_equal "Comment successfully added.", assigns(:message)
  1317 + end
  1318 +
  1319 + should "leave a comment on another profile's activity" do
  1320 + login_as(profile.identifier)
  1321 + another_person = fast_create(Person)
  1322 + TinyMceArticle.create!(:profile => another_person, :name => 'An article about free software')
  1323 + activity = ActionTracker::Record.last
  1324 + count = activity.comments.count
  1325 + assert_equal 0, count
  1326 + post :leave_comment_on_activity, :profile => another_person.identifier, :comment => {:body => 'something'}, :source_id => activity.id
  1327 + assert_equal count + 1, ActionTracker::Record.find(activity.id).comments_count
  1328 + assert_response :success
  1329 + assert_equal "Comment successfully added.", assigns(:message)
  1330 + end
1250 1331 end
... ...
test/unit/action_tracker_notification_test.rb
... ... @@ -76,4 +76,28 @@ 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 + person = fast_create(Person)
  81 + community = fast_create(Community)
  82 + community.add_member(person)
  83 + activity = ActionTracker::Record.last
  84 + process_delayed_job_queue
  85 + notification = ActionTrackerNotification.last
  86 +
  87 + comment = create(Comment, :source => activity, :author => person)
  88 +
  89 + assert_equal activity.comments, notification.comments
  90 + end
  91 +
  92 + should "have comments through article action_tracker" do
  93 + person = fast_create(Person)
  94 + article = create(TextileArticle, :profile_id => person.id)
  95 + process_delayed_job_queue
  96 + notification = ActionTrackerNotification.last
  97 +
  98 + comment = create(Comment, :source => article, :author => person)
  99 +
  100 + assert_equal article.activity.comments, notification.comments
  101 + end
  102 +
79 103 end
... ...
test/unit/approve_article_test.rb
... ... @@ -251,7 +251,7 @@ class ApproveArticleTest &lt; ActiveSupport::TestCase
251 251 assert_equal 1, ActionTracker::Record.count
252 252 end
253 253  
254   - should 'notify with different trackers activity create with different targets' do
  254 + should 'not group trackers activity of article\'s creation' do
255 255 ActionTracker::Record.delete_all
256 256  
257 257 article = fast_create(TextileArticle)
... ... @@ -261,28 +261,15 @@ class ApproveArticleTest &lt; ActiveSupport::TestCase
261 261 article = fast_create(TextileArticle)
262 262 a = ApproveArticle.create!(:name => 'another bar', :article => article, :target => community, :requestor => profile)
263 263 a.finish
264   - assert_equal 1, ActionTracker::Record.count
265 264  
266 265 article = fast_create(TextileArticle)
267 266 other_community = fast_create(Community)
268 267 a = ApproveArticle.create!(:name => 'another bar', :article => article, :target => other_community, :requestor => profile)
269 268 a.finish
270   - assert_equal 2, ActionTracker::Record.count
271   - end
272   -
273   - should 'notify activity on update' do
274   - ActionTracker::Record.delete_all
275   - a = ApproveArticle.create!(:name => 'bar', :article => article, :target => community, :requestor => profile)
276   - a.finish
277   - assert_equal 1, ActionTracker::Record.count
278   -
279   - published = article.class.last
280   - published.name = 'foo'
281   - published.save!
282   - assert_equal 2, ActionTracker::Record.count
  269 + assert_equal 3, ActionTracker::Record.count
283 270 end
284 271  
285   - should 'notify with different trackers activity update with different targets' do
  272 + should 'not create trackers activity when updating articles' do
286 273 ActionTracker::Record.delete_all
287 274 article1 = fast_create(TextileArticle)
288 275 a = ApproveArticle.create!(:name => 'bar', :article => article1, :target => community, :requestor => profile)
... ... @@ -294,16 +281,16 @@ class ApproveArticleTest &lt; ActiveSupport::TestCase
294 281 a.finish
295 282 assert_equal 2, ActionTracker::Record.count
296 283  
297   - published = article1.class.last
298   - published.name = 'foo';published.save!
299   - assert_equal 3, ActionTracker::Record.count
300   -
301   - published = article2.class.last
302   - published.name = 'another foo';published.save!
303   - assert_equal 4, ActionTracker::Record.count
  284 + assert_no_difference ActionTracker::Record, :count do
  285 + published = article1.class.last
  286 + published.name = 'foo';published.save!
  287 +
  288 + published = article2.class.last
  289 + published.name = 'another foo';published.save!
  290 + end
304 291 end
305 292  
306   - should "the tracker action target be defined as Community by custom_target method on articles'creation in communities" do
  293 + should "the tracker action target be defined as the article on articles'creation in communities" do
307 294 ActionTracker::Record.delete_all
308 295 person = fast_create(Person)
309 296 community.add_member(person)
... ... @@ -311,17 +298,21 @@ class ApproveArticleTest &lt; ActiveSupport::TestCase
311 298 a = ApproveArticle.create!(:article => article, :target => community, :requestor => profile)
312 299 a.finish
313 300  
314   - assert_equal Community, ActionTracker::Record.last.target.class
  301 + approved_article = community.articles.find_by_name(article.name)
  302 +
  303 + assert_equal approved_article, ActionTracker::Record.last.target
315 304 end
316 305  
317   - should "the tracker action target be defined as person by custom_target method on articles'creation in profile" do
  306 + should "the tracker action target be defined as the article on articles'creation in profile" do
318 307 ActionTracker::Record.delete_all
319 308 person = fast_create(Person)
320 309  
321 310 a = ApproveArticle.create!(:article => article, :target => person, :requestor => profile)
322 311 a.finish
323 312  
324   - assert_equal Person, ActionTracker::Record.last.target.class
  313 + approved_article = person.articles.find_by_name(article.name)
  314 +
  315 + assert_equal approved_article, ActionTracker::Record.last.target
325 316 end
326 317  
327 318 should "have the same is_trackable method as original article" do
... ...
test/unit/article_test.rb
... ... @@ -322,15 +322,16 @@ class ArticleTest &lt; ActiveSupport::TestCase
322 322  
323 323 should 'list most commented articles' do
324 324 Article.delete_all
  325 + (1..4).each do |n|
  326 + create(TextileArticle, :name => "art #{n}", :profile_id => profile.id)
  327 + end
  328 + first_article = profile.articles.first
  329 + 2.times { Comment.create(:title => 'test', :body => 'asdsad', :author => profile, :source => first_article).save! }
325 330  
326   - person = create_user('testuser').person
327   - articles = (1..4).map {|n| a = person.articles.build(:name => "art #{n}"); a.save!; a }
328   -
329   - 2.times { articles[0].comments.build(:title => 'test', :body => 'asdsad', :author => person).save! }
330   - 4.times { articles[1].comments.build(:title => 'test', :body => 'asdsad', :author => person).save! }
331   -
  331 + last_article = profile.articles.last
  332 + 4.times { Comment.create(:title => 'test', :body => 'asdsad', :author => profile, :source => last_article).save! }
332 333 # should respect the order (more commented comes first)
333   - assert_equal [articles[1], articles[0]], person.articles.most_commented(2)
  334 + assert_equal [last_article, first_article], profile.articles.most_commented(2)
334 335 end
335 336  
336 337 should 'identify itself as a non-folder' do
... ... @@ -365,8 +366,8 @@ class ArticleTest &lt; ActiveSupport::TestCase
365 366 should 'index comments title together with article' do
366 367 TestSolr.enable
367 368 owner = create_user('testuser').person
368   - art = owner.articles.build(:name => 'ytest'); art.save!
369   - c1 = art.comments.build(:title => 'a nice comment', :body => 'anything', :author => owner); c1.save!
  369 + art = fast_create(TinyMceArticle, :profile_id => owner.id, :name => 'ytest')
  370 + c1 = Comment.create(:title => 'a nice comment', :body => 'anything', :author => owner, :source => art ); c1.save!
370 371  
371 372 assert_includes Article.find_by_contents('nice')[:results], art
372 373 end
... ... @@ -374,8 +375,8 @@ class ArticleTest &lt; ActiveSupport::TestCase
374 375 should 'index comments body together with article' do
375 376 TestSolr.enable
376 377 owner = create_user('testuser').person
377   - art = owner.articles.build(:name => 'ytest'); art.save!
378   - c1 = art.comments.build(:title => 'test comment', :body => 'anything', :author => owner); c1.save!
  378 + art = fast_create(TinyMceArticle, :profile_id => owner.id, :name => 'ytest')
  379 + c1 = Comment.create(:title => 'test comment', :body => 'anything', :author => owner, :source => art); c1.save!
379 380  
380 381 assert_includes Article.find_by_contents('anything')[:results], art
381 382 end
... ... @@ -953,79 +954,34 @@ class ArticleTest &lt; ActiveSupport::TestCase
953 954 end
954 955  
955 956 should 'track action when a published article is created outside a community' do
956   - article = TinyMceArticle.create! :name => 'Tracked Article', :profile_id => profile.id
957   - assert article.published?
958   - assert_kind_of Person, article.profile
959   - ta = ActionTracker::Record.last
960   - assert_equal 'Tracked Article', ta.get_name.last
961   - assert_equal article.url, ta.get_url.last
962   - assert_kind_of Person, ta.user
963   - ta.created_at = Time.now.ago(26.hours); ta.save!
964   - article = TinyMceArticle.create! :name => 'Another Tracked Article', :profile_id => profile.id
965   - ta = ActionTracker::Record.last
966   - assert_equal ['Another Tracked Article'], ta.get_name
967   - assert_equal [article.url], ta.get_url
  957 + article = create(TinyMceArticle, :profile_id => profile.id)
  958 + ta = article.activity
  959 + assert_equal article.name, ta.get_name
  960 + assert_equal article.url, ta.get_url
968 961 end
969 962  
970 963 should 'track action when a published article is created in a community' do
971 964 community = fast_create(Community)
972   - p1 = ActionTracker::Record.current_user_from_model
  965 + p1 = fast_create(Person)
973 966 p2 = fast_create(Person)
974 967 p3 = fast_create(Person)
975 968 community.add_member(p1)
976 969 community.add_member(p2)
977   - assert p1.is_member_of?(community)
978   - assert p2.is_member_of?(community)
979   - assert !p3.is_member_of?(community)
980   - Article.destroy_all
981   - ActionTracker::Record.destroy_all
982   - article = TinyMceArticle.create! :name => 'Tracked Article', :profile_id => community.id
983   - assert article.published?
984   - assert_kind_of Community, article.profile
985   - ta = ActionTracker::Record.last
986   - assert_equal 'Tracked Article', ta.get_name.last
987   - assert_equal article.url, ta.get_url.last
988   - assert_kind_of Person, ta.user
  970 + UserStampSweeper.any_instance.expects(:current_user).returns(p1).at_least_once
  971 +
  972 + article = create(TinyMceArticle, :profile_id => community.id)
  973 + activity = article.activity
  974 +
989 975 process_delayed_job_queue
990   - assert_equal 3, ActionTrackerNotification.count
991   - ActionTrackerNotification.all.map{|a|a.profile}.map do |profile|
992   - assert [p1,p2,community].include?(profile)
993   - end
  976 + assert_equal 3, ActionTrackerNotification.find_all_by_action_tracker_id(activity.id).count
  977 + assert_equivalent [p1,p2,community], ActionTrackerNotification.find_all_by_action_tracker_id(activity.id).map(&:profile)
994 978 end
995 979  
996   - should 'track action when a published article is updated' do
997   - a = TinyMceArticle.create! :name => 'a', :profile_id => profile.id
998   - a.update_attributes! :name => 'b'
999   - ta = ActionTracker::Record.last
1000   - assert_equal ['b'], ta.get_name
1001   - assert_equal [a.reload.url], ta.get_url
1002   - a.update_attributes! :name => 'c'
1003   - ta = ActionTracker::Record.last
1004   - assert_equal ['b','c'], ta.get_name
1005   - assert_equal [a.url,a.reload.url], ta.get_url
1006   - a.update_attributes! :body => 'test'
1007   - ta = ActionTracker::Record.last
1008   - assert_equal ['b','c','c'], ta.get_name
1009   - assert_equal [a.url,a.reload.url,a.reload.url], ta.get_url
1010   - a.update_attributes! :hits => 50
1011   - ta = ActionTracker::Record.last
1012   - assert_equal ['b','c','c'], ta.get_name
1013   - assert_equal [a.url,a.reload.url,a.reload.url], ta.get_url
1014   - end
1015   -
1016   - should 'track action when a published article is removed' do
1017   - a = TinyMceArticle.create! :name => 'a', :profile_id => profile.id
1018   - a.destroy
1019   - ta = ActionTracker::Record.last
1020   - assert_equal ['a'], ta.get_name
1021   - a = TinyMceArticle.create! :name => 'b', :profile_id => profile.id
1022   - a.destroy
1023   - ta = ActionTracker::Record.last
1024   - assert_equal ['a','b'], ta.get_name
1025   - a = TinyMceArticle.create! :name => 'c', :profile_id => profile.id, :published => false
1026   - a.destroy
1027   - ta = ActionTracker::Record.last
1028   - assert_equal ['a','b'], ta.get_name
  980 + should 'not track action when a published article is removed' do
  981 + a = create(TinyMceArticle, :profile_id => profile.id)
  982 + assert_no_difference ActionTracker::Record, :count do
  983 + a.destroy
  984 + end
1029 985 end
1030 986  
1031 987 should 'notifiable is false by default' do
... ... @@ -1054,6 +1010,15 @@ class ArticleTest &lt; ActiveSupport::TestCase
1054 1010 assert_equal 0, ActionTracker::Record.count
1055 1011 end
1056 1012  
  1013 + should 'create activity' do
  1014 + a = TextileArticle.create! :name => 'bar', :profile_id => fast_create(Profile).id, :published => true
  1015 + a.activity.destroy
  1016 + assert_nil a.activity
  1017 +
  1018 + a.create_activity
  1019 + assert_not_nil a.activity
  1020 + end
  1021 +
1057 1022 should "the action_tracker_target method be defined" do
1058 1023 assert Article.method_defined?(:action_tracker_target)
1059 1024 end
... ... @@ -1090,141 +1055,64 @@ class ArticleTest &lt; ActiveSupport::TestCase
1090 1055 assert_equal false, a.is_trackable?
1091 1056 end
1092 1057  
1093   - should 'not create more than one notification track action to community when update more than one artile' do
1094   - community = fast_create(Community)
1095   - p1 = Person.first || fast_create(Person)
1096   - community.add_member(p1)
1097   - assert p1.is_member_of?(community)
1098   - Article.destroy_all
1099   - ActionTracker::Record.destroy_all
1100   - article = TinyMceArticle.create! :name => 'Tracked Article 1', :profile_id => community.id
1101   - assert article.published?
1102   - assert_kind_of Community, article.profile
1103   - assert_equal 1, ActionTracker::Record.count
1104   - ta = ActionTracker::Record.last
1105   - assert_equal 'Tracked Article 1', ta.get_name.last
1106   - assert_equal article.url, ta.get_url.last
1107   - assert p1, ta.user
1108   - assert community, ta.target
1109   - process_delayed_job_queue
1110   - assert_equal 2, ActionTrackerNotification.count
1111   -
1112   - article = TinyMceArticle.create! :name => 'Tracked Article 2', :profile_id => community.id
1113   - assert article.published?
1114   - assert_kind_of Community, article.profile
1115   - assert_equal 1, ActionTracker::Record.count
1116   - ta = ActionTracker::Record.last
1117   - assert_equal 'Tracked Article 2', ta.get_name.last
1118   - assert_equal article.url, ta.get_url.last
1119   - assert_equal p1, ta.user
1120   - assert_equal community, ta.target
1121   - process_delayed_job_queue
1122   - assert_equal 2, ActionTrackerNotification.count
  1058 + should "not be trackable if article is inside a private community" do
  1059 + private_community = fast_create(Community, :public_profile => false)
  1060 + a = fast_create(TinyMceArticle, :profile_id => private_community.id)
  1061 + assert_equal false, a.is_trackable?
1123 1062 end
1124 1063  
1125   - should 'create the notification to the member when one member has the notification and the other no' do
  1064 + should 'create the notification to organization and all organization members' do
1126 1065 community = fast_create(Community)
1127   - p1 = Person.first || fast_create(Person)
1128   - community.add_member(p1)
1129   - assert p1.is_member_of?(community)
1130   - Article.destroy_all
1131   - ActionTracker::Record.destroy_all
  1066 + member_1 = Person.first
  1067 + community.add_member(member_1)
  1068 +
1132 1069 article = TinyMceArticle.create! :name => 'Tracked Article 1', :profile_id => community.id
1133   - assert article.published?
1134   - assert_kind_of Community, article.profile
1135   - assert_equal 1, ActionTracker::Record.count
1136   - ta = ActionTracker::Record.first
1137   - assert_equal 'Tracked Article 1', ta.get_name.last
1138   - assert_equal article.url, ta.get_url.last
1139   - assert p1, ta.user
1140   - assert community, ta.target
1141   - process_delayed_job_queue
1142   - assert_equal 2, ActionTrackerNotification.count
  1070 + first_activity = article.activity
  1071 + assert_equal [first_activity], ActionTracker::Record.find_all_by_verb('create_article')
1143 1072  
1144   - p2 = fast_create(Person)
1145   - community.add_member(p2)
1146 1073 process_delayed_job_queue
1147   - assert_equal 5, ActionTrackerNotification.count
1148   -
1149   - article = TinyMceArticle.create! :name => 'Tracked Article 2', :profile_id => community.id
1150   - assert article.published?
1151   - assert_kind_of Community, article.profile
1152   - assert_equal 3, ActionTracker::Record.count
1153   - ta = ActionTracker::Record.first
1154   - assert_equal 'Tracked Article 2', ta.get_name.last
1155   - assert_equal article.url, ta.get_url.last
1156   - assert_equal p1, ta.user
1157   - assert_equal community, ta.target
  1074 + assert_equal 2, ActionTrackerNotification.find_all_by_action_tracker_id(first_activity.id).count
  1075 +
  1076 + member_2 = fast_create(Person)
  1077 + community.add_member(member_2)
  1078 +
  1079 + article2 = TinyMceArticle.create! :name => 'Tracked Article 2', :profile_id => community.id
  1080 + second_activity = article2.activity
  1081 + assert_equivalent [first_activity, second_activity], ActionTracker::Record.find_all_by_verb('create_article')
  1082 +
1158 1083 process_delayed_job_queue
1159   - assert_equal 6, ActionTrackerNotification.count
  1084 + assert_equal 3, ActionTrackerNotification.find_all_by_action_tracker_id(second_activity.id).count
1160 1085 end
1161 1086  
1162   - should 'not create more than one notification track action to friends when update more than one artile' do
1163   - p1 = Person.first || fast_create(Person)
  1087 + should 'create notifications to friends when creating an article' do
1164 1088 friend = fast_create(Person)
1165   - p1.add_friend(friend)
  1089 + profile.add_friend(friend)
1166 1090 Article.destroy_all
1167 1091 ActionTracker::Record.destroy_all
1168 1092 ActionTrackerNotification.destroy_all
1169   - article = TinyMceArticle.create! :name => 'Tracked Article 1', :profile_id => p1.id
1170   - assert article.published?
1171   - assert_kind_of Person, article.profile
1172   - assert_equal 1, ActionTracker::Record.count
1173   - ta = ActionTracker::Record.last
1174   - assert_equal 'Tracked Article 1', ta.get_name.last
1175   - assert_equal article.url, ta.get_url.last
1176   - assert p1, ta.user
1177   - assert p1, ta.target
1178   - process_delayed_job_queue
1179   - assert_equal 2, ActionTrackerNotification.count
1180   -
1181   - article = TinyMceArticle.create! :name => 'Tracked Article 2', :profile_id => p1.id
1182   - assert article.published?
1183   - assert_kind_of Person, article.profile
1184   - assert_equal 1, ActionTracker::Record.count
1185   - ta = ActionTracker::Record.last
1186   - assert_equal 'Tracked Article 2', ta.get_name.last
1187   - assert_equal article.url, ta.get_url.last
1188   - assert_equal p1, ta.user
1189   - assert_equal p1, ta.target
  1093 + UserStampSweeper.any_instance.expects(:current_user).returns(profile).at_least_once
  1094 + article = create(TinyMceArticle, :profile_id => profile.id)
  1095 +
1190 1096 process_delayed_job_queue
1191   - assert_equal 2, ActionTrackerNotification.count
  1097 + assert_equal friend, ActionTrackerNotification.last.profile
1192 1098 end
1193 1099  
1194 1100 should 'create the notification to the friend when one friend has the notification and the other no' do
1195   - p1 = Person.first || fast_create(Person)
1196 1101 f1 = fast_create(Person)
1197   - p1.add_friend(f1)
1198   - Article.destroy_all
1199   - ActionTracker::Record.destroy_all
1200   - ActionTrackerNotification.destroy_all
1201   - article = TinyMceArticle.create! :name => 'Tracked Article 1', :profile_id => p1.id
1202   - assert article.published?
1203   - assert_kind_of Person, article.profile
1204   - assert_equal 1, ActionTracker::Record.count
1205   - ta = ActionTracker::Record.first
1206   - assert_equal 'Tracked Article 1', ta.get_name.last
1207   - assert_equal article.url, ta.get_url.last
1208   - assert p1, ta.user
1209   - assert p1, ta.target
  1102 + profile.add_friend(f1)
  1103 +
  1104 + UserStampSweeper.any_instance.expects(:current_user).returns(profile).at_least_once
  1105 + article = TinyMceArticle.create! :name => 'Tracked Article 1', :profile_id => profile.id
  1106 + assert_equal 1, ActionTracker::Record.find_all_by_verb('create_article').count
1210 1107 process_delayed_job_queue
1211   - assert_equal 2, ActionTrackerNotification.count
  1108 + assert_equal 2, ActionTrackerNotification.find_all_by_action_tracker_id(article.activity.id).count
1212 1109  
1213 1110 f2 = fast_create(Person)
1214   - p1.add_friend(f2)
1215   - process_delayed_job_queue
1216   - assert_equal 5, ActionTrackerNotification.count
1217   - article = TinyMceArticle.create! :name => 'Tracked Article 2', :profile_id => p1.id
1218   - assert article.published?
1219   - assert_kind_of Person, article.profile
1220   - assert_equal 2, ActionTracker::Record.count
1221   - ta = ActionTracker::Record.first
1222   - assert_equal 'Tracked Article 2', ta.get_name.last
1223   - assert_equal article.url, ta.get_url.last
1224   - assert_equal p1, ta.user
1225   - assert_equal p1, ta.target
  1111 + profile.add_friend(f2)
  1112 + article2 = TinyMceArticle.create! :name => 'Tracked Article 2', :profile_id => profile.id
  1113 + assert_equal 2, ActionTracker::Record.find_all_by_verb('create_article').count
1226 1114 process_delayed_job_queue
1227   - assert_equal 6, ActionTrackerNotification.count
  1115 + assert_equal 3, ActionTrackerNotification.find_all_by_action_tracker_id(article2.activity.id).count
1228 1116 end
1229 1117  
1230 1118 should 'found articles with published date between a range' do
... ... @@ -1582,7 +1470,7 @@ class ArticleTest &lt; ActiveSupport::TestCase
1582 1470 domain = Environment.default.domains.first || Domain.new(:name => 'localhost')
1583 1471 article = Article.new(:body => "An article with invalid src in img tag <img src='path with spaces.png' />", :profile => @profile)
1584 1472 assert_nothing_raised URI::InvalidURIError do
1585   - assert_equal ["http://#{domain.name}/path%20with%20spaces.png"], article.body_images_paths
  1473 + assert_equal ["http://#{profile.environment.default_hostname}/path%20with%20spaces.png"], article.body_images_paths
1586 1474 end
1587 1475 end
1588 1476  
... ... @@ -1814,4 +1702,24 @@ class ArticleTest &lt; ActiveSupport::TestCase
1814 1702 assert !a.allow_edit?(nil)
1815 1703 end
1816 1704  
  1705 + should 'get first image from lead' do
  1706 + a = fast_create(Article, :body => '<p>Foo</p><p><img src="bar.png" />Bar<img src="foo.png" /></p>',
  1707 + :abstract => '<p>Lead</p><p><img src="leadbar.png" />Bar<img src="leadfoo.png" /></p>')
  1708 + assert_equal 'leadbar.png', a.first_image
  1709 + end
  1710 +
  1711 + should 'get first image from body' do
  1712 + a = fast_create(Article, :body => '<p>Foo</p><p><img src="bar.png" />Bar<img src="foo.png" /></p>')
  1713 + assert_equal 'bar.png', a.first_image
  1714 + end
  1715 +
  1716 + should 'not get first image from anywhere' do
  1717 + a = fast_create(Article, :body => '<p>Foo</p><p>Bar</p>')
  1718 + assert_equal '', a.first_image
  1719 + end
  1720 +
  1721 + should 'store first image in tracked action' do
  1722 + a = TinyMceArticle.create! :name => 'Tracked Article', :body => '<p>Foo<img src="foo.png" />Bar</p>', :profile_id => profile.id
  1723 + assert_equal 'foo.png', ActionTracker::Record.last.get_first_image
  1724 + end
1817 1725 end
... ...
test/unit/category_test.rb
... ... @@ -311,10 +311,10 @@ class CategoryTest &lt; ActiveSupport::TestCase
311 311 a2 = person.articles.build(:name => 'art2', :category_ids => [c.id]); a2.save!
312 312 a3 = person.articles.build(:name => 'art3', :category_ids => [c.id]); a3.save!
313 313  
314   - a1.comments.build(:title => 'test', :body => 'asdsa', :author => person).save!
315   - 5.times { a2.comments.build(:title => 'test', :body => 'asdsa', :author => person).save! }
  314 + Comment.create(:title => 'test', :body => 'asdsa', :author => person, :source => a1)
  315 + 5.times { Comment.create(:title => 'test', :body => 'asdsa', :author => person, :source => a2) }
316 316  
317   - 10.times { a3.comments.build(:title => 'test', :body => 'kajsdsa', :author => person).save! }
  317 + 10.times { Comment.create(:title => 'test', :body => 'kajsdsa', :author => person, :source => a3) }
318 318  
319 319 assert_equal [a3, a2], c.most_commented_articles(2)
320 320 end
... ...
test/unit/comment_notifier_test.rb
... ... @@ -12,26 +12,26 @@ class CommentNotifierTest &lt; ActiveSupport::TestCase
12 12 @article = fast_create(Article, :name => 'Article test', :profile_id => @profile.id, :notify_comments => true)
13 13 end
14 14  
15   - should 'deliver mail after make aarticle commment' do
  15 + should 'deliver mail after make an article comment' do
16 16 assert_difference ActionMailer::Base.deliveries, :size do
17   - @article.comments << Comment.new(:author => @profile, :title => 'test comment', :body => 'you suck!')
  17 + Comment.create(:author => @profile, :title => 'test comment', :body => 'you suck!', :source => @article )
18 18 end
19 19 end
20 20  
21 21 should 'deliver mail to owner of article' do
22   - @article.comments << Comment.new(:author => @profile, :title => 'test comment', :body => 'you suck!')
  22 + Comment.create(:author => @profile, :title => 'test comment', :body => 'you suck!', :source => @article )
23 23 sent = ActionMailer::Base.deliveries.first
24 24 assert_equal [@profile.email], sent.to
25 25 end
26 26  
27 27 should 'display author name in delivered mail' do
28   - @article.comments << Comment.new(:author => @profile, :title => 'test comment', :body => 'you suck!')
  28 + Comment.create(:author => @profile, :title => 'test comment', :body => 'you suck!', :source => @article)
29 29 sent = ActionMailer::Base.deliveries.first
30 30 assert_match /user_comment_test/, sent.body
31 31 end
32 32  
33 33 should 'display unauthenticated author name and email in delivered mail' do
34   - @article.comments << Comment.new(:name => 'flatline', :email => 'flatline@invalid.com', :title => 'test comment', :body => 'you suck!')
  34 + Comment.create(:name => 'flatline', :email => 'flatline@invalid.com', :title => 'test comment', :body => 'you suck!', :source => @article )
35 35 sent = ActionMailer::Base.deliveries.first
36 36 assert_match /flatline/, sent.body
37 37 assert_match /flatline@invalid.com/, sent.body
... ... @@ -45,13 +45,13 @@ class CommentNotifierTest &lt; ActiveSupport::TestCase
45 45 end
46 46  
47 47 should 'include comment title in the e-mail' do
48   - @article.comments << Comment.new(:author => @profile, :title => 'comment title', :body => 'comment title')
  48 + Comment.create(:author => @profile, :title => 'comment title', :body => 'comment body', :source => @article)
49 49 sent = ActionMailer::Base.deliveries.first
50 50 assert_match /comment title/, sent.body
51 51 end
52 52  
53 53 should 'include comment text in the e-mail' do
54   - @article.comments << Comment.new(:author => @profile, :title => 'comment title', :body => 'comment body')
  54 + Comment.create(:author => @profile, :title => 'comment title', :body => 'comment body', :source => @article)
55 55 sent = ActionMailer::Base.deliveries.first
56 56 assert_match /comment body/, sent.body
57 57 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  
... ... @@ -65,12 +65,33 @@ class CommentTest &lt; ActiveSupport::TestCase
65 65  
66 66 should 'update counter cache in article' do
67 67 owner = create_user('testuser').person
68   - art = owner.articles.build(:name => 'ytest'); art.save!
69   -
  68 + art = create(TextileArticle, :profile_id => owner.id)
70 69 cc = art.comments_count
71   - art.comments.build(:title => 'test comment', :body => 'anything', :author => owner).save!
72   - art.reload
73   - assert_equal cc + 1, art.comments_count
  70 +
  71 + comment = create(Comment, :source => art, :author_id => owner.id)
  72 + assert_equal cc + 1, Article.find(art.id).comments_count
  73 + end
  74 +
  75 + should 'update counter cache in article activity' do
  76 + owner = create_user('testuser').person
  77 + article = create(TextileArticle, :profile_id => owner.id)
  78 +
  79 + action = article.activity
  80 + cc = action.comments_count
  81 + comment = create(Comment, :source => action, :author_id => owner.id)
  82 + assert_equal cc + 1, ActionTracker::Record.find(action.id).comments_count
  83 + end
  84 +
  85 + should 'update counter cache in general activity when add a comment' do
  86 + person = fast_create(Person)
  87 + community = fast_create(Community)
  88 +
  89 + activity = ActionTracker::Record.create :user => person, :target => community, :verb => 'add_member_in_community'
  90 +
  91 + cc = activity.comments_count
  92 +
  93 + comment = create(Comment, :source => activity, :author_id => person.id)
  94 + assert_equal cc + 1, ActionTracker::Record.find(activity.id).comments_count
74 95 end
75 96  
76 97 should 'provide author name for authenticated authors' do
... ... @@ -217,30 +238,10 @@ class CommentTest &lt; ActiveSupport::TestCase
217 238 assert File.exists?(File.join(Rails.root, 'public', image)), "#{image} does not exist."
218 239 end
219 240  
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 241 should 'have the action_tracker_target defined' do
233 242 assert Comment.method_defined?(:action_tracker_target)
234 243 end
235 244  
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 245 should "get children of a comment" do
245 246 c = fast_create(Comment)
246 247 c1 = fast_create(Comment, :reply_of_id => c.id)
... ... @@ -307,11 +308,11 @@ class CommentTest &lt; ActiveSupport::TestCase
307 308  
308 309 should "return comments as a thread" do
309 310 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)
  311 + c0 = fast_create(Comment, :source_id => a.id)
  312 + c1 = fast_create(Comment, :reply_of_id => c0.id, :source_id => a.id)
  313 + c2 = fast_create(Comment, :reply_of_id => c1.id, :source_id => a.id)
  314 + c3 = fast_create(Comment, :reply_of_id => c0.id, :source_id => a.id)
  315 + c4 = fast_create(Comment, :source_id => a.id)
315 316 result = a.comments.as_thread
316 317 assert_equal c0.id, result[0].id
317 318 assert_equal [c1.id, c3.id], result[0].replies.map(&:id)
... ... @@ -320,6 +321,22 @@ class CommentTest &lt; ActiveSupport::TestCase
320 321 assert result[1].replies.empty?
321 322 end
322 323  
  324 + should "return activities comments as a thread" do
  325 + person = fast_create(Person)
  326 + a = TextileArticle.create!(:profile => person, :name => 'My article', :body => 'Article body')
  327 + c0 = Comment.create!(:source => a, :body => 'My comment', :author => person)
  328 + c1 = Comment.create!(:reply_of_id => c0.id, :source => a, :body => 'bla', :author => person)
  329 + c2 = Comment.create!(:reply_of_id => c1.id, :source => a, :body => 'bla', :author => person)
  330 + c3 = Comment.create!(:reply_of_id => c0.id, :source => a, :body => 'bla', :author => person)
  331 + c4 = Comment.create!(:source => a, :body => 'My comment', :author => person)
  332 + result = a.activity.comments_as_thread
  333 + assert_equal c0, result[0]
  334 + assert_equal [c1, c3], result[0].replies
  335 + assert_equal [c2], result[0].replies[0].replies
  336 + assert_equal c4, result[1]
  337 + assert result[1].replies.empty?
  338 + end
  339 +
323 340 should 'provide author url for authenticated user' do
324 341 author = Person.new
325 342 author.expects(:url).returns('http://blabla.net/author')
... ... @@ -338,4 +355,27 @@ class CommentTest &lt; ActiveSupport::TestCase
338 355 assert c.rejected?
339 356 end
340 357  
  358 + should 'update article activity when add a comment' do
  359 + profile = create_user('testuser').person
  360 + article = create(TinyMceArticle, :profile => profile)
  361 + action = article.activity
  362 + time = action.updated_at
  363 +
  364 + Time.stubs(:now).returns(time + 1.day)
  365 +
  366 + comment = create(Comment, :source => article, :author => profile)
  367 + assert_equal time + 1.day, article.activity.updated_at
  368 + end
  369 +
  370 + should 'create a new activity when add a comment and the activity was removed' do
  371 + profile = create_user('testuser').person
  372 + article = create(TinyMceArticle, :profile => profile)
  373 + article.activity.destroy
  374 +
  375 + assert_nil article.activity
  376 +
  377 + comment = create(Comment, :source => article, :author => profile)
  378 + assert_not_nil article.activity
  379 + end
  380 +
341 381 end
... ...
test/unit/community_test.rb
... ... @@ -274,22 +274,19 @@ class CommunityTest &lt; ActiveSupport::TestCase
274 274 end
275 275 end
276 276  
277   - should "be created an tracked action to the community when an community's article is commented" do
  277 + should "update the action of article creation when an community's article is commented" do
278 278 ActionTrackerNotification.delete_all
279 279 p1 = Person.first
280 280 community = fast_create(Community)
281 281 p2 = fast_create(Person)
282 282 p3 = fast_create(Person)
283 283 community.add_member(p3)
284   - article = fast_create(Article, :profile_id => community.id)
285   - ActionTracker::Record.destroy_all
286   - assert_difference(ActionTrackerNotification, :count, 3) do
287   - Comment.create!(:article_id => article.id, :title => 'some', :body => 'some', :author_id => p2.id)
288   - process_delayed_job_queue
289   - end
290   - ActionTrackerNotification.all.map{|a|a.profile}.map do |profile|
291   - assert [community,p1,p3].include?(profile)
292   - end
  284 + article = create(TextileArticle, :profile_id => community.id)
  285 + time = article.activity.updated_at
  286 + Time.stubs(:now).returns(time + 1.day)
  287 + Comment.create!(:source_id => article.id, :title => 'some', :body => 'some', :author_id => p2.id)
  288 + process_delayed_job_queue
  289 + assert_equal time, article.activity.updated_at
293 290 end
294 291  
295 292 should "see get all received scraps" do
... ... @@ -341,4 +338,35 @@ class CommunityTest &lt; ActiveSupport::TestCase
341 338 assert_equal false, community.receives_scrap_notification?
342 339 end
343 340  
  341 + should 'return scraps as activities' do
  342 + person = fast_create(Person)
  343 + community = fast_create(Community)
  344 +
  345 + scrap = Scrap.create!(defaults_for_scrap(:sender => person, :receiver => community, :content => 'A scrap'))
  346 + activity = ActionTracker::Record.last
  347 +
  348 + assert_equal [activity,scrap], community.activities.map { |a| a.klass.constantize.find(a.id) }
  349 + end
  350 +
  351 + should 'return tracked_actions of community as activities' do
  352 + person = fast_create(Person)
  353 + community = fast_create(Community)
  354 +
  355 + UserStampSweeper.any_instance.expects(:current_user).returns(person).at_least_once
  356 + article = create(TinyMceArticle, :profile => community, :name => 'An article about free software')
  357 +
  358 + assert_equal [article.activity], community.activities.map { |a| a.klass.constantize.find(a.id) }
  359 + end
  360 +
  361 + should 'not return tracked_actions of other community as activities' do
  362 + person = fast_create(Person)
  363 + community = fast_create(Community)
  364 + community2 = fast_create(Community)
  365 +
  366 + UserStampSweeper.any_instance.expects(:current_user).returns(person).at_least_once
  367 + article = create(TinyMceArticle, :profile => community2, :name => 'Another article about free software')
  368 +
  369 + assert_not_includes community.activities.map { |a| a.klass.constantize.find(a.id) }, article.activity
  370 + end
  371 +
344 372 end
... ...
test/unit/enterprise_test.rb
... ... @@ -470,4 +470,36 @@ class EnterpriseTest &lt; ActiveSupport::TestCase
470 470 ent.save!
471 471 end
472 472  
  473 + should 'return scraps as activities' do
  474 + person = fast_create(Person)
  475 + enterprise = fast_create(Enterprise)
  476 +
  477 +
  478 + activity = ActionTracker::Record.last
  479 + scrap = Scrap.create!(defaults_for_scrap(:sender => person, :receiver => enterprise, :content => 'A scrap'))
  480 +
  481 + assert_equal [scrap], enterprise.activities.map { |a| a.klass.constantize.find(a.id) }
  482 + end
  483 +
  484 + should 'return tracked_actions of community as activities' do
  485 + person = fast_create(Person)
  486 + enterprise = fast_create(Enterprise)
  487 +
  488 + UserStampSweeper.any_instance.expects(:current_user).returns(person).at_least_once
  489 + article = create(TinyMceArticle, :profile => enterprise, :name => 'An article about free software')
  490 +
  491 + assert_equal [article.activity], enterprise.activities.map { |a| a.klass.constantize.find(a.id) }
  492 + end
  493 +
  494 + should 'not return tracked_actions of other community as activities' do
  495 + person = fast_create(Person)
  496 + enterprise = fast_create(Enterprise)
  497 + enterprise2 = fast_create(Enterprise)
  498 +
  499 + UserStampSweeper.any_instance.expects(:current_user).returns(person).at_least_once
  500 + article = create(TinyMceArticle, :profile => enterprise2, :name => 'Another article about free software')
  501 +
  502 + assert_not_includes enterprise.activities.map { |a| a.klass.constantize.find(a.id) }, article.activity
  503 + end
  504 +
473 505 end
... ...
test/unit/event_test.rb
... ... @@ -276,4 +276,7 @@ class EventTest &lt; ActiveSupport::TestCase
276 276 assert Event.new.tiny_mce?
277 277 end
278 278  
  279 + should 'be notifiable' do
  280 + assert Event.new.notifiable?
  281 + end
279 282 end
... ...
test/unit/forum_helper_test.rb
... ... @@ -65,7 +65,7 @@ class ForumHelperTest &lt; ActiveSupport::TestCase
65 65 some_post.comments << Comment.new(:name => 'John', :email => 'lenon@example.com', :title => 'test', :body => 'test')
66 66 c = Comment.last
67 67 out = last_topic_update(some_post)
68   - assert_match "#{c.created_at.to_s} ago by John", out
  68 + assert_match "#{c.created_at.to_s} by John", out
69 69 assert_match 'John', out
70 70  
71 71 assert_match(/#{Regexp.escape(c.created_at.to_s)} ago by John/m, last_topic_update(some_post))
... ...
test/unit/forum_test.rb
... ... @@ -28,21 +28,21 @@ class ForumTest &lt; ActiveSupport::TestCase
28 28  
29 29 should 'create rss feed automatically' do
30 30 p = create_user('testuser').person
31   - b = create(Forum, :profile_id => p.id, :name => 'forum_feed_test')
  31 + b = create(Forum, :profile_id => p.id, :name => 'forum_feed_test', :body => 'Forum')
32 32 assert_kind_of RssFeed, b.feed
33 33 end
34 34  
35 35 should 'save feed options' do
36 36 p = create_user('testuser').person
37   - p.articles << Forum.new(:profile => p, :name => 'forum_feed_test')
  37 + p.articles << forum = Forum.new(:profile => p, :name => 'forum_feed_test', :body => 'Forum test')
38 38 p.forum.feed = { :limit => 7 }
39   - assert_equal 7, p.forum.feed.limit
  39 + assert_equal 7, Forum.find(forum.id).feed.limit
40 40 end
41 41  
42 42 should 'save feed options after create forum' do
43 43 p = create_user('testuser').person
44   - p.articles << Forum.new(:profile => p, :name => 'forum_feed_test', :feed => { :limit => 7 })
45   - assert_equal 7, p.forum.feed.limit
  44 + p.articles << forum = Forum.new(:profile => p, :name => 'forum_feed_test', :body => 'Forum test', :feed => { :limit => 7 })
  45 + assert_equal 7, Forum.find(forum.id).feed.limit
46 46 end
47 47  
48 48 should 'list 5 posts per page by default' do
... ... @@ -52,16 +52,15 @@ class ForumTest &lt; ActiveSupport::TestCase
52 52  
53 53 should 'update posts per page setting' do
54 54 p = create_user('testuser').person
55   - p.articles << Forum.new(:profile => p, :name => 'Forum test')
56   - forum = p.forum
  55 + p.articles << forum = Forum.new(:profile => p, :name => 'Forum test', :body => 'Forum test')
57 56 forum.posts_per_page = 7
58 57 assert forum.save!
59   - assert_equal 7, p.forum.posts_per_page
  58 + assert_equal 7, Forum.find(forum.id).posts_per_page
60 59 end
61 60  
62 61 should 'has posts' do
63 62 p = create_user('testuser').person
64   - forum = fast_create(Forum, :profile_id => p.id, :name => 'Forum test')
  63 + p.articles << forum = Forum.new(:profile => p, :name => 'Forum test', :body => 'Forum test')
65 64 post = fast_create(TextileArticle, :name => 'First post', :profile_id => p.id, :parent_id => forum.id)
66 65 forum.children << post
67 66 assert_includes forum.posts, post
... ... @@ -69,7 +68,7 @@ class ForumTest &lt; ActiveSupport::TestCase
69 68  
70 69 should 'not includes rss feed in posts' do
71 70 p = create_user('testuser').person
72   - forum = create(Forum, :profile_id => p.id, :name => 'Forum test')
  71 + forum = create(Forum, :profile_id => p.id, :name => 'Forum test', :body => 'Forum')
73 72 assert_includes forum.children, forum.feed
74 73 assert_not_includes forum.posts, forum.feed
75 74 end
... ... @@ -89,13 +88,13 @@ class ForumTest &lt; ActiveSupport::TestCase
89 88 p = create_user('testuser').person
90 89 fast_create(Forum, :name => 'Forum test', :profile_id => p.id)
91 90 assert_nothing_raised ActiveRecord::RecordInvalid do
92   - Forum.create!(:name => 'Another Forum', :profile => p)
  91 + Forum.create!(:name => 'Another Forum', :profile => p, :body => 'Forum test')
93 92 end
94 93 end
95 94  
96 95 should 'not update slug from name for existing forum' do
97 96 p = create_user('testuser').person
98   - forum = Forum.create!(:name => 'Forum test', :profile => p)
  97 + forum = Forum.create(:name => 'Forum test', :profile_id => p.id, :body => 'Forum')
99 98 assert_equal 'forum-test', forum.slug
100 99 forum.name = 'Changed name'
101 100 assert_not_equal 'changed-name', forum.slug
... ... @@ -110,4 +109,28 @@ class ForumTest &lt; ActiveSupport::TestCase
110 109 assert !folder.accept_uploads?
111 110 end
112 111  
  112 + should 'be notifiable' do
  113 + assert Forum.new.notifiable?
  114 + end
  115 +
  116 + should 'get first paragraph' do
  117 + f = fast_create(Forum, :body => '<p>First</p><p>Second</p>')
  118 + assert_equal '<p>First</p>', f.first_paragraph
  119 + end
  120 +
  121 + should 'not get first paragraph' do
  122 + f = fast_create(Forum, :body => 'Nothing to do here')
  123 + assert_equal '', f.first_paragraph
  124 + end
  125 +
  126 + should 'provide first_paragraph even if body was not given' do
  127 + f = fast_create(Forum)
  128 + assert_equal '', f.first_paragraph
  129 + end
  130 +
  131 + should 'provide first_paragraph even if body is nil' do
  132 + f = fast_create(Forum, :body => nil)
  133 + assert_equal '', f.first_paragraph
  134 + end
  135 +
113 136 end
... ...
test/unit/notify_activity_to_profiles_job_test.rb
... ... @@ -24,28 +24,6 @@ class NotifyActivityToProfilesJobTest &lt; ActiveSupport::TestCase
24 24 end
25 25 end
26 26  
27   - should 'notify just the community in tracker with remove_member_in_community verb' do
28   - person = fast_create(Person)
29   - community = fast_create(Community)
30   - action_tracker = fast_create(ActionTracker::Record, :user_type => 'Profile', :user_id => person.id, :target_type => 'Profile', :target_id => community.id, :verb => 'remove_member_in_community')
31   - assert NotifyActivityToProfilesJob::NOTIFY_ONLY_COMMUNITY.include?(action_tracker.verb)
32   - p1, p2, m1, m2 = fast_create(Person), fast_create(Person), fast_create(Person), fast_create(Person)
33   - fast_create(Friendship, :person_id => person.id, :friend_id => p1.id)
34   - fast_create(Friendship, :person_id => person.id, :friend_id => p2.id)
35   - fast_create(RoleAssignment, :accessor_id => m1.id, :role_id => 3, :resource_id => community.id)
36   - fast_create(RoleAssignment, :accessor_id => m2.id, :role_id => 3, :resource_id => community.id)
37   - ActionTrackerNotification.delete_all
38   - job = NotifyActivityToProfilesJob.new(action_tracker.id)
39   - job.perform
40   - process_delayed_job_queue
41   -
42   - assert_equal 1, ActionTrackerNotification.count
43   - [community].each do |profile|
44   - notification = ActionTrackerNotification.find_by_profile_id profile.id
45   - assert_equal action_tracker, notification.action_tracker
46   - end
47   - end
48   -
49 27 should 'notify just the users and his friends tracking user actions' do
50 28 person = fast_create(Person)
51 29 community = fast_create(Community)
... ... @@ -132,36 +110,14 @@ class NotifyActivityToProfilesJobTest &lt; ActiveSupport::TestCase
132 110 end
133 111 end
134 112  
135   - should 'not notify the community tracking leave_community verb' do
136   - person = fast_create(Person)
137   - community = fast_create(Community)
138   - action_tracker = fast_create(ActionTracker::Record, :user_type => 'Profile', :user_id => person.id, :target_type => 'Profile', :target_id => community.id, :verb => 'leave_community')
139   - assert !NotifyActivityToProfilesJob::NOTIFY_ONLY_COMMUNITY.include?(action_tracker.verb)
140   - p1, p2, m1, m2 = fast_create(Person), fast_create(Person), fast_create(Person), fast_create(Person)
141   - fast_create(Friendship, :person_id => person.id, :friend_id => p1.id)
142   - fast_create(Friendship, :person_id => person.id, :friend_id => p2.id)
143   - fast_create(RoleAssignment, :accessor_id => m1.id, :role_id => 3, :resource_id => community.id)
144   - fast_create(RoleAssignment, :accessor_id => m2.id, :role_id => 3, :resource_id => community.id)
145   - ActionTrackerNotification.delete_all
146   - job = NotifyActivityToProfilesJob.new(action_tracker.id)
147   - job.perform
148   - process_delayed_job_queue
149   -
150   - assert_equal 5, ActionTrackerNotification.count
151   - [person, p1, p2, m1, m2].each do |profile|
152   - notification = ActionTrackerNotification.find_by_profile_id profile.id
153   - assert_equal action_tracker, notification.action_tracker
154   - end
155   - end
156   -
157 113 should "the NOTIFY_ONLY_COMMUNITY constant has all the verbs tested" do
158   - notify_community_verbs = ['add_member_in_community', 'remove_member_in_community']
  114 + notify_community_verbs = ['add_member_in_community']
159 115 assert_equal [], notify_community_verbs - NotifyActivityToProfilesJob::NOTIFY_ONLY_COMMUNITY
160 116 assert_equal [], NotifyActivityToProfilesJob::NOTIFY_ONLY_COMMUNITY - notify_community_verbs
161 117 end
162 118  
163 119 should "the NOT_NOTIFY_COMMUNITY constant has all the verbs tested" do
164   - not_notify_community_verbs = ['join_community', 'leave_community']
  120 + not_notify_community_verbs = ['join_community']
165 121 assert_equal [], not_notify_community_verbs - NotifyActivityToProfilesJob::NOT_NOTIFY_COMMUNITY
166 122 assert_equal [], NotifyActivityToProfilesJob::NOT_NOTIFY_COMMUNITY - not_notify_community_verbs
167 123 end
... ...
test/unit/person_test.rb
... ... @@ -1013,65 +1013,14 @@ class PersonTest &lt; ActiveSupport::TestCase
1013 1013 assert has_add_member_notification
1014 1014 end
1015 1015  
1016   - should 'track only one action when a person leaves a community' do
  1016 + should 'not track when a person leaves a community' do
1017 1017 p = create_user('test_user').person
1018 1018 c = fast_create(Community, :name => "Foo")
1019 1019 c.add_member(p)
1020 1020 c.add_moderator(p)
1021 1021 ActionTracker::Record.delete_all
1022 1022 c.remove_member(p)
1023   - assert_equal ["Foo"], ActionTracker::Record.last(:conditions => {:verb => 'leave_community'}).get_resource_name
1024   - end
1025   -
1026   - should 'the tracker target be Community when a person leaves a community' do
1027   - ActionTracker::Record.delete_all
1028   - p = create_user('test_user').person
1029   - c = fast_create(Community, :name => "Foo")
1030   - c.add_member(p)
1031   - c.add_moderator(p)
1032   - ActionTracker::Record.delete_all
1033   - c.remove_member(p)
1034   - assert_kind_of Community, ActionTracker::Record.last(:conditions => {:verb => 'leave_community'}).target
1035   - end
1036   -
1037   - should 'the community be notified specifically when a person leaves a community' do
1038   - ActionTracker::Record.delete_all
1039   - p = create_user('test_user').person
1040   - c = fast_create(Community, :name => "Foo")
1041   - c.add_member(p)
1042   - c.add_moderator(p)
1043   - ActionTracker::Record.delete_all
1044   - c.remove_member(p)
1045   - assert_not_nil ActionTracker::Record.last(:conditions => {:verb => 'remove_member_in_community'})
1046   - end
1047   -
1048   - should 'the community specific notification created when a member leaves community could not be propagated to members' do
1049   - ActionTracker::Record.delete_all
1050   - p1 = Person.first
1051   - p2 = create_user('test_user').person
1052   - p3 = create_user('test_user').person
1053   - c = fast_create(Community, :name => "Foo")
1054   - process_delayed_job_queue
1055   - Delayed::Job.delete_all
1056   - c.add_member(p1)
1057   - c.add_member(p3)
1058   - c.add_moderator(p1)
1059   - c.add_moderator(p3)
1060   - ActionTracker::Record.delete_all
1061   - c.remove_member(p1)
1062   - process_delayed_job_queue
1063   - c.remove_member(p3)
1064   - process_delayed_job_queue
1065   - assert_equal 4, ActionTracker::Record.count
1066   - assert_equal 5, ActionTrackerNotification.count
1067   - has_remove_member_notification = false
1068   - ActionTrackerNotification.all.map do |notification|
1069   - if notification.action_tracker.verb == 'remove_member_in_community'
1070   - has_remove_member_notification = true
1071   - assert_equal c, notification.profile
1072   - end
1073   - end
1074   - assert has_remove_member_notification
  1023 + assert_equal [], ActionTracker::Record.all
1075 1024 end
1076 1025  
1077 1026 should 'get all friends online' do
... ... @@ -1243,4 +1192,32 @@ class PersonTest &lt; ActiveSupport::TestCase
1243 1192 assert !person.visible
1244 1193 assert_not_equal password, person.user.password
1245 1194 end
  1195 +
  1196 + should 'return tracked_actions and scraps as activities' do
  1197 + person = fast_create(Person)
  1198 + another_person = fast_create(Person)
  1199 +
  1200 + scrap = Scrap.create!(defaults_for_scrap(:sender => another_person, :receiver => person, :content => 'A scrap'))
  1201 + UserStampSweeper.any_instance.expects(:current_user).returns(person).at_least_once
  1202 + article = TinyMceArticle.create!(:profile => person, :name => 'An article about free software')
  1203 +
  1204 + assert_equivalent [scrap,article.activity], person.activities.map { |a| a.klass.constantize.find(a.id) }
  1205 + end
  1206 +
  1207 + should 'not return tracked_actions and scraps from others as activities' do
  1208 + person = fast_create(Person)
  1209 + another_person = fast_create(Person)
  1210 +
  1211 + person_scrap = Scrap.create!(defaults_for_scrap(:sender => person, :receiver => person, :content => 'A scrap from person'))
  1212 + another_person_scrap = Scrap.create!(defaults_for_scrap(:sender => another_person, :receiver => another_person, :content => 'A scrap from another person'))
  1213 +
  1214 + TinyMceArticle.create!(:profile => another_person, :name => 'An article about free software from another person')
  1215 + another_person_activity = ActionTracker::Record.last
  1216 +
  1217 + UserStampSweeper.any_instance.stubs(:current_user).returns(person)
  1218 + TinyMceArticle.create!(:profile => person, :name => 'An article about free software')
  1219 + person_activity = ActionTracker::Record.last
  1220 +
  1221 + assert_equivalent [person_scrap,person_activity], person.activities.map { |a| a.klass.constantize.find(a.id) }
  1222 + end
1246 1223 end
... ...
test/unit/profile_test.rb
... ... @@ -1648,7 +1648,7 @@ class ProfileTest &lt; ActiveSupport::TestCase
1648 1648  
1649 1649 should 'have forum' do
1650 1650 p = fast_create(Profile)
1651   - p.articles << Forum.new(:profile => p, :name => 'forum_feed_test')
  1651 + p.articles << Forum.new(:profile => p, :name => 'forum_feed_test', :body => 'Forum test')
1652 1652 assert p.has_forum?
1653 1653 end
1654 1654  
... ... @@ -1664,9 +1664,9 @@ class ProfileTest &lt; ActiveSupport::TestCase
1664 1664  
1665 1665 should 'get first forum when has multiple forums' do
1666 1666 p = fast_create(Profile)
1667   - p.forums << Forum.new(:profile => p, :name => 'Forum one')
1668   - p.forums << Forum.new(:profile => p, :name => 'Forum two')
1669   - p.forums << Forum.new(:profile => p, :name => 'Forum three')
  1667 + p.forums << Forum.new(:profile => p, :name => 'Forum one', :body => 'Forum test')
  1668 + p.forums << Forum.new(:profile => p, :name => 'Forum two', :body => 'Forum test')
  1669 + p.forums << Forum.new(:profile => p, :name => 'Forum three', :body => 'Forum test')
1670 1670 assert_equal 'Forum one', p.forum.name
1671 1671 assert_equal 3, p.forums.count
1672 1672 end
... ... @@ -1731,6 +1731,7 @@ class ProfileTest &lt; ActiveSupport::TestCase
1731 1731 assert profile.is_on_homepage?("/#{profile.identifier}/#{homepage.slug}", homepage)
1732 1732 end
1733 1733  
  1734 +
1734 1735 should 'find profiles with image' do
1735 1736 env = fast_create(Environment)
1736 1737 2.times do |n|
... ... @@ -1791,6 +1792,11 @@ class ProfileTest &lt; ActiveSupport::TestCase
1791 1792 end
1792 1793 end
1793 1794  
  1795 + should 'return empty array as activities' do
  1796 + profile = Profile.new
  1797 + assert_equal [], profile.activities
  1798 + end
  1799 +
1794 1800 private
1795 1801  
1796 1802 def assert_invalid_identifier(id)
... ...
test/unit/textile_article_test.rb
... ... @@ -38,80 +38,72 @@ class TextileArticleTest &lt; ActiveSupport::TestCase
38 38 assert_equal 1, ActionTracker::Record.count
39 39 end
40 40  
41   - should 'notify with different trackers activity create with different targets' do
  41 + should 'not group trackers activity of article\'s creation' do
42 42 ActionTracker::Record.delete_all
43 43 profile = fast_create(Profile)
44 44 TextileArticle.create! :name => 'bar', :profile_id => profile.id, :published => true
45 45 TextileArticle.create! :name => 'another bar', :profile_id => profile.id, :published => true
46   - assert_equal 1, ActionTracker::Record.count
47 46 TextileArticle.create! :name => 'another bar', :profile_id => fast_create(Profile).id, :published => true
48   - assert_equal 2, ActionTracker::Record.count
  47 + assert_equal 3, ActionTracker::Record.count
49 48 end
50 49  
51   - should 'notify activity on update' do
  50 + should 'not update activity on update of an article' do
52 51 ActionTracker::Record.delete_all
53   - a = TextileArticle.create! :name => 'bar', :profile_id => fast_create(Profile).id, :published => true
54   - assert_equal 1, ActionTracker::Record.count
55   - a.name = 'foo'
56   - a.save!
57   - assert_equal 2, ActionTracker::Record.count
  52 + profile = fast_create(Profile)
  53 + article = create(TextileArticle, :profile_id => profile.id)
  54 + time = article.activity.updated_at
  55 + Time.stubs(:now).returns(time + 1.day)
  56 + assert_no_difference ActionTracker::Record, :count do
  57 + article.name = 'foo'
  58 + article.save!
  59 + end
  60 + assert_equal time, article.activity.updated_at
58 61 end
59 62  
60   - should 'notify with different trackers activity update with different targets' do
  63 + should 'not create trackers activity when updating articles' do
61 64 ActionTracker::Record.delete_all
62 65 a1 = TextileArticle.create! :name => 'bar', :profile_id => fast_create(Profile).id, :published => true
63 66 a2 = TextileArticle.create! :name => 'another bar', :profile_id => fast_create(Profile).id, :published => true
64   - assert_equal 2, ActionTracker::Record.count
65   - a1.name = 'foo'
66   - a1.save!
67   - assert_equal 3, ActionTracker::Record.count
68   - a2.name = 'another foo'
69   - a2.save!
70   - assert_equal 4, ActionTracker::Record.count
  67 + assert_no_difference ActionTracker::Record, :count do
  68 + a1.name = 'foo';a1.save!
  69 + a2.name = 'another foo';a2.save!
  70 + end
71 71 end
72 72  
73   - should 'notify activity on destroy' do
  73 + should 'not notify activity on destroy' do
74 74 ActionTracker::Record.delete_all
75 75 a = TextileArticle.create! :name => 'bar', :profile_id => fast_create(Profile).id, :published => true
76   - assert_equal 1, ActionTracker::Record.count
77   - a.destroy
78   - assert_equal 2, ActionTracker::Record.count
  76 + assert_no_difference ActionTracker::Record, :count do
  77 + a.destroy
  78 + end
79 79 end
80 80  
81   - should 'notify different activities when destroy articles with diferrents targets' do
  81 + should 'not notify when an article is destroyed' do
82 82 ActionTracker::Record.delete_all
83 83 a1 = TextileArticle.create! :name => 'bar', :profile_id => fast_create(Profile).id, :published => true
84 84 a2 = TextileArticle.create! :name => 'another bar', :profile_id => fast_create(Profile).id, :published => true
85 85 assert_equal 2, ActionTracker::Record.count
86   - a1.destroy
87   - assert_equal 3, ActionTracker::Record.count
88   - a2.destroy
89   - assert_equal 4, ActionTracker::Record.count
  86 + assert_no_difference ActionTracker::Record, :count do
  87 + a1.destroy
  88 + a2.destroy
  89 + end
90 90 end
91 91  
92   - should "the tracker action target be defined as Community by custom_target method on articles'creation in communities" do
  92 + should "the tracker action target be defined as the article on articles'creation in communities" do
93 93 ActionTracker::Record.delete_all
94 94 community = fast_create(Community)
95 95 p1 = Person.first
96 96 community.add_member(p1)
97 97 assert p1.is_member_of?(community)
98 98 article = TextileArticle.create! :name => 'test', :profile_id => community.id
99   - assert_equal true, article.published?
100   - assert_equal true, article.notifiable?
101   - assert_equal false, article.image?
102   - assert_equal Community, article.profile.class
103   - assert_equal Community, ActionTracker::Record.last.target.class
  99 + assert_equal article, ActionTracker::Record.last.target
104 100 end
105 101  
106   - should "the tracker action target be defined as person by custom_target method on articles'creation in profile" do
  102 + should "the tracker action target be defined as the article on articles'creation in profile" do
107 103 ActionTracker::Record.delete_all
108 104 person = Person.first
109 105 article = TextileArticle.create! :name => 'test', :profile_id => person.id
110   - assert_equal true, article.published?
111   - assert_equal true, article.notifiable?
112   - assert_equal false, article.image?
113   - assert_equal Person, article.profile.class
114   - assert_equal person, ActionTracker::Record.last.target
  106 + assert_equal article, ActionTracker::Record.last.target
115 107 end
116 108  
117 109 should 'not notify activity if the article is not advertise' do
... ... @@ -129,7 +121,7 @@ class TextileArticleTest &lt; ActiveSupport::TestCase
129 121 end
130 122  
131 123 should "the common trackable conditions return the correct value" do
132   - a = TextileArticle.new
  124 + a = TextileArticle.new(:profile => profile)
133 125 a.published = a.advertise = true
134 126 assert_equal true, a.published?
135 127 assert_equal true, a.notifiable?
... ...
test/unit/tiny_mce_article_test.rb
... ... @@ -135,80 +135,64 @@ class TinyMceArticleTest &lt; ActiveSupport::TestCase
135 135 assert_equal 1, ActionTracker::Record.count
136 136 end
137 137  
138   - should 'notify with different trackers activity create with different targets' do
  138 + should 'not group trackers activity of article\'s creation' do
139 139 ActionTracker::Record.delete_all
140 140 profile = fast_create(Profile)
141 141 TinyMceArticle.create! :name => 'bar', :profile_id => profile.id, :published => true
142 142 TinyMceArticle.create! :name => 'another bar', :profile_id => profile.id, :published => true
143   - assert_equal 1, ActionTracker::Record.count
144   - TinyMceArticle.create! :name => 'another bar', :profile_id => fast_create(Profile).id, :published => true
145 143 assert_equal 2, ActionTracker::Record.count
  144 + TinyMceArticle.create! :name => 'another bar', :profile_id => fast_create(Profile).id, :published => true
  145 + assert_equal 3, ActionTracker::Record.count
146 146 end
147 147  
148   - should 'notify activity on update' do
  148 + should 'not update activity on update of an article' do
149 149 ActionTracker::Record.delete_all
150   - a = TinyMceArticle.create! :name => 'bar', :profile_id => fast_create(Profile).id, :published => true
151   - assert_equal 1, ActionTracker::Record.count
152   - a.name = 'foo'
153   - a.save!
154   - assert_equal 2, ActionTracker::Record.count
  150 + profile = fast_create(Profile)
  151 + article = create(TinyMceArticle, :profile_id => profile.id)
  152 + time = article.activity.updated_at
  153 + Time.stubs(:now).returns(time + 1.day)
  154 + assert_no_difference ActionTracker::Record, :count do
  155 + article.name = 'foo'
  156 + article.save!
  157 + end
  158 + assert_equal time, article.activity.updated_at
155 159 end
156 160  
157   - should 'notify with different trackers activity update with different targets' do
  161 + should 'not create trackers activity when updating articles' do
158 162 ActionTracker::Record.delete_all
159 163 a1 = TinyMceArticle.create! :name => 'bar', :profile_id => fast_create(Profile).id, :published => true
160 164 a2 = TinyMceArticle.create! :name => 'another bar', :profile_id => fast_create(Profile).id, :published => true
161   - assert_equal 2, ActionTracker::Record.count
162   - a1.name = 'foo'
163   - a1.save!
164   - assert_equal 3, ActionTracker::Record.count
165   - a2.name = 'another foo'
166   - a2.save!
167   - assert_equal 4, ActionTracker::Record.count
  165 + assert_no_difference ActionTracker::Record, :count do
  166 + a1.name = 'foo';a1.save!
  167 + a2.name = 'another foo';a2.save!
  168 + end
168 169 end
169 170  
170   - should 'notify activity on destroy' do
171   - ActionTracker::Record.delete_all
172   - a = TinyMceArticle.create! :name => 'bar', :profile_id => fast_create(Profile).id, :published => true
173   - assert_equal 1, ActionTracker::Record.count
174   - a.destroy
175   - assert_equal 2, ActionTracker::Record.count
176   - end
177   -
178   - should 'notify different activities when destroy articles with diferrents targets' do
  171 + should 'not notify when an article is destroyed' do
179 172 ActionTracker::Record.delete_all
180 173 a1 = TinyMceArticle.create! :name => 'bar', :profile_id => fast_create(Profile).id, :published => true
181 174 a2 = TinyMceArticle.create! :name => 'another bar', :profile_id => fast_create(Profile).id, :published => true
182   - assert_equal 2, ActionTracker::Record.count
183   - a1.destroy
184   - assert_equal 3, ActionTracker::Record.count
185   - a2.destroy
186   - assert_equal 4, ActionTracker::Record.count
  175 + assert_no_difference ActionTracker::Record, :count do
  176 + a1.destroy
  177 + a2.destroy
  178 +end
187 179 end
188 180  
189   - should "the tracker action target be defined as Community by custom_target method on articles'creation in communities" do
  181 + should "the tracker action target be defined as the article on articles'creation in communities" do
190 182 ActionTracker::Record.delete_all
191 183 community = fast_create(Community)
192 184 p1 = Person.first
193 185 community.add_member(p1)
194 186 assert p1.is_member_of?(community)
195 187 article = TinyMceArticle.create! :name => 'test', :profile_id => community.id
196   - assert_equal true, article.published?
197   - assert_equal true, article.notifiable?
198   - assert_equal false, article.image?
199   - assert_equal Community, article.profile.class
200   - assert_equal Community, ActionTracker::Record.last.target.class
  188 + assert_equal article, ActionTracker::Record.last.target
201 189 end
202 190  
203   - should "the tracker action target be defined as person by custom_target method on articles'creation in profile" do
  191 + should "the tracker action target be defined as the article on articles'creation in profile" do
204 192 ActionTracker::Record.delete_all
205 193 person = Person.first
206 194 article = TinyMceArticle.create! :name => 'test', :profile_id => person.id
207   - assert_equal true, article.published?
208   - assert_equal true, article.notifiable?
209   - assert_equal false, article.image?
210   - assert_equal Person, article.profile.class
211   - assert_equal person, ActionTracker::Record.last.target
  195 + assert_equal article, ActionTracker::Record.last.target
212 196 end
213 197  
214 198 should 'not notify activity if the article is not advertise' do
... ... @@ -226,7 +210,7 @@ class TinyMceArticleTest &lt; ActiveSupport::TestCase
226 210 end
227 211  
228 212 should "the common trackable conditions return the correct value" do
229   - a = TinyMceArticle.new
  213 + a = TinyMceArticle.new(:profile => profile)
230 214 a.published = a.advertise = true
231 215 assert_equal true, a.published?
232 216 assert_equal true, a.notifiable?
... ...
test/unit/uploaded_file_test.rb
... ... @@ -231,10 +231,10 @@ class UploadedFileTest &lt; ActiveSupport::TestCase
231 231 should 'return a thumbnail for images' do
232 232 f = UploadedFile.new
233 233 f.expects(:image?).returns(true)
234   - f.expects(:full_filename).with(:thumb).returns(File.join(RAILS_ROOT, 'public', 'images', '0000', '0005', 'x.png'))
  234 + f.expects(:full_filename).with(:display).returns(File.join(RAILS_ROOT, 'public', 'images', '0000', '0005', 'x.png'))
235 235 assert_equal '/images/0000/0005/x.png', f.thumbnail_path
236 236 f = UploadedFile.new
237   - f.stubs(:full_filename).with(:thumb).returns(File.join(RAILS_ROOT, 'public', 'images', '0000', '0005', 'x.png'))
  237 + f.stubs(:full_filename).with(:display).returns(File.join(RAILS_ROOT, 'public', 'images', '0000', '0005', 'x.png'))
238 238 f.expects(:image?).returns(false)
239 239 assert_nil f.thumbnail_path
240 240 end
... ... @@ -330,4 +330,11 @@ class UploadedFileTest &lt; ActiveSupport::TestCase
330 330 assert_equal 'hello_world.php.txt', file.filename
331 331 end
332 332  
  333 + should 'use itself as target for action tracker' do
  334 + p = fast_create(Gallery, :profile_id => @profile.id)
  335 + f = UploadedFile.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :parent => p, :profile => @profile)
  336 + ta = f.activity
  337 + assert_equal f, ta.target
  338 + end
  339 +
333 340 end
... ...
vendor/plugins/access_control/lib/role_assignment.rb
... ... @@ -9,10 +9,6 @@ class RoleAssignment &lt; ActiveRecord::Base
9 9  
10 10 track_actions :add_member_in_community, :after_create, :if => Proc.new { |x| x.resource.is_a?(Community) && x.accessor.role_assignments.count(:conditions => { :resource_id => x.resource.id, :resource_type => 'Profile' }) == 1 }, :custom_user => :accessor, :custom_target => :resource
11 11  
12   - track_actions :leave_community, :before_destroy, :keep_params => ["resource.name", "resource.url", "resource.profile_custom_icon"], :if => Proc.new { |x| x.resource.is_a?(Community) && x.accessor.role_assignments.count(:conditions => { :resource_id => x.resource.id, :resource_type => 'Profile' }) == 1 }, :custom_user => :accessor, :custom_target => :resource
13   -
14   - track_actions :remove_member_in_community, :before_destroy, :if => Proc.new { |x| x.resource.is_a?(Community) && x.accessor.role_assignments.count(:conditions => { :resource_id => x.resource.id, :resource_type => 'Profile' }) == 1 }, :custom_target => :resource, :custom_user => :accessor
15   -
16 12 def has_permission?(perm, res)
17 13 return false unless role.has_permission?(perm.to_s) && (resource || is_global)
18 14 return true if is_global
... ...
vendor/plugins/action_tracker/lib/action_tracker_model.rb
... ... @@ -24,6 +24,7 @@ module ActionTracker
24 24 RECENT_DELAY = 30
25 25  
26 26 named_scope :recent, :conditions => ['created_at >= ?', RECENT_DELAY.days.ago]
  27 + named_scope :visible, :conditions => { :visible => true }
27 28  
28 29 def self.current_user_from_model
29 30 u = new
... ...
vendor/plugins/action_tracker_has_comments/init.rb 0 → 100644
... ... @@ -0,0 +1,23 @@
  1 +# monkey patch to add comments on action_tracker
  2 +
  3 +ActionTracker::Record.module_eval do
  4 +
  5 + has_many :comments, :class_name => 'Comment', :foreign_key => 'source_id', :dependent => :destroy, :finder_sql => 'SELECT * FROM comments WHERE #{conditions_for_comments} ORDER BY created_at ASC', :counter_sql => 'SELECT * FROM comments WHERE #{conditions_for_comments}'
  6 +
  7 + def conditions_for_comments
  8 + type, id = (self.target_type == 'Article' ? ['Article', self.target_id] : [self.class.to_s, self.id])
  9 + "source_type = '#{type}' AND source_id = '#{id}'"
  10 + end
  11 +
  12 + def comments_as_thread
  13 + result = {}
  14 + root = []
  15 + self.comments.each do |c|
  16 + c.replies = []
  17 + result[c.id] ||= c
  18 + c.reply_of_id.nil? ? root << c : result[c.reply_of_id].replies << c
  19 + end
  20 + root
  21 + end
  22 +
  23 +end
... ...
vendor/plugins/active_record_counter_cache_on_polymorphic_association/init.rb 0 → 100644
... ... @@ -0,0 +1,36 @@
  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.module_eval do
  6 +#
  7 +# def replace(record)
  8 +#
  9 +# counter_cache_name = @reflection.counter_cache_column
  10 +#
  11 +# if record.nil?
  12 +# if counter_cache_name && !@owner.new_record?
  13 +# record.class.base_class.decrement_counter(counter_cache_name, @owner[@reflection.primary_key_name]) if @owner[@reflection.primary_key_name]
  14 +# end
  15 +#
  16 +# @target = @owner[@reflection.primary_key_name] = @owner[@reflection.options[:foreign_type]] = nil
  17 +# else
  18 +# @target = (AssociationProxy === record ? record.target : record)
  19 +#
  20 +# if counter_cache_name && !@owner.new_record?
  21 +# record.class.base_class.increment_counter(counter_cache_name, record.id)
  22 +# record.class.base_class.decrement_counter(counter_cache_name, @owner[@reflection.primary_key_name]) if @owner[@reflection.primary_key_name]
  23 +# end
  24 +#
  25 +# @owner[@reflection.primary_key_name] = record.id
  26 +# @owner[@reflection.options[:foreign_type]] = record.class.base_class.name.to_s
  27 +#
  28 +#
  29 +# @updated = true
  30 +# end
  31 +#
  32 +# loaded
  33 +# record
  34 +# end
  35 +#
  36 +#end
... ...