Skip to content

Commit a36ad66

Browse files
committed
Add abilities based on Downloader associations
1 parent 2582562 commit a36ad66

File tree

6 files changed

+90
-12
lines changed

6 files changed

+90
-12
lines changed

app/models/ability.rb

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,22 @@ def user_with_roles_abilities
3535
return if user.roles.empty?
3636

3737
can :read, :pages_data
38-
organization_ability_restrictions
38+
39+
# record/download access for unrestricted organizations
40+
can :read, ActiveStorage::Attachment, { record: { organization: { restrict_downloads: false } } }
41+
can :read, MarcRecord, upload: { organization: { restrict_downloads: false } }
42+
can :read, Stream, organization: { restrict_downloads: false }
43+
can :read, Upload, organization: { restrict_downloads: false }
44+
45+
# record/download access for restricted organizations where access has been granted
46+
can :read, ActiveStorage::Attachment, { record: { organization: { id: permitted_organization_ids } } }
47+
can :read, MarcRecord, upload: { organization: { id: permitted_organization_ids } }
48+
can :read, Stream, organization: { id: permitted_organization_ids }
49+
can :read, Upload, organization: { id: permitted_organization_ids }
3950
end
4051

41-
def organization_ability_restrictions(restrictions = { restrict_downloads: false })
42-
can :read, ActiveStorage::Attachment, { record: { organization: restrictions } }
43-
can :read, MarcRecord, upload: { organization: restrictions }
44-
can :read, Stream, organization: restrictions
45-
can :read, Upload, organization: restrictions
52+
def permitted_organization_ids
53+
@permitted_organization_ids ||= user.organizations.flat_map(&:effective_downloadable_organizations).pluck(:id).uniq
4654
end
4755

4856
def site_admin_user_abilities
@@ -75,7 +83,11 @@ def organization_member_abilities
7583

7684
can %i[create], [Upload], organization: { id: member_organization_ids }
7785
can :read, AllowlistedJwt, resource_type: 'Organization', resource_id: member_organization_ids
78-
organization_ability_restrictions({ id: member_organization_ids })
86+
# record/download access for organizations where the user is a member
87+
can :read, ActiveStorage::Attachment, { record: { organization: { id: member_organization_ids } } }
88+
can :read, MarcRecord, upload: { organization: { id: member_organization_ids } }
89+
can :read, Stream, organization: { id: member_organization_ids }
90+
can :read, Upload, organization: { id: member_organization_ids }
7991
end
8092

8193
def member_organization_ids

app/models/organization.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,9 @@ def slug=(slug)
5555
def latest_upload
5656
uploads.recent.first
5757
end
58+
59+
def effective_downloadable_organizations
60+
@effective_downloadable_organizations ||=
61+
(downloadable_organizations + groups.flat_map(&:downloadable_organizations)).uniq
62+
end
5863
end

app/models/token_ability.rb

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,21 @@ def token_upload_abilities
4747
def token_download_abilities
4848
can :read, Organization
4949

50-
organization_ability_restrictions
51-
organization_ability_restrictions({ allowlisted_jwts: { jti: token_jti } })
50+
# record/download access for unrestricted organizations
51+
can :read, [Stream, Upload], organization: { restrict_downloads: false }
52+
can :read, ActiveStorage::Attachment, { record: { organization: { restrict_downloads: false } } }
53+
54+
# record/download access for organization linked to the token
55+
can :read, [Stream, Upload], organization: { allowlisted_jwts: { jti: token_jti } }
56+
can :read, ActiveStorage::Attachment, { record: { organization: { allowlisted_jwts: { jti: token_jti } } } }
57+
58+
# record/download access for restricted organizations where access has been granted
59+
can :read, [Stream, Upload], organization: { id: permitted_organization_ids }
60+
can :read, ActiveStorage::Attachment, { record: { organization: { id: permitted_organization_ids } } }
5261
end
5362

54-
def organization_ability_restrictions(restrictions = { restrict_downloads: false })
55-
can :read, [Stream, Upload], organization: restrictions
56-
can :read, ActiveStorage::Attachment, { record: { organization: restrictions } }
63+
def permitted_organization_ids
64+
@permitted_organization_ids ||= @allowlisted_jwt&.resource&.effective_downloadable_organizations&.pluck(:id)
5765
end
5866

5967
def token_jti

