diff --git a/api/.env.development b/api/.env.development index e88f36d..887d2a4 100644 --- a/api/.env.development +++ b/api/.env.development @@ -12,4 +12,6 @@ CORS_ORIGIN="http://localhost:5173" R2_ACCOUNT_ID="9715fa14c5e5d1612301572cf1c6bbee" R2_ACCESS_KEY_ID="caeb987bbcd601708a93c6aa562064ef" -R2_SECRET_ACCESS_KEY="42e455b25804687f7cff3d15be23c1f0f47ca742d7a41b6fa1a05a91041e0215" \ No newline at end of file +R2_SECRET_ACCESS_KEY="42e455b25804687f7cff3d15be23c1f0f47ca742d7a41b6fa1a05a91041e0215" + +SYNC_CALS_SECRET="hello" \ No newline at end of file diff --git a/api/.env.production b/api/.env.production index 0ad3fcd..5c36144 100644 --- a/api/.env.production +++ b/api/.env.production @@ -12,4 +12,6 @@ CORS_ORIGIN="https://app.xtablo.com" R2_ACCOUNT_ID="9715fa14c5e5d1612301572cf1c6bbee" R2_ACCESS_KEY_ID="caeb987bbcd601708a93c6aa562064ef" -R2_SECRET_ACCESS_KEY="42e455b25804687f7cff3d15be23c1f0f47ca742d7a41b6fa1a05a91041e0215" \ No newline at end of file +R2_SECRET_ACCESS_KEY="42e455b25804687f7cff3d15be23c1f0f47ca742d7a41b6fa1a05a91041e0215" + +SYNC_CALS_SECRET="gT3BAytmNwhe1wKmvgREBlWcqK0=" \ No newline at end of file diff --git a/api/src/config.ts b/api/src/config.ts index 087d601..b7fafe6 100644 --- a/api/src/config.ts +++ b/api/src/config.ts @@ -16,6 +16,7 @@ export interface AppConfig { R2_SECRET_ACCESS_KEY: string; CORS_ORIGIN: string[]; LOG_LEVEL: "debug" | "info" | "warn" | "error"; + SYNC_CALS_SECRET: string; } function validateEnvVar(name: string, value: string | undefined): string { @@ -65,6 +66,7 @@ function createConfig(): AppConfig { "R2_SECRET_ACCESS_KEY", process.env.R2_SECRET_ACCESS_KEY ), + SYNC_CALS_SECRET: process.env.SYNC_CALS_SECRET || "", LOG_LEVEL: "info", }; diff --git a/api/src/routers.ts b/api/src/routers.ts index 80eab74..3b06b1e 100644 --- a/api/src/routers.ts +++ b/api/src/routers.ts @@ -2,6 +2,7 @@ import { Hono } from "hono"; import { userRouter } from "./user.js"; import { supabaseMiddleware } from "./middleware.js"; import { tabloRouter } from "./tablo.js"; +import { taskRouter } from "./tasks.js"; export const mainRouter = new Hono<{ Bindings: { @@ -30,3 +31,4 @@ mainRouter.use(supabaseMiddleware); mainRouter.route("/users", userRouter); mainRouter.route("/tablos", tabloRouter); +mainRouter.route("/tasks", taskRouter); diff --git a/api/src/tasks.ts b/api/src/tasks.ts new file mode 100644 index 0000000..5b86707 --- /dev/null +++ b/api/src/tasks.ts @@ -0,0 +1,50 @@ +import { config } from "./config.js"; +import { Hono } from "hono"; +import { S3Client } from "@aws-sdk/client-s3"; +import { writeCalendarFileToR2 } from "./helpers.js"; +import type { SupabaseClient } from "@supabase/supabase-js"; + +export const taskRouter = new Hono<{ + Variables: { supabase: SupabaseClient }; +}>(); + +taskRouter.post("/sync-calendars", async (c) => { + const supabase = c.get("supabase"); + if (c.req.header("Authorization") !== "Basic " + config.SYNC_CALS_SECRET) { + return c.json({ error: "Unauthorized" }, 401); + } + + const s3 = new S3Client({ + region: "auto", + endpoint: `https://${config.R2_ACCOUNT_ID}.r2.cloudflarestorage.com`, + credentials: { + accessKeyId: config.R2_ACCESS_KEY_ID, + secretAccessKey: config.R2_SECRET_ACCESS_KEY, + }, + }); + const { data, error } = await supabase + .from("calendar_subscriptions") + .select("token, tablo_id, tablos(name)"); + if (error) { + return c.json({ error: error.message }, 500); + } + + const calendarSubscriptionsData = data as unknown as [ + { + token: string; + tablo_id: string; + tablos: { name: string }; + } + ]; + + calendarSubscriptionsData.forEach(async (subscription) => { + const tabloName = subscription.tablos.name.replace(/ /g, "_"); + await writeCalendarFileToR2(s3, supabase, { + tabloName, + token: subscription.token, + tablo_id: subscription.tablo_id, + }); + }); + + return c.json({ message: "Synced calendars" }); +});