From 84dbef16a4c85f45a91a1ece0dcd0fc124b28780 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Mon, 26 Jun 2017 20:36:09 +0200 Subject: [PATCH 01/22] Create followable concern, follow model. Add followable to proposal model. --- app/controllers/follows_controller.rb | 28 ++++ app/helpers/follows_helper.rb | 28 ++++ app/models/abilities/common.rb | 2 + app/models/concerns/followable.rb | 8 ++ app/models/follow.rb | 32 +++++ app/models/proposal.rb | 1 + app/models/user.rb | 1 + app/views/follows/_followable_button.html.erb | 20 +++ .../follows/refresh_follow_button.js.erb | 1 + app/views/proposals/show.html.erb | 4 + config/locales/en/general.yml | 5 +- config/locales/es/general.yml | 6 +- config/routes.rb | 2 + db/migrate/20170626180127_create_follows.rb | 12 ++ db/schema.rb | 13 ++ spec/factories.rb | 12 +- spec/features/proposals_spec.rb | 67 +++++++++ spec/models/follow_spec.rb | 134 ++++++++++++++++++ 18 files changed, 372 insertions(+), 4 deletions(-) create mode 100644 app/controllers/follows_controller.rb create mode 100644 app/helpers/follows_helper.rb create mode 100644 app/models/concerns/followable.rb create mode 100644 app/models/follow.rb create mode 100644 app/views/follows/_followable_button.html.erb create mode 100644 app/views/follows/refresh_follow_button.js.erb create mode 100644 db/migrate/20170626180127_create_follows.rb create mode 100644 spec/models/follow_spec.rb diff --git a/app/controllers/follows_controller.rb b/app/controllers/follows_controller.rb new file mode 100644 index 000000000..32fea6813 --- /dev/null +++ b/app/controllers/follows_controller.rb @@ -0,0 +1,28 @@ +class FollowsController < ApplicationController + before_action :authenticate_user! + load_and_authorize_resource + + def create + @followable = find_followable + @follow = Follow.create(user: current_user, followable: @followable) + render :refresh_follow_button + end + + def destroy + @follow = Follow.find(params[:id]) + @followable = @follow.followable + @follow.destroy + render :refresh_follow_button + end + + private + + def find_followable + params.each do |name, value| + if name =~ /(.+)_id$/ + return $1.classify.constantize.find(value) + end + end + nil + end +end diff --git a/app/helpers/follows_helper.rb b/app/helpers/follows_helper.rb new file mode 100644 index 000000000..19c8f9ca6 --- /dev/null +++ b/app/helpers/follows_helper.rb @@ -0,0 +1,28 @@ +module FollowsHelper + + def show_follow_action?(followable) + current_user && !followed?(followable) + end + + def show_unfollow_action?(followable) + current_user && followed?(followable) + end + + def follow_entity_text(entity) + t('shared.follow_entity', entity: t("activerecord.models.#{entity}.one").downcase) + end + + def unfollow_entity_text(entity) + t('shared.unfollow_entity', entity: t("activerecord.models.#{entity}.one").downcase) + end + + def entity_name(followable) + followable.class.name.downcase + end + private + + def followed?(followable) + Follow.followed?(current_user, followable) + end + +end diff --git a/app/models/abilities/common.rb b/app/models/abilities/common.rb index 2b32abd07..cf183ec53 100644 --- a/app/models/abilities/common.rb +++ b/app/models/abilities/common.rb @@ -34,6 +34,8 @@ module Abilities can [:flag, :unflag], Proposal cannot [:flag, :unflag], Proposal, author_id: user.id + can [:create, :destroy], Follow + unless user.organization? can :vote, Debate can :vote, Comment diff --git a/app/models/concerns/followable.rb b/app/models/concerns/followable.rb new file mode 100644 index 000000000..7ac30ddc4 --- /dev/null +++ b/app/models/concerns/followable.rb @@ -0,0 +1,8 @@ +module Followable + extend ActiveSupport::Concern + + included do + has_many :follows, as: :followable + end + +end diff --git a/app/models/follow.rb b/app/models/follow.rb new file mode 100644 index 000000000..571635b15 --- /dev/null +++ b/app/models/follow.rb @@ -0,0 +1,32 @@ +class Follow < ActiveRecord::Base + belongs_to :user + #TODO Rock&RoR: Check touch usage on cache system + belongs_to :followable, polymorphic: true + + validates :user_id, presence: true + validates :followable_id, presence: true + validates :followable_type, presence: true + + scope(:by_user_and_followable, lambda do |user, followable| + where(user_id: user.id, + followable_type: followable.class.to_s, + followable_id: followable.id) + end) + + # def self.follow(user, followable) + # return false if interested?(user, followable) + # create(user: user, followable: followable) + # end + # + # def self.unfollow(user, followable) + # interests = by_user_and_followable(user, followable) + # return false if interests.empty? + # interests.destroy_all + # end + # + def self.followed?(user, followable) + return false unless user + !! by_user_and_followable(user, followable).try(:first) + end + +end diff --git a/app/models/proposal.rb b/app/models/proposal.rb index 9e02c197e..054c00c4a 100644 --- a/app/models/proposal.rb +++ b/app/models/proposal.rb @@ -8,6 +8,7 @@ class Proposal < ActiveRecord::Base include Filterable include HasPublicAuthor include Graphqlable + include Followable acts_as_votable acts_as_paranoid column: :hidden_at diff --git a/app/models/user.rb b/app/models/user.rb index b41057157..fb11aacf9 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -31,6 +31,7 @@ class User < ActiveRecord::Base has_many :direct_messages_sent, class_name: 'DirectMessage', foreign_key: :sender_id has_many :direct_messages_received, class_name: 'DirectMessage', foreign_key: :receiver_id has_many :legislation_answers, class_name: 'Legislation::Answer', dependent: :destroy, inverse_of: :user + has_many :follows belongs_to :geozone validates :username, presence: true, if: :username_required? diff --git a/app/views/follows/_followable_button.html.erb b/app/views/follows/_followable_button.html.erb new file mode 100644 index 000000000..2f838448e --- /dev/null +++ b/app/views/follows/_followable_button.html.erb @@ -0,0 +1,20 @@ + + <% if show_follow_action? followable %> + + <%= t('shared.follow') %> + + + <% end %> + + <% if show_unfollow_action? followable %> + <% follow = followable.follows.where(user: current_user).first %> + + <%= t('shared.unfollow') %> + + + <% end %> + diff --git a/app/views/follows/refresh_follow_button.js.erb b/app/views/follows/refresh_follow_button.js.erb new file mode 100644 index 000000000..1e8dc89f9 --- /dev/null +++ b/app/views/follows/refresh_follow_button.js.erb @@ -0,0 +1 @@ +$("#<%= dom_id(@followable) %> .js-follow").html('<%= j render("followable_button", followable: @followable) %>'); diff --git a/app/views/proposals/show.html.erb b/app/views/proposals/show.html.erb index d678214d2..c82503f27 100644 --- a/app/views/proposals/show.html.erb +++ b/app/views/proposals/show.html.erb @@ -53,6 +53,10 @@ <%= render 'proposals/flag_actions', proposal: @proposal %> +  •  + + <%= render 'follows/followable_button', followable: @proposal %> +
diff --git a/config/locales/en/general.yml b/config/locales/en/general.yml index 8c0763b32..408489fa1 100644 --- a/config/locales/en/general.yml +++ b/config/locales/en/general.yml @@ -500,6 +500,8 @@ en: check_none: None collective: Collective flag: Flag as inappropriate + follow: "Follow" + follow_entity: "Follow %{entity}" hide: Hide print: print_button: Print this info @@ -532,6 +534,8 @@ en: target_blank_html: " (link opens in new window)" you_are_in: "You are in" unflag: Unflag + unfollow: "Unfollow" + unfollow_entity: "Unfollow %{entity}" outline: debates: Debates proposals: Proposals @@ -708,4 +712,3 @@ en: invisible_captcha: sentence_for_humans: "If you are human, ignore this field" timestamp_error_message: "Sorry, that was too quick! Please resubmit." - diff --git a/config/locales/es/general.yml b/config/locales/es/general.yml index d38184647..72bed0a59 100644 --- a/config/locales/es/general.yml +++ b/config/locales/es/general.yml @@ -500,6 +500,8 @@ es: check_none: Ninguno collective: Colectivo flag: Denunciar como inapropiado + follow: "Seguir" + follow_entity: "Seguir %{entity}" hide: Ocultar print: print_button: Imprimir esta información @@ -532,6 +534,8 @@ es: target_blank_html: " (se abre en ventana nueva)" you_are_in: "Estás en" unflag: Deshacer denuncia + unfollow: Dejar de seguir + unfollow_entity: "Dejar de seguir %{entity}" outline: debates: Debates proposals: Propuestas @@ -707,4 +711,4 @@ es: user_permission_votes: Participar en las votaciones finales* invisible_captcha: sentence_for_humans: "Si eres humano, por favor ignora este campo" - timestamp_error_message: "Eso ha sido demasiado rápido. Por favor, reenvía el formulario." \ No newline at end of file + timestamp_error_message: "Eso ha sido demasiado rápido. Por favor, reenvía el formulario." diff --git a/config/routes.rb b/config/routes.rb index bdf1e22f3..ab54fd739 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -93,6 +93,8 @@ Rails.application.routes.draw do end end + resources :follows, only: [:create, :destroy] + resources :stats, only: [:index] resources :legacy_legislations, only: [:show], path: 'legislations' diff --git a/db/migrate/20170626180127_create_follows.rb b/db/migrate/20170626180127_create_follows.rb new file mode 100644 index 000000000..d4225cab8 --- /dev/null +++ b/db/migrate/20170626180127_create_follows.rb @@ -0,0 +1,12 @@ +class CreateFollows < ActiveRecord::Migration + def change + create_table :follows do |t| + t.references :user, index: true, foreign_key: true + t.references :followable, polymorphic: true, index: true + + t.timestamps null: false + end + + add_index :follows, [:user_id, :followable_type, :followable_id], name: "access_follows" + end +end diff --git a/db/schema.rb b/db/schema.rb index 0787b5ed1..0ad6a401f 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -326,6 +326,18 @@ ActiveRecord::Schema.define(version: 20170704105112) do add_index "flags", ["user_id", "flaggable_type", "flaggable_id"], name: "access_inappropiate_flags", using: :btree add_index "flags", ["user_id"], name: "index_flags_on_user_id", using: :btree + create_table "follows", force: :cascade do |t| + t.integer "user_id" + t.integer "followable_id" + t.string "followable_type" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + add_index "follows", ["followable_type", "followable_id"], name: "index_follows_on_followable_type_and_followable_id", using: :btree + add_index "follows", ["user_id", "followable_type", "followable_id"], name: "access_follows", using: :btree + add_index "follows", ["user_id"], name: "index_follows_on_user_id", using: :btree + create_table "geozones", force: :cascade do |t| t.string "name" t.string "html_map_coordinates" @@ -1036,6 +1048,7 @@ ActiveRecord::Schema.define(version: 20170704105112) do add_foreign_key "failed_census_calls", "poll_officers" add_foreign_key "failed_census_calls", "users" add_foreign_key "flags", "users" + add_foreign_key "follows", "users" add_foreign_key "geozones_polls", "geozones" add_foreign_key "geozones_polls", "polls" add_foreign_key "identities", "users" diff --git a/spec/factories.rb b/spec/factories.rb index 9a3c292b3..b7caa73b4 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -166,8 +166,8 @@ FactoryGirl.define do end trait :flagged do - after :create do |debate| - Flag.flag(FactoryGirl.create(:user), debate) + after :create do |proposal| + Flag.flag(FactoryGirl.create(:user), proposal) end end @@ -349,6 +349,14 @@ FactoryGirl.define do association :user, factory: :user end + factory :follow do + association :user, factory: :user + + trait :followed_proposal do + association :followable, factory: :proposal + end + end + factory :comment do association :commentable, factory: :debate user diff --git a/spec/features/proposals_spec.rb b/spec/features/proposals_spec.rb index 8faa899f9..30bfa7faa 100644 --- a/spec/features/proposals_spec.rb +++ b/spec/features/proposals_spec.rb @@ -1223,6 +1223,73 @@ feature 'Proposals' do expect(Flag.flagged?(user, proposal)).to_not be end + feature "Follows" do + + scenario "Should not show follow button when there is no logged user" do + proposal = create(:proposal) + + visit proposal_path(proposal) + + within "#proposal_#{proposal.id}" do + expect(page).not_to have_link("Follow citizen proposal") + end + end + + scenario "Following", :js do + user = create(:user) + proposal = create(:proposal) + login_as(user) + + visit proposal_path(proposal) + within "#proposal_#{proposal.id}" do + page.find("#follow-expand-proposal-#{proposal.id}").click + page.find("#follow-proposal-#{proposal.id}").click + + expect(page).to have_css("#unfollow-expand-proposal-#{proposal.id}") + end + + expect(Follow.followed?(user, proposal)).to be + end + + scenario "Show unfollow button when user already follow this proposal" do + user = create(:user) + follow = create(:follow, :followed_proposal, user: user) + login_as(user) + + visit proposal_path(follow.followable) + + expect(page).to have_link("Unfollow citizen proposal") + end + + scenario "Unfollowing", :js do + user = create(:user) + proposal = create(:proposal) + follow = create(:follow, :followed_proposal, user: user, followable: proposal) + login_as(user) + + visit proposal_path(proposal) + within "#proposal_#{proposal.id}" do + page.find("#unfollow-expand-proposal-#{proposal.id}").click + page.find("#unfollow-proposal-#{proposal.id}").click + + expect(page).to have_css("#follow-expand-proposal-#{proposal.id}") + end + + expect(Follow.followed?(user, proposal)).not_to be + end + + scenario "Show follow button when user is not following this proposal" do + user = create(:user) + proposal = create(:proposal) + login_as(user) + + visit proposal_path(proposal) + + expect(page).to have_link("Follow citizen proposal") + end + + end + scenario 'Erased author' do user = create(:user) proposal = create(:proposal, author: user) diff --git a/spec/models/follow_spec.rb b/spec/models/follow_spec.rb new file mode 100644 index 000000000..07e891dd8 --- /dev/null +++ b/spec/models/follow_spec.rb @@ -0,0 +1,134 @@ +require 'rails_helper' + +describe Follow do + + let(:follow) { build(:follow, :followed_proposal) } + + # it_behaves_like "has_public_author" + + it "should be valid" do + expect(follow).to be_valid + end + + it "should not be valid without an user_id" do + follow.user_id = nil + expect(follow).to_not be_valid + end + + it "should not be valid without an followable_id" do + follow.followable_id = nil + expect(follow).to_not be_valid + end + + it "should not be valid without an followable_type" do + follow.followable_type = nil + expect(follow).to_not be_valid + end + + + # describe "proposal" do + # + # let(:proposal) { create(:proposal) } + # + # describe 'create' do + # + # it 'creates a interest when there is none' do + # expect { described_class.follow(user, proposal) }.to change{ Interest.count }.by(1) + # expect(Interest.last.user).to eq(user) + # expect(Interest.last.interestable).to eq(proposal) + # end + # + # it 'does nothing if the interest already exists' do + # described_class.follow(user, proposal) + # expect(described_class.follow(user, proposal)).to eq(false) + # expect(Interest.by_user_and_interestable(user, proposal).count).to eq(1) + # end + # + # it 'increases the interest count' do + # expect { described_class.follow(user, proposal) }.to change{ proposal.reload.interests_count }.by(1) + # end + # end + # + # describe 'destroy' do + # it 'raises an error if the interest does not exist' do + # expect(described_class.unfollow(user, proposal)).to eq(false) + # end + # + # describe 'when the interest already exists' do + # before(:each) { described_class.follow(user, proposal) } + # + # it 'removes an existing interest' do + # expect { described_class.unfollow(user, proposal) }.to change{ Interest.count }.by(-1) + # end + # + # it 'decreases the interest count' do + # expect { described_class.unfollow(user, proposal) }.to change{ proposal.reload.interests_count }.by(-1) + # end + # end + # end + # + # describe '.interested?' do + # it 'returns false when the user has not flagged the proposal' do + # expect(described_class.interested?(user, proposal)).to_not be + # end + # + # it 'returns true when the user has interested the proposal' do + # described_class.follow(user, proposal) + # expect(described_class.interested?(user, proposal)).to be + # end + # end + # end + # + # describe "debate" do + # + # let(:debate) { create(:debate) } + # + # describe 'create' do + # + # it 'creates a interest when there is none' do + # expect { described_class.follow(user, debate) }.to change{ Interest.count }.by(1) + # expect(Interest.last.user).to eq(user) + # expect(Interest.last.interestable).to eq(debate) + # end + # + # it 'does nothing if the interest already exists' do + # described_class.follow(user, debate) + # expect(described_class.follow(user, debate)).to eq(false) + # expect(Interest.by_user_and_interestable(user, debate).count).to eq(1) + # end + # + # it 'increases the interest count' do + # expect { described_class.follow(user, debate) }.to change{ debate.reload.interests_count }.by(1) + # end + # end + # + # describe 'destroy' do + # it 'raises an error if the interest does not exist' do + # expect(described_class.unfollow(user, debate)).to eq(false) + # end + # + # describe 'when the interest already exists' do + # before(:each) { described_class.follow(user, debate) } + # + # it 'removes an existing interest' do + # expect { described_class.unfollow(user, debate) }.to change{ Interest.count }.by(-1) + # end + # + # it 'decreases the interest count' do + # expect { described_class.unfollow(user, debate) }.to change{ debate.reload.interests_count }.by(-1) + # end + # end + # end + # + # describe '.interested?' do + # it 'returns false when the user has not flagged the debate' do + # expect(described_class.interested?(user, debate)).to_not be + # end + # + # it 'returns true when the user has interested the debate' do + # described_class.follow(user, debate) + # expect(described_class.interested?(user, debate)).to be + # end + # end + # end +end From bce28afe36c415b4bf7a4ea15d90a582520feede Mon Sep 17 00:00:00 2001 From: taitus Date: Thu, 29 Jun 2017 18:07:22 +0200 Subject: [PATCH 02/22] Add followable to budget investment model. --- app/controllers/follows_controller.rb | 7 +- app/helpers/follows_helper.rb | 10 +- app/models/budget/investment.rb | 1 + app/models/follow.rb | 11 -- .../investments/_investment_show.html.erb | 4 + app/views/follows/_followable_button.html.erb | 13 ++- spec/factories.rb | 4 + spec/features/budgets/investments_spec.rb | 68 +++++++++++ spec/models/follow_spec.rb | 108 ------------------ 9 files changed, 92 insertions(+), 134 deletions(-) diff --git a/app/controllers/follows_controller.rb b/app/controllers/follows_controller.rb index 32fea6813..9cec999fa 100644 --- a/app/controllers/follows_controller.rb +++ b/app/controllers/follows_controller.rb @@ -18,11 +18,6 @@ class FollowsController < ApplicationController private def find_followable - params.each do |name, value| - if name =~ /(.+)_id$/ - return $1.classify.constantize.find(value) - end - end - nil + params[:followable_type].constantize.find(params[:followable_id]) end end diff --git a/app/helpers/follows_helper.rb b/app/helpers/follows_helper.rb index 19c8f9ca6..0ba6a8862 100644 --- a/app/helpers/follows_helper.rb +++ b/app/helpers/follows_helper.rb @@ -8,17 +8,21 @@ module FollowsHelper current_user && followed?(followable) end - def follow_entity_text(entity) + def follow_entity_text(followable) + entity = followable.class.name.gsub('::', '/').downcase t('shared.follow_entity', entity: t("activerecord.models.#{entity}.one").downcase) end - def unfollow_entity_text(entity) + def unfollow_entity_text(followable) + entity = followable.class.name.gsub('::', '/').downcase t('shared.unfollow_entity', entity: t("activerecord.models.#{entity}.one").downcase) end def entity_name(followable) - followable.class.name.downcase + entity_name = followable.class.name.split('::').last + entity_name.downcase end + private def followed?(followable) diff --git a/app/models/budget/investment.rb b/app/models/budget/investment.rb index 5fcf2e882..1cb3733a6 100644 --- a/app/models/budget/investment.rb +++ b/app/models/budget/investment.rb @@ -6,6 +6,7 @@ class Budget include Taggable include Searchable include Reclassification + include Followable acts_as_votable acts_as_paranoid column: :hidden_at diff --git a/app/models/follow.rb b/app/models/follow.rb index 571635b15..ee44cac96 100644 --- a/app/models/follow.rb +++ b/app/models/follow.rb @@ -13,17 +13,6 @@ class Follow < ActiveRecord::Base followable_id: followable.id) end) - # def self.follow(user, followable) - # return false if interested?(user, followable) - # create(user: user, followable: followable) - # end - # - # def self.unfollow(user, followable) - # interests = by_user_and_followable(user, followable) - # return false if interests.empty? - # interests.destroy_all - # end - # def self.followed?(user, followable) return false unless user !! by_user_and_followable(user, followable).try(:first) diff --git a/app/views/budgets/investments/_investment_show.html.erb b/app/views/budgets/investments/_investment_show.html.erb index 42a8b9f26..b26db7263 100644 --- a/app/views/budgets/investments/_investment_show.html.erb +++ b/app/views/budgets/investments/_investment_show.html.erb @@ -13,6 +13,10 @@ <%= l investment.created_at.to_date %>  •  <%= investment.heading.name %> +  •  + + <%= render 'follows/followable_button', followable: investment %> +
diff --git a/app/views/follows/_followable_button.html.erb b/app/views/follows/_followable_button.html.erb index 2f838448e..3eefc774c 100644 --- a/app/views/follows/_followable_button.html.erb +++ b/app/views/follows/_followable_button.html.erb @@ -1,20 +1,21 @@ +<% entity = entity_name(followable) %> <% if show_follow_action? followable %> - + <%= t('shared.follow') %> - diff --git a/config/locales/en/general.yml b/config/locales/en/general.yml index 408489fa1..b2ec63d06 100644 --- a/config/locales/en/general.yml +++ b/config/locales/en/general.yml @@ -13,6 +13,7 @@ en: personal: Personal details phone_number_label: Phone number public_activity_label: Keep my list of activities public + public_interests_label: Keep my interests public save_changes_submit: Save changes subscription_to_website_newsletter_label: Receive by email website relevant information email_on_direct_message_label: Receive emails about direct messages diff --git a/config/locales/es/general.yml b/config/locales/es/general.yml index 72bed0a59..e149f1bc4 100644 --- a/config/locales/es/general.yml +++ b/config/locales/es/general.yml @@ -13,6 +13,7 @@ es: personal: Datos personales phone_number_label: Teléfono public_activity_label: Mostrar públicamente mi lista de actividades + public_interests_label: Mostrar públicamente mis intereses save_changes_submit: Guardar cambios subscription_to_website_newsletter_label: Recibir emails con información interesante sobre la web email_on_direct_message_label: Recibir emails con mensajes privados diff --git a/db/migrate/20170630105250_add_public_interests_to_user.rb b/db/migrate/20170630105250_add_public_interests_to_user.rb new file mode 100644 index 000000000..8fec4a748 --- /dev/null +++ b/db/migrate/20170630105250_add_public_interests_to_user.rb @@ -0,0 +1,5 @@ +class AddPublicInterestsToUser < ActiveRecord::Migration + def change + add_column :users, :public_interests, :boolean, default: false + end +end diff --git a/db/schema.rb b/db/schema.rb index 0ad6a401f..fc9c3e387 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -955,6 +955,7 @@ ActiveRecord::Schema.define(version: 20170704105112) do t.boolean "created_from_signature", default: false t.integer "failed_email_digests_count", default: 0 t.text "former_users_data_log", default: "" + t.boolean "public_interests", default: false end add_index "users", ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true, using: :btree diff --git a/spec/features/users_spec.rb b/spec/features/users_spec.rb index 90ee6b94c..b9beef626 100644 --- a/spec/features/users_spec.rb +++ b/spec/features/users_spec.rb @@ -213,6 +213,88 @@ feature 'Users' do end + feature 'Public interest' do + background do + @user = create(:user) + end + + scenario 'show interests' do + proposal = create(:proposal, tag_list: "Sport") + create(:follow, :followed_proposal, followable: proposal, user: @user) + + login_as(@user) + visit account_path + + check 'account_public_interests' + click_button 'Save changes' + + logout + + visit user_path(@user) + expect(page).to have_content("Sport") + end + + scenario 'no visible by default' do + visit user_path(@user) + + expect(page).to have_content(@user.username) + expect(page).not_to have_css('#public_interests') + end + + scenario 'user can show public page' do + login_as(@user) + visit account_path + + check 'account_public_interests' + click_button 'Save changes' + + logout + + visit user_path(@user) + expect(page).to have_css('#public_interests') + end + + scenario 'is always visible for the owner' do + login_as(@user) + visit account_path + + uncheck 'account_public_interests' + click_button 'Save changes' + + visit user_path(@user) + expect(page).to have_css('#public_interests') + end + + scenario 'is always visible for admins' do + login_as(@user) + visit account_path + + uncheck 'account_public_interests' + click_button 'Save changes' + + logout + + login_as(create(:administrator).user) + visit user_path(@user) + expect(page).to have_css('#public_interests') + end + + scenario 'is always visible for moderators' do + login_as(@user) + visit account_path + + uncheck 'account_public_interests' + click_button 'Save changes' + + logout + + login_as(create(:moderator).user) + visit user_path(@user) + expect(page).to have_css('#public_interests') + end + + end + feature 'Special comments' do scenario 'comments posted as moderator are not visible in user activity' do diff --git a/spec/models/follow_spec.rb b/spec/models/follow_spec.rb index 4ea0238ec..46fa4653b 100644 --- a/spec/models/follow_spec.rb +++ b/spec/models/follow_spec.rb @@ -23,4 +23,17 @@ describe Follow do expect(follow).to_not be_valid end + describe "interests" do + + let(:user) { create(:user) } + + it "interests_by user" do + proposal = create(:proposal, tag_list: "Sport") + create(:follow, :followed_proposal, followable: proposal, user: user) + + expect(Follow.interests_by(user)).to eq ["Sport"] + end + + end + end From 1f22286e2961f6b3511b17671697fea4a9d0cb5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Fri, 30 Jun 2017 16:02:49 +0200 Subject: [PATCH 04/22] Create rspec shared examples to test followable features on any followable entity. --- app/helpers/follows_helper.rb | 5 ++ app/views/follows/_followable_button.html.erb | 12 +-- spec/features/budgets/investments_spec.rb | 68 +-------------- spec/features/proposals_spec.rb | 67 +-------------- spec/shared/features/followable.rb | 83 +++++++++++++++++++ spec/spec_helper.rb | 1 + 6 files changed, 97 insertions(+), 139 deletions(-) create mode 100644 spec/shared/features/followable.rb diff --git a/app/helpers/follows_helper.rb b/app/helpers/follows_helper.rb index 0ba6a8862..cc01e9fc6 100644 --- a/app/helpers/follows_helper.rb +++ b/app/helpers/follows_helper.rb @@ -23,6 +23,11 @@ module FollowsHelper entity_name.downcase end + def entity_full_name(followable) + entity_name = followable.class.name + entity_name.downcase.gsub("::", "-") + end + private def followed?(followable) diff --git a/app/views/follows/_followable_button.html.erb b/app/views/follows/_followable_button.html.erb index 3eefc774c..cd6bae621 100644 --- a/app/views/follows/_followable_button.html.erb +++ b/app/views/follows/_followable_button.html.erb @@ -1,21 +1,21 @@ <% entity = entity_name(followable) %> <% if show_follow_action? followable %> - + <%= t('shared.follow') %> -