import 'server-only' import config from '@payload-config' import { getPayload, type Payload } from 'payload' import type { CampaignUser } from '@/payload-types' import { isCampaignStaff, isCampaignUnrestricted } from '@/utilities/campaignAccess' import { getCampaignUser } from '@/utilities/campaignAuth' import { CAMPAIGN_AUTH_REQUIRED_MESSAGE } from '@/utilities/campaignFormActionError' import type { PayloadTransactionRequest } from '@/utilities/payloadTransaction' export type CampaignActionContext = { payload: Payload actor: CampaignUser } type CampaignUserGetter = () => Promise type CampaignActorPayload = Pick export const requireCampaignUser = async ( getUser: CampaignUserGetter = getCampaignUser, ): Promise => { const actor = await getUser() if (!actor) throw new Error(CAMPAIGN_AUTH_REQUIRED_MESSAGE) return actor } export const reloadCampaignActor = ( payload: CampaignActorPayload, actor: CampaignUser, req?: PayloadTransactionRequest, ): Promise => payload.findByID({ collection: 'campaignUser', id: actor.id, depth: 0, // Intentional admin bypass: this is the trusted fresh-role reload used before authorization. overrideAccess: true, req, }) /** * Reloads the actor's fresh role and asserts they are campaign staff * (coordinator, advisor, or candidate — matching collection-level access via * `isCampaignStaff`). Throws `errorMessage` otherwise. */ export const reloadStaffActor = async ( payload: CampaignActorPayload, actor: CampaignUser, errorMessage: string, req?: PayloadTransactionRequest, ): Promise => { const currentActor = await reloadCampaignActor(payload, actor, req) if (!isCampaignStaff(currentActor)) throw new Error(errorMessage) return currentActor } /** * Reloads the actor's fresh role and asserts they are the coordinator. * Throws `errorMessage` otherwise. */ export const reloadCoordinatorActor = async ( payload: CampaignActorPayload, actor: CampaignUser, errorMessage: string, req?: PayloadTransactionRequest, ): Promise => { const currentActor = await reloadCampaignActor(payload, actor, req) if (currentActor.role !== 'coordinator') throw new Error(errorMessage) return currentActor } /** * Reloads the actor's fresh role and asserts they are unrestricted * (coordinator or candidate). Throws `errorMessage` otherwise. */ export const reloadUnrestrictedActor = async ( payload: CampaignActorPayload, actor: CampaignUser, errorMessage: string, req?: PayloadTransactionRequest, ): Promise => { const currentActor = await reloadCampaignActor(payload, actor, req) if (!isCampaignUnrestricted(currentActor)) throw new Error(errorMessage) return currentActor } export const getCampaignActionContext = async (): Promise => { const [payload, actor] = await Promise.all([getPayload({ config }), requireCampaignUser()]) return { payload, actor } }