standardization of policies/permissions
This commit is contained in:
parent
c60033b365
commit
188c4435cb
@ -13,6 +13,13 @@ class MutationResource extends BaseResource
|
||||
*/
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return parent::toArray($request);
|
||||
$data = parent::toArray($request);
|
||||
|
||||
$data['can'] = [
|
||||
'update' => $request->user()?->can('update', $this->resource) ?? false,
|
||||
'void' => $request->user()?->can('void', $this->resource) ?? false,
|
||||
];
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,8 +24,9 @@ class MutationPolicy
|
||||
public function update(User $user, Mutation $mutation): bool
|
||||
{
|
||||
$dynamic = $mutation->ledger->dynamic;
|
||||
$isOwner = $dynamic->participants()->where('user_id', $user->id)->where('role', 'owner')->exists();
|
||||
|
||||
return $dynamic->participants()->where('user_id', $user->id)->where('role', 'owner')->exists();
|
||||
return $isOwner && $mutation->status === 'pending';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -34,7 +35,8 @@ class MutationPolicy
|
||||
public function void(User $user, Mutation $mutation): bool
|
||||
{
|
||||
$dynamic = $mutation->ledger->dynamic;
|
||||
$isOwner = $dynamic->participants()->where('user_id', $user->id)->where('role', 'owner')->exists();
|
||||
|
||||
return $dynamic->participants()->where('user_id', $user->id)->where('role', 'owner')->exists();
|
||||
return $isOwner && $mutation->status !== 'voided';
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,13 +17,16 @@ const props = defineProps<{
|
||||
created_at: string;
|
||||
chat: any;
|
||||
media?: Array<{ id: number; url: string; mime_type: string }>;
|
||||
can: {
|
||||
update: boolean;
|
||||
void: boolean;
|
||||
};
|
||||
}>;
|
||||
participants?: Array<{
|
||||
id: number;
|
||||
name: string;
|
||||
pivot?: { role: string };
|
||||
}>;
|
||||
isOwner: boolean;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
@ -167,25 +170,25 @@ function getAmountClass(amount: number): string {
|
||||
|
||||
<!-- Owner Approve/Reject Actions -->
|
||||
<div
|
||||
v-if="isOwner && (mutation.status === 'pending' || mutation.status === 'approved')"
|
||||
v-if="mutation.can.update || mutation.can.void"
|
||||
class="c-mutation-list__actions"
|
||||
>
|
||||
<button
|
||||
v-if="mutation.status === 'pending'"
|
||||
v-if="mutation.can.update"
|
||||
@click="updateStatus(mutation.id, 'approved')"
|
||||
class="c-mutation-list__approve-btn"
|
||||
>
|
||||
Approve
|
||||
</button>
|
||||
<button
|
||||
v-if="mutation.status === 'pending'"
|
||||
v-if="mutation.can.update"
|
||||
@click="updateStatus(mutation.id, 'rejected')"
|
||||
class="c-mutation-list__reject-btn"
|
||||
>
|
||||
Reject
|
||||
</button>
|
||||
<button
|
||||
v-if="mutation.status !== 'voided'"
|
||||
v-if="mutation.can.void"
|
||||
@click="voidMutation(mutation.id)"
|
||||
class="c-mutation-list__void-btn"
|
||||
>
|
||||
|
||||
@ -2,22 +2,26 @@
|
||||
import { Head, useForm } from '@inertiajs/vue3';
|
||||
import { route } from 'ziggy-js';
|
||||
|
||||
defineOptions({
|
||||
layout: {
|
||||
breadcrumbs: [
|
||||
{
|
||||
title: 'Dynamics',
|
||||
href: route('dynamics.index'),
|
||||
},
|
||||
{
|
||||
title: 'Create',
|
||||
href: route('dynamics.create'),
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
const form = useForm({
|
||||
name: '',
|
||||
rules: '',
|
||||
});
|
||||
|
||||
const breadcrumbs = [
|
||||
{
|
||||
name: 'Dynamics',
|
||||
href: route('dynamics.index'),
|
||||
},
|
||||
{
|
||||
name: 'Create',
|
||||
href: route('dynamics.create'),
|
||||
},
|
||||
];
|
||||
|
||||
function submit() {
|
||||
form.post(route('dynamics.store'));
|
||||
}
|
||||
|
||||
@ -2,6 +2,17 @@
|
||||
import { Head, Link } from '@inertiajs/vue3';
|
||||
import { route } from 'ziggy-js';
|
||||
|
||||
defineOptions({
|
||||
layout: {
|
||||
breadcrumbs: [
|
||||
{
|
||||
title: 'Dynamics',
|
||||
href: route('dynamics.index'),
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
defineProps<{
|
||||
dynamics: Array<{
|
||||
id: string;
|
||||
@ -9,13 +20,6 @@ defineProps<{
|
||||
rules: string;
|
||||
}>;
|
||||
}>();
|
||||
|
||||
const breadcrumbs = [
|
||||
{
|
||||
name: 'Dynamics',
|
||||
href: route('dynamics.index'),
|
||||
},
|
||||
];
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@ -1,7 +1,25 @@
|
||||
<script setup lang="ts">
|
||||
import { Head, useForm } from '@inertiajs/vue3';
|
||||
import { route } from 'ziggy-js';
|
||||
import AppLayout from '@/layouts/AppLayout.vue';
|
||||
|
||||
defineOptions({
|
||||
layout: (props: any) => ({
|
||||
breadcrumbs: [
|
||||
{
|
||||
title: 'Dynamics',
|
||||
href: route('dynamics.index'),
|
||||
},
|
||||
{
|
||||
title: props.dynamic.name,
|
||||
href: route('dynamics.show', props.dynamic.id),
|
||||
},
|
||||
{
|
||||
title: 'Invite User',
|
||||
href: route('dynamics.invitations.create', props.dynamic.id),
|
||||
},
|
||||
],
|
||||
}),
|
||||
});
|
||||
|
||||
const props = defineProps<{
|
||||
dynamic: {
|
||||
@ -15,21 +33,6 @@ const form = useForm({
|
||||
role: 'participant',
|
||||
});
|
||||
|
||||
const breadcrumbs = [
|
||||
{
|
||||
name: 'Dynamics',
|
||||
href: route('dynamics.index'),
|
||||
},
|
||||
{
|
||||
name: props.dynamic.name,
|
||||
href: route('dynamics.show', props.dynamic.id),
|
||||
},
|
||||
{
|
||||
name: 'Invite User',
|
||||
href: route('dynamics.invitations.create', props.dynamic.id),
|
||||
},
|
||||
];
|
||||
|
||||
function submit() {
|
||||
form.post(route('dynamics.invitations.store', props.dynamic.id), {
|
||||
onSuccess: () => form.reset(),
|
||||
|
||||
@ -1,7 +1,25 @@
|
||||
<script setup lang="ts">
|
||||
import { Head, useForm, Link as InertiaLink } from '@inertiajs/vue3';
|
||||
import { route } from 'ziggy-js';
|
||||
import AppLayout from '@/layouts/AppLayout.vue';
|
||||
|
||||
defineOptions({
|
||||
layout: (props: any) => ({
|
||||
breadcrumbs: [
|
||||
{
|
||||
title: 'Dynamics',
|
||||
href: route('dynamics.index'),
|
||||
},
|
||||
{
|
||||
title: props.dynamic.name,
|
||||
href: route('dynamics.show', props.dynamic.id),
|
||||
},
|
||||
{
|
||||
title: 'Settings',
|
||||
href: route('dynamics.edit', props.dynamic.id),
|
||||
},
|
||||
],
|
||||
}),
|
||||
});
|
||||
|
||||
const props = defineProps<{
|
||||
dynamic: {
|
||||
@ -16,21 +34,6 @@ const form = useForm({
|
||||
rules: props.dynamic.rules,
|
||||
});
|
||||
|
||||
const breadcrumbs = [
|
||||
{
|
||||
name: 'Dynamics',
|
||||
href: route('dynamics.index'),
|
||||
},
|
||||
{
|
||||
name: props.dynamic.name,
|
||||
href: route('dynamics.show', props.dynamic.id),
|
||||
},
|
||||
{
|
||||
name: 'Settings',
|
||||
href: route('dynamics.edit', props.dynamic.id),
|
||||
},
|
||||
];
|
||||
|
||||
function submit() {
|
||||
form.patch(route('dynamics.update', props.dynamic.id));
|
||||
}
|
||||
|
||||
@ -43,18 +43,6 @@ const props = defineProps<{
|
||||
update: boolean;
|
||||
}
|
||||
}>();
|
||||
|
||||
|
||||
const breadcrumbs = [
|
||||
{
|
||||
name: 'Dynamics',
|
||||
href: route('dynamics.index'),
|
||||
},
|
||||
{
|
||||
name: props.dynamic.name,
|
||||
href: route('dynamics.show', props.dynamic.id),
|
||||
},
|
||||
];
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@ -1,30 +1,33 @@
|
||||
<script setup lang="ts">
|
||||
import { Head, useForm } from '@inertiajs/vue3';
|
||||
import { route } from 'ziggy-js';
|
||||
import AppLayout from '@/layouts/AppLayout.vue';
|
||||
import CreateLedgerForm from '@/components/CreateLedgerForm.vue';
|
||||
|
||||
defineOptions({
|
||||
layout: (props: any) => ({
|
||||
breadcrumbs: [
|
||||
{
|
||||
title: 'Dynamics',
|
||||
href: route('dynamics.index'),
|
||||
},
|
||||
{
|
||||
title: props.dynamic.name,
|
||||
href: route('dynamics.show', props.dynamic.id),
|
||||
},
|
||||
{
|
||||
title: 'Create Ledger',
|
||||
href: route('dynamics.ledgers.create', props.dynamic.id),
|
||||
},
|
||||
],
|
||||
}),
|
||||
});
|
||||
|
||||
const props = defineProps<{
|
||||
dynamic: {
|
||||
id: number;
|
||||
name: string;
|
||||
};
|
||||
}>();
|
||||
|
||||
const breadcrumbs = [
|
||||
{
|
||||
name: 'Dynamics',
|
||||
href: route('dynamics.index'),
|
||||
},
|
||||
{
|
||||
name: props.dynamic.name,
|
||||
href: route('dynamics.show', props.dynamic.id),
|
||||
},
|
||||
{
|
||||
name: 'Create Ledger',
|
||||
href: route('dynamics.ledgers.create', props.dynamic.id),
|
||||
},
|
||||
];
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@ -1,7 +1,29 @@
|
||||
<script setup lang="ts">
|
||||
import { Head, useForm } from '@inertiajs/vue3';
|
||||
import { Head, useForm, Link } from '@inertiajs/vue3';
|
||||
import { route } from 'ziggy-js';
|
||||
import AppLayout from '@/layouts/AppLayout.vue';
|
||||
|
||||
defineOptions({
|
||||
layout: (props: any) => ({
|
||||
breadcrumbs: [
|
||||
{
|
||||
title: 'Dynamics',
|
||||
href: route('dynamics.index'),
|
||||
},
|
||||
{
|
||||
title: props.dynamic.name,
|
||||
href: route('dynamics.show', props.dynamic.id),
|
||||
},
|
||||
{
|
||||
title: props.ledger.name,
|
||||
href: route('dynamics.ledgers.show', [props.dynamic.id, props.ledger.id]),
|
||||
},
|
||||
{
|
||||
title: 'Edit',
|
||||
href: route('dynamics.ledgers.edit', [props.dynamic.id, props.ledger.id]),
|
||||
},
|
||||
],
|
||||
}),
|
||||
});
|
||||
|
||||
const props = defineProps<{
|
||||
dynamic: {
|
||||
@ -20,25 +42,6 @@ const form = useForm({
|
||||
rules: props.ledger.rules,
|
||||
});
|
||||
|
||||
const breadcrumbs = [
|
||||
{
|
||||
name: 'Dynamics',
|
||||
href: route('dynamics.index'),
|
||||
},
|
||||
{
|
||||
name: props.dynamic.name,
|
||||
href: route('dynamics.show', props.dynamic.id),
|
||||
},
|
||||
{
|
||||
name: props.ledger.name,
|
||||
href: route('dynamics.ledgers.show', [props.dynamic.id, props.ledger.id]),
|
||||
},
|
||||
{
|
||||
name: 'Edit',
|
||||
href: route('dynamics.ledgers.edit', [props.dynamic.id, props.ledger.id]),
|
||||
},
|
||||
];
|
||||
|
||||
function submit() {
|
||||
form.put(route('dynamics.ledgers.update', [props.dynamic.id, props.ledger.id]));
|
||||
}
|
||||
@ -47,45 +50,43 @@ function submit() {
|
||||
<template>
|
||||
<Head title="Edit Ledger" />
|
||||
|
||||
<AppLayout :breadcrumbs="breadcrumbs">
|
||||
<div class="c-ledger-edit">
|
||||
<div class="c-ledger-edit__container">
|
||||
<div class="c-ledger-edit__card">
|
||||
<div class="c-ledger-edit__body">
|
||||
<h3 class="c-ledger-edit__title">
|
||||
Edit {{ ledger.name }}
|
||||
</h3>
|
||||
<div class="c-ledger-edit">
|
||||
<div class="c-ledger-edit__container">
|
||||
<div class="c-ledger-edit__card">
|
||||
<div class="c-ledger-edit__body">
|
||||
<h3 class="c-ledger-edit__title">
|
||||
Edit {{ ledger.name }}
|
||||
</h3>
|
||||
|
||||
<form @submit.prevent="submit" class="c-ledger-edit__form">
|
||||
<div class="c-ledger-edit__field">
|
||||
<label for="name" class="c-ledger-edit__label">Name</label>
|
||||
<input v-model="form.name" id="name" type="text" class="c-ledger-edit__input" />
|
||||
</div>
|
||||
<form @submit.prevent="submit" class="c-ledger-edit__form">
|
||||
<div class="c-ledger-edit__field">
|
||||
<label for="name" class="c-ledger-edit__label">Name</label>
|
||||
<input v-model="form.name" id="name" type="text" class="c-ledger-edit__input" />
|
||||
</div>
|
||||
|
||||
<div class="c-ledger-edit__field">
|
||||
<label for="rules" class="c-ledger-edit__label">Rules</label>
|
||||
<textarea v-model="form.rules" id="rules" rows="4" class="c-ledger-edit__textarea"></textarea>
|
||||
</div>
|
||||
<div class="c-ledger-edit__field">
|
||||
<label for="rules" class="c-ledger-edit__label">Rules</label>
|
||||
<textarea v-model="form.rules" id="rules" rows="4" class="c-ledger-edit__textarea"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="c-ledger-edit__actions">
|
||||
<button type="submit" :disabled="form.processing" class="c-ledger-edit__submit-btn">
|
||||
Save
|
||||
</button>
|
||||
<Link
|
||||
:href="route('dynamics.ledgers.close', [dynamic.id, ledger.id])"
|
||||
method="put"
|
||||
as="button"
|
||||
class="c-ledger-edit__submit-btn c-ledger-edit__submit-btn--danger"
|
||||
>
|
||||
Close Ledger
|
||||
</Link>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="c-ledger-edit__actions">
|
||||
<button type="submit" :disabled="form.processing" class="c-ledger-edit__submit-btn">
|
||||
Save
|
||||
</button>
|
||||
<Link
|
||||
:href="route('dynamics.ledgers.close', [dynamic.id, ledger.id])"
|
||||
method="put"
|
||||
as="button"
|
||||
class="c-ledger-edit__submit-btn c-ledger-edit__submit-btn--danger"
|
||||
>
|
||||
Close Ledger
|
||||
</Link>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</AppLayout>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@ -43,6 +43,7 @@ const props = defineProps<{
|
||||
score: number;
|
||||
rules: string;
|
||||
alignment: string;
|
||||
status: string;
|
||||
media?: Array<{ id: number; url: string; mime_type: string }>;
|
||||
mutations: Array<{
|
||||
id: number;
|
||||
@ -56,30 +57,15 @@ const props = defineProps<{
|
||||
media?: Array<{ id: number; url: string; mime_type: string }>;
|
||||
}>;
|
||||
};
|
||||
isOwner: boolean;
|
||||
can: {
|
||||
update: boolean;
|
||||
close: boolean;
|
||||
};
|
||||
messages: {
|
||||
data: Array<any>;
|
||||
next_page_url: string | null;
|
||||
};
|
||||
}>();
|
||||
|
||||
const breadcrumbs = [
|
||||
{
|
||||
name: 'Dynamics',
|
||||
href: route('dynamics.index'),
|
||||
},
|
||||
{
|
||||
name: props.dynamic.name,
|
||||
href: route('dynamics.show', props.dynamic.id),
|
||||
},
|
||||
{
|
||||
name: props.ledger.name,
|
||||
href: route('dynamics.ledgers.show', {
|
||||
dynamic: props.dynamic.id,
|
||||
ledger: props.ledger.id,
|
||||
}),
|
||||
},
|
||||
];
|
||||
}>();
|
||||
|
||||
// Lightbox Modal state
|
||||
const activeLightboxUrl = ref<string | null>(null);
|
||||
@ -202,7 +188,7 @@ function isOwnerUser(userId: number): boolean {
|
||||
{{ ledger.rules }}
|
||||
</p>
|
||||
</div>
|
||||
<div v-if="isOwner" class="flex flex-col gap-2">
|
||||
<div v-if="can.update" class="flex flex-col gap-2">
|
||||
<InertiaLink
|
||||
:href="route('dynamics.ledgers.predefined-mutations.index', [dynamic.id, ledger.id])"
|
||||
class="c-ledger-show__manage-btn"
|
||||
@ -284,7 +270,7 @@ function isOwnerUser(userId: number): boolean {
|
||||
:ledger-id="ledger.id"
|
||||
:mutations="ledger.mutations"
|
||||
:participants="dynamic.participants"
|
||||
:is-owner="isOwner"
|
||||
:can-update="can.update"
|
||||
:ledger-alignment="ledger.alignment"
|
||||
@open-lightbox="openLightbox"
|
||||
/>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user