Skip to content

Commit 1f44fa0

Browse files
committed
Enhance available_addresses_for and available_buildings_for methods with context-based logic and comprehensive specs
1 parent b951c2f commit 1f44fa0

File tree

2 files changed

+189
-11
lines changed

2 files changed

+189
-11
lines changed

app/models/better_together/geography/locatable_location.rb

Lines changed: 56 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -66,16 +66,65 @@ def building?
6666
end
6767

6868
# Helper method for forms - get available addresses for the user/context
69-
def self.available_addresses_for(_context = nil)
70-
# This would be customized based on your business logic
71-
# For example, user's addresses, community addresses, etc.
72-
BetterTogether::Address.includes(:string_translations)
69+
def self.available_addresses_for(context = nil)
70+
return BetterTogether::Address.none unless context
71+
72+
case context
73+
when BetterTogether::Person
74+
# Use policy to get authorized addresses for the person
75+
user = context.user
76+
if user
77+
policy_scope = BetterTogether::AddressPolicy::Scope.new(user, BetterTogether::Address).resolve
78+
policy_scope.includes(:contact_detail)
79+
else
80+
# Person without user - only public addresses
81+
BetterTogether::Address.where(privacy: 'public').includes(:contact_detail)
82+
end
83+
when BetterTogether::Community
84+
# Communities can access public addresses and their own addresses
85+
community_address_ids = BetterTogether::Address
86+
.joins(:contact_detail)
87+
.where(better_together_contact_details: { contactable: context })
88+
.pluck(:id)
89+
90+
public_address_ids = BetterTogether::Address.where(privacy: 'public').pluck(:id)
91+
92+
# Combine IDs and query with includes
93+
all_address_ids = (community_address_ids + public_address_ids).uniq
94+
BetterTogether::Address.where(id: all_address_ids).includes(:contact_detail)
95+
else
96+
# Default: return public addresses only
97+
BetterTogether::Address.where(privacy: 'public').includes(:contact_detail)
98+
end
7399
end
74100

75101
# Helper method for forms - get available buildings for the user/context
76-
def self.available_buildings_for(_context = nil)
77-
# This would be customized based on your business logic
78-
BetterTogether::Infrastructure::Building.includes(:string_translations)
102+
def self.available_buildings_for(context = nil)
103+
return BetterTogether::Infrastructure::Building.none unless context
104+
105+
case context
106+
when BetterTogether::Person
107+
if context.user
108+
# Person with user can access buildings they created and public buildings
109+
BetterTogether::Infrastructure::Building
110+
.where(creator: context)
111+
.or(BetterTogether::Infrastructure::Building.where(privacy: 'public'))
112+
.includes(:string_translations, :address)
113+
else
114+
# Person without user - only public buildings
115+
BetterTogether::Infrastructure::Building
116+
.where(privacy: 'public')
117+
.includes(:string_translations, :address)
118+
end
119+
when BetterTogether::Community
120+
# Communities get public buildings for now
121+
BetterTogether::Infrastructure::Building
122+
.where(privacy: 'public')
123+
.includes(:string_translations, :address)
124+
else
125+
# Fallback: return empty scope for unsupported context types
126+
BetterTogether::Infrastructure::Building.none
127+
end
79128
end
80129

81130
private

spec/models/better_together/geography/locatable_location_spec.rb

Lines changed: 133 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -206,14 +206,143 @@ module Geography # rubocop:todo Metrics/ModuleLength
206206

