Skip to content

Commit fcf0bf7

Browse files
committed
Attachments: Hid edit/delete controls where lacking permission
Added test to cover. Also migrated related ajax-delete-row component to ts. For #5323
1 parent 0ece664 commit fcf0bf7

File tree

4 files changed

+74
-22
lines changed

4 files changed

+74
-22
lines changed

resources/js/components/ajax-delete-row.js renamed to resources/js/components/ajax-delete-row.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
1-
import {onSelect} from '../services/dom.ts';
1+
import {onSelect} from '../services/dom';
22
import {Component} from './component';
33

44
export class AjaxDeleteRow extends Component {
55

6+
protected row!: HTMLElement;
7+
protected url!: string;
8+
protected deleteButtons: HTMLElement[] = [];
9+
610
setup() {
711
this.row = this.$el;
812
this.url = this.$opts.url;
9-
this.deleteButtons = this.$manyRefs.delete;
13+
this.deleteButtons = this.$manyRefs.delete || [];
1014

1115
onSelect(this.deleteButtons, this.runDelete.bind(this));
1216
}
@@ -21,8 +25,8 @@ export class AjaxDeleteRow extends Component {
2125
}
2226
this.row.remove();
2327
}).catch(() => {
24-
this.row.style.opacity = null;
25-
this.row.style.pointerEvents = null;
28+
this.row.style.removeProperty('opacity');
29+
this.row.style.removeProperty('pointer-events');
2630
});
2731
}
2832

resources/js/components/component.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,20 @@ export class Component {
88

99
/**
1010
* The element that the component is registered upon.
11-
* @type {Element}
11+
* @type {HTMLElement}
1212
*/
1313
$el = null;
1414

1515
/**
1616
* Mapping of referenced elements within the component.
17-
* @type {Object<string, Element>}
17+
* @type {Object<string, HTMLElement>}
1818
*/
1919
$refs = {};
2020

2121
/**
2222
* Mapping of arrays of referenced elements within the component so multiple
2323
* references, sharing the same name, can be fetched.
24-
* @type {Object<string, Element[]>}
24+
* @type {Object<string, HTMLElement[]>}
2525
*/
2626
$manyRefs = {};
2727

resources/views/attachments/manager-list.blade.php

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,27 @@ class="card drag-card">
1515
option:event-emit-select:name="insert"
1616
type="button"
1717
title="{{ trans('entities.attachments_insert_link') }}"
18-
class="drag-card-action text-center text-link">@icon('link') </button>
19-
<button component="event-emit-select"
20-
option:event-emit-select:name="edit"
21-
option:event-emit-select:id="{{ $attachment->id }}"
22-
type="button"
23-
title="{{ trans('common.edit') }}"
24-
class="drag-card-action text-center text-link">@icon('edit')</button>
25-
<div component="dropdown" class="flex-fill relative">
26-
<button refs="dropdown@toggle"
18+
class="drag-card-action text-center text-link">@icon('link')</button>
19+
@if(userCan('attachment-update', $attachment))
20+
<button component="event-emit-select"
21+
option:event-emit-select:name="edit"
22+
option:event-emit-select:id="{{ $attachment->id }}"
2723
type="button"
28-
title="{{ trans('common.delete') }}"
29-
class="drag-card-action text-center text-neg">@icon('close')</button>
30-
<div refs="dropdown@menu" class="dropdown-menu">
31-
<p class="text-neg small px-m mb-xs">{{ trans('entities.attachments_delete') }}</p>
32-
<button refs="ajax-delete-row@delete" type="button" class="text-link small delete text-item">{{ trans('common.confirm') }}</button>
24+
title="{{ trans('common.edit') }}"
25+
class="drag-card-action text-center text-link">@icon('edit')</button>
26+
@endif
27+
@if(userCan('attachment-delete', $attachment))
28+
<div component="dropdown" class="flex-fill relative">
29+
<button refs="dropdown@toggle"
30+
type="button"
31+
title="{{ trans('common.delete') }}"
32+
class="drag-card-action text-center text-neg">@icon('close')</button>
33+
<div refs="dropdown@menu" class="dropdown-menu">
34+
<p class="text-neg small px-m mb-xs">{{ trans('entities.attachments_delete') }}</p>
35+
<button refs="ajax-delete-row@delete" type="button" class="text-link small delete text-item">{{ trans('common.confirm') }}</button>
36+
</div>
3337
</div>
34-
</div>
38+
@endif
3539
</div>
3640
</div>
3741
@endforeach

tests/Uploads/AttachmentTest.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,50 @@ public function test_data_and_js_links_cannot_be_attached_to_a_page()
267267
}
268268
}
269269

270+
public function test_attachment_delete_only_shows_with_permission()
271+
{
272+
$this->asAdmin();
273+
$page = $this->entities->page();
274+
$this->files->uploadAttachmentFile($this, 'upload_test.txt', $page->id);
275+
$attachment = $page->attachments()->first();
276+
$viewer = $this->users->viewer();
277+
278+
$this->permissions->grantUserRolePermissions($viewer, ['page-update-all', 'attachment-create-all']);
279+
280+
$resp = $this->actingAs($viewer)->get($page->getUrl('/edit'));
281+
$html = $this->withHtml($resp);
282+
$html->assertElementExists(".card[data-id=\"{$attachment->id}\"]");
283+
$html->assertElementNotExists(".card[data-id=\"{$attachment->id}\"] button[title=\"Delete\"]");
284+
285+
$this->permissions->grantUserRolePermissions($viewer, ['attachment-delete-all']);
286+
287+
$resp = $this->actingAs($viewer)->get($page->getUrl('/edit'));
288+
$html = $this->withHtml($resp);
289+
$html->assertElementExists(".card[data-id=\"{$attachment->id}\"] button[title=\"Delete\"]");
290+
}
291+
292+
public function test_attachment_edit_only_shows_with_permission()
293+
{
294+
$this->asAdmin();
295+
$page = $this->entities->page();
296+
$this->files->uploadAttachmentFile($this, 'upload_test.txt', $page->id);
297+
$attachment = $page->attachments()->first();
298+
$viewer = $this->users->viewer();
299+
300+
$this->permissions->grantUserRolePermissions($viewer, ['page-update-all', 'attachment-create-all']);
301+
302+
$resp = $this->actingAs($viewer)->get($page->getUrl('/edit'));
303+
$html = $this->withHtml($resp);
304+
$html->assertElementExists(".card[data-id=\"{$attachment->id}\"]");
305+
$html->assertElementNotExists(".card[data-id=\"{$attachment->id}\"] button[title=\"Edit\"]");
306+
307+
$this->permissions->grantUserRolePermissions($viewer, ['attachment-update-all']);
308+
309+
$resp = $this->actingAs($viewer)->get($page->getUrl('/edit'));
310+
$html = $this->withHtml($resp);
311+
$html->assertElementExists(".card[data-id=\"{$attachment->id}\"] button[title=\"Edit\"]");
312+
}
313+
270314
public function test_file_access_with_open_query_param_provides_inline_response_with_correct_content_type()
271315
{
272316
$page = $this->entities->page();

0 commit comments

Comments
 (0)