Go-live: live data wiring, auth callback, SEO, legal pages, UI fixes

This commit is contained in:
Ryan Salazar
2026-06-27 14:08:31 -04:00
parent d533cdc194
commit 910a7d8516
34 changed files with 2780 additions and 61 deletions

View File

@@ -0,0 +1,163 @@
-- ExposedGays v6: Sniffies-style user hosting events (map parties)
-- Run on SUPABASE_01 after migration_v5_privacy.sql
CREATE TABLE IF NOT EXISTS public.hosting_events (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
host_id UUID NOT NULL REFERENCES public.profiles(id) ON DELETE CASCADE,
title TEXT NOT NULL CHECK (char_length(title) <= 80),
description TEXT NOT NULL DEFAULT '' CHECK (char_length(description) <= 2000),
event_type TEXT NOT NULL DEFAULT 'custom'
CHECK (event_type IN ('cum-dump', 'orgy', 'group', 'pnp', 'vanilla', 'gloryhole', 'custom')),
status TEXT NOT NULL DEFAULT 'scheduled'
CHECK (status IN ('scheduled', 'live', 'ended', 'cancelled')),
starts_at TIMESTAMPTZ NOT NULL,
ends_at TIMESTAMPTZ NOT NULL,
location GEOGRAPHY(POINT, 4326) NOT NULL,
city TEXT,
auto_accept BOOLEAN NOT NULL DEFAULT false,
max_guests INTEGER CHECK (max_guests IS NULL OR max_guests BETWEEN 1 AND 500),
tags TEXT[] NOT NULL DEFAULT '{}',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
CHECK (ends_at > starts_at)
);
CREATE INDEX IF NOT EXISTS idx_hosting_events_host ON public.hosting_events (host_id);
CREATE INDEX IF NOT EXISTS idx_hosting_events_status ON public.hosting_events (status);
CREATE INDEX IF NOT EXISTS idx_hosting_events_starts ON public.hosting_events (starts_at);
CREATE INDEX IF NOT EXISTS idx_hosting_events_location ON public.hosting_events USING GIST (location);
CREATE TABLE IF NOT EXISTS public.hosting_event_media (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
event_id UUID NOT NULL REFERENCES public.hosting_events(id) ON DELETE CASCADE,
media_type TEXT NOT NULL CHECK (media_type IN ('photo', 'video')),
url TEXT NOT NULL,
thumbnail_url TEXT,
sort_order INTEGER NOT NULL DEFAULT 0,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX IF NOT EXISTS idx_hosting_event_media_event ON public.hosting_event_media (event_id);
CREATE TABLE IF NOT EXISTS public.hosting_event_attendees (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
event_id UUID NOT NULL REFERENCES public.hosting_events(id) ON DELETE CASCADE,
user_id UUID NOT NULL REFERENCES public.profiles(id) ON DELETE CASCADE,
status TEXT NOT NULL DEFAULT 'requested'
CHECK (status IN ('invited', 'requested', 'accepted', 'declined', 'cancelled')),
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
UNIQUE (event_id, user_id)
);
CREATE INDEX IF NOT EXISTS idx_hosting_event_attendees_event ON public.hosting_event_attendees (event_id);
CREATE INDEX IF NOT EXISTS idx_hosting_event_attendees_user ON public.hosting_event_attendees (user_id);
-- Max 2 photos + 1 video per event
CREATE OR REPLACE FUNCTION public.enforce_hosting_event_media_limit()
RETURNS TRIGGER AS $$
DECLARE
photo_count INTEGER;
video_count INTEGER;
BEGIN
SELECT COUNT(*) INTO photo_count
FROM public.hosting_event_media
WHERE event_id = NEW.event_id AND media_type = 'photo';
SELECT COUNT(*) INTO video_count
FROM public.hosting_event_media
WHERE event_id = NEW.event_id AND media_type = 'video';
IF NEW.media_type = 'photo' AND photo_count >= 2 THEN
RAISE EXCEPTION 'Maximum 2 photos per hosting event';
END IF;
IF NEW.media_type = 'video' AND video_count >= 1 THEN
RAISE EXCEPTION 'Maximum 1 video per hosting event';
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
DROP TRIGGER IF EXISTS trg_hosting_event_media_limit ON public.hosting_event_media;
CREATE TRIGGER trg_hosting_event_media_limit
BEFORE INSERT ON public.hosting_event_media
FOR EACH ROW EXECUTE FUNCTION public.enforce_hosting_event_media_limit();
CREATE OR REPLACE FUNCTION public.touch_hosting_event_updated()
RETURNS TRIGGER AS $$
BEGIN
UPDATE public.hosting_events SET updated_at = now() WHERE id = NEW.event_id;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
DROP TRIGGER IF EXISTS trg_hosting_event_attendee_touch ON public.hosting_event_attendees;
CREATE TRIGGER trg_hosting_event_attendee_touch
AFTER INSERT OR UPDATE ON public.hosting_event_attendees
FOR EACH ROW EXECUTE FUNCTION public.touch_hosting_event_updated();
ALTER TABLE public.hosting_events ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.hosting_event_media ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.hosting_event_attendees ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Hosting events viewable by authenticated users"
ON public.hosting_events FOR SELECT
USING (auth.role() = 'authenticated' AND status != 'cancelled');
CREATE POLICY "Users can create hosting events"
ON public.hosting_events FOR INSERT
WITH CHECK (auth.uid() = host_id);
CREATE POLICY "Hosts can update own events"
ON public.hosting_events FOR UPDATE
USING (auth.uid() = host_id);
CREATE POLICY "Hosts can delete own events"
ON public.hosting_events FOR DELETE
USING (auth.uid() = host_id);
CREATE POLICY "Event media viewable by authenticated users"
ON public.hosting_event_media FOR SELECT
USING (auth.role() = 'authenticated');
CREATE POLICY "Hosts manage event media"
ON public.hosting_event_media FOR ALL
USING (
EXISTS (
SELECT 1 FROM public.hosting_events e
WHERE e.id = event_id AND e.host_id = auth.uid()
)
);
CREATE POLICY "Attendees viewable by authenticated users"
ON public.hosting_event_attendees FOR SELECT
USING (auth.role() = 'authenticated');
CREATE POLICY "Users manage own attendance"
ON public.hosting_event_attendees FOR INSERT
WITH CHECK (auth.uid() = user_id);
CREATE POLICY "Users update own attendance"
ON public.hosting_event_attendees FOR UPDATE
USING (auth.uid() = user_id OR EXISTS (
SELECT 1 FROM public.hosting_events e
WHERE e.id = event_id AND e.host_id = auth.uid()
));
CREATE POLICY "Hosts delete attendees"
ON public.hosting_event_attendees FOR DELETE
USING (
auth.uid() = user_id OR EXISTS (
SELECT 1 FROM public.hosting_events e
WHERE e.id = event_id AND e.host_id = auth.uid()
)
);
ALTER PUBLICATION supabase_realtime ADD TABLE public.hosting_events;
ALTER PUBLICATION supabase_realtime ADD TABLE public.hosting_event_attendees;
INSERT INTO storage.buckets (id, name, public)
VALUES ('hosting-events', 'hosting-events', true)
ON CONFLICT (id) DO NOTHING;