test(12.2-05): prove relation child and protected file scoping through the router

- acme.deferred fixture plugin over testdata/deferred (test-only), two
  controllers, recording Form and Relation hooks, two admins
- TestRelationChildScope*: every child route answers 404 for another
  parent, a hidden parent and another admin's pending child, changes
  nothing; undeclared toolbar buttons 403 before SQL; pivot whitelist
- TestProtectedFile*: foreign, pending and public files 404; only jpeg,
  png, gif and webp inline; nosniff, no-store and sandbox CSP everywhere
This commit is contained in:
Jakub Zych
2026-10-02 20:10:10 +02:00
parent 162a8ec5a1
commit 9d2b1c1848
15 changed files with 1336 additions and 0 deletions

View File

@@ -0,0 +1,10 @@
name: New gadget
form: ~/plugins/acme/deferred/models/gadget/fields.yaml
modelClass: Gadget
defaultRedirect: acme/deferred/gadgets
create:
redirect: acme/deferred/gadgets/update/:id
redirectClose: acme/deferred/gadgets
update:
redirect: acme/deferred/gadgets
redirectClose: acme/deferred/gadgets

View File

@@ -0,0 +1,8 @@
list: ~/plugins/acme/deferred/models/gadget/columns.yaml
modelClass: Gadget
title: Gadgets
recordUrl: acme/deferred/gadgets/update/:id
recordsPerPage: 20
showCheckboxes: true
toolbar:
buttons: [create, delete]

View File

@@ -0,0 +1,36 @@
# A belongsToMany relation with a manage form and a pivot form, and a
# deferrable hasMany relation (nullable gadget_id) whose manage form lives
# in the plugin's models directory ($/ path) and carries a fileupload and a
# datepicker field. Both declare every toolbar button.
members:
label: Members
view:
list:
columns:
email:
label: Email
toolbarButtons: create|update|delete|link|unlink
showSearch: true
manage:
form: $/acme/deferred/models/member/fields.yaml
list:
columns:
email:
label: Email
showSearch: true
pivot:
form: $/acme/deferred/models/member/pivot_fields.yaml
parts:
label: Parts
view:
list:
columns:
label:
label: Label
toolbarButtons: create|update|delete|link|unlink
manage:
form: $/acme/deferred/models/part/fields.yaml
list:
columns:
label:
label: Label

View File

@@ -0,0 +1,8 @@
name: New gadget
form: ~/plugins/acme/deferred/models/gadget/locked_fields.yaml
modelClass: Gadget
defaultRedirect: acme/deferred/locked
create:
redirect: acme/deferred/locked/update/:id
update:
redirect: acme/deferred/locked

View File

@@ -0,0 +1,4 @@
list: ~/plugins/acme/deferred/models/gadget/columns.yaml
modelClass: Gadget
title: Locked gadgets
recordUrl: acme/deferred/locked/update/:id

View File

@@ -0,0 +1,20 @@
# The same relations with a reduced toolbar: parts may only be linked and
# members only unlinked, so every other relation route answers 403.
members:
label: Members
view:
list:
columns:
email:
label: Email
toolbarButtons: unlink
pivot:
form: $/acme/deferred/models/member/pivot_fields.yaml
parts:
label: Parts
view:
list:
columns:
label:
label: Label
toolbarButtons: link

View File

@@ -0,0 +1,10 @@
columns:
name:
label: Name
searchable: true
released_on:
label: Released on
type: date
opens_at:
label: Opens at
type: time

View File

@@ -0,0 +1,37 @@
fields:
name:
label: Name
type: text
required: true
released_on:
label: Released on
type: datepicker
mode: date
minDate: 2000-01-01
maxDate: 2030-12-31
starts_at:
label: Starts at
type: datepicker
mode: datetime
minDate: 2000-01-01
maxDate: 2030-12-31
opens_at:
label: Opens at
type: datepicker
mode: time
members:
type: relation-manager
relation: members
parts:
type: relation-manager
relation: parts
photos:
label: Photos
type: fileupload
mode: image
maxFiles: 3
manual:
label: Manual
type: fileupload
fileTypes: [pdf, png, svg, txt, html]
useCaption: true

View File

@@ -0,0 +1,15 @@
fields:
name:
label: Name
type: text
required: true
members:
type: relation-manager
relation: members
parts:
type: relation-manager
relation: parts
manual:
label: Manual
type: fileupload
required: true

View File

@@ -0,0 +1,5 @@
fields:
email:
label: Email
type: text
required: true

View File

@@ -0,0 +1,4 @@
fields:
pivot[note]:
label: Note
type: text

View File

@@ -0,0 +1,19 @@
fields:
label:
label: Label
type: text
required: true
due_on:
label: Due on
type: datepicker
mode: date
minDate: 2020-01-01
images:
label: Images
type: fileupload
mode: image
useCaption: true
sheet:
label: Sheet
type: fileupload
fileTypes: [txt, pdf]