2024-04-10 22:03:32 +00:00
|
|
|
import { SupabaseClient, createClient } from "https://esm.sh/@supabase/supabase-js@2";
|
2024-04-10 15:00:22 +00:00
|
|
|
|
|
|
|
interface StraetoVariables {
|
|
|
|
[key: string]: number | string;
|
|
|
|
}
|
|
|
|
|
|
|
|
interface StraetoQuery {
|
|
|
|
operationName: string;
|
|
|
|
variables: StraetoVariables;
|
|
|
|
extensions: StraetoQueryExtensions;
|
|
|
|
}
|
|
|
|
|
|
|
|
interface StraetoQueryExtensions {
|
|
|
|
persistedQuery: StraetoPersistedQuery;
|
|
|
|
}
|
|
|
|
|
|
|
|
interface StraetoPersistedQuery {
|
|
|
|
version: number;
|
|
|
|
sha256Hash: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
interface StraetoBusStop {
|
|
|
|
id: number;
|
|
|
|
name: string;
|
|
|
|
lat: number;
|
|
|
|
lon: number;
|
|
|
|
type: number;
|
|
|
|
rotation: number;
|
|
|
|
code: string | null;
|
|
|
|
isTerminal: boolean;
|
|
|
|
routes: Array<string>;
|
|
|
|
alerts: Array<string>;
|
|
|
|
__typename: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
interface DbBusStop {
|
|
|
|
id: number;
|
|
|
|
stop_name: string;
|
|
|
|
coords: string; // TODO better geometry type representation
|
|
|
|
type: number;
|
|
|
|
rotation: number;
|
|
|
|
code: string | null;
|
|
|
|
is_terminal: boolean;
|
|
|
|
routes: Array<string>;
|
|
|
|
}
|
|
|
|
|
|
|
|
function toDbBusStop(straetoStop: StraetoBusStop): DbBusStop {
|
|
|
|
return {
|
|
|
|
id: straetoStop.id,
|
|
|
|
code: straetoStop.code,
|
|
|
|
stop_name: straetoStop.name,
|
|
|
|
coords: `POINT(${straetoStop.lat} ${straetoStop.lon})`,
|
|
|
|
type: straetoStop.type,
|
|
|
|
rotation: straetoStop.rotation,
|
|
|
|
is_terminal: straetoStop.isTerminal,
|
|
|
|
routes: straetoStop.routes,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
function toQuerystring(obj: StraetoQuery) {
|
|
|
|
return Object.keys(obj).map(function (variableName) {
|
|
|
|
const variableValue = obj[variableName as keyof typeof obj];
|
|
|
|
if (typeof variableValue == "object") {
|
|
|
|
return encodeURIComponent(variableName) + "=" +
|
|
|
|
encodeURIComponent(JSON.stringify(variableValue));
|
|
|
|
} else {
|
|
|
|
return encodeURIComponent(variableName) + "=" +
|
|
|
|
encodeURIComponent(variableValue);
|
|
|
|
}
|
|
|
|
}).join("&");
|
|
|
|
}
|
|
|
|
|
|
|
|
const graphqlParams: StraetoQuery = {
|
|
|
|
operationName: "Stops",
|
|
|
|
variables: {},
|
|
|
|
extensions: {
|
|
|
|
persistedQuery: {
|
|
|
|
version: 1,
|
|
|
|
sha256Hash:
|
|
|
|
"6303de055cc42db47a4e1f1cc941b8c86d11c147903bed231e6d4bddcf0e1312",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
async function getStops(): Promise<Array<StraetoBusStop>> {
|
|
|
|
const apiUrl = `https://straeto.is/graphql?${toQuerystring(graphqlParams)}`;
|
|
|
|
|
|
|
|
const opts = {
|
|
|
|
method: "GET",
|
|
|
|
headers: {
|
|
|
|
"Content-Type": "application/json",
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
const resp = await fetch(apiUrl, opts);
|
2024-04-10 22:03:32 +00:00
|
|
|
const body = await resp.json();
|
2024-04-10 15:00:22 +00:00
|
|
|
return body.data.GtfsStops.results;
|
|
|
|
}
|
|
|
|
|
2024-04-10 22:03:32 +00:00
|
|
|
async function verifyUserIsAdmin(userClient: SupabaseClient): Promise<boolean> {
|
|
|
|
const user = await userClient.auth.getUser();
|
|
|
|
const metadata = user.data.user?.app_metadata;
|
|
|
|
|
|
|
|
if (!metadata || (metadata && !metadata.claims_admin)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2024-04-10 15:00:22 +00:00
|
|
|
|
2024-04-10 22:03:32 +00:00
|
|
|
Deno.serve(async (req) => {
|
2024-04-10 15:00:22 +00:00
|
|
|
const authHeader = req.headers.get("Authorization")!;
|
2024-04-10 22:03:32 +00:00
|
|
|
|
|
|
|
const userClient = createClient(
|
2024-04-10 15:00:22 +00:00
|
|
|
Deno.env.get("SUPABASE_URL") ?? "",
|
2024-04-10 22:03:32 +00:00
|
|
|
Deno.env.get("SUPABASE_SERVICE_ROLE_KEY") ?? "",
|
2024-04-10 15:00:22 +00:00
|
|
|
{ global: { headers: { Authorization: authHeader } } },
|
|
|
|
);
|
|
|
|
|
2024-04-10 22:03:32 +00:00
|
|
|
const secureClient = createClient(
|
|
|
|
Deno.env.get("SUPABASE_URL") ?? "",
|
|
|
|
Deno.env.get("SUPABASE_SERVICE_ROLE_KEY") ?? "",
|
|
|
|
);
|
|
|
|
|
|
|
|
if (!(await verifyUserIsAdmin(userClient))) {
|
|
|
|
return new Response(
|
|
|
|
JSON.stringify({ status: "denied", error: "must be an admin" }),
|
|
|
|
{ status: 403, headers: { "Content-Type": "application/json" } },
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
const busStops = await getStops();
|
|
|
|
|
2024-04-10 15:00:22 +00:00
|
|
|
console.log("inserting", busStops.length, "rows");
|
|
|
|
const toInsert = busStops.map(toDbBusStop);
|
|
|
|
|
2024-04-10 22:03:32 +00:00
|
|
|
const insert = await secureClient.from("bus_stops")
|
2024-04-10 15:00:22 +00:00
|
|
|
.upsert(toInsert, { ignoreDuplicates: true });
|
|
|
|
|
|
|
|
console.log(insert.statusText, insert.error?.code, insert.error?.message);
|
|
|
|
|
|
|
|
return new Response(
|
|
|
|
JSON.stringify({
|
|
|
|
"status": insert.statusText,
|
|
|
|
"inserted": toInsert.length,
|
|
|
|
"error": insert.error,
|
|
|
|
}),
|
|
|
|
{ headers: { "Content-Type": "application/json" } },
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
/* To invoke locally:
|
|
|
|
|
|
|
|
1. Run `supabase start` (see: https://supabase.com/docs/reference/cli/supabase-start)
|
|
|
|
2. Make an HTTP request:
|
|
|
|
|
|
|
|
curl -i --location --request POST 'http://127.0.0.1:54321/functions/v1/download-bus-stops' \
|
|
|
|
--header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0' \
|
2024-04-10 22:03:32 +00:00
|
|
|
--header 'Content-Type: application/json'
|
2024-04-10 15:00:22 +00:00
|
|
|
|
|
|
|
*/
|