Hide what users are following unless they allow it
It could be argued that seeing which proposals a user follows is a good
indicator of which proposals a user has supported, since we're
automatically creating follows for supported proposals since commit
74fbde09f. So now, we're extending the `public_interests` funcionality,
so it only shows elements users are following if they've enabled it.
This is an improvement over using the `public_activity` attribute in two
ways:
* The `public_interests` attribute is disabled by default, so by default
other users won't be able to see what a user is following
* Who has created proposals/debates/investments/comments is public
information, while who is following which elements is not; so enabling
`public_activity` shouldn't imply potentially private information should
be displayed as well
We've considered removing the `public_interests` attribute completely
and just hiding the "following" page for everyone except its owner, but
keeping it provides more compatibility with existing installations.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -22,6 +22,6 @@
|
||||
</div>
|
||||
|
||||
<div class="small-12 medium-4 column interests" data-equalizer-watch>
|
||||
<%= render "interests", user: user if valid_interests_access? %>
|
||||
<%= render "interests", user: user %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)"
|
||||
|
||||
82
spec/components/users/public_activity_component_spec.rb
Normal file
82
spec/components/users/public_activity_component_spec.rb
Normal file
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -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,18 +286,16 @@ 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")
|
||||
end
|
||||
|
||||
scenario "Active following tab by default when follows filters selected" do
|
||||
create(:proposal, author: user, followers: [user])
|
||||
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_selector(".activity li.is-active", text: "1 Following")
|
||||
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
|
||||
@@ -409,6 +307,14 @@ describe "Users" do
|
||||
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])
|
||||
@@ -482,14 +388,13 @@ describe "Users" do
|
||||
expect(page).to have_link("Investments", href: "#investments")
|
||||
end
|
||||
|
||||
scenario "Not display budget investment tab when user is not following any budget investment" do
|
||||
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
|
||||
user = create(:user, :level_two)
|
||||
budget_investment = create(:budget_investment, author: user, followers: [user])
|
||||
|
||||
visit user_path(user, filter: "follows")
|
||||
@@ -500,6 +405,87 @@ describe "Users" do
|
||||
end
|
||||
end
|
||||
|
||||
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_css "#public_interests"
|
||||
expect(page).to have_content "Sport"
|
||||
end
|
||||
|
||||
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).not_to have_content("Sport")
|
||||
end
|
||||
end
|
||||
|
||||
describe "Initials" do
|
||||
scenario "display SVG avatars when loaded into the DOM" do
|
||||
login_as(create(:user))
|
||||
|
||||
Reference in New Issue
Block a user