207207
describe 'class methods' do
208208
describe '.available_addresses_for' do
209-
it 'returns addresses with translations' do
210-
expect(described_class.available_addresses_for).to respond_to(:includes)
209+
let(:user) { create(:better_together_user, :confirmed) }
210+
let(:person) { user.person }
211+
let(:community) { create(:better_together_community) }
212+
let!(:public_address) { create(:better_together_address, privacy: 'public') }
213+
let!(:private_address) { create(:better_together_address, privacy: 'private') }
214+
215+
context 'when context is nil' do
216+
it 'returns empty scope' do
217+
expect(described_class.available_addresses_for(nil)).to eq(BetterTogether::Address.none)
218+
end
219+
end
220+
221+
context 'when context is a Person with user' do
222+
let!(:person_contact_detail) do
223+
create(:better_together_contact_detail, contactable: person)
224+
end
225+
226+
let!(:person_address) do
227+
create(:better_together_address, privacy: 'private', contact_detail: person_contact_detail)
228+
end
229+
230+
it 'uses policy scope to return authorized addresses' do
231+
result = described_class.available_addresses_for(person)
232+
233+
# Should include public addresses at minimum
234+
expect(result).to include(public_address)
235+
end
236+
237+
it 'includes proper associations' do
238+
result = described_class.available_addresses_for(person)
239+
240+
expect(result.includes_values).to include(:contact_detail)
241+
end
242+
end
243+
244+
context 'when context is a Person without user' do
245+
let(:person_without_user) { create(:better_together_person) }
246+
247+
it 'returns only public addresses' do
248+
result = described_class.available_addresses_for(person_without_user)
249+
250+
expect(result).to include(public_address)
251+
expect(result).not_to include(private_address)
252+
end
253+
end
254+
255+
context 'when context is a Community' do
256+
let!(:community_contact_detail) do
257+
create(:better_together_contact_detail, contactable: community)
258+
end
259+
260+
let!(:community_address) do
261+
create(:better_together_address, privacy: 'private', contact_detail: community_contact_detail)
262+
end
263+
264+
it 'returns community addresses and public addresses' do
265+
result = described_class.available_addresses_for(community)
266+
267+
expect(result).to include(community_address)
268+
expect(result).to include(public_address)
269+
expect(result).not_to include(private_address)
270+
end
271+
end
272+
273+
context 'when context is unsupported type' do
274+
it 'returns only public addresses' do
275+
result = described_class.available_addresses_for('unsupported')
276+
277+
expect(result).to include(public_address)
278+
expect(result).not_to include(private_address)
279+
end
211280
end
212281
end
213282

214283
describe '.available_buildings_for' do
215-
it 'returns buildings with translations' do
216-
expect(described_class.available_buildings_for).to respond_to(:includes)
284+
let(:user) { create(:better_together_user, :confirmed) }
285+
let(:person) { user.person }
286+
let(:community) { create(:better_together_community) }
287+
let!(:public_building) { create(:better_together_infrastructure_building, privacy: 'public') }
288+
let!(:private_building) { create(:better_together_infrastructure_building, privacy: 'private') }
289+
290+
context 'when context is nil' do
291+
it 'returns empty scope' do
292+
expect(described_class.available_buildings_for(nil)).to eq(BetterTogether::Infrastructure::Building.none)
293+
end
294+
end
295+
296+
context 'when context is a Person with user' do
297+
let!(:person_building) do
298+
create(:better_together_infrastructure_building,
299+
creator: person,
300+
privacy: 'private')
301+
end
302+
303+
it 'uses policy scope to return authorized buildings' do
304+
result = described_class.available_buildings_for(person)
305+
306+
# Should include public buildings and person's own buildings
307+
expect(result).to include(public_building)
308+
expect(result).to include(person_building)
309+
expect(result).not_to include(private_building)
310+
end
311+
312+
it 'includes proper associations' do
313+
result = described_class.available_buildings_for(person)
314+
315+
expect(result.includes_values).to include(:string_translations)
316+
expect(result.includes_values).to include(:address)
317+
end
318+
end
319+
320+
context 'when context is a Person without user' do
321+
let(:person_without_user) { create(:better_together_person) }
322+
323+
it 'returns only public buildings' do
324+
result = described_class.available_buildings_for(person_without_user)
325+
326+
expect(result).to include(public_building)
327+
expect(result).not_to include(private_building)
328+
end
329+
end
330+
331+
context 'when context is a Community' do
332+
it 'returns only public buildings' do
333+
result = described_class.available_buildings_for(community)
334+
335+
expect(result).to include(public_building)
336+
expect(result).not_to include(private_building)
337+
end
338+
end
339+
340+
context 'when context is unsupported type' do
341+
it 'returns empty scope' do
342+
result = described_class.available_buildings_for('unsupported')
343+
344+
expect(result).to eq(BetterTogether::Infrastructure::Building.none)
345+
end
217346
end
218347
end
219348

0 commit comments

Comments
 (0)