-- -- Name: collaborators; Type: TABLE; Schema: public; Owner: postgres -- CREATE TABLE "public"."collaborators" ( "id" bigint NOT NULL, "created_at" timestamp with time zone DEFAULT "now"(), "site" "uuid", "user" "uuid" NOT NULL, "role" "text" NOT NULL ); ALTER TABLE "public"."collaborators" OWNER TO "postgres"; -- -- Name: collaborators_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres -- ALTER TABLE "public"."collaborators" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( SEQUENCE NAME "public"."collaborators_id_seq" START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1 ); -- -- Name: config; Type: TABLE; Schema: public; Owner: postgres -- CREATE TABLE "public"."config" ( "id" "text" NOT NULL, "value" "text", "options" "jsonb", "created_at" timestamp with time zone DEFAULT "now"() ); ALTER TABLE "public"."config" OWNER TO "postgres"; -- -- Name: invitations; Type: TABLE; Schema: public; Owner: postgres -- CREATE TABLE "public"."invitations" ( "created_at" timestamp with time zone DEFAULT "now"(), "email" "text", "site" "uuid", "inviter_email" "text", "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL, "role" "text" NOT NULL, "server_invitation" boolean ); ALTER TABLE "public"."invitations" OWNER TO "postgres"; INSERT INTO public.config (id, value, options, created_at) VALUES ('github_token', null, null, now()); -- -- Name: pages; Type: TABLE; Schema: public; Owner: postgres -- CREATE TABLE "public"."pages" ( "code" "jsonb" DEFAULT '{"js": "", "css": "", "html": {"head": "", "below": ""}}' :: "jsonb", "name" "text", "fields" "jsonb" DEFAULT '[]' :: "jsonb", "created_at" timestamp with time zone DEFAULT "now"(), "url" "text", "content" "jsonb" DEFAULT '{}' :: "jsonb" NOT NULL, "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL, "site" "uuid" NOT NULL, "parent" "uuid" ); ALTER TABLE "public"."pages" OWNER TO "postgres"; -- -- Name: sections; Type: TABLE; Schema: public; Owner: postgres -- CREATE TABLE "public"."sections" ( "content" "jsonb" DEFAULT '{"en": {}}' :: "jsonb" NOT NULL, "created_at" timestamp with time zone DEFAULT "now"(), "index" smallint DEFAULT '1' :: smallint NOT NULL, "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL, "page" "uuid" NOT NULL, "symbol" "uuid" NOT NULL ); ALTER TABLE "public"."sections" OWNER TO "postgres"; -- Enable realtime for 'sections' table alter publication supabase_realtime add table sections; -- -- Name: server_members; Type: TABLE; Schema: public; Owner: postgres -- CREATE TABLE "public"."server_members" ( "id" bigint NOT NULL, "user" "uuid", "role" "text" DEFAULT 'DEV' :: "text", "created_at" timestamp with time zone DEFAULT "now"(), "admin" boolean DEFAULT false ); ALTER TABLE "public"."server_members" OWNER TO "postgres"; -- -- Name: server_members_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres -- ALTER TABLE "public"."server_members" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( SEQUENCE NAME "public"."server_members_id_seq" START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1 ); -- -- Name: sites; Type: TABLE; Schema: public; Owner: postgres -- CREATE TABLE "public"."sites" ( "id" "uuid" NOT NULL, "name" "text", "active_deployment" "jsonb", "created_at" timestamp with time zone DEFAULT "now"(), "code" "jsonb" DEFAULT '{"js": "", "css": "", "html": {"head": "", "below": ""}}' :: "jsonb" NOT NULL, "fields" "jsonb" DEFAULT '[]' :: "jsonb" NOT NULL, "content" "jsonb" DEFAULT '{}' :: "jsonb" NOT NULL, "url" "text" NOT NULL ); ALTER TABLE "public"."sites" OWNER TO "postgres"; -- -- Name: symbols; Type: TABLE; Schema: public; Owner: postgres -- CREATE TABLE "public"."symbols" ( "name" "text", "code" "jsonb" DEFAULT '{"js": "", "css": "", "html": ""}' :: "jsonb" NOT NULL, "fields" "jsonb" DEFAULT '[]' :: "jsonb" NOT NULL, "content" "jsonb" DEFAULT '{}' :: "jsonb", "created_at" timestamp with time zone DEFAULT "now"(), "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL, "site" "uuid" NOT NULL, "index" smallint DEFAULT '1' :: smallint NOT NULL ); ALTER TABLE "public"."symbols" OWNER TO "postgres"; -- -- Name: users; Type: TABLE; Schema: public; Owner: postgres -- CREATE TABLE "public"."users" ( "email" "text", "created_at" timestamp with time zone DEFAULT "now"(), "id" "uuid" NOT NULL ); ALTER TABLE "public"."users" OWNER TO "postgres"; -- -- Name: collaborators collaborators_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres -- ALTER TABLE ONLY "public"."collaborators" ADD CONSTRAINT "collaborators_pkey" PRIMARY KEY ("id"); -- -- Name: config config_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres -- ALTER TABLE ONLY "public"."config" ADD CONSTRAINT "config_pkey" PRIMARY KEY ("id"); -- -- Name: invitations invitations_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres -- ALTER TABLE ONLY "public"."invitations" ADD CONSTRAINT "invitations_pkey" PRIMARY KEY ("id"); -- -- Name: pages pages_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres -- ALTER TABLE ONLY "public"."pages" ADD CONSTRAINT "pages_id_key" UNIQUE ("id"); -- -- Name: pages pages_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres -- ALTER TABLE ONLY "public"."pages" ADD CONSTRAINT "pages_pkey" PRIMARY KEY ("id"); -- -- Name: sections sections_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres -- ALTER TABLE ONLY "public"."sections" ADD CONSTRAINT "sections_pkey" PRIMARY KEY ("id"); -- -- Name: server_members server_members_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres -- ALTER TABLE ONLY "public"."server_members" ADD CONSTRAINT "server_members_pkey" PRIMARY KEY ("id"); -- -- Name: sites sites_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres -- ALTER TABLE ONLY "public"."sites" ADD CONSTRAINT "sites_pkey" PRIMARY KEY ("id"); -- -- Name: sites sites_url_key; Type: CONSTRAINT; Schema: public; Owner: postgres -- ALTER TABLE ONLY "public"."sites" ADD CONSTRAINT "sites_url_key" UNIQUE ("url"); -- -- Name: symbols symbols_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres -- ALTER TABLE ONLY "public"."symbols" ADD CONSTRAINT "symbols_id_key" UNIQUE ("id"); -- -- Name: symbols symbols_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres -- ALTER TABLE ONLY "public"."symbols" ADD CONSTRAINT "symbols_pkey" PRIMARY KEY ("id"); -- -- Name: users users_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres -- ALTER TABLE ONLY "public"."users" ADD CONSTRAINT "users_pkey" PRIMARY KEY ("id"); -- -- Name: collaborators collaborators_site_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres -- ALTER TABLE ONLY "public"."collaborators" ADD CONSTRAINT "collaborators_site_fkey" FOREIGN KEY ("site") REFERENCES "public"."sites"("id"); -- -- Name: collaborators collaborators_user_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres -- ALTER TABLE ONLY "public"."collaborators" ADD CONSTRAINT "collaborators_user_fkey" FOREIGN KEY ("user") REFERENCES "public"."users"("id"); -- -- Name: invitations invitations_site_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres -- ALTER TABLE ONLY "public"."invitations" ADD CONSTRAINT "invitations_site_fkey" FOREIGN KEY ("site") REFERENCES "public"."sites"("id"); -- -- Name: pages pages_parent_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres -- ALTER TABLE ONLY "public"."pages" ADD CONSTRAINT "pages_parent_fkey" FOREIGN KEY ("parent") REFERENCES "public"."pages"("id"); -- -- Name: pages pages_site_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres -- ALTER TABLE ONLY "public"."pages" ADD CONSTRAINT "pages_site_fkey" FOREIGN KEY ("site") REFERENCES "public"."sites"("id"); -- -- Name: sections sections_page_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres -- ALTER TABLE ONLY "public"."sections" ADD CONSTRAINT "sections_page_fkey" FOREIGN KEY ("page") REFERENCES "public"."pages"("id"); -- -- Name: sections sections_symbol_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres -- ALTER TABLE ONLY "public"."sections" ADD CONSTRAINT "sections_symbol_fkey" FOREIGN KEY ("symbol") REFERENCES "public"."symbols"("id"); -- -- Name: server_members server_members_user_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres -- ALTER TABLE ONLY "public"."server_members" ADD CONSTRAINT "server_members_user_fkey" FOREIGN KEY ("user") REFERENCES "public"."users"("id") ON DELETE CASCADE; -- -- Name: symbols symbols_site_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres -- ALTER TABLE ONLY "public"."symbols" ADD CONSTRAINT "symbols_site_fkey" FOREIGN KEY ("site") REFERENCES "public"."sites"("id"); -- Set Row Level Security ALTER TABLE public.collaborators ENABLE ROW LEVEL SECURITY; ALTER TABLE public.config ENABLE ROW LEVEL SECURITY; ALTER TABLE public.invitations ENABLE ROW LEVEL SECURITY; ALTER TABLE public.pages ENABLE ROW LEVEL SECURITY; ALTER TABLE public.sections ENABLE ROW LEVEL SECURITY; ALTER TABLE public.server_members ENABLE ROW LEVEL SECURITY; ALTER TABLE public.sites ENABLE ROW LEVEL SECURITY; ALTER TABLE public.symbols ENABLE ROW LEVEL SECURITY; ALTER TABLE public.users ENABLE ROW LEVEL SECURITY; -- Set RLS Policy CREATE POLICY "Enable ALL for authenticated users" ON "public"."collaborators" AS PERMISSIVE FOR ALL TO authenticated USING (true) WITH CHECK (true); CREATE POLICY "Enable ALL for authenticated users" ON "public"."config" AS PERMISSIVE FOR ALL TO authenticated USING (true) WITH CHECK (true); CREATE POLICY "Enable ALL for authenticated users" ON "public"."invitations" AS PERMISSIVE FOR ALL TO authenticated USING (true) WITH CHECK (true); CREATE POLICY "Enable ALL for authenticated users" ON "public"."pages" AS PERMISSIVE FOR ALL TO authenticated USING (true) WITH CHECK (true); CREATE POLICY "Enable ALL for authenticated users" ON "public"."sections" AS PERMISSIVE FOR ALL TO authenticated USING (true) WITH CHECK (true); CREATE POLICY "Enable ALL for authenticated users" ON "public"."server_members" AS PERMISSIVE FOR ALL TO authenticated USING (true) WITH CHECK (true); CREATE POLICY "Enable ALL for authenticated users" ON "public"."sites" AS PERMISSIVE FOR ALL TO authenticated USING (true) WITH CHECK (true); CREATE POLICY "Enable ALL for authenticated users" ON "public"."symbols" AS PERMISSIVE FOR ALL TO authenticated USING (true) WITH CHECK (true); CREATE POLICY "Enable ALL for authenticated users" ON "public"."users" AS PERMISSIVE FOR ALL TO authenticated USING (true) WITH CHECK (true); -- Create storage buckets for site files and images INSERT INTO storage.buckets (id, name, public) VALUES ('sites', 'sites', TRUE), ('images', 'images', TRUE); -- Set storage security CREATE POLICY "Public access to view sites" ON storage.objects FOR SELECT USING (((bucket_id = 'sites' :: text))); CREATE POLICY "Give Authenticated users access to upload new sites" ON storage.objects FOR INSERT WITH CHECK ( ( (bucket_id = 'sites' :: text) AND (auth.role() = 'authenticated' :: text) ) ); CREATE POLICY "Give Authenticated users access to update sites" ON storage.objects FOR UPDATE USING ( ( (bucket_id = 'sites' :: text) AND (auth.role() = 'authenticated' :: text) ) ); CREATE POLICY "Give Authenticated users access to delete sites" ON storage.objects FOR DELETE USING ( ( (bucket_id = 'sites' :: text) AND (auth.role() = 'authenticated' :: text) ) ); -- Set storage security CREATE POLICY "Public access to view images" ON storage.objects FOR SELECT USING (((bucket_id = 'images' :: text))); CREATE POLICY "Give Authenticated users access to upload new images" ON storage.objects FOR INSERT WITH CHECK ( ( (bucket_id = 'images' :: text) AND (auth.role() = 'authenticated' :: text) ) ); CREATE POLICY "Give Authenticated users access to update images" ON storage.objects FOR UPDATE USING ( ( (bucket_id = 'images' :: text) AND (auth.role() = 'authenticated' :: text) ) ); CREATE POLICY "Give Authenticated users access to delete images" ON storage.objects FOR DELETE USING ( ( (bucket_id = 'images' :: text) AND (auth.role() = 'authenticated' :: text) ) ); -- helper functions CREATE OR REPLACE FUNCTION page_search(search_terms text, site_url text) RETURNS TABLE(id uuid, name text, url text, created_at timestamp with time zone) AS $$ BEGIN RETURN QUERY WITH RECURSIVE parent_urls AS ( SELECT p.id, ARRAY[p.url] AS urls FROM pages p INNER JOIN sites s ON p.site = s.id WHERE p.parent IS NULL AND s.url = site_url UNION ALL SELECT p.id, pu.urls || p.url FROM pages p INNER JOIN sites s ON p.site = s.id INNER JOIN parent_urls pu ON p.parent = pu.id WHERE s.url = site_url ) SELECT DISTINCT p.id, p.name, ARRAY_TO_STRING(parent_urls.urls, '/', '/') AS url, p.created_at FROM pages p INNER JOIN sites s ON p.site = s.id INNER JOIN sections se ON p.id = se.page INNER JOIN parent_urls ON p.id = parent_urls.id WHERE s.url = site_url AND to_tsvector(se.content) @@ to_tsquery(search_terms); END; $$ LANGUAGE plpgsql;