spec/models/ability_spec.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,22 @@
123123
it { is_expected.to be_able_to(:read, restricted_other_org) }
124124
it { is_expected.not_to be_able_to(:read, Upload.new(organization: restricted_other_org)) }
125125
it { is_expected.not_to be_able_to(:read, Stream.new(organization: restricted_other_org)) }
126+
it { is_expected.not_to be_able_to(:read, MarcRecord.new(upload: Upload.new(organization: restricted_other_org))) }
127+
it { is_expected.not_to be_able_to(:read, ActiveStorage::Attachment.new(record: Upload.new(organization: restricted_other_org))) }
128+
end
129+
130+
context 'when an organization is restricted but the user belongs to an organization granted access' do
131+
let(:user) { create(:user) }
132+
133+
before do
134+
user.add_role :member, organization
135+
Downloader.create!(organization: restricted_other_org, resource: organization)
136+
end
137+
138+
it { is_expected.to be_able_to(:read, Upload.new(organization: restricted_other_org)) }
139+
it { is_expected.to be_able_to(:read, Stream.new(organization: restricted_other_org)) }
140+
it { is_expected.to be_able_to(:read, MarcRecord.new(upload: Upload.new(organization: restricted_other_org))) }
141+
it { is_expected.to be_able_to(:read, ActiveStorage::Attachment.new(record: Upload.new(organization: restricted_other_org))) }
126142
end
127143
end
128144
end

spec/models/organization_spec.rb

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,4 +101,19 @@
101101
expect(organization.downloadable_organizations).to include(other_organization)
102102
end
103103
end
104+
105+
describe '#effective_downloadable_organizations' do
106+
let(:group) { create(:group) }
107+
let(:group_org) { create(:organization) }
108+
109+
before do
110+
GroupMembership.create!(group: group, organization: organization)
111+
Downloader.create!(resource: organization, organization: other_organization)
112+
Downloader.create!(resource: group, organization: group_org)
113+
end
114+
115+
it 'returns all organizations that can be downloaded by this organization via direct access or group membership' do
116+
expect(organization.effective_downloadable_organizations).to contain_exactly(other_organization, group_org)
117+
end
118+
end
104119
end

spec/models/token_ability_spec.rb

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,31 @@
2424
it { is_expected.to be_able_to(:read, unrestricted_other_org) }
2525
it { is_expected.to be_able_to(:read, restricted_other_org) }
2626

27+
it { is_expected.to be_able_to(:read, create(:upload, :binary_marc, organization: organization)) }
28+
it { is_expected.to be_able_to(:read, create(:upload, :binary_marc, organization: unrestricted_other_org)) }
29+
it { is_expected.not_to be_able_to(:read, create(:upload, :binary_marc, organization: restricted_other_org)) }
30+
31+
it { is_expected.to be_able_to(:read, create(:stream, organization: organization)) }
32+
it { is_expected.to be_able_to(:read, create(:stream, organization: unrestricted_other_org)) }
33+
it { is_expected.not_to be_able_to(:read, create(:stream, organization: restricted_other_org)) }
34+
35+
it { is_expected.to be_able_to(:read, ActiveStorage::Attachment.new(record: Upload.new(organization: organization))) }
36+
it { is_expected.to be_able_to(:read, ActiveStorage::Attachment.new(record: Upload.new(organization: unrestricted_other_org))) }
37+
it { is_expected.not_to be_able_to(:read, ActiveStorage::Attachment.new(record: Upload.new(organization: restricted_other_org))) }
38+
2739
it { is_expected.to be_able_to(:create, Upload.new(organization: organization)) }
2840
it { is_expected.not_to be_able_to(:create, Upload.new(organization: unrestricted_other_org)) }
2941

42+
context 'when the organization has been granted record/download access to the restricted organization' do
43+
before do
44+
Downloader.create!(organization: restricted_other_org, resource: organization)
45+
end
46+
47+
it { is_expected.to be_able_to(:read, create(:upload, :binary_marc, organization: restricted_other_org)) }
48+
it { is_expected.to be_able_to(:read, create(:stream, organization: restricted_other_org)) }
49+
it { is_expected.to be_able_to(:read, ActiveStorage::Attachment.new(record: Upload.new(organization: restricted_other_org))) }
50+
end
51+
3052
context 'with a token scoped to reads' do
3153
let(:token_attributes) { { scope: 'download' } }
3254

0 commit comments

Comments
 (0)