Commit 45c0df82cf8ce0fa3d49810da8f225415f7da412
Committed by
Rodrigo Souto
1 parent
c95e0983
Exists in
staging
and in
8 other branches
Add feature: Article Followers
- Every article can be followed so the user can receive notifications without having to comment on it Signed-off-by: Marcos Ronaldo <marcos.rpj2@gmail.com> Signed-off-by: Marcos Ramos <ms.ramos@outlook.com> Signed-off-by: Gustavo Coelho <gust.rod.coelho@gmail.com> Signed-off-by: Joenio Costa <joenio@colivre.coop.br> Signed-off-by: Carlos Purificacao <carloseugenio@gmail.com> Signed-off-by: Victor Costa <vfcosta@gmail.com> Signed-off-by: Caio SBA <caio@colivre.coop.br> Signed-off-by: Leandro Nunes dos Santos <leandro.santos@serpro.gov.br> Signed-off-by: Michel Felipe de Oliveira Ferreira <michel.ferreira@serpro.gov.br> Signed-off-by: Evandro Jr <evandrojr@gmail.com>
Showing
21 changed files
with
269 additions
and
43 deletions
Show diff stats
app/controllers/public/profile_controller.rb
| ... | ... | @@ -155,6 +155,18 @@ class ProfileController < PublicController |
| 155 | 155 | end |
| 156 | 156 | end |
| 157 | 157 | |
| 158 | + def follow_article | |
| 159 | + article = profile.environment.articles.find params[:article_id] | |
| 160 | + article.person_followers << user | |
| 161 | + redirect_to article.url | |
| 162 | + end | |
| 163 | + | |
| 164 | + def unfollow_article | |
| 165 | + article = profile.environment.articles.find params[:article_id] | |
| 166 | + article.person_followers.delete(user) | |
| 167 | + redirect_to article.url | |
| 168 | + end | |
| 169 | + | |
| 158 | 170 | def unblock |
| 159 | 171 | if current_user.person.is_admin?(profile.environment) |
| 160 | 172 | profile.unblock | ... | ... |
app/helpers/article_helper.rb
| ... | ... | @@ -155,4 +155,30 @@ module ArticleHelper |
| 155 | 155 | _('Edit') |
| 156 | 156 | end |
| 157 | 157 | |
| 158 | + def follow_button_text(article) | |
| 159 | + if article.event? | |
| 160 | + _('Attend') | |
| 161 | + else | |
| 162 | + _('Follow') | |
| 163 | + end | |
| 164 | + end | |
| 165 | + | |
| 166 | + def unfollow_button_text(article) | |
| 167 | + if article.event? | |
| 168 | + _('Unattend') | |
| 169 | + else | |
| 170 | + _('Unfollow') | |
| 171 | + end | |
| 172 | + end | |
| 173 | + | |
| 174 | + def following_button(page, user) | |
| 175 | + if !user.blank? and user != page.author | |
| 176 | + if page.is_followed_by? user | |
| 177 | + button :cancel, unfollow_button_text(page), {:controller => 'profile', :action => 'unfollow_article', :article_id => page.id} | |
| 178 | + else | |
| 179 | + button :add, follow_button_text(page), {:controller => 'profile', :action => 'follow_article', :article_id => page.id} | |
| 180 | + end | |
| 181 | + end | |
| 182 | + end | |
| 183 | + | |
| 158 | 184 | end | ... | ... |
app/models/article.rb
| ... | ... | @@ -9,7 +9,7 @@ class Article < ActiveRecord::Base |
| 9 | 9 | :highlighted, :notify_comments, :display_hits, :slug, |
| 10 | 10 | :external_feed_builder, :display_versions, :external_link, |
| 11 | 11 | :image_builder, :show_to_followers, |
| 12 | - :author, :display_preview, :published_at | |
| 12 | + :author, :display_preview, :published_at, :person_followers | |
| 13 | 13 | |
| 14 | 14 | acts_as_having_image |
| 15 | 15 | |
| ... | ... | @@ -77,8 +77,15 @@ class Article < ActiveRecord::Base |
| 77 | 77 | belongs_to :last_changed_by, :class_name => 'Person', :foreign_key => 'last_changed_by_id' |
| 78 | 78 | belongs_to :created_by, :class_name => 'Person', :foreign_key => 'created_by_id' |
| 79 | 79 | |
| 80 | +<<<<<<< 6fa2f904983046ed816efe293ba9dcad19a67a4b | |
| 80 | 81 | has_many :comments, :class_name => 'Comment', :as => 'source', :dependent => :destroy, :order => 'created_at asc' |
| 81 | 82 | |
| 83 | +======= | |
| 84 | + has_many :comments, :class_name => 'Comment', :foreign_key => 'source_id', :dependent => :destroy, :order => 'created_at asc' | |
| 85 | + has_many :article_followers, :dependent => :destroy | |
| 86 | + has_many :person_followers, :class_name => 'Person', :through => :article_followers, :source => :person | |
| 87 | + has_many :person_followers_emails, :class_name => 'User', :through => :person_followers, :source => :user, :select => :email | |
| 88 | +>>>>>>> Add feature: Article Followers | |
| 82 | 89 | has_many :article_categorizations, -> { where 'articles_categories.virtual = ?', false } |
| 83 | 90 | has_many :categories, :through => :article_categorizations |
| 84 | 91 | |
| ... | ... | @@ -91,7 +98,6 @@ class Article < ActiveRecord::Base |
| 91 | 98 | settings_items :author_name, :type => :string, :default => "" |
| 92 | 99 | settings_items :allow_members_to_edit, :type => :boolean, :default => false |
| 93 | 100 | settings_items :moderate_comments, :type => :boolean, :default => false |
| 94 | - settings_items :followers, :type => Array, :default => [] | |
| 95 | 101 | has_and_belongs_to_many :article_privacy_exceptions, :class_name => 'Person', :join_table => 'article_privacy_exceptions' |
| 96 | 102 | |
| 97 | 103 | belongs_to :reference_article, :class_name => "Article", :foreign_key => 'reference_article_id' |
| ... | ... | @@ -167,7 +173,6 @@ class Article < ActiveRecord::Base |
| 167 | 173 | end |
| 168 | 174 | end |
| 169 | 175 | |
| 170 | - | |
| 171 | 176 | def is_trackable? |
| 172 | 177 | self.published? && self.notifiable? && self.advertise? && self.profile.public_profile |
| 173 | 178 | end |
| ... | ... | @@ -368,6 +373,10 @@ class Article < ActiveRecord::Base |
| 368 | 373 | self.parent and self.parent.forum? |
| 369 | 374 | end |
| 370 | 375 | |
| 376 | + def person_followers_email_list | |
| 377 | + person_followers_emails.map{|p|p.email} | |
| 378 | + end | |
| 379 | + | |
| 371 | 380 | def info_from_last_update |
| 372 | 381 | last_comment = comments.last |
| 373 | 382 | if last_comment |
| ... | ... | @@ -407,6 +416,10 @@ class Article < ActiveRecord::Base |
| 407 | 416 | (not self.uploaded_file? and self.mime_type != 'text/html') |
| 408 | 417 | end |
| 409 | 418 | |
| 419 | + def is_followed_by?(user) | |
| 420 | + self.person_followers.include? user | |
| 421 | + end | |
| 422 | + | |
| 410 | 423 | def download_headers |
| 411 | 424 | {} |
| 412 | 425 | end | ... | ... |
app/models/comment.rb
| ... | ... | @@ -6,13 +6,14 @@ class Comment < ActiveRecord::Base |
| 6 | 6 | :body => {:label => _('Content'), :weight => 2}, |
| 7 | 7 | } |
| 8 | 8 | |
| 9 | - attr_accessible :body, :author, :name, :email, :title, :reply_of_id, :source | |
| 9 | + attr_accessible :body, :author, :name, :email, :title, :reply_of_id, :source, :follow_article | |
| 10 | 10 | |
| 11 | 11 | validates_presence_of :body |
| 12 | 12 | |
| 13 | 13 | belongs_to :source, :counter_cache => true, :polymorphic => true |
| 14 | 14 | alias :article :source |
| 15 | 15 | alias :article= :source= |
| 16 | + attr_accessor :follow_article | |
| 16 | 17 | |
| 17 | 18 | belongs_to :author, :class_name => 'Person', :foreign_key => 'author_id' |
| 18 | 19 | has_many :children, :class_name => 'Comment', :foreign_key => 'reply_of_id', :dependent => :destroy |
| ... | ... | @@ -100,10 +101,9 @@ class Comment < ActiveRecord::Base |
| 100 | 101 | |
| 101 | 102 | after_create :new_follower |
| 102 | 103 | def new_follower |
| 103 | - if source.kind_of?(Article) | |
| 104 | - article.followers += [author_email] | |
| 105 | - article.followers -= article.profile.notification_emails | |
| 106 | - article.followers.uniq! | |
| 104 | + if source.kind_of?(Article) and !author.nil? and @follow_article | |
| 105 | + article.person_followers += [author] | |
| 106 | + article.person_followers.uniq! | |
| 107 | 107 | article.save |
| 108 | 108 | end |
| 109 | 109 | end |
| ... | ... | @@ -145,7 +145,7 @@ class Comment < ActiveRecord::Base |
| 145 | 145 | if !notification_emails.empty? |
| 146 | 146 | CommentNotifier.notification(self).deliver |
| 147 | 147 | end |
| 148 | - emails = article.followers - [author_email] | |
| 148 | + emails = article.person_followers_email_list - [author_email] | |
| 149 | 149 | if !emails.empty? |
| 150 | 150 | CommentNotifier.mail_to_followers(self, emails).deliver |
| 151 | 151 | end | ... | ... |
app/models/person.rb
| 1 | 1 | # A person is the profile of an user holding all relationships with the rest of the system |
| 2 | 2 | class Person < Profile |
| 3 | 3 | |
| 4 | - attr_accessible :organization, :contact_information, :sex, :birth_date, :cell_phone, :comercial_phone, :jabber_id, :personal_website, :nationality, :address_reference, :district, :schooling, :schooling_status, :formation, :custom_formation, :area_of_study, :custom_area_of_study, :professional_activity, :organization_website | |
| 4 | + attr_accessible :organization, :contact_information, :sex, :birth_date, :cell_phone, :comercial_phone, :jabber_id, :personal_website, :nationality, :address_reference, :district, :schooling, :schooling_status, :formation, :custom_formation, :area_of_study, :custom_area_of_study, :professional_activity, :organization_website, :following_articles | |
| 5 | 5 | |
| 6 | 6 | SEARCH_FILTERS = { |
| 7 | 7 | :order => %w[more_recent more_popular more_active], |
| ... | ... | @@ -84,7 +84,8 @@ class Person < Profile |
| 84 | 84 | end |
| 85 | 85 | |
| 86 | 86 | has_many :comments, :foreign_key => :author_id |
| 87 | - | |
| 87 | + has_many :article_followers, :dependent => :destroy | |
| 88 | + has_many :following_articles, :class_name => 'Article', :through => :article_followers, :source => :article | |
| 88 | 89 | has_many :friendships, :dependent => :destroy |
| 89 | 90 | has_many :friends, :class_name => 'Person', :through => :friendships |
| 90 | 91 | ... | ... |
app/views/comment/_comment_form.html.erb
| ... | ... | @@ -77,6 +77,10 @@ function check_captcha(button, confirm_action) { |
| 77 | 77 | <%= labelled_form_field(_('Title'), f.text_field(:title)) %> |
| 78 | 78 | <%= required labelled_form_field(_('Enter your comment'), f.text_area(:body, :rows => 5)) %> |
| 79 | 79 | |
| 80 | + <% if logged_in? %> | |
| 81 | + <%= labelled_form_field check_box(:comment, :follow_article, {}, true, false) + _('Follow this article'), '' %> | |
| 82 | + <% end%> | |
| 83 | + | |
| 80 | 84 | <%= hidden_field_tag(:confirm, 'false') %> |
| 81 | 85 | <%= hidden_field_tag(:view, params[:view])%> |
| 82 | 86 | <%= f.hidden_field(:reply_of_id) %> | ... | ... |
app/views/content_viewer/_article_toolbar.html.erb
app/views/content_viewer/_publishing_info.html.erb
| ... | ... | @@ -10,6 +10,24 @@ |
| 10 | 10 | <%= (" - %s") % link_to_comments(@page)%> |
| 11 | 11 | </span> |
| 12 | 12 | <% end %> |
| 13 | + | |
| 14 | +<span class="followers-count"> | |
| 15 | +| | |
| 16 | +<% if @page.event? %> | |
| 17 | + <% if @page.person_followers.size > 0 %> | |
| 18 | + <%= _("%s will attend this event.") % [ pluralize(@page.person_followers.size, _("person"))]%> | |
| 19 | + <% else %> | |
| 20 | + <%= _("No one attending this event yet.") %> | |
| 21 | + <% end %> | |
| 22 | +<% else %> | |
| 23 | + <% if @page.person_followers.size > 0 %> | |
| 24 | + <%= _("%s following this article.") % [ pluralize(@page.person_followers.size, _("person"))]%> | |
| 25 | + <% else %> | |
| 26 | + <%= _("No one following this article yet.") %> | |
| 27 | + <% end %> | |
| 28 | +<% end %> | |
| 29 | +</span> | |
| 30 | + | |
| 13 | 31 | </span> |
| 14 | 32 | |
| 15 | 33 | <% if @page.display_hits? || @page.license.present? %> | ... | ... |
db/migrate/20151210230319_add_followers_count_to_article.rb
0 → 100644
| ... | ... | @@ -0,0 +1,13 @@ |
| 1 | +class AddFollowersCountToArticle < ActiveRecord::Migration | |
| 2 | + | |
| 3 | + def self.up | |
| 4 | + add_column :articles, :followers_count, :integer, :default => 0 | |
| 5 | + | |
| 6 | + execute "update articles set followers_count = (select count(*) from article_followers where article_followers.article_id = articles.id)" | |
| 7 | + end | |
| 8 | + | |
| 9 | + def self.down | |
| 10 | + remove_column :articles, :followers_count | |
| 11 | + end | |
| 12 | + | |
| 13 | +end | ... | ... |
db/schema.rb
| ... | ... | @@ -51,6 +51,18 @@ ActiveRecord::Schema.define(version: 20160202142247) do |
| 51 | 51 | add_index "action_tracker_notifications", ["profile_id", "action_tracker_id"], name: "index_action_tracker_notif_on_prof_id_act_tracker_id", unique: true, using: :btree |
| 52 | 52 | add_index "action_tracker_notifications", ["profile_id"], name: "index_action_tracker_notifications_on_profile_id", using: :btree |
| 53 | 53 | |
| 54 | + create_table "article_followers", force: :cascade do |t| | |
| 55 | + t.integer "person_id", null: false | |
| 56 | + t.integer "article_id", null: false | |
| 57 | + t.datetime "since" | |
| 58 | + t.datetime "created_at" | |
| 59 | + t.datetime "updated_at" | |
| 60 | + end | |
| 61 | + | |
| 62 | + add_index "article_followers", ["article_id"], name: "index_article_followers_on_article_id", using: :btree | |
| 63 | + add_index "article_followers", ["person_id", "article_id"], name: "index_article_followers_on_person_id_and_article_id", unique: true, using: :btree | |
| 64 | + add_index "article_followers", ["person_id"], name: "index_article_followers_on_person_id", using: :btree | |
| 65 | + | |
| 54 | 66 | create_table "article_privacy_exceptions", id: false, force: :cascade do |t| |
| 55 | 67 | t.integer "article_id" |
| 56 | 68 | t.integer "person_id" |
| ... | ... | @@ -101,6 +113,7 @@ ActiveRecord::Schema.define(version: 20160202142247) do |
| 101 | 113 | t.integer "spam_comments_count", default: 0 |
| 102 | 114 | t.integer "author_id" |
| 103 | 115 | t.integer "created_by_id" |
| 116 | + t.integer "followers_count" | |
| 104 | 117 | end |
| 105 | 118 | |
| 106 | 119 | add_index "article_versions", ["article_id"], name: "index_article_versions_on_article_id", using: :btree |
| ... | ... | @@ -154,6 +167,7 @@ ActiveRecord::Schema.define(version: 20160202142247) do |
| 154 | 167 | t.integer "author_id" |
| 155 | 168 | t.integer "created_by_id" |
| 156 | 169 | t.boolean "show_to_followers", default: true |
| 170 | + t.integer "followers_count", default: 0 | |
| 157 | 171 | end |
| 158 | 172 | |
| 159 | 173 | add_index "articles", ["comments_count"], name: "index_articles_on_comments_count", using: :btree | ... | ... |
lib/noosfero/api/entities.rb
lib/noosfero/api/v1/articles.rb
| ... | ... | @@ -112,6 +112,37 @@ module Noosfero |
| 112 | 112 | {:vote => vote.save} |
| 113 | 113 | end |
| 114 | 114 | |
| 115 | + desc "Returns the total followers for the article" do | |
| 116 | + detail 'Get the followers of a specific article by id' | |
| 117 | + failure [[403, 'Forbidden']] | |
| 118 | + named 'ArticleFollowers' | |
| 119 | + end | |
| 120 | + get ':id/followers' do | |
| 121 | + article = find_article(environment.articles, params[:id]) | |
| 122 | + total = article.person_followers.count | |
| 123 | + {:total_followers => total} | |
| 124 | + end | |
| 125 | + | |
| 126 | + desc "Add a follower for the article" do | |
| 127 | + detail 'Add the current user identified by private token, like a follower of a article' | |
| 128 | + params Noosfero::API::Entities::UserLogin.documentation | |
| 129 | + failure [[401, 'Unauthorized']] | |
| 130 | + named 'ArticleFollow' | |
| 131 | + end | |
| 132 | + post ':id/follow' do | |
| 133 | + authenticate! | |
| 134 | + article = find_article(environment.articles, params[:id]) | |
| 135 | + if article.article_followers.exists?(:person_id => current_person.id) | |
| 136 | + {:success => false, :already_follow => true} | |
| 137 | + else | |
| 138 | + article_follower = ArticleFollower.new | |
| 139 | + article_follower.article = article | |
| 140 | + article_follower.person = current_person | |
| 141 | + article_follower.save! | |
| 142 | + {:success => true} | |
| 143 | + end | |
| 144 | + end | |
| 145 | + | |
| 115 | 146 | desc 'Return the children of a article identified by id' do |
| 116 | 147 | detail 'Get all children articles of a specific article' |
| 117 | 148 | params Noosfero::API::Entities::Article.documentation | ... | ... |
test/functional/comment_controller_test.rb
| ... | ... | @@ -387,10 +387,26 @@ class CommentControllerTest < ActionController::TestCase |
| 387 | 387 | Article.record_timestamps = true |
| 388 | 388 | |
| 389 | 389 | login_as @profile.identifier |
| 390 | - xhr :post, :create, :profile => profile.identifier, :id => page.id, :comment => { :title => 'crap!', :body => 'I think that this article is crap' }, :confirm => 'true' | |
| 390 | + xhr :post, :create, :profile => profile.identifier, :id => page.id, :comment => {:title => 'crap!', :body => 'I think that this article is crap' }, :confirm => 'true' | |
| 391 | 391 | assert_not_equal yesterday, page.reload.updated_at |
| 392 | 392 | end |
| 393 | 393 | |
| 394 | + should 'follow article when commenting' do | |
| 395 | + page = create(Article, :profile => profile, :name => 'myarticle', :body => 'the body of the text') | |
| 396 | + login_as @profile.identifier | |
| 397 | + | |
| 398 | + xhr :post, :create, :profile => profile.identifier, :id => page.id, :comment => {:title => 'crap!', :body => 'I think that this article is crap', :follow_article => true}, :confirm => 'true' | |
| 399 | + assert_includes page.person_followers, @profile | |
| 400 | + end | |
| 401 | + | |
| 402 | + should 'not follow article when commenting' do | |
| 403 | + page = create(Article, :profile => profile, :name => 'myarticle', :body => 'the body of the text') | |
| 404 | + login_as @profile.identifier | |
| 405 | + | |
| 406 | + xhr :post, :create, :profile => profile.identifier, :id => page.id, :comment => {:title => 'crap!', :body => 'I think that this article is crap', :follow_article => false }, :confirm => 'true' | |
| 407 | + assert_not_includes page.person_followers, @profile | |
| 408 | + end | |
| 409 | + | |
| 394 | 410 | should 'be able to mark comments as spam' do |
| 395 | 411 | login_as profile.identifier |
| 396 | 412 | article = fast_create(Article, :profile_id => profile.id) | ... | ... |
test/functional/content_viewer_controller_test.rb
| ... | ... | @@ -1278,18 +1278,6 @@ class ContentViewerControllerTest < ActionController::TestCase |
| 1278 | 1278 | assert_tag :tag => 'div', :attributes => { :id => 'article-actions' }, :descendant => { :tag => 'a', :attributes => { :title => 'This button is expired.', :class => 'button with-text icon-edit disabled' } } |
| 1279 | 1279 | end |
| 1280 | 1280 | |
| 1281 | - should 'remove email from article followers when unfollow' do | |
| 1282 | - profile = create_user('testuser').person | |
| 1283 | - follower_email = 'john@doe.br' | |
| 1284 | - article = profile.articles.create(:name => 'test') | |
| 1285 | - article.followers = [follower_email] | |
| 1286 | - article.save | |
| 1287 | - | |
| 1288 | - assert_includes Article.find(article.id).followers, follower_email | |
| 1289 | - post :view_page, :profile => profile.identifier, :page => [article.name], :unfollow => 'commit', :email => follower_email | |
| 1290 | - assert_not_includes Article.find(article.id).followers, follower_email | |
| 1291 | - end | |
| 1292 | - | |
| 1293 | 1281 | should 'not display comments marked as spam' do |
| 1294 | 1282 | article = fast_create(Article, :profile_id => profile.id) |
| 1295 | 1283 | ham = fast_create(Comment, :source_id => article.id, :source_type => 'Article', :title => 'some content') | ... | ... |
test/functional/profile_controller_test.rb
| ... | ... | @@ -18,6 +18,19 @@ class ProfileControllerTest < ActionController::TestCase |
| 18 | 18 | assert assigns(:friends) |
| 19 | 19 | end |
| 20 | 20 | |
| 21 | + should 'remove person from article followers when unfollow' do | |
| 22 | + profile = create_user('testuser').person | |
| 23 | + follower = create_user('follower').person | |
| 24 | + article = profile.articles.create(:name => 'test') | |
| 25 | + article.person_followers = [follower] | |
| 26 | + article.save | |
| 27 | + login_as('follower') | |
| 28 | + article.reload | |
| 29 | + assert_includes Article.find(article.id).person_followers, follower | |
| 30 | + post :unfollow_article, :article_id => article.id | |
| 31 | + assert_not_includes Article.find(article.id).person_followers, follower | |
| 32 | + end | |
| 33 | + | |
| 21 | 34 | should 'point to manage friends in user is seeing his own friends' do |
| 22 | 35 | login_as('testuser') |
| 23 | 36 | get :friends |
| ... | ... | @@ -1338,6 +1351,24 @@ class ProfileControllerTest < ActionController::TestCase |
| 1338 | 1351 | assert_equivalent [scrap,activity], assigns(:activities).map(&:activity) |
| 1339 | 1352 | end |
| 1340 | 1353 | |
| 1354 | + should "follow an article" do | |
| 1355 | + article = TinyMceArticle.create!(:profile => profile, :name => 'An article about free software') | |
| 1356 | + login_as(@profile.identifier) | |
| 1357 | + post :follow_article, :profile => profile.identifier, :article_id => article.id | |
| 1358 | + assert_includes article.person_followers, @profile | |
| 1359 | + end | |
| 1360 | + | |
| 1361 | + should "unfollow an article" do | |
| 1362 | + article = TinyMceArticle.create!(:profile => profile, :name => 'An article about free software') | |
| 1363 | + article.person_followers << @profile | |
| 1364 | + article.save! | |
| 1365 | + assert_includes article.person_followers, @profile | |
| 1366 | + | |
| 1367 | + login_as(@profile.identifier) | |
| 1368 | + post :unfollow_article, :profile => profile.identifier, :article_id => article.id | |
| 1369 | + assert_not_includes article.person_followers, @profile | |
| 1370 | + end | |
| 1371 | + | |
| 1341 | 1372 | should "be logged in to leave comment on an activity" do |
| 1342 | 1373 | article = TinyMceArticle.create!(:profile => profile, :name => 'An article about free software') |
| 1343 | 1374 | activity = ActionTracker::Record.last | ... | ... |
test/unit/api/articles_test.rb
| ... | ... | @@ -39,6 +39,41 @@ class ArticlesTest < ActiveSupport::TestCase |
| 39 | 39 | assert_equal 403, last_response.status |
| 40 | 40 | end |
| 41 | 41 | |
| 42 | + should 'follow a article identified by id' do | |
| 43 | + article = fast_create(Article, :profile_id => @person.id, :name => "Some thing") | |
| 44 | + post "/api/v1/articles/#{article.id}/follow?#{params.to_query}" | |
| 45 | + json = JSON.parse(last_response.body) | |
| 46 | + | |
| 47 | + assert_not_equal 401, last_response.status | |
| 48 | + assert_equal true, json['success'] | |
| 49 | + end | |
| 50 | + | |
| 51 | + should 'return the followers count of an article' do | |
| 52 | + article = fast_create(Article, :profile_id => @person.id, :name => "Some thing") | |
| 53 | + article.person_followers << @person | |
| 54 | + | |
| 55 | + get "/api/v1/articles/#{article.id}?#{params.to_query}" | |
| 56 | + json = JSON.parse(last_response.body) | |
| 57 | + | |
| 58 | + assert_equal 200, last_response.status | |
| 59 | + assert_equal 1, json['article']['followers_count'] | |
| 60 | + end | |
| 61 | + | |
| 62 | + should 'return the followers of a article identified by id' do | |
| 63 | + article = fast_create(Article, :profile_id => @person.id, :name => "Some thing") | |
| 64 | + | |
| 65 | + article_follower = ArticleFollower.new | |
| 66 | + article_follower.article = article | |
| 67 | + article_follower.person = @person | |
| 68 | + article_follower.save! | |
| 69 | + | |
| 70 | + get "/api/v1/articles/#{article.id}/followers?#{params.to_query}" | |
| 71 | + json = JSON.parse(last_response.body) | |
| 72 | + | |
| 73 | + assert_equal 200, last_response.status | |
| 74 | + assert_equal 1, json['total_followers'] | |
| 75 | + end | |
| 76 | + | |
| 42 | 77 | should 'list article children' do |
| 43 | 78 | article = fast_create(Article, :profile_id => user.person.id, :name => "Some thing") |
| 44 | 79 | child1 = fast_create(Article, :parent_id => article.id, :profile_id => user.person.id, :name => "Some thing") | ... | ... |
test/unit/article_test.rb
| ... | ... | @@ -22,6 +22,21 @@ class ArticleTest < ActiveSupport::TestCase |
| 22 | 22 | refute a.errors[:profile_id.to_s].present? |
| 23 | 23 | end |
| 24 | 24 | |
| 25 | + should 'keep unique users in list of followers' do | |
| 26 | + person1 = create_user('article_owner').person | |
| 27 | + person2 = create_user('article_follower').person | |
| 28 | + | |
| 29 | + article = fast_create(Article, :profile_id => person1.id) | |
| 30 | + | |
| 31 | + article.person_followers=[person2] | |
| 32 | + article.save | |
| 33 | + article.reload | |
| 34 | + article.person_followers=[person2] | |
| 35 | + article.save | |
| 36 | + | |
| 37 | + assert_equal 1, article.reload.person_followers.size | |
| 38 | + end | |
| 39 | + | |
| 25 | 40 | should 'require value for name' do |
| 26 | 41 | a = Article.new |
| 27 | 42 | a.valid? |
| ... | ... | @@ -1700,7 +1715,7 @@ class ArticleTest < ActiveSupport::TestCase |
| 1700 | 1715 | |
| 1701 | 1716 | should 'has a empty list of followers by default' do |
| 1702 | 1717 | a = Article.new |
| 1703 | - assert_equal [], a.followers | |
| 1718 | + assert_equal [], a.person_followers | |
| 1704 | 1719 | end |
| 1705 | 1720 | |
| 1706 | 1721 | should 'get first image from lead' do | ... | ... |
test/unit/comment_notifier_test.rb
| ... | ... | @@ -60,7 +60,7 @@ class CommentNotifierTest < ActiveSupport::TestCase |
| 60 | 60 | should "deliver mail to followers" do |
| 61 | 61 | author = create_user('follower_author').person |
| 62 | 62 | follower = create_user('follower').person |
| 63 | - @article.followers += [follower.email] | |
| 63 | + @article.person_followers += [follower] | |
| 64 | 64 | @article.save! |
| 65 | 65 | create_comment_and_notify(:source => @article, :author => author, :title => 'comment title', :body => 'comment body') |
| 66 | 66 | assert_includes ActionMailer::Base.deliveries.map(&:bcc).flatten, follower.email | ... | ... |
test/unit/comment_test.rb
| ... | ... | @@ -328,34 +328,27 @@ class CommentTest < ActiveSupport::TestCase |
| 328 | 328 | assert c.rejected? |
| 329 | 329 | end |
| 330 | 330 | |
| 331 | - should 'subscribe user as follower of an article on new comment' do | |
| 331 | + should 'not subscribe user as follower of an article automatically on new comment' do | |
| 332 | 332 | owner = create_user('owner_of_article').person |
| 333 | 333 | person = create_user('follower').person |
| 334 | 334 | article = fast_create(Article, :profile_id => owner.id) |
| 335 | - assert_not_includes article.followers, person.email | |
| 335 | + assert_not_includes article.person_followers, person | |
| 336 | 336 | create(Comment, :source => article, :author => person, :title => 'new comment', :body => 'new comment') |
| 337 | - assert_includes article.reload.followers, person.email | |
| 337 | + assert_not_includes article.reload.person_followers, person | |
| 338 | 338 | end |
| 339 | 339 | |
| 340 | - should 'subscribe guest user as follower of an article on new comment' do | |
| 340 | + should 'not subscribe guest user as follower of an article on new comment' do | |
| 341 | 341 | article = fast_create(Article, :profile_id => create_user('article_owner').person.id) |
| 342 | - assert_not_includes article.followers, 'follower@example.com' | |
| 342 | + old_num_followers = article.reload.person_followers.size | |
| 343 | 343 | create(Comment, :source => article, :name => 'follower', :email => 'follower@example.com', :title => 'new comment', :body => 'new comment') |
| 344 | - assert_includes article.reload.followers, 'follower@example.com' | |
| 345 | - end | |
| 346 | - | |
| 347 | - should 'keep unique emails in list of followers' do | |
| 348 | - article = fast_create(Article, :profile_id => create_user('article_owner').person.id) | |
| 349 | - create(Comment, :source => article, :name => 'follower one', :email => 'follower@example.com', :title => 'new comment', :body => 'new comment') | |
| 350 | - create(Comment, :source => article, :name => 'follower two', :email => 'follower@example.com', :title => 'another comment', :body => 'new comment') | |
| 351 | - assert_equal 1, article.reload.followers.select{|v| v == 'follower@example.com'}.count | |
| 344 | + assert_equal old_num_followers, article.reload.person_followers.size | |
| 352 | 345 | end |
| 353 | 346 | |
| 354 | 347 | should 'not subscribe owner as follower of an article on new comment' do |
| 355 | 348 | owner = create_user('owner_of_article').person |
| 356 | 349 | article = fast_create(Article, :profile_id => owner.id) |
| 357 | 350 | create(Comment, :source => article, :author => owner, :title => 'new comment', :body => 'new comment') |
| 358 | - assert_not_includes article.reload.followers, owner.email | |
| 351 | + assert_not_includes article.reload.person_followers, owner | |
| 359 | 352 | end |
| 360 | 353 | |
| 361 | 354 | should 'not subscribe admins as follower of an article on new comment' do |
| ... | ... | @@ -366,8 +359,13 @@ class CommentTest < ActiveSupport::TestCase |
| 366 | 359 | article = fast_create(Article, :profile_id => owner.id) |
| 367 | 360 | create(Comment, :source => article, :author => follower, :title => 'new comment', :body => 'new comment') |
| 368 | 361 | create(Comment, :source => article, :author => admin, :title => 'new comment', :body => 'new comment') |
| 369 | - assert_not_includes article.reload.followers, admin.email | |
| 370 | - assert_includes article.followers, follower.email | |
| 362 | + | |
| 363 | + article.person_followers += [follower] | |
| 364 | + article.save! | |
| 365 | + article.reload | |
| 366 | + | |
| 367 | + assert_not_includes article.reload.person_followers, admin | |
| 368 | + assert_includes article.reload.person_followers, follower | |
| 371 | 369 | end |
| 372 | 370 | |
| 373 | 371 | should 'update article activity when add a comment' do | ... | ... |
test/unit/person_notifier_test.rb
| ... | ... | @@ -49,7 +49,8 @@ class PersonNotifierTest < ActiveSupport::TestCase |
| 49 | 49 | should 'display author name in delivered mail' do |
| 50 | 50 | @community.add_member(@member) |
| 51 | 51 | User.current = @admin.user |
| 52 | - Comment.create!(:author => @admin, :title => 'test comment', :body => 'body!', :source => @article) | |
| 52 | + comment = Comment.create!(:author => @admin, :title => 'test comment', :body => 'body!', :source => @article) | |
| 53 | + comment.save! | |
| 53 | 54 | process_delayed_job_queue |
| 54 | 55 | notify |
| 55 | 56 | sent = ActionMailer::Base.deliveries.last | ... | ... |