mirror of
https://github.com/renee-png/acmcc.git
synced 2026-06-21 09:50:01 +00:00
abd46bcb2b
- HostingerReachPage (replaces MailchimpPage): connect Reach via reach-connection, per-association segment sync via reach-sync - ARC Applications: Buildium import review/matching updates - buildium-import-stage/apply: latest staging + apply changes (already deployed to Supabase) - migrations: hostinger_reach_integration + arc_finalized_lock service role (already applied to live DB) - CI: note that deployment is VPS-side polling (auto-deploy.sh cron) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
57 lines
2.6 KiB
TypeScript
57 lines
2.6 KiB
TypeScript
// Hostinger Reach — connection test. Validates the stored global API token by listing segments.
|
|
import { createClient } from "https://esm.sh/@supabase/supabase-js@2";
|
|
|
|
const corsHeaders = {
|
|
"Access-Control-Allow-Origin": "*",
|
|
"Access-Control-Allow-Headers": "authorization, x-client-info, apikey, content-type",
|
|
};
|
|
|
|
const REACH_BASE = "https://developers.hostinger.com/api/reach/v1";
|
|
|
|
Deno.serve(async (req) => {
|
|
if (req.method === "OPTIONS") return new Response(null, { headers: corsHeaders });
|
|
const json = (b: unknown, status = 200) =>
|
|
new Response(JSON.stringify(b), { status, headers: { ...corsHeaders, "Content-Type": "application/json" } });
|
|
|
|
try {
|
|
const authHeader = req.headers.get("Authorization");
|
|
if (!authHeader) return json({ error: "Unauthorized" }, 401);
|
|
|
|
const userClient = createClient(
|
|
Deno.env.get("SUPABASE_URL")!,
|
|
Deno.env.get("SUPABASE_ANON_KEY")!,
|
|
{ global: { headers: { Authorization: authHeader } } },
|
|
);
|
|
const admin = createClient(Deno.env.get("SUPABASE_URL")!, Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!);
|
|
|
|
const { data: { user } } = await userClient.auth.getUser();
|
|
if (!user) return json({ error: "Unauthorized" }, 401);
|
|
const { data: roles } = await admin.from("user_roles").select("role").eq("user_id", user.id);
|
|
if (!(roles || []).some((r: any) => r.role === "admin")) return json({ error: "Admin only" }, 403);
|
|
|
|
// A token can be supplied in the body to test before saving; otherwise use the stored one.
|
|
const body = await req.json().catch(() => ({}));
|
|
let token: string | null = typeof body.api_token === "string" && body.api_token.trim() ? body.api_token.trim() : null;
|
|
if (!token) {
|
|
const { data: cfg } = await admin
|
|
.from("hostinger_reach_config").select("api_token").order("updated_at", { ascending: false }).limit(1).maybeSingle();
|
|
token = cfg?.api_token || null;
|
|
}
|
|
if (!token) return json({ success: false, error: "No Hostinger Reach API token configured." }, 400);
|
|
|
|
const res = await fetch(`${REACH_BASE}/segmentation/segments`, {
|
|
headers: { Authorization: `Bearer ${token}`, Accept: "application/json" },
|
|
});
|
|
const text = await res.text();
|
|
if (!res.ok) {
|
|
return json({ success: false, error: `Reach API ${res.status}: ${text.slice(0, 300)}` }, 200);
|
|
}
|
|
let parsed: any = {};
|
|
try { parsed = JSON.parse(text); } catch { /* ignore */ }
|
|
const list = Array.isArray(parsed) ? parsed : (parsed.data ?? parsed.segments ?? []);
|
|
return json({ success: true, segment_count: Array.isArray(list) ? list.length : 0 });
|
|
} catch (err) {
|
|
return json({ success: false, error: (err as Error).message }, 500);
|
|
}
|
|
});
|