diff --git a/app/components/users/public_activity_component.rb b/app/components/users/public_activity_component.rb index 4c11f6069..8cdaa895c 100644 --- a/app/components/users/public_activity_component.rb +++ b/app/components/users/public_activity_component.rb @@ -1,6 +1,6 @@ class Users::PublicActivityComponent < ApplicationComponent attr_reader :user - delegate :authorized_current_user?, :current_path_with_query_params, to: :helpers + delegate :current_user, :valid_interests_access?, :current_path_with_query_params, to: :helpers def initialize(user) @user = user @@ -24,12 +24,16 @@ class Users::PublicActivityComponent < ApplicationComponent ("debates" if feature?(:debates)), ("budget_investments" if feature?(:budgets)), "comments", - "follows" + ("follows" if valid_interests_access?(user)) ].compact.select { |filter| send(filter).any? } end private + def authorized_current_user? + current_user == user || current_user&.moderator? || current_user&.administrator? + end + def proposals Proposal.where(author_id: user.id) end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 0912f3295..8ccee9692 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -1,18 +1,14 @@ class UsersController < ApplicationController load_and_authorize_resource helper_method :valid_interests_access? - helper_method :authorized_current_user? def show + raise CanCan::AccessDenied if params[:filter] == "follows" && !valid_interests_access?(@user) end private - def valid_interests_access? - @user.public_interests || authorized_current_user? - end - - def authorized_current_user? - @authorized_current_user ||= current_user && (current_user == @user || current_user.moderator? || current_user.administrator?) + def valid_interests_access?(user) + user.public_interests || user == current_user end end diff --git a/app/views/users/_following.html.erb b/app/views/users/_following.html.erb index 480bb2da2..d09f99fe6 100644 --- a/app/views/users/_following.html.erb +++ b/app/views/users/_following.html.erb @@ -22,6 +22,6 @@
- <%= render "interests", user: user if valid_interests_access? %> + <%= render "interests", user: user %>
diff --git a/config/locales/en/activerecord.yml b/config/locales/en/activerecord.yml index c2057e07b..2613671b5 100644 --- a/config/locales/en/activerecord.yml +++ b/config/locales/en/activerecord.yml @@ -281,7 +281,7 @@ en: official_level: "Official level" phone_number: "Phone number" public_activity: "Keep my list of activities public" - public_interests: "Keep the labels of the elements I follow public" + public_interests: "Keep the elements I follow public" recommended_debates: "Show debates recommendations" recommended_proposals: "Show proposals recommendations" redeemable_code: "Verification code received via email" diff --git a/config/locales/es/activerecord.yml b/config/locales/es/activerecord.yml index a6454e6e3..8af18867c 100644 --- a/config/locales/es/activerecord.yml +++ b/config/locales/es/activerecord.yml @@ -281,7 +281,7 @@ es: official_level: "Nivel del cargo" phone_number: "Teléfono" public_activity: "Mostrar públicamente mi lista de actividades" - public_interests: "Mostrar públicamente las etiquetas de los elementos que sigo" + public_interests: "Mostrar públicamente los elementos que sigo" recommended_debates: "Mostrar recomendaciones en el listado de debates" recommended_proposals: "Mostrar recomendaciones en el listado de propuestas" redeemable_code: "Código de verificación por carta (opcional)" diff --git a/spec/components/users/public_activity_component_spec.rb b/spec/components/users/public_activity_component_spec.rb new file mode 100644 index 000000000..39ae4010d --- /dev/null +++ b/spec/components/users/public_activity_component_spec.rb @@ -0,0 +1,82 @@ +require "rails_helper" + +describe Users::PublicActivityComponent, controller: UsersController do + around do |example| + with_request_url(Rails.application.routes.url_helpers.user_path(user)) { example.run } + end + + describe "follows tab" do + context "public interests is checked" do + let(:user) { create(:user, public_interests: true) } + let(:component) { Users::PublicActivityComponent.new(user) } + + it "is displayed for everyone" do + create(:proposal, author: user, followers: [user]) + + render_inline component + + expect(page).to have_content "1 Following" + end + + it "is not displayed when the user isn't following any followables" do + create(:proposal, author: user) + + render_inline component + + expect(page).not_to have_content "Following" + end + + it "is the active tab when the follows filters is selected" do + create(:proposal, author: user, followers: [user]) + controller.params["filter"] = "follows" + + render_inline component + + expect(page).to have_selector "li.is-active", text: "1 Following" + end + end + + context "public interests is not checked" do + let(:user) { create(:user, public_interests: false) } + let(:component) { Users::PublicActivityComponent.new(user) } + + it "is displayed for its owner" do + create(:proposal, followers: [user]) + sign_in(user) + + render_inline component + + expect(page).to have_content "1 Following" + end + + it "is not displayed for anonymous users" do + create(:proposal, author: user, followers: [user]) + + render_inline component + + expect(page).to have_content "1 Proposal" + expect(page).not_to have_content "Following" + end + + it "is not displayed for other users" do + create(:proposal, author: user, followers: [user]) + sign_in(create(:user)) + + render_inline component + + expect(page).to have_content "1 Proposal" + expect(page).not_to have_content "Following" + end + + it "is not displayed for administrators" do + create(:proposal, author: user, followers: [user]) + sign_in(create(:administrator).user) + + render_inline component + + expect(page).to have_content "1 Proposal" + expect(page).not_to have_content "Following" + end + end + end +end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 3c6103c44..d24392549 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -739,6 +739,12 @@ describe User do end end + describe "#public_interests" do + it "is false by default" do + expect(User.new.public_interests).to be false + end + end + describe ".find_by_manager_login" do it "works with a low ID" do user = create(:user) diff --git a/spec/system/users_spec.rb b/spec/system/users_spec.rb index 5a9607f9c..127bb1b11 100644 --- a/spec/system/users_spec.rb +++ b/spec/system/users_spec.rb @@ -231,106 +231,6 @@ describe "Users" do end end - describe "Public interests" do - let(:user) { create(:user) } - - scenario "Display interests" do - create(:proposal, tag_list: "Sport", followers: [user]) - - login_as(user) - visit account_path - - check "account_public_interests" - click_button "Save changes" - - logout - - visit user_path(user, filter: "follows") - - expect(page).to have_css "#public_interests" - expect(page).to have_content "Sport" - end - - scenario "Not display interests when proposal has been destroyed" do - proposal = create(:proposal, tag_list: "Sport", followers: [user]) - proposal.destroy! - - login_as(user) - visit account_path - - check "account_public_interests" - click_button "Save changes" - - logout - - visit user_path(user) - expect(page).not_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 "Is always visible for the owner" do - create(:proposal, tag_list: "Sport", followers: [user]) - - login_as(user) - visit account_path - - uncheck "account_public_interests" - click_button "Save changes" - - visit user_path(user, filter: "follows", page: "1") - - expect(page).to have_css "#public_interests" - expect(page).to have_content "Tags of elements you follow" - end - - scenario "Is always visible for admins" do - create(:proposal, tag_list: "Sport", followers: [user]) - - login_as(user) - visit account_path - - uncheck "account_public_interests" - click_button "Save changes" - - logout - - login_as(create(:administrator).user) - visit user_path(user, filter: "follows", page: "1") - expect(page).to have_css("#public_interests") - end - - scenario "Is always visible for moderators" do - create(:proposal, tag_list: "Sport", followers: [user]) - - login_as(user) - visit account_path - - uncheck "account_public_interests" - click_button "Save changes" - - logout - - login_as(create(:moderator).user) - visit user_path(user, filter: "follows", page: "1") - expect(page).to have_css("#public_interests") - end - - scenario "Should display generic interests title" do - create(:proposal, tag_list: "Sport", followers: [user]) - - user.update!(public_interests: true) - visit user_path(user, filter: "follows", page: "1") - - expect(page).to have_content("Tags of elements this user follows") - end - end - describe "Special comments" do scenario "comments posted as moderator are not visible in user activity" do moderator = create(:administrator).user @@ -386,117 +286,203 @@ describe "Users" do describe "Following (public page)" do let(:user) { create(:user) } - scenario "Do not display follows' tab when user is not following any followables" do - visit user_path(user) + context "public interests is checked" do + let(:user) { create(:user, public_interests: true) } - expect(page).not_to have_content("0 Following") + scenario "can be accessed by anyone" do + create(:proposal, followers: [user], title: "Others follow me") + + visit user_path(user, filter: "follows") + + expect(page).to have_content "1 Following" + expect(page).to have_content "Others follow me" + end + + scenario "Gracefully handle followables that have been hidden" do + create(:proposal, followers: [user]) + create(:proposal, followers: [user], &:hide) + + visit user_path(user) + + expect(page).to have_content("1 Following") + end + + scenario "displays generic interests title" do + create(:proposal, tag_list: "Sport", followers: [user]) + + visit user_path(user, filter: "follows", page: "1") + + expect(page).to have_content("Tags of elements this user follows") + end + + describe "Proposals" do + scenario "Display following tab when user is following one proposal at least" do + create(:proposal, followers: [user]) + + visit user_path(user) + + expect(page).to have_content("1 Following") + end + + scenario "Display proposal tab when user is following one proposal at least" do + create(:proposal, followers: [user]) + + visit user_path(user, filter: "follows") + + expect(page).to have_link("Citizen proposals", href: "#citizen_proposals") + end + + scenario "Do not display proposals' tab when user is not following any proposal" do + visit user_path(user, filter: "follows") + + expect(page).not_to have_link("Citizen proposals", href: "#citizen_proposals") + end + + scenario "Display proposals with link to proposal" do + proposal = create(:proposal, author: user, followers: [user]) + + login_as user + + visit user_path(user, filter: "follows") + + expect(page).to have_link "Citizen proposals", href: "#citizen_proposals" + expect(page).to have_content proposal.title + end + + scenario "Retired proposals do not have a link to the dashboard" do + proposal = create(:proposal, :retired, author: user) + login_as user + + visit user_path(user) + + expect(page).to have_content proposal.title + expect(page).not_to have_link "Dashboard" + expect(page).to have_content("Dashboard not available for retired proposals") + end + + scenario "Published proposals have a link to the dashboard" do + proposal = create(:proposal, :published, author: user) + login_as user + + visit user_path(user) + + expect(page).to have_content proposal.title + expect(page).to have_link "Dashboard" + end + end + + describe "Budget Investments" do + scenario "Display following tab when user is following one budget investment at least" do + create(:budget_investment, followers: [user]) + + visit user_path(user) + + expect(page).to have_content("1 Following") + end + + scenario "Display budget investment tab when user is following one budget investment at least" do + create(:budget_investment, followers: [user]) + + visit user_path(user, filter: "follows") + + expect(page).to have_link("Investments", href: "#investments") + end + + scenario "Do not display budget investment tab when user is not following any budget investment" do + visit user_path(user, filter: "follows") + + expect(page).not_to have_link("Investments", href: "#investments") + end + + scenario "Display budget investment with link to budget investment" do + budget_investment = create(:budget_investment, author: user, followers: [user]) + + visit user_path(user, filter: "follows") + + expect(page).to have_link "Investments", href: "#investments" + expect(page).to have_link budget_investment.title + end + end end - scenario "Active following tab by default when follows filters selected" do - create(:proposal, author: user, followers: [user]) + context "public interests is not checked" do + let(:user) { create(:user, public_interests: false) } + + scenario "can be accessed by its owner" do + create(:proposal, followers: [user], title: "Follow me!") + + login_as(user) + + visit user_path(user, filter: "follows") + + expect(page).to have_content "1 Following" + expect(page).to have_content "Follow me!" + expect(page).to have_content "Tags of elements you follow" + end + + scenario "cannot be accessed by anonymous users" do + create(:proposal, followers: [user]) + + visit user_path(user, filter: "follows") + + expect(page).to have_content "You do not have permission to access this page" + expect(page).to have_current_path root_path + end + + scenario "cannot be accessed by other users" do + create(:proposal, followers: [user]) + + login_as(create(:user)) + + visit user_path(user, filter: "follows") + + expect(page).to have_content "You do not have permission to access this page" + expect(page).to have_current_path root_path + end + + scenario "cannot be accessed by administrators" do + create(:proposal, followers: [user]) + + login_as(create(:administrator).user) + + visit user_path(user, filter: "follows") + + expect(page).to have_content "You do not have permission to access this page" + expect(page).to have_current_path root_path + end + end + + scenario "Display interests" do + create(:proposal, tag_list: "Sport", followers: [user]) + + login_as(user) + visit account_path + + check "account_public_interests" + click_button "Save changes" + + logout visit user_path(user, filter: "follows") - expect(page).to have_selector(".activity li.is-active", text: "1 Following") + expect(page).to have_css "#public_interests" + expect(page).to have_content "Sport" end - scenario "Gracefully handle followables that have been hidden" do - create(:proposal, followers: [user]) - create(:proposal, followers: [user], &:hide) + scenario "Do not display interests when proposal has been destroyed" do + proposal = create(:proposal, tag_list: "Sport", followers: [user]) + proposal.destroy! + + login_as(user) + visit account_path + + check "account_public_interests" + click_button "Save changes" + + logout visit user_path(user) - - expect(page).to have_content("1 Following") - end - - describe "Proposals" do - scenario "Display following tab when user is following one proposal at least" do - create(:proposal, followers: [user]) - - visit user_path(user) - - expect(page).to have_content("1 Following") - end - - scenario "Display proposal tab when user is following one proposal at least" do - create(:proposal, followers: [user]) - - visit user_path(user, filter: "follows") - - expect(page).to have_link("Citizen proposals", href: "#citizen_proposals") - end - - scenario "Do not display proposals' tab when user is not following any proposal" do - visit user_path(user, filter: "follows") - - expect(page).not_to have_link("Citizen proposals", href: "#citizen_proposals") - end - - scenario "Display proposals with link to proposal" do - proposal = create(:proposal, author: user, followers: [user]) - - login_as user - - visit user_path(user, filter: "follows") - - expect(page).to have_link "Citizen proposals", href: "#citizen_proposals" - expect(page).to have_content proposal.title - end - - scenario "Retired proposals do not have a link to the dashboard" do - proposal = create(:proposal, :retired, author: user) - login_as user - - visit user_path(user) - - expect(page).to have_content proposal.title - expect(page).not_to have_link "Dashboard" - expect(page).to have_content("Dashboard not available for retired proposals") - end - - scenario "Published proposals have a link to the dashboard" do - proposal = create(:proposal, :published, author: user) - login_as user - - visit user_path(user) - - expect(page).to have_content proposal.title - expect(page).to have_link "Dashboard" - end - end - - describe "Budget Investments" do - scenario "Display following tab when user is following one budget investment at least" do - create(:budget_investment, followers: [user]) - - visit user_path(user) - - expect(page).to have_content("1 Following") - end - - scenario "Display budget investment tab when user is following one budget investment at least" do - create(:budget_investment, followers: [user]) - - visit user_path(user, filter: "follows") - - expect(page).to have_link("Investments", href: "#investments") - end - - scenario "Not display budget investment tab when user is not following any budget investment" do - visit user_path(user, filter: "follows") - - expect(page).not_to have_link("Investments", href: "#investments") - end - - scenario "Display budget investment with link to budget investment" do - user = create(:user, :level_two) - budget_investment = create(:budget_investment, author: user, followers: [user]) - - visit user_path(user, filter: "follows") - - expect(page).to have_link "Investments", href: "#investments" - expect(page).to have_link budget_investment.title - end + expect(page).not_to have_content("Sport") end end