fix(permissions): viewers open posts read-only instead of hitting the editor
A viewer clicking a draft/scheduled post landed on the editor route (authorizes update) and got a 403. The post list/calendar routed every editable post to the edit page, and PostController@show redirected draft/scheduled posts to the editor for everyone. - show only redirects to the editor when the user can update the post; viewers get the read-only Show page - posts index + calendar route to show (not edit) when the user cannot create posts - cover viewer-sees-show, member-redirected-to-editor, and viewer-403-on-direct-edit in WorkspaceRolePermissionsTest
This commit is contained in:
parent
0eb6f4df24
commit
8b52ea2082
4 changed files with 24 additions and 5 deletions
|
|
@ -212,7 +212,8 @@ public function show(Request $request, Post $post): Response|RedirectResponse
|
|||
|
||||
$this->authorize('view', $post);
|
||||
|
||||
if (in_array($post->status, [PostStatus::Draft, PostStatus::Scheduled], true)) {
|
||||
if ($request->user()->can('update', $post)
|
||||
&& in_array($post->status, [PostStatus::Draft, PostStatus::Scheduled], true)) {
|
||||
return redirect()->route('app.posts.edit', $post);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -237,7 +237,7 @@ const getStatusColor = (status: string): string => {
|
|||
const EDITABLE_STATUSES: readonly string[] = [PostStatus.Draft, PostStatus.Scheduled];
|
||||
|
||||
const getPostUrl = (post: Post): string => {
|
||||
return EDITABLE_STATUSES.includes(post.status)
|
||||
return canCreatePost.value && EDITABLE_STATUSES.includes(post.status)
|
||||
? editPost.url(post.id)
|
||||
: showPost.url(post.id);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -143,13 +143,13 @@ const DELETABLE_STATUSES: readonly string[] = [PostStatus.Draft, PostStatus.Sche
|
|||
const canEdit = (post: Post): boolean => EDITABLE_STATUSES.includes(post.status);
|
||||
const canDelete = (post: Post): boolean => DELETABLE_STATUSES.includes(post.status);
|
||||
|
||||
const { canCreatePost } = useWorkspaceRole();
|
||||
|
||||
const postUrl = (post: Post): string =>
|
||||
canEdit(post) ? editPost.url(post.id) : showPost.url(post.id);
|
||||
canCreatePost.value && canEdit(post) ? editPost.url(post.id) : showPost.url(post.id);
|
||||
|
||||
const deleteModal = ref<InstanceType<typeof ConfirmDeleteModal> | null>(null);
|
||||
|
||||
const { canCreatePost } = useWorkspaceRole();
|
||||
|
||||
const handleDelete = (post: Post) => {
|
||||
deleteModal.value?.open({
|
||||
url: destroyPost.url(post.id),
|
||||
|
|
|
|||
|
|
@ -60,3 +60,21 @@
|
|||
'user_id' => $this->viewer->id,
|
||||
]);
|
||||
});
|
||||
|
||||
test('a viewer opening a draft post sees the read-only page instead of the editor', function () {
|
||||
$this->actingAs($this->viewer)
|
||||
->get(route('app.posts.show', $this->post))
|
||||
->assertOk();
|
||||
});
|
||||
|
||||
test('a member opening a draft post is redirected to the editor', function () {
|
||||
$this->actingAs($this->member)
|
||||
->get(route('app.posts.show', $this->post))
|
||||
->assertRedirect(route('app.posts.edit', $this->post));
|
||||
});
|
||||
|
||||
test('a viewer cannot open the post editor directly', function () {
|
||||
$this->actingAs($this->viewer)
|
||||
->get(route('app.posts.edit', $this->post))
|
||||
->assertForbidden();
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue