Skip to content

Commit cadc13f

Browse files
committed
Open the create form on the ACL the Collection would inherit
Atlas copies the destination's read AND edit lists onto a new child wholesale, group grants included - a Collection made under a public Community is born public, and one made under a container granting 'editors' is born granting 'editors'. The form defaulted to Private with no grant rows, which would have narrowed every child of a public container and dropped the inherited grants along with it. Open it holding what the child would inherit instead: the reader sees the audience the Collection is about to be born with, and submitting untouched lands exactly where a bare create would.
1 parent 8fd7ff5 commit cadc13f

3 files changed

Lines changed: 65 additions & 26 deletions

File tree

app/controllers/concerns/transformable.rb

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -106,26 +106,32 @@ def assign_visibility_ceiling(resource)
106106
@public_allowed = true
107107
end
108108

109-
# Everything the permissions section of a *create* form needs. The resource
110-
# does not exist yet, so it has no grants to show and nothing beneath it to
111-
# cascade to: the rows start empty and @narrowing_allowed stays unset, which
112-
# is what puts shared/_visibility_control on its ordinary offered branch (see
113-
# the `== false` test there).
109+
# Everything the permissions section of a *create* form needs.
114110
#
115-
# Order is load-bearing. The ceiling is read off the destination container's
116-
# envelope, which @permissions holds from the create gate until the last line
117-
# replaces it with the form's (empty) row list.
111+
# Atlas copies the destination's read ACL onto a new child wholesale — group
112+
# grants included — so the form opens holding exactly what the resource would
113+
# be born with, rather than a blank slate or a fixed default. That is what
114+
# lets it add a choice without moving the outcome: submit it untouched and the
115+
# ACL is the one inheritance would have produced anyway. A form that defaulted
116+
# to Private instead would quietly narrow every child of a public container,
117+
# and drop the inherited group grants with it.
118+
#
119+
# @narrowing_allowed stays unset, which is what puts _visibility_control on
120+
# its ordinary offered branch (see the `== false` test there) — there is
121+
# nothing inside a resource that does not exist to cascade to.
122+
#
123+
# Order is load-bearing twice. The ceiling reads the destination's envelope,
124+
# and pretty_resource_permissions then MUTATES that same envelope (stripping
125+
# the public sentinel) before returning the form's rows, so the ceiling has to
126+
# be settled first.
118127
#
119128
# @param destination_id [String] the container this resource will be made in.
120129
def new_form_permissions!(destination_id)
130+
inherited = @permissions
121131
assign_destination_ceiling(destination_id)
122-
# Private, matching the ACL Atlas mints a container with (read: []). The
123-
# control adds a choice here; it must not also move the outcome for someone
124-
# who leaves it alone, and of the two directions to be wrong in silently,
125-
# publishing is the one that cannot be taken back.
126-
@public = false
132+
@public = @public_allowed
127133
@groups = groups_for_permissions_picker
128-
@permissions = []
134+
@permissions = pretty_resource_permissions(inherited)
129135
end
130136

131137
# The create-form counterpart to {#assign_visibility_ceiling}. That one walks

app/views/collections/new.html.haml

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,12 @@
1212
= c.text_field :title, required: true
1313
= c.text_area :description, rows: 10
1414
15-
-# The two controls the Permissions tab offers, so a Collection is born with
16-
-# the audience its creator chose instead of inheriting one silently and
17-
-# needing a second visit to correct it. No embargo field — that is a
18-
-# Work-level affordance — and no narrowing confirmation, because a
19-
-# Collection this new has nothing inside it to cascade to.
15+
-# The two controls the Permissions tab offers. They open holding the ACL
16+
-# this Collection would inherit from its destination, so the audience it is
17+
-# about to be born with is visible and editable here rather than only
18+
-# discoverable afterwards. No embargo field — that is a Work-level
19+
-# affordance — and no narrowing confirmation, because a Collection this new
20+
-# has nothing inside it to cascade to.
2021
%h4.pt-4.pb-2 Permissions
2122
.row
2223
.col-sm

