From 6c95cd9856638d9451eb23c165dfe2a662ec3f6a Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Thu, 2 Oct 2025 00:53:29 +0000 Subject: [PATCH] Refactor: Create typed submission tables --- src/integrations/supabase/types.ts | 480 ++++++++++++++++++ ...5_048cdb6a-2a52-4619-9b00-38564a770063.sql | 451 ++++++++++++++++ 2 files changed, 931 insertions(+) create mode 100644 supabase/migrations/20251002005315_048cdb6a-2a52-4619-9b00-38564a770063.sql diff --git a/src/integrations/supabase/types.ts b/src/integrations/supabase/types.ts index 6ba6fb40..d772c47d 100644 --- a/src/integrations/supabase/types.ts +++ b/src/integrations/supabase/types.ts @@ -137,6 +137,74 @@ export type Database = { } Relationships: [] } + company_submissions: { + Row: { + banner_image_id: string | null + banner_image_url: string | null + card_image_id: string | null + card_image_url: string | null + company_type: string + created_at: string + description: string | null + founded_year: number | null + headquarters_location: string | null + id: string + logo_url: string | null + name: string + person_type: string | null + slug: string + submission_id: string + updated_at: string + website_url: string | null + } + Insert: { + banner_image_id?: string | null + banner_image_url?: string | null + card_image_id?: string | null + card_image_url?: string | null + company_type: string + created_at?: string + description?: string | null + founded_year?: number | null + headquarters_location?: string | null + id?: string + logo_url?: string | null + name: string + person_type?: string | null + slug: string + submission_id: string + updated_at?: string + website_url?: string | null + } + Update: { + banner_image_id?: string | null + banner_image_url?: string | null + card_image_id?: string | null + card_image_url?: string | null + company_type?: string + created_at?: string + description?: string | null + founded_year?: number | null + headquarters_location?: string | null + id?: string + logo_url?: string | null + name?: string + person_type?: string | null + slug?: string + submission_id?: string + updated_at?: string + website_url?: string | null + } + Relationships: [ + { + foreignKeyName: "company_submissions_submission_id_fkey" + columns: ["submission_id"] + isOneToOne: true + referencedRelation: "content_submissions" + referencedColumns: ["id"] + }, + ] + } content_submissions: { Row: { approval_mode: string | null @@ -434,6 +502,93 @@ export type Database = { }, ] } + park_submissions: { + Row: { + banner_image_id: string | null + banner_image_url: string | null + card_image_id: string | null + card_image_url: string | null + closing_date: string | null + created_at: string + description: string | null + email: string | null + id: string + location_id: string | null + name: string + opening_date: string | null + operator_id: string | null + park_type: string + phone: string | null + property_owner_id: string | null + slug: string + status: string + submission_id: string + updated_at: string + website_url: string | null + } + Insert: { + banner_image_id?: string | null + banner_image_url?: string | null + card_image_id?: string | null + card_image_url?: string | null + closing_date?: string | null + created_at?: string + description?: string | null + email?: string | null + id?: string + location_id?: string | null + name: string + opening_date?: string | null + operator_id?: string | null + park_type: string + phone?: string | null + property_owner_id?: string | null + slug: string + status?: string + submission_id: string + updated_at?: string + website_url?: string | null + } + Update: { + banner_image_id?: string | null + banner_image_url?: string | null + card_image_id?: string | null + card_image_url?: string | null + closing_date?: string | null + created_at?: string + description?: string | null + email?: string | null + id?: string + location_id?: string | null + name?: string + opening_date?: string | null + operator_id?: string | null + park_type?: string + phone?: string | null + property_owner_id?: string | null + slug?: string + status?: string + submission_id?: string + updated_at?: string + website_url?: string | null + } + Relationships: [ + { + foreignKeyName: "park_submissions_location_id_fkey" + columns: ["location_id"] + isOneToOne: false + referencedRelation: "locations" + referencedColumns: ["id"] + }, + { + foreignKeyName: "park_submissions_submission_id_fkey" + columns: ["submission_id"] + isOneToOne: true + referencedRelation: "content_submissions" + referencedColumns: ["id"] + }, + ] + } parks: { Row: { average_rating: number | null @@ -948,6 +1103,141 @@ export type Database = { }, ] } + ride_coaster_stats: { + Row: { + category: string | null + created_at: string + id: string + ride_submission_id: string + stat_name: string + stat_value: number + unit: string | null + } + Insert: { + category?: string | null + created_at?: string + id?: string + ride_submission_id: string + stat_name: string + stat_value: number + unit?: string | null + } + Update: { + category?: string | null + created_at?: string + id?: string + ride_submission_id?: string + stat_name?: string + stat_value?: number + unit?: string | null + } + Relationships: [ + { + foreignKeyName: "ride_coaster_stats_ride_submission_id_fkey" + columns: ["ride_submission_id"] + isOneToOne: false + referencedRelation: "ride_submissions" + referencedColumns: ["id"] + }, + ] + } + ride_former_names: { + Row: { + created_at: string + date_changed: string | null + former_name: string + id: string + order_index: number | null + reason: string | null + ride_submission_id: string + } + Insert: { + created_at?: string + date_changed?: string | null + former_name: string + id?: string + order_index?: number | null + reason?: string | null + ride_submission_id: string + } + Update: { + created_at?: string + date_changed?: string | null + former_name?: string + id?: string + order_index?: number | null + reason?: string | null + ride_submission_id?: string + } + Relationships: [ + { + foreignKeyName: "ride_former_names_ride_submission_id_fkey" + columns: ["ride_submission_id"] + isOneToOne: false + referencedRelation: "ride_submissions" + referencedColumns: ["id"] + }, + ] + } + ride_model_submissions: { + Row: { + banner_image_id: string | null + banner_image_url: string | null + card_image_id: string | null + card_image_url: string | null + category: string + created_at: string + description: string | null + id: string + manufacturer_id: string | null + name: string + ride_type: string + slug: string + submission_id: string + updated_at: string + } + Insert: { + banner_image_id?: string | null + banner_image_url?: string | null + card_image_id?: string | null + card_image_url?: string | null + category: string + created_at?: string + description?: string | null + id?: string + manufacturer_id?: string | null + name: string + ride_type: string + slug: string + submission_id: string + updated_at?: string + } + Update: { + banner_image_id?: string | null + banner_image_url?: string | null + card_image_id?: string | null + card_image_url?: string | null + category?: string + created_at?: string + description?: string | null + id?: string + manufacturer_id?: string | null + name?: string + ride_type?: string + slug?: string + submission_id?: string + updated_at?: string + } + Relationships: [ + { + foreignKeyName: "ride_model_submissions_submission_id_fkey" + columns: ["submission_id"] + isOneToOne: true + referencedRelation: "content_submissions" + referencedColumns: ["id"] + }, + ] + } ride_models: { Row: { banner_image_id: string | null @@ -1007,6 +1297,166 @@ export type Database = { }, ] } + ride_submissions: { + Row: { + age_requirement: number | null + banner_image_id: string | null + banner_image_url: string | null + capacity_per_hour: number | null + card_image_id: string | null + card_image_url: string | null + category: string + closing_date: string | null + coaster_type: string | null + created_at: string + description: string | null + designer_id: string | null + drop_height_meters: number | null + duration_seconds: number | null + height_requirement: number | null + id: string + image_url: string | null + intensity_level: string | null + inversions: number | null + length_meters: number | null + manufacturer_id: string | null + max_g_force: number | null + max_height_meters: number | null + max_speed_kmh: number | null + name: string + opening_date: string | null + park_id: string | null + ride_model_id: string | null + ride_sub_type: string | null + seating_type: string | null + slug: string + status: string + submission_id: string + updated_at: string + } + Insert: { + age_requirement?: number | null + banner_image_id?: string | null + banner_image_url?: string | null + capacity_per_hour?: number | null + card_image_id?: string | null + card_image_url?: string | null + category: string + closing_date?: string | null + coaster_type?: string | null + created_at?: string + description?: string | null + designer_id?: string | null + drop_height_meters?: number | null + duration_seconds?: number | null + height_requirement?: number | null + id?: string + image_url?: string | null + intensity_level?: string | null + inversions?: number | null + length_meters?: number | null + manufacturer_id?: string | null + max_g_force?: number | null + max_height_meters?: number | null + max_speed_kmh?: number | null + name: string + opening_date?: string | null + park_id?: string | null + ride_model_id?: string | null + ride_sub_type?: string | null + seating_type?: string | null + slug: string + status?: string + submission_id: string + updated_at?: string + } + Update: { + age_requirement?: number | null + banner_image_id?: string | null + banner_image_url?: string | null + capacity_per_hour?: number | null + card_image_id?: string | null + card_image_url?: string | null + category?: string + closing_date?: string | null + coaster_type?: string | null + created_at?: string + description?: string | null + designer_id?: string | null + drop_height_meters?: number | null + duration_seconds?: number | null + height_requirement?: number | null + id?: string + image_url?: string | null + intensity_level?: string | null + inversions?: number | null + length_meters?: number | null + manufacturer_id?: string | null + max_g_force?: number | null + max_height_meters?: number | null + max_speed_kmh?: number | null + name?: string + opening_date?: string | null + park_id?: string | null + ride_model_id?: string | null + ride_sub_type?: string | null + seating_type?: string | null + slug?: string + status?: string + submission_id?: string + updated_at?: string + } + Relationships: [ + { + foreignKeyName: "ride_submissions_submission_id_fkey" + columns: ["submission_id"] + isOneToOne: true + referencedRelation: "content_submissions" + referencedColumns: ["id"] + }, + ] + } + ride_technical_specs: { + Row: { + category: string | null + created_at: string + id: string + ride_submission_id: string + spec_name: string + spec_type: string + spec_value: string + unit: string | null + } + Insert: { + category?: string | null + created_at?: string + id?: string + ride_submission_id: string + spec_name: string + spec_type: string + spec_value: string + unit?: string | null + } + Update: { + category?: string | null + created_at?: string + id?: string + ride_submission_id?: string + spec_name?: string + spec_type?: string + spec_value?: string + unit?: string | null + } + Relationships: [ + { + foreignKeyName: "ride_technical_specs_ride_submission_id_fkey" + columns: ["ride_submission_id"] + isOneToOne: false + referencedRelation: "ride_submissions" + referencedColumns: ["id"] + }, + ] + } rides: { Row: { age_requirement: number | null @@ -1159,6 +1609,36 @@ export type Database = { }, ] } + submission_dependencies: { + Row: { + child_entity_type: string + child_submission_id: string + created_at: string + dependency_type: string + id: string + parent_entity_type: string + parent_submission_id: string + } + Insert: { + child_entity_type: string + child_submission_id: string + created_at?: string + dependency_type?: string + id?: string + parent_entity_type: string + parent_submission_id: string + } + Update: { + child_entity_type?: string + child_submission_id?: string + created_at?: string + dependency_type?: string + id?: string + parent_entity_type?: string + parent_submission_id?: string + } + Relationships: [] + } submission_items: { Row: { approved_entity_id: string | null diff --git a/supabase/migrations/20251002005315_048cdb6a-2a52-4619-9b00-38564a770063.sql b/supabase/migrations/20251002005315_048cdb6a-2a52-4619-9b00-38564a770063.sql new file mode 100644 index 00000000..6d3ac3ec --- /dev/null +++ b/supabase/migrations/20251002005315_048cdb6a-2a52-4619-9b00-38564a770063.sql @@ -0,0 +1,451 @@ +-- Phase 2: Create Typed Submission Tables + +-- 1. Park Submissions +CREATE TABLE park_submissions ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + submission_id UUID NOT NULL REFERENCES content_submissions(id) ON DELETE CASCADE, + name TEXT NOT NULL, + slug TEXT NOT NULL, + description TEXT, + park_type TEXT NOT NULL, + status TEXT NOT NULL DEFAULT 'operating', + opening_date DATE, + closing_date DATE, + website_url TEXT, + phone TEXT, + email TEXT, + operator_id UUID, + property_owner_id UUID, + location_id UUID REFERENCES locations(id), + banner_image_url TEXT, + banner_image_id TEXT, + card_image_url TEXT, + card_image_id TEXT, + created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), + updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), + UNIQUE(submission_id) +); + +-- 2. Ride Submissions +CREATE TABLE ride_submissions ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + submission_id UUID NOT NULL REFERENCES content_submissions(id) ON DELETE CASCADE, + park_id UUID, + name TEXT NOT NULL, + slug TEXT NOT NULL, + description TEXT, + category TEXT NOT NULL, + ride_sub_type TEXT, + status TEXT NOT NULL DEFAULT 'operating', + opening_date DATE, + closing_date DATE, + manufacturer_id UUID, + designer_id UUID, + ride_model_id UUID, + height_requirement INTEGER, + age_requirement INTEGER, + capacity_per_hour INTEGER, + duration_seconds INTEGER, + max_speed_kmh NUMERIC, + max_height_meters NUMERIC, + length_meters NUMERIC, + drop_height_meters NUMERIC, + inversions INTEGER DEFAULT 0, + max_g_force NUMERIC, + coaster_type TEXT, + seating_type TEXT, + intensity_level TEXT, + banner_image_url TEXT, + banner_image_id TEXT, + card_image_url TEXT, + card_image_id TEXT, + image_url TEXT, + created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), + updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), + UNIQUE(submission_id) +); + +-- 3. Company Submissions +CREATE TABLE company_submissions ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + submission_id UUID NOT NULL REFERENCES content_submissions(id) ON DELETE CASCADE, + name TEXT NOT NULL, + slug TEXT NOT NULL, + description TEXT, + company_type TEXT NOT NULL, + person_type TEXT DEFAULT 'company', + founded_year INTEGER, + headquarters_location TEXT, + website_url TEXT, + logo_url TEXT, + banner_image_url TEXT, + banner_image_id TEXT, + card_image_url TEXT, + card_image_id TEXT, + created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), + updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), + UNIQUE(submission_id) +); + +-- 4. Ride Model Submissions +CREATE TABLE ride_model_submissions ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + submission_id UUID NOT NULL REFERENCES content_submissions(id) ON DELETE CASCADE, + manufacturer_id UUID, + name TEXT NOT NULL, + slug TEXT NOT NULL, + description TEXT, + category TEXT NOT NULL, + ride_type TEXT NOT NULL, + banner_image_url TEXT, + banner_image_id TEXT, + card_image_url TEXT, + card_image_id TEXT, + created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), + updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), + UNIQUE(submission_id) +); + +-- 5. Ride Technical Specifications +CREATE TABLE ride_technical_specs ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + ride_submission_id UUID NOT NULL REFERENCES ride_submissions(id) ON DELETE CASCADE, + spec_name TEXT NOT NULL, + spec_value TEXT NOT NULL, + spec_type TEXT NOT NULL, + category TEXT, + unit TEXT, + created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW() +); + +-- 6. Ride Coaster Statistics +CREATE TABLE ride_coaster_stats ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + ride_submission_id UUID NOT NULL REFERENCES ride_submissions(id) ON DELETE CASCADE, + stat_name TEXT NOT NULL, + stat_value NUMERIC NOT NULL, + unit TEXT, + category TEXT, + created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW() +); + +-- 7. Ride Former Names +CREATE TABLE ride_former_names ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + ride_submission_id UUID NOT NULL REFERENCES ride_submissions(id) ON DELETE CASCADE, + former_name TEXT NOT NULL, + date_changed DATE, + reason TEXT, + order_index INTEGER DEFAULT 0, + created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW() +); + +-- 8. Submission Dependencies +CREATE TABLE submission_dependencies ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + parent_submission_id UUID NOT NULL, + child_submission_id UUID NOT NULL, + parent_entity_type TEXT NOT NULL, + child_entity_type TEXT NOT NULL, + dependency_type TEXT NOT NULL DEFAULT 'requires', + created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), + UNIQUE(parent_submission_id, child_submission_id) +); + +-- Create indexes for better query performance +CREATE INDEX idx_park_submissions_submission_id ON park_submissions(submission_id); +CREATE INDEX idx_ride_submissions_submission_id ON ride_submissions(submission_id); +CREATE INDEX idx_ride_submissions_park_id ON ride_submissions(park_id); +CREATE INDEX idx_company_submissions_submission_id ON company_submissions(submission_id); +CREATE INDEX idx_ride_model_submissions_submission_id ON ride_model_submissions(submission_id); +CREATE INDEX idx_ride_technical_specs_ride_submission_id ON ride_technical_specs(ride_submission_id); +CREATE INDEX idx_ride_coaster_stats_ride_submission_id ON ride_coaster_stats(ride_submission_id); +CREATE INDEX idx_ride_former_names_ride_submission_id ON ride_former_names(ride_submission_id); +CREATE INDEX idx_submission_dependencies_parent ON submission_dependencies(parent_submission_id); +CREATE INDEX idx_submission_dependencies_child ON submission_dependencies(child_submission_id); + +-- Enable RLS on all tables +ALTER TABLE park_submissions ENABLE ROW LEVEL SECURITY; +ALTER TABLE ride_submissions ENABLE ROW LEVEL SECURITY; +ALTER TABLE company_submissions ENABLE ROW LEVEL SECURITY; +ALTER TABLE ride_model_submissions ENABLE ROW LEVEL SECURITY; +ALTER TABLE ride_technical_specs ENABLE ROW LEVEL SECURITY; +ALTER TABLE ride_coaster_stats ENABLE ROW LEVEL SECURITY; +ALTER TABLE ride_former_names ENABLE ROW LEVEL SECURITY; +ALTER TABLE submission_dependencies ENABLE ROW LEVEL SECURITY; + +-- RLS Policies for park_submissions +CREATE POLICY "Users can view their own park submissions" + ON park_submissions FOR SELECT + USING ( + EXISTS ( + SELECT 1 FROM content_submissions cs + WHERE cs.id = park_submissions.submission_id + AND cs.user_id = auth.uid() + ) + ); + +CREATE POLICY "Moderators can view all park submissions" + ON park_submissions FOR SELECT + USING (is_moderator(auth.uid())); + +CREATE POLICY "Users can insert their own park submissions" + ON park_submissions FOR INSERT + WITH CHECK ( + EXISTS ( + SELECT 1 FROM content_submissions cs + WHERE cs.id = park_submissions.submission_id + AND cs.user_id = auth.uid() + ) + ); + +CREATE POLICY "Moderators can update park submissions" + ON park_submissions FOR UPDATE + USING (is_moderator(auth.uid())); + +CREATE POLICY "Moderators can delete park submissions" + ON park_submissions FOR DELETE + USING (is_moderator(auth.uid())); + +-- RLS Policies for ride_submissions +CREATE POLICY "Users can view their own ride submissions" + ON ride_submissions FOR SELECT + USING ( + EXISTS ( + SELECT 1 FROM content_submissions cs + WHERE cs.id = ride_submissions.submission_id + AND cs.user_id = auth.uid() + ) + ); + +CREATE POLICY "Moderators can view all ride submissions" + ON ride_submissions FOR SELECT + USING (is_moderator(auth.uid())); + +CREATE POLICY "Users can insert their own ride submissions" + ON ride_submissions FOR INSERT + WITH CHECK ( + EXISTS ( + SELECT 1 FROM content_submissions cs + WHERE cs.id = ride_submissions.submission_id + AND cs.user_id = auth.uid() + ) + ); + +CREATE POLICY "Moderators can update ride submissions" + ON ride_submissions FOR UPDATE + USING (is_moderator(auth.uid())); + +CREATE POLICY "Moderators can delete ride submissions" + ON ride_submissions FOR DELETE + USING (is_moderator(auth.uid())); + +-- RLS Policies for company_submissions +CREATE POLICY "Users can view their own company submissions" + ON company_submissions FOR SELECT + USING ( + EXISTS ( + SELECT 1 FROM content_submissions cs + WHERE cs.id = company_submissions.submission_id + AND cs.user_id = auth.uid() + ) + ); + +CREATE POLICY "Moderators can view all company submissions" + ON company_submissions FOR SELECT + USING (is_moderator(auth.uid())); + +CREATE POLICY "Users can insert their own company submissions" + ON company_submissions FOR INSERT + WITH CHECK ( + EXISTS ( + SELECT 1 FROM content_submissions cs + WHERE cs.id = company_submissions.submission_id + AND cs.user_id = auth.uid() + ) + ); + +CREATE POLICY "Moderators can update company submissions" + ON company_submissions FOR UPDATE + USING (is_moderator(auth.uid())); + +CREATE POLICY "Moderators can delete company submissions" + ON company_submissions FOR DELETE + USING (is_moderator(auth.uid())); + +-- RLS Policies for ride_model_submissions +CREATE POLICY "Users can view their own ride model submissions" + ON ride_model_submissions FOR SELECT + USING ( + EXISTS ( + SELECT 1 FROM content_submissions cs + WHERE cs.id = ride_model_submissions.submission_id + AND cs.user_id = auth.uid() + ) + ); + +CREATE POLICY "Moderators can view all ride model submissions" + ON ride_model_submissions FOR SELECT + USING (is_moderator(auth.uid())); + +CREATE POLICY "Users can insert their own ride model submissions" + ON ride_model_submissions FOR INSERT + WITH CHECK ( + EXISTS ( + SELECT 1 FROM content_submissions cs + WHERE cs.id = ride_model_submissions.submission_id + AND cs.user_id = auth.uid() + ) + ); + +CREATE POLICY "Moderators can update ride model submissions" + ON ride_model_submissions FOR UPDATE + USING (is_moderator(auth.uid())); + +CREATE POLICY "Moderators can delete ride model submissions" + ON ride_model_submissions FOR DELETE + USING (is_moderator(auth.uid())); + +-- RLS Policies for ride_technical_specs +CREATE POLICY "Users can view specs for their own ride submissions" + ON ride_technical_specs FOR SELECT + USING ( + EXISTS ( + SELECT 1 FROM ride_submissions rs + JOIN content_submissions cs ON cs.id = rs.submission_id + WHERE rs.id = ride_technical_specs.ride_submission_id + AND cs.user_id = auth.uid() + ) + ); + +CREATE POLICY "Moderators can view all ride technical specs" + ON ride_technical_specs FOR SELECT + USING (is_moderator(auth.uid())); + +CREATE POLICY "Users can insert specs for their own ride submissions" + ON ride_technical_specs FOR INSERT + WITH CHECK ( + EXISTS ( + SELECT 1 FROM ride_submissions rs + JOIN content_submissions cs ON cs.id = rs.submission_id + WHERE rs.id = ride_technical_specs.ride_submission_id + AND cs.user_id = auth.uid() + ) + ); + +CREATE POLICY "Moderators can manage ride technical specs" + ON ride_technical_specs FOR ALL + USING (is_moderator(auth.uid())); + +-- RLS Policies for ride_coaster_stats +CREATE POLICY "Users can view stats for their own ride submissions" + ON ride_coaster_stats FOR SELECT + USING ( + EXISTS ( + SELECT 1 FROM ride_submissions rs + JOIN content_submissions cs ON cs.id = rs.submission_id + WHERE rs.id = ride_coaster_stats.ride_submission_id + AND cs.user_id = auth.uid() + ) + ); + +CREATE POLICY "Moderators can view all ride coaster stats" + ON ride_coaster_stats FOR SELECT + USING (is_moderator(auth.uid())); + +CREATE POLICY "Users can insert stats for their own ride submissions" + ON ride_coaster_stats FOR INSERT + WITH CHECK ( + EXISTS ( + SELECT 1 FROM ride_submissions rs + JOIN content_submissions cs ON cs.id = rs.submission_id + WHERE rs.id = ride_coaster_stats.ride_submission_id + AND cs.user_id = auth.uid() + ) + ); + +CREATE POLICY "Moderators can manage ride coaster stats" + ON ride_coaster_stats FOR ALL + USING (is_moderator(auth.uid())); + +-- RLS Policies for ride_former_names +CREATE POLICY "Users can view former names for their own ride submissions" + ON ride_former_names FOR SELECT + USING ( + EXISTS ( + SELECT 1 FROM ride_submissions rs + JOIN content_submissions cs ON cs.id = rs.submission_id + WHERE rs.id = ride_former_names.ride_submission_id + AND cs.user_id = auth.uid() + ) + ); + +CREATE POLICY "Moderators can view all ride former names" + ON ride_former_names FOR SELECT + USING (is_moderator(auth.uid())); + +CREATE POLICY "Users can insert former names for their own ride submissions" + ON ride_former_names FOR INSERT + WITH CHECK ( + EXISTS ( + SELECT 1 FROM ride_submissions rs + JOIN content_submissions cs ON cs.id = rs.submission_id + WHERE rs.id = ride_former_names.ride_submission_id + AND cs.user_id = auth.uid() + ) + ); + +CREATE POLICY "Moderators can manage ride former names" + ON ride_former_names FOR ALL + USING (is_moderator(auth.uid())); + +-- RLS Policies for submission_dependencies +CREATE POLICY "Users can view dependencies for their own submissions" + ON submission_dependencies FOR SELECT + USING ( + EXISTS ( + SELECT 1 FROM content_submissions cs + WHERE (cs.id = submission_dependencies.parent_submission_id + OR cs.id = submission_dependencies.child_submission_id) + AND cs.user_id = auth.uid() + ) + ); + +CREATE POLICY "Moderators can view all submission dependencies" + ON submission_dependencies FOR SELECT + USING (is_moderator(auth.uid())); + +CREATE POLICY "Users can insert dependencies for their own submissions" + ON submission_dependencies FOR INSERT + WITH CHECK ( + EXISTS ( + SELECT 1 FROM content_submissions cs + WHERE cs.id = submission_dependencies.child_submission_id + AND cs.user_id = auth.uid() + ) + ); + +CREATE POLICY "Moderators can manage submission dependencies" + ON submission_dependencies FOR ALL + USING (is_moderator(auth.uid())); + +-- Add triggers for updated_at timestamps +CREATE TRIGGER update_park_submissions_updated_at + BEFORE UPDATE ON park_submissions + FOR EACH ROW + EXECUTE FUNCTION update_updated_at_column(); + +CREATE TRIGGER update_ride_submissions_updated_at + BEFORE UPDATE ON ride_submissions + FOR EACH ROW + EXECUTE FUNCTION update_updated_at_column(); + +CREATE TRIGGER update_company_submissions_updated_at + BEFORE UPDATE ON company_submissions + FOR EACH ROW + EXECUTE FUNCTION update_updated_at_column(); + +CREATE TRIGGER update_ride_model_submissions_updated_at + BEFORE UPDATE ON ride_model_submissions + FOR EACH ROW + EXECUTE FUNCTION update_updated_at_column(); \ No newline at end of file