Files
hackerspace.sh/lib/equipment-guard.ts
T
Moheeb Zara 39c00260c7 feat(equipment): server actions + page guard
equipment.ts: registry CRUD (equipment.manage; delete refused once
reservations exist, archive instead), listEquipmentForMembers (active
items with a member_certified flag computed via the service client),
reserveEquipment / cancelReservation as validated service-client writes
that enforce status, no-overlap and the required-certification gate with
an equipment.manage override (and manager booking on a member's behalf),
listEquipmentReservations and getMyReservations. equipment-guard mirrors
the other module guards. Barrel + API_REFERENCE updated.
2026-05-16 19:51:51 -07:00

32 lines
1.0 KiB
TypeScript

import { redirect } from 'next/navigation'
import { createClient } from '@/lib/supabase/server'
// Server-component guard for the /equipment/manage surface. Mirrors the
// forms/certifications/classes guards: resolve the member, check
// equipment.manage via the same RPC the RLS uses, redirect non-managers
// before any data is fetched. The RLS independently enforces this.
export async function requireEquipmentManagerPage() {
const supabase = await createClient()
const {
data: { user },
} = await supabase.auth.getUser()
if (!user) redirect('/login')
const { data: member } = await supabase
.from('space_members')
.select('id, space_id, role, user_id, display_name')
.eq('user_id', user.id)
.in('status', ['current', 'unverified', 'late'])
.single()
if (!member) redirect('/login')
const { data: allowed } = await supabase.rpc('user_has_permission', {
uid: user.id,
sid: member.space_id,
perm: 'equipment.manage',
})
if (!allowed) redirect('/dashboard')
return { supabase, member }
}