spec/controllers/collections_controller_spec.rb

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -270,14 +270,26 @@
270270
context 'permissions section' do
271271
render_views
272272

273-
it 'renders the group grant editor with no committed rows' do
273+
it 'renders the group grant editor' do
274274
get :new, params: { community_id: community.id }
275275

276-
expect(assigns(:permissions)).to eq([])
277276
expect(response.body).to include('Group Permissions')
278277
expect(response.body).to include('collection[permissions][new][group_id]')
279278
end
280279

280+
# Atlas copies the destination's read ACL onto a new child, so the form has
281+
# to open holding it. Showing a blank slate would invite a curator to
282+
# submit one and silently drop grants they never saw.
283+
it 'prefills the grants the new collection would inherit' do
284+
AtlasRb::Community.metadata(community.id,
285+
{ 'permissions' => { 'read' => ['editors'] } }, nuid: '000000004')
286+
287+
get :new, params: { community_id: community.id }
288+
289+
expect(assigns(:permissions).map(&:group_id)).to include('editors')
290+
expect(response.body).to include('collection[permissions][1][group_id]')
291+
end
292+
281293
# A brand-new Collection has nothing inside it, so the cascade warning the
282294
# edit tab carries must not appear — and leaving @narrowing_allowed unset
283295
# is what keeps _visibility_control off its locked branch.
@@ -298,18 +310,20 @@
298310
expect(CGI.unescapeHTML(response.body)).to include("#{community.title}” is private")
299311
end
300312

301-
# Private matches the ACL Atlas mints a Collection with, so the control
302-
# adds a choice without moving the outcome for a reader who ignores it.
303-
it 'offers the choice under a public destination and preselects Private' do
313+
# Public is what the Collection would inherit, so preselecting it is what
314+
# lets the control add a choice without moving the outcome for a reader
315+
# who ignores it. Preselecting Private would narrow every child of a
316+
# public container instead.
317+
it 'offers the choice under a public destination and preselects the inherited Public' do
304318
publicize_ancestry!(community: community)
305319

306320
get :new, params: { community_id: community.id }
307321

308322
control = response.parsed_body.at_css('[name="mass"]')
309323
expect(assigns(:public_allowed)).to be(true)
310-
expect(assigns(:public)).to be(false)
324+
expect(assigns(:public)).to be(true)
311325
expect(control.name).to eq('select')
312-
expect(control.at_css('option[selected]')['value']).to eq('private')
326+
expect(control.at_css('option[selected]')['value']).to eq('public')
313327
end
314328
end
315329
end
@@ -372,6 +386,24 @@
372386
expect(response).to redirect_to(new_community_collection_path(community.id))
373387
end
374388

389+
# Atlas copies the destination's ACL onto a new child, and the form opens
390+
# holding that copy — so submitting it untouched has to land where a bare
391+
# create would. Otherwise adding the control would itself change what
392+
# creating a Collection does.
393+
it 'lands on the inherited ACL when the prefilled controls are submitted untouched' do
394+
publicize_ancestry!(community: community)
395+
reference = AtlasRb::Collection.create(community.id, nuid: '000000004')
396+
inherited = Array(AtlasRb::Resource.permissions(reference.id)&.read)
397+
398+
post :create, params: { community_id: community.id, mass: 'public',
399+
collection: { title: 'InheritedCollection', description: 'D' } }
400+
401+
created_id = response.location.split('/').last
402+
expect(Array(AtlasRb::Resource.permissions(created_id)&.read)).to match_array(inherited)
403+
ensure
404+
[reference&.id, created_id].compact.each { |id| AtlasRb::Collection.tombstone(id) }
405+
end
406+
375407
it 'applies the submitted visibility and group grants to the new collection' do
376408
publicize_ancestry!(community: community)
377409

0 commit comments

Comments
 (0)