From 89ace3c5bec8692adc8b1be5ffb79a7a1b63b630 Mon Sep 17 00:00:00 2001 From: Rachael Wright-Munn Date: Thu, 6 Jun 2024 18:10:44 +0000 Subject: [PATCH] Ensure friendship takes precendence over other permissions. If a profile has marked another profile as "friendly", then they want to befriend that profile, and we should prioritize that over any other permission constraints they've placed such as confirmed emails, etc. With the exception of myself - where friends are explicitly excluded. --- app/models/profile.rb | 5 +- app/policies/profile_policy.rb | 7 +-- spec/models/profile_spec.rb | 31 ++++++++++++ spec/policies/profile_policy_spec.rb | 74 ++++++++++++++++++++++++++++ 4 files changed, 113 insertions(+), 4 deletions(-) diff --git a/app/models/profile.rb b/app/models/profile.rb index 40196e9..8674ea3 100644 --- a/app/models/profile.rb +++ b/app/models/profile.rb @@ -17,7 +17,10 @@ class Profile < ApplicationRecord scope :with_authenticated, -> { where(visibility: %i[everyone authenticated]) } scope :nonblocked, ->(profile) { where.not(id: Friendship.blocks(profile).select(:buddy_id)) } - scope :befriended, ->(profile) { where(id: Friendship.friends_of(profile).select(:buddy_id), visibility: :friends) } + scope :befriended, lambda { |profile| + where(id: Friendship.friends_of(profile).select(:buddy_id)) + .where.not(visibility: :myself) + } # Relationships belongs_to :user diff --git a/app/policies/profile_policy.rb b/app/policies/profile_policy.rb index 1974edd..dd1327d 100644 --- a/app/policies/profile_policy.rb +++ b/app/policies/profile_policy.rb @@ -16,7 +16,7 @@ def index? # Whether the user can view the Profile's Handle, Bio, and Avatar. def show? return true if mine? || admin? || profile.visible_to_everyone? - confirmed_user? + confirmed_user? || profile.friends_with?(current_profile) end # This method controls whether a user can view a profile's details. @@ -29,8 +29,9 @@ def show? # * Myself - only the user can view - NOT EVEN EXISTING FRIENDS! def show_details? return true if mine? || admin? || profile.visible_to_everyone? - return confirmed_user? if profile.visible_to_authenticated? - profile.friends_with? current_profile if profile.visible_to_friends? + return false if profile.visible_to_myself? + return true if profile.friends_with? current_profile + confirmed_user? if profile.visible_to_authenticated? end def create? diff --git a/spec/models/profile_spec.rb b/spec/models/profile_spec.rb index 0d8ec3d..0d8000f 100644 --- a/spec/models/profile_spec.rb +++ b/spec/models/profile_spec.rb @@ -34,4 +34,35 @@ it { is_expected.to be_truthy } end end + + describe "#befriended" do + subject { described_class.befriended(profile) } + + context "with 'authenticated' visbility friend" do + let(:authenticated_profile) { create :profile, :authenticated } + let!(:friendship) { create :friendship, buddy: authenticated_profile, friend: profile, status: :accepted } + + it "does include" do + expect(subject).to include authenticated_profile + end + end + + context "with 'friends' visbility friend" do + let(:friends_profile) { create :profile, :friends } + let!(:friendship) { create :friendship, buddy: friends_profile, friend: profile, status: :accepted } + + it "does include" do + expect(subject).to include friends_profile + end + end + + context "with 'myself' visibility friend" do + let(:myself_profile) { create :profile, :myself } + let!(:friendship) { create :friendship, buddy: myself_profile, friend: profile, status: :accepted } + + it "does not include" do + expect(subject).not_to include myself_profile + end + end + end end diff --git a/spec/policies/profile_policy_spec.rb b/spec/policies/profile_policy_spec.rb index 885cf15..fc7d76e 100644 --- a/spec/policies/profile_policy_spec.rb +++ b/spec/policies/profile_policy_spec.rb @@ -23,6 +23,67 @@ end end + permissions :show? do + context "with viewing everyone profile" do + let(:profile) { build :profile, visibility: :everyone } + + context "with no user" do + it { expect(described_class).to permit(nil, profile) } + end + + context "with unconfirmed user" do + let(:user) { create :user, :unconfirmed } + + it { expect(described_class).to permit(user, profile) } + end + + context "with confirmed user" do + let(:user) { create :user } + + it { expect(described_class).to permit(user, profile) } + end + + context "with admin" do + let(:user) { create :user, :admin } + + it { expect(described_class).to permit(user, profile) } + end + end + + context "when viewing authenticated profile" do + let(:profile) { build :profile, visibility: :authenticated } + + context "with no user" do + it { expect(described_class).not_to permit(nil, profile) } + end + + context "with unconfirmed user" do + let(:user) { create :user, :unconfirmed } + + it { expect(described_class).not_to permit(user, profile) } + + context "when friends" do + let!(:user_profile) { create :profile, user: } + let!(:friendship) { create :friendship, buddy: profile, friend: user.profile, status: :accepted } + + it { expect(described_class).to permit(user, profile) } + end + end + + context "with confirmed user" do + let(:user) { create :user } + + it { expect(described_class).to permit(user, profile) } + end + + context "with admin" do + let(:user) { create :user, :admin } + + it { expect(described_class).to permit(user, profile) } + end + end + end + permissions :show_details? do context "with viewing everyone profile" do let(:profile) { build :profile, visibility: :everyone } @@ -61,6 +122,13 @@ let(:user) { create :user, :unconfirmed } it { expect(described_class).not_to permit(user, profile) } + + context "when friends" do + let!(:user_profile) { create :profile, user: } + let!(:friendship) { create :friendship, buddy: profile, friend: user.profile, status: :accepted } + + it { expect(described_class).to permit(user, profile) } + end end context "with confirmed user" do @@ -193,6 +261,12 @@ it { is_expected.to match_array %w[everyone myself] } end + context "when authenticated profile is friendly with you" do + let!(:friendship) { create :friendship, buddy: authenticated, friend: current_profile, status: :accepted } + + it { is_expected.to match_array %w[everyone authenticated myself] } + end + context "when you are blocked" do let!(:blocked_by_friends) { create :friendship, buddy: friends, friend: current_profile, status: :blocked } let!(:blocked_by_everyone) { create :friendship, buddy: everyone, friend: current_profile, status: :blocked }