diff --git a/src/controllers/internal/new-episode/index.ts b/src/controllers/internal/new-episode/index.ts index a90202c..128e0ce 100644 --- a/src/controllers/internal/new-episode/index.ts +++ b/src/controllers/internal/new-episode/index.ts @@ -1,16 +1,13 @@ import { zValidator } from "@hono/zod-validator"; import { Hono } from "hono"; import { env } from "hono/adapter"; -import mapKeys from "lodash.mapkeys"; import { z } from "zod"; import { fetchEpisodeUrlFromAllProviders } from "~/controllers/episodes/getEpisodeUrl"; -import { Case, changeStringCase } from "~/libs/changeStringCase"; -import type { AdminSdkCredentials } from "~/libs/gcloud/getGoogleAuthToken"; +import { getAdminSdkCredentials } from "~/libs/gcloud/getAdminSdkCredentials"; import { sendFcmMessage } from "~/libs/gcloud/sendFcmMessage"; import { maybeScheduleNextAiringEpisode } from "~/libs/maybeScheduleNextAiringEpisode"; import { verifyQstashHeader } from "~/libs/qstash/verifyQstashHeader"; -import { readEnvVariable } from "~/libs/readEnvVariable"; import { getTokensSubscribedToTitle } from "~/models/token"; import { isWatchingTitle } from "~/models/watchStatus"; import type { Env } from "~/types/env"; @@ -83,13 +80,7 @@ app.post( await Promise.allSettled( tokens.map(async (token) => { return sendFcmMessage( - mapKeys( - readEnvVariable( - env(c, "workerd"), - "ADMIN_SDK_JSON", - ), - (_, key) => changeStringCase(key, Case.snake_case, Case.camelCase), - ) as unknown as AdminSdkCredentials, + getAdminSdkCredentials(env(c, "workerd")), { token, data: { diff --git a/src/controllers/internal/upcoming-titles/index.ts b/src/controllers/internal/upcoming-titles/index.ts index 53f5b9f..ee44111 100644 --- a/src/controllers/internal/upcoming-titles/index.ts +++ b/src/controllers/internal/upcoming-titles/index.ts @@ -1,13 +1,10 @@ import { Hono } from "hono"; import { env } from "hono/adapter"; -import mapKeys from "lodash.mapkeys"; import { DateTime } from "luxon"; -import { Case, changeStringCase } from "~/libs/changeStringCase"; -import type { AdminSdkCredentials } from "~/libs/gcloud/getGoogleAuthToken"; +import { getAdminSdkCredentials } from "~/libs/gcloud/getAdminSdkCredentials"; import { sendFcmMessage } from "~/libs/gcloud/sendFcmMessage"; import { verifyQstashHeader } from "~/libs/qstash/verifyQstashHeader"; -import { readEnvVariable } from "~/libs/readEnvVariable"; import type { Env } from "~/types/env"; import { ErrorResponse, SuccessResponse } from "~/types/schema"; @@ -32,35 +29,29 @@ app.post("/", async (c) => { title.media.title?.english ?? "Unknown Title"; - return sendFcmMessage( - mapKeys( - readEnvVariable(c.env, "ADMIN_SDK_JSON"), - (_, key) => changeStringCase(key, Case.snake_case, Case.camelCase), - ) as unknown as AdminSdkCredentials, - { - topic: "newTitles", - data: { - type: "new_title", - aniListId: title.media.id.toString(), - title: titleName, - airingAt: title.airingAt.toString(), - }, + return sendFcmMessage(getAdminSdkCredentials(c.env), { + topic: "newTitles", + data: { + type: "new_title", + aniListId: title.media.id.toString(), + title: titleName, + airingAt: title.airingAt.toString(), + }, + notification: { + title: "New Series Alert", + body: `${titleName} will be released ${DateTime.fromSeconds(title.airingAt).toRelative({ unit: ["hours", "minutes"] })}`, + image: + title.media.coverImage?.medium ?? + title.media.coverImage?.large ?? + title.media.coverImage?.extraLarge ?? + undefined, + }, + android: { notification: { - title: "New Series Alert", - body: `${titleName} will be released ${DateTime.fromSeconds(title.airingAt).toRelative({ unit: ["hours", "minutes"] })}`, - image: - title.media.coverImage?.medium ?? - title.media.coverImage?.large ?? - title.media.coverImage?.extraLarge ?? - undefined, - }, - android: { - notification: { - click_action: "HANDLE_FCM_NOTIFICATION", - }, + click_action: "HANDLE_FCM_NOTIFICATION", }, }, - ); + }); }), ); diff --git a/src/controllers/token/index.ts b/src/controllers/token/index.ts index a2b2bbe..645fb7d 100644 --- a/src/controllers/token/index.ts +++ b/src/controllers/token/index.ts @@ -1,11 +1,8 @@ import { OpenAPIHono, createRoute, z } from "@hono/zod-openapi"; import { env } from "hono/adapter"; -import mapKeys from "lodash.mapkeys"; -import { Case, changeStringCase } from "~/libs/changeStringCase"; -import type { AdminSdkCredentials } from "~/libs/gcloud/getGoogleAuthToken"; +import { getAdminSdkCredentials } from "~/libs/gcloud/getAdminSdkCredentials"; import { verifyFcmToken } from "~/libs/gcloud/verifyFcmToken"; -import { readEnvVariable } from "~/libs/readEnvVariable"; import { saveToken } from "~/models/token"; import type { Env } from "~/types/env"; import { @@ -73,10 +70,7 @@ app.openapi(route, async (c) => { try { const isValidToken = await verifyFcmToken( token, - mapKeys( - readEnvVariable(c.env, "ADMIN_SDK_JSON"), - (_, key) => changeStringCase(key, Case.snake_case, Case.camelCase), - ) as unknown as AdminSdkCredentials, + getAdminSdkCredentials(c.env), ); if (!isValidToken) { return c.json(ErrorResponse, 401); diff --git a/src/libs/gcloud/getAdminSdkCredentials.ts b/src/libs/gcloud/getAdminSdkCredentials.ts new file mode 100644 index 0000000..1d3d0eb --- /dev/null +++ b/src/libs/gcloud/getAdminSdkCredentials.ts @@ -0,0 +1,27 @@ +import mapKeys from "lodash.mapkeys"; + +import type { Env } from "~/types/env"; + +import { Case, changeStringCase } from "../changeStringCase"; +import { readEnvVariable } from "../readEnvVariable"; + +export function getAdminSdkCredentials(env: Env) { + return mapKeys( + readEnvVariable(env, "ADMIN_SDK_JSON"), + (_, key) => changeStringCase(key, Case.snake_case, Case.camelCase), + ) as unknown as AdminSdkCredentials; +} + +export interface AdminSdkCredentials { + type: string; + projectId: string; + privateKeyId: string; + privateKey: string; + clientEmail: string; + clientID: string; + authURI: string; + tokenURI: string; + authProviderX509CertUrl: string; + clientX509CertUrl: string; + universeDomain: string; +} diff --git a/src/libs/gcloud/getGoogleAuthToken.ts b/src/libs/gcloud/getGoogleAuthToken.ts index f1d782f..66028fd 100644 --- a/src/libs/gcloud/getGoogleAuthToken.ts +++ b/src/libs/gcloud/getGoogleAuthToken.ts @@ -3,6 +3,7 @@ import { SignJWT, importPKCS8 } from "jose"; import { DateTime } from "luxon"; import { lazy } from "../lazy"; +import type { AdminSdkCredentials } from "./getAdminSdkCredentials"; export async function getGoogleAuthToken(adminSdkJson: AdminSdkCredentials) { const { privateKey, clientEmail } = adminSdkJson; @@ -11,7 +12,10 @@ export async function getGoogleAuthToken(adminSdkJson: AdminSdkCredentials) { { key: privateKey, email: clientEmail, - scope: ["https://www.googleapis.com/auth/firebase.messaging"], + scope: [ + "https://www.googleapis.com/auth/firebase.messaging", + "https://www.googleapis.com/auth/cloud-tasks", + ], }, adminSdkJson, ); @@ -155,17 +159,3 @@ interface TokenData { token: GoogleTokenData; expiresAt: DateTime; } - -export interface AdminSdkCredentials { - type: string; - projectId: string; - privateKeyId: string; - privateKey: string; - clientEmail: string; - clientID: string; - authURI: string; - tokenURI: string; - authProviderX509CertUrl: string; - clientX509CertUrl: string; - universeDomain: string; -} diff --git a/src/libs/gcloud/sendFcmMessage.ts b/src/libs/gcloud/sendFcmMessage.ts index ee2d54f..117ec4e 100644 --- a/src/libs/gcloud/sendFcmMessage.ts +++ b/src/libs/gcloud/sendFcmMessage.ts @@ -1,7 +1,5 @@ -import { - type AdminSdkCredentials, - getGoogleAuthToken, -} from "./getGoogleAuthToken"; +import type { AdminSdkCredentials } from "./getAdminSdkCredentials"; +import { getGoogleAuthToken } from "./getGoogleAuthToken"; export async function sendFcmMessage( adminSdkJson: AdminSdkCredentials, @@ -20,7 +18,7 @@ export async function sendFcmMessage( Authorization: `Bearer ${await getGoogleAuthToken(adminSdkJson)}`, }, }, - ).then((res) => res.json()); + ).then((res) => res.json() as Promise); } type SendFcmMessageResponse = diff --git a/src/libs/gcloud/verifyFcmToken.spec.ts b/src/libs/gcloud/verifyFcmToken.spec.ts index 1ea78ed..c563a40 100644 --- a/src/libs/gcloud/verifyFcmToken.spec.ts +++ b/src/libs/gcloud/verifyFcmToken.spec.ts @@ -2,7 +2,7 @@ import { describe, expect, it } from "bun:test"; import { server } from "~/mocks"; -import type { AdminSdkCredentials } from "./getGoogleAuthToken"; +import type { AdminSdkCredentials } from "./getAdminSdkCredentials"; import { verifyFcmToken } from "./verifyFcmToken"; server.listen(); diff --git a/src/libs/gcloud/verifyFcmToken.ts b/src/libs/gcloud/verifyFcmToken.ts index 3e041b1..65c1e0a 100644 --- a/src/libs/gcloud/verifyFcmToken.ts +++ b/src/libs/gcloud/verifyFcmToken.ts @@ -1,4 +1,4 @@ -import type { AdminSdkCredentials } from "./getGoogleAuthToken"; +import type { AdminSdkCredentials } from "./getAdminSdkCredentials"; import { sendFcmMessage } from "./sendFcmMessage"; export async function verifyFcmToken( diff --git a/src/mocks/getGoogleAuthToken.ts b/src/mocks/getGoogleAuthToken.ts index 78ccff5..a0280b5 100644 --- a/src/mocks/getGoogleAuthToken.ts +++ b/src/mocks/getGoogleAuthToken.ts @@ -2,7 +2,7 @@ import type { TokenOptions } from "gtoken"; import { mock } from "bun:test"; -import type { AdminSdkCredentials } from "~/libs/gcloud/getGoogleAuthToken"; +import type { AdminSdkCredentials } from "~/libs/gcloud/getAdminSdkCredentials"; const emailRegex = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|.(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;