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..7576309 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' visibility 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' visibility 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 } diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 01f7c97..4d5e486 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -48,13 +48,14 @@ # The settings below are suggested to provide a good initial experience # with RSpec, but feel free to customize to your heart's content. - # # This allows you to limit a spec run to individual examples or groups - # # you care about by tagging them with `:focus` metadata. When nothing - # # is tagged with `:focus`, all examples get run. RSpec also provides - # # aliases for `it`, `describe`, and `context` that include `:focus` - # # metadata: `fit`, `fdescribe` and `fcontext`, respectively. - # config.filter_run_when_matching :focus - # + + # This allows you to limit a spec run to individual examples or groups + # you care about by tagging them with `:focus` metadata. When nothing + # is tagged with `:focus`, all examples get run. RSpec also provides + # aliases for `it`, `describe`, and `context` that include `:focus` + # metadata: `fit`, `fdescribe` and `fcontext`, respectively. + config.filter_run_when_matching :focus + # # Allows RSpec to persist some state between runs in order to support # # the `--only-failures` and `--next-failure` CLI options. We recommend # # you configure your source control system to ignore this file. @@ -66,17 +67,17 @@ # # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ # # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode # config.disable_monkey_patching! - # - # # Many RSpec users commonly either run the entire suite or an individual - # # file, and it's useful to allow more verbose output when running an - # # individual spec file. - # if config.files_to_run.one? - # # Use the documentation formatter for detailed output, - # # unless a formatter has already been configured - # # (e.g. via a command-line flag). - # config.default_formatter = "doc" - # end - # + + # Many RSpec users commonly either run the entire suite or an individual + # file, and it's useful to allow more verbose output when running an + # individual spec file. + if config.files_to_run.one? + # Use the documentation formatter for detailed output, + # unless a formatter has already been configured + # (e.g. via a command-line flag). + config.default_formatter = "doc" + end + # # Print the 10 slowest examples and example groups at the # # end of the spec run, to help surface which specs are running # # particularly slow.