security: A01-13 — nest all event routes under organisation prefix
Move all authenticated organiser-facing event sub-resource routes from
/events/{event}/... to /organisations/{organisation}/events/{event}/...
to enforce multi-tenancy at the routing layer.
Changes:
- Routes: restructured api.php to nest all event sub-resources under
the existing organisation prefix group
- Controllers: added Organisation parameter and VerifiesOrganisationEvent
trait to all 12 affected controllers (sections, time-slots, shifts,
persons, crowd-lists, locations, shift-assignments, registration-fields,
availabilities, field-values, section-preferences, stats)
- Tests: updated all 20 feature test files with new route paths
- Frontend: updated 8 API composables and 20 Vue components/pages
- API.md: updated documentation to reflect new route structure
Portal routes, public routes (volunteer-register), and invitation routes
remain unchanged as they operate without organisation context.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { useAssignablePersons, useAssignPersonToShift } from '@/composables/api/useShiftAssignments'
|
||||
import { getApiErrorMessage } from '@/lib/apiErrors'
|
||||
import { useAuthStore } from '@/stores/useAuthStore'
|
||||
import type { AssignablePerson } from '@/types/shiftAssignment'
|
||||
import type { Shift } from '@/types/section'
|
||||
|
||||
@@ -16,11 +17,13 @@ const emit = defineEmits<{
|
||||
|
||||
const modelValue = defineModel<boolean>({ required: true })
|
||||
|
||||
const authStore = useAuthStore()
|
||||
const orgIdRef = computed(() => authStore.currentOrganisation?.id ?? '')
|
||||
const eventIdRef = computed(() => props.eventId)
|
||||
const shiftIdRef = computed(() => props.shift?.id ?? '')
|
||||
|
||||
const { data: assignableData, isLoading } = useAssignablePersons(eventIdRef, shiftIdRef)
|
||||
const { mutateAsync: assignPerson, isPending: isAssigning } = useAssignPersonToShift(eventIdRef)
|
||||
const { data: assignableData, isLoading } = useAssignablePersons(orgIdRef, eventIdRef, shiftIdRef)
|
||||
const { mutateAsync: assignPerson, isPending: isAssigning } = useAssignPersonToShift(orgIdRef, eventIdRef)
|
||||
|
||||
// Search and filters
|
||||
const searchQuery = ref('')
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
} from '@/composables/api/useShiftAssignments'
|
||||
import AssignPersonDialog from '@/components/shifts/AssignPersonDialog.vue'
|
||||
import { getApiErrorMessage } from '@/lib/apiErrors'
|
||||
import { useAuthStore } from '@/stores/useAuthStore'
|
||||
import { useShiftDetailStore } from '@/stores/useShiftDetailStore'
|
||||
import { ShiftAssignmentStatus } from '@/types/shiftAssignment'
|
||||
import type { ShiftAssignment } from '@/types/shiftAssignment'
|
||||
@@ -21,7 +22,9 @@ const props = defineProps<{
|
||||
|
||||
const modelValue = defineModel<boolean>({ required: true })
|
||||
|
||||
const authStore = useAuthStore()
|
||||
const store = useShiftDetailStore()
|
||||
const orgIdRef = computed(() => authStore.currentOrganisation?.id ?? '')
|
||||
const eventIdRef = computed(() => props.eventId)
|
||||
|
||||
// Fetch assignments filtered by this shift
|
||||
@@ -34,16 +37,16 @@ const {
|
||||
isLoading: assignmentsLoading,
|
||||
isError: assignmentsError,
|
||||
refetch: refetchAssignments,
|
||||
} = useShiftAssignmentList(eventIdRef, filters)
|
||||
} = useShiftAssignmentList(orgIdRef, eventIdRef, filters)
|
||||
|
||||
const assignments = computed(() => assignmentsResponse.value?.data ?? [])
|
||||
|
||||
// Mutations
|
||||
const { mutate: approveAssignment, isPending: isApproving } = useApproveAssignment(eventIdRef)
|
||||
const { mutate: rejectAssignment, isPending: isRejecting } = useRejectAssignment(eventIdRef)
|
||||
const { mutate: cancelAssignment, isPending: isCancelling } = useCancelAssignment(eventIdRef)
|
||||
const { mutate: bulkApprove, isPending: isBulkApproving } = useBulkApproveAssignments(eventIdRef)
|
||||
const { mutateAsync: assignPersonMutation } = useAssignPersonToShift(eventIdRef)
|
||||
const { mutate: approveAssignment, isPending: isApproving } = useApproveAssignment(orgIdRef, eventIdRef)
|
||||
const { mutate: rejectAssignment, isPending: isRejecting } = useRejectAssignment(orgIdRef, eventIdRef)
|
||||
const { mutate: cancelAssignment, isPending: isCancelling } = useCancelAssignment(orgIdRef, eventIdRef)
|
||||
const { mutate: bulkApprove, isPending: isBulkApproving } = useBulkApproveAssignments(orgIdRef, eventIdRef)
|
||||
const { mutateAsync: assignPersonMutation } = useAssignPersonToShift(orgIdRef, eventIdRef)
|
||||
|
||||
// Re-assign
|
||||
const reassigning = ref<string | null>(null)
|
||||
|
||||
Reference in New Issue
Block a user