Attachments: Hid edit/delete controls where lacking permission
Some checks are pending
analyse-php / build (push) Waiting to run
lint-js / build (push) Waiting to run
lint-php / build (push) Waiting to run
test-js / build (push) Waiting to run
test-migrations / build (8.1) (push) Waiting to run
test-migrations / build (8.2) (push) Waiting to run
test-migrations / build (8.3) (push) Waiting to run
test-migrations / build (8.4) (push) Waiting to run
test-php / build (8.1) (push) Waiting to run
test-php / build (8.2) (push) Waiting to run
test-php / build (8.3) (push) Waiting to run
test-php / build (8.4) (push) Waiting to run

Added test to cover.
Also migrated related ajax-delete-row component to ts.

For #5323
This commit is contained in:
Dan Brown 2024-12-11 20:38:30 +00:00
parent 0ece664475
commit fcf0bf79a9
No known key found for this signature in database
GPG Key ID: 46D9F943C24A2EF9
4 changed files with 74 additions and 22 deletions

View File

@ -1,12 +1,16 @@
import {onSelect} from '../services/dom.ts'; import {onSelect} from '../services/dom';
import {Component} from './component'; import {Component} from './component';
export class AjaxDeleteRow extends Component { export class AjaxDeleteRow extends Component {
protected row!: HTMLElement;
protected url!: string;
protected deleteButtons: HTMLElement[] = [];
setup() { setup() {
this.row = this.$el; this.row = this.$el;
this.url = this.$opts.url; this.url = this.$opts.url;
this.deleteButtons = this.$manyRefs.delete; this.deleteButtons = this.$manyRefs.delete || [];
onSelect(this.deleteButtons, this.runDelete.bind(this)); onSelect(this.deleteButtons, this.runDelete.bind(this));
} }
@ -21,8 +25,8 @@ export class AjaxDeleteRow extends Component {
} }
this.row.remove(); this.row.remove();
}).catch(() => { }).catch(() => {
this.row.style.opacity = null; this.row.style.removeProperty('opacity');
this.row.style.pointerEvents = null; this.row.style.removeProperty('pointer-events');
}); });
} }

View File

@ -8,20 +8,20 @@ export class Component {
/** /**
* The element that the component is registered upon. * The element that the component is registered upon.
* @type {Element} * @type {HTMLElement}
*/ */
$el = null; $el = null;
/** /**
* Mapping of referenced elements within the component. * Mapping of referenced elements within the component.
* @type {Object<string, Element>} * @type {Object<string, HTMLElement>}
*/ */
$refs = {}; $refs = {};
/** /**
* Mapping of arrays of referenced elements within the component so multiple * Mapping of arrays of referenced elements within the component so multiple
* references, sharing the same name, can be fetched. * references, sharing the same name, can be fetched.
* @type {Object<string, Element[]>} * @type {Object<string, HTMLElement[]>}
*/ */
$manyRefs = {}; $manyRefs = {};

View File

@ -15,23 +15,27 @@
option:event-emit-select:name="insert" option:event-emit-select:name="insert"
type="button" type="button"
title="{{ trans('entities.attachments_insert_link') }}" title="{{ trans('entities.attachments_insert_link') }}"
class="drag-card-action text-center text-link">@icon('link') </button> class="drag-card-action text-center text-link">@icon('link')</button>
<button component="event-emit-select" @if(userCan('attachment-update', $attachment))
option:event-emit-select:name="edit" <button component="event-emit-select"
option:event-emit-select:id="{{ $attachment->id }}" option:event-emit-select:name="edit"
type="button" option:event-emit-select:id="{{ $attachment->id }}"
title="{{ trans('common.edit') }}"
class="drag-card-action text-center text-link">@icon('edit')</button>
<div component="dropdown" class="flex-fill relative">
<button refs="dropdown@toggle"
type="button" type="button"
title="{{ trans('common.delete') }}" title="{{ trans('common.edit') }}"
class="drag-card-action text-center text-neg">@icon('close')</button> class="drag-card-action text-center text-link">@icon('edit')</button>
<div refs="dropdown@menu" class="dropdown-menu"> @endif
<p class="text-neg small px-m mb-xs">{{ trans('entities.attachments_delete') }}</p> @if(userCan('attachment-delete', $attachment))
<button refs="ajax-delete-row@delete" type="button" class="text-link small delete text-item">{{ trans('common.confirm') }}</button> <div component="dropdown" class="flex-fill relative">
<button refs="dropdown@toggle"
type="button"
title="{{ trans('common.delete') }}"
class="drag-card-action text-center text-neg">@icon('close')</button>
<div refs="dropdown@menu" class="dropdown-menu">
<p class="text-neg small px-m mb-xs">{{ trans('entities.attachments_delete') }}</p>
<button refs="ajax-delete-row@delete" type="button" class="text-link small delete text-item">{{ trans('common.confirm') }}</button>
</div>
</div> </div>
</div> @endif
</div> </div>
</div> </div>
@endforeach @endforeach

View File

@ -267,6 +267,50 @@ class AttachmentTest extends TestCase
} }
} }
public function test_attachment_delete_only_shows_with_permission()
{
$this->asAdmin();
$page = $this->entities->page();
$this->files->uploadAttachmentFile($this, 'upload_test.txt', $page->id);
$attachment = $page->attachments()->first();
$viewer = $this->users->viewer();
$this->permissions->grantUserRolePermissions($viewer, ['page-update-all', 'attachment-create-all']);
$resp = $this->actingAs($viewer)->get($page->getUrl('/edit'));
$html = $this->withHtml($resp);
$html->assertElementExists(".card[data-id=\"{$attachment->id}\"]");
$html->assertElementNotExists(".card[data-id=\"{$attachment->id}\"] button[title=\"Delete\"]");
$this->permissions->grantUserRolePermissions($viewer, ['attachment-delete-all']);
$resp = $this->actingAs($viewer)->get($page->getUrl('/edit'));
$html = $this->withHtml($resp);
$html->assertElementExists(".card[data-id=\"{$attachment->id}\"] button[title=\"Delete\"]");
}
public function test_attachment_edit_only_shows_with_permission()
{
$this->asAdmin();
$page = $this->entities->page();
$this->files->uploadAttachmentFile($this, 'upload_test.txt', $page->id);
$attachment = $page->attachments()->first();
$viewer = $this->users->viewer();
$this->permissions->grantUserRolePermissions($viewer, ['page-update-all', 'attachment-create-all']);
$resp = $this->actingAs($viewer)->get($page->getUrl('/edit'));
$html = $this->withHtml($resp);
$html->assertElementExists(".card[data-id=\"{$attachment->id}\"]");
$html->assertElementNotExists(".card[data-id=\"{$attachment->id}\"] button[title=\"Edit\"]");
$this->permissions->grantUserRolePermissions($viewer, ['attachment-update-all']);
$resp = $this->actingAs($viewer)->get($page->getUrl('/edit'));
$html = $this->withHtml($resp);
$html->assertElementExists(".card[data-id=\"{$attachment->id}\"] button[title=\"Edit\"]");
}
public function test_file_access_with_open_query_param_provides_inline_response_with_correct_content_type() public function test_file_access_with_open_query_param_provides_inline_response_with_correct_content_type()
{ {
$page = $this->entities->page(); $page = $this->entities->page();