refactor: create function to read admin SDK JSON

This commit is contained in:
2024-10-05 11:21:20 -04:00
parent 62217ae75b
commit 44d579ee6d
9 changed files with 63 additions and 72 deletions

View File

@@ -1,16 +1,13 @@
import { zValidator } from "@hono/zod-validator"; import { zValidator } from "@hono/zod-validator";
import { Hono } from "hono"; import { Hono } from "hono";
import { env } from "hono/adapter"; import { env } from "hono/adapter";
import mapKeys from "lodash.mapkeys";
import { z } from "zod"; import { z } from "zod";
import { fetchEpisodeUrlFromAllProviders } from "~/controllers/episodes/getEpisodeUrl"; import { fetchEpisodeUrlFromAllProviders } from "~/controllers/episodes/getEpisodeUrl";
import { Case, changeStringCase } from "~/libs/changeStringCase"; import { getAdminSdkCredentials } from "~/libs/gcloud/getAdminSdkCredentials";
import type { AdminSdkCredentials } from "~/libs/gcloud/getGoogleAuthToken";
import { sendFcmMessage } from "~/libs/gcloud/sendFcmMessage"; import { sendFcmMessage } from "~/libs/gcloud/sendFcmMessage";
import { maybeScheduleNextAiringEpisode } from "~/libs/maybeScheduleNextAiringEpisode"; import { maybeScheduleNextAiringEpisode } from "~/libs/maybeScheduleNextAiringEpisode";
import { verifyQstashHeader } from "~/libs/qstash/verifyQstashHeader"; import { verifyQstashHeader } from "~/libs/qstash/verifyQstashHeader";
import { readEnvVariable } from "~/libs/readEnvVariable";
import { getTokensSubscribedToTitle } from "~/models/token"; import { getTokensSubscribedToTitle } from "~/models/token";
import { isWatchingTitle } from "~/models/watchStatus"; import { isWatchingTitle } from "~/models/watchStatus";
import type { Env } from "~/types/env"; import type { Env } from "~/types/env";
@@ -83,13 +80,7 @@ app.post(
await Promise.allSettled( await Promise.allSettled(
tokens.map(async (token) => { tokens.map(async (token) => {
return sendFcmMessage( return sendFcmMessage(
mapKeys( getAdminSdkCredentials(env<Env, typeof c>(c, "workerd")),
readEnvVariable<AdminSdkCredentials>(
env<Env, typeof c>(c, "workerd"),
"ADMIN_SDK_JSON",
),
(_, key) => changeStringCase(key, Case.snake_case, Case.camelCase),
) as unknown as AdminSdkCredentials,
{ {
token, token,
data: { data: {

View File

@@ -1,13 +1,10 @@
import { Hono } from "hono"; import { Hono } from "hono";
import { env } from "hono/adapter"; import { env } from "hono/adapter";
import mapKeys from "lodash.mapkeys";
import { DateTime } from "luxon"; import { DateTime } from "luxon";
import { Case, changeStringCase } from "~/libs/changeStringCase"; import { getAdminSdkCredentials } from "~/libs/gcloud/getAdminSdkCredentials";
import type { AdminSdkCredentials } from "~/libs/gcloud/getGoogleAuthToken";
import { sendFcmMessage } from "~/libs/gcloud/sendFcmMessage"; import { sendFcmMessage } from "~/libs/gcloud/sendFcmMessage";
import { verifyQstashHeader } from "~/libs/qstash/verifyQstashHeader"; import { verifyQstashHeader } from "~/libs/qstash/verifyQstashHeader";
import { readEnvVariable } from "~/libs/readEnvVariable";
import type { Env } from "~/types/env"; import type { Env } from "~/types/env";
import { ErrorResponse, SuccessResponse } from "~/types/schema"; import { ErrorResponse, SuccessResponse } from "~/types/schema";
@@ -32,35 +29,29 @@ app.post("/", async (c) => {
title.media.title?.english ?? title.media.title?.english ??
"Unknown Title"; "Unknown Title";
return sendFcmMessage( return sendFcmMessage(getAdminSdkCredentials(c.env), {
mapKeys( topic: "newTitles",
readEnvVariable<AdminSdkCredentials>(c.env, "ADMIN_SDK_JSON"), data: {
(_, key) => changeStringCase(key, Case.snake_case, Case.camelCase), type: "new_title",
) as unknown as AdminSdkCredentials, aniListId: title.media.id.toString(),
{ title: titleName,
topic: "newTitles", airingAt: title.airingAt.toString(),
data: { },
type: "new_title", notification: {
aniListId: title.media.id.toString(), title: "New Series Alert",
title: titleName, body: `${titleName} will be released ${DateTime.fromSeconds(title.airingAt).toRelative({ unit: ["hours", "minutes"] })}`,
airingAt: title.airingAt.toString(), image:
}, title.media.coverImage?.medium ??
title.media.coverImage?.large ??
title.media.coverImage?.extraLarge ??
undefined,
},
android: {
notification: { notification: {
title: "New Series Alert", click_action: "HANDLE_FCM_NOTIFICATION",
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",
},
}, },
}, },
); });
}), }),
); );

View File

@@ -1,11 +1,8 @@
import { OpenAPIHono, createRoute, z } from "@hono/zod-openapi"; import { OpenAPIHono, createRoute, z } from "@hono/zod-openapi";
import { env } from "hono/adapter"; import { env } from "hono/adapter";
import mapKeys from "lodash.mapkeys";
import { Case, changeStringCase } from "~/libs/changeStringCase"; import { getAdminSdkCredentials } from "~/libs/gcloud/getAdminSdkCredentials";
import type { AdminSdkCredentials } from "~/libs/gcloud/getGoogleAuthToken";
import { verifyFcmToken } from "~/libs/gcloud/verifyFcmToken"; import { verifyFcmToken } from "~/libs/gcloud/verifyFcmToken";
import { readEnvVariable } from "~/libs/readEnvVariable";
import { saveToken } from "~/models/token"; import { saveToken } from "~/models/token";
import type { Env } from "~/types/env"; import type { Env } from "~/types/env";
import { import {
@@ -73,10 +70,7 @@ app.openapi(route, async (c) => {
try { try {
const isValidToken = await verifyFcmToken( const isValidToken = await verifyFcmToken(
token, token,
mapKeys( getAdminSdkCredentials(c.env),
readEnvVariable<AdminSdkCredentials>(c.env, "ADMIN_SDK_JSON"),
(_, key) => changeStringCase(key, Case.snake_case, Case.camelCase),
) as unknown as AdminSdkCredentials,
); );
if (!isValidToken) { if (!isValidToken) {
return c.json(ErrorResponse, 401); return c.json(ErrorResponse, 401);

View File

@@ -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<AdminSdkCredentials>(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;
}

View File

@@ -3,6 +3,7 @@ import { SignJWT, importPKCS8 } from "jose";
import { DateTime } from "luxon"; import { DateTime } from "luxon";
import { lazy } from "../lazy"; import { lazy } from "../lazy";
import type { AdminSdkCredentials } from "./getAdminSdkCredentials";
export async function getGoogleAuthToken(adminSdkJson: AdminSdkCredentials) { export async function getGoogleAuthToken(adminSdkJson: AdminSdkCredentials) {
const { privateKey, clientEmail } = adminSdkJson; const { privateKey, clientEmail } = adminSdkJson;
@@ -11,7 +12,10 @@ export async function getGoogleAuthToken(adminSdkJson: AdminSdkCredentials) {
{ {
key: privateKey, key: privateKey,
email: clientEmail, 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, adminSdkJson,
); );
@@ -155,17 +159,3 @@ interface TokenData {
token: GoogleTokenData; token: GoogleTokenData;
expiresAt: DateTime; 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;
}

View File

@@ -1,7 +1,5 @@
import { import type { AdminSdkCredentials } from "./getAdminSdkCredentials";
type AdminSdkCredentials, import { getGoogleAuthToken } from "./getGoogleAuthToken";
getGoogleAuthToken,
} from "./getGoogleAuthToken";
export async function sendFcmMessage( export async function sendFcmMessage(
adminSdkJson: AdminSdkCredentials, adminSdkJson: AdminSdkCredentials,
@@ -20,7 +18,7 @@ export async function sendFcmMessage(
Authorization: `Bearer ${await getGoogleAuthToken(adminSdkJson)}`, Authorization: `Bearer ${await getGoogleAuthToken(adminSdkJson)}`,
}, },
}, },
).then((res) => res.json<SendFcmMessageResponse>()); ).then((res) => res.json() as Promise<SendFcmMessageResponse>);
} }
type SendFcmMessageResponse = type SendFcmMessageResponse =

View File

@@ -2,7 +2,7 @@ import { describe, expect, it } from "bun:test";
import { server } from "~/mocks"; import { server } from "~/mocks";
import type { AdminSdkCredentials } from "./getGoogleAuthToken"; import type { AdminSdkCredentials } from "./getAdminSdkCredentials";
import { verifyFcmToken } from "./verifyFcmToken"; import { verifyFcmToken } from "./verifyFcmToken";
server.listen(); server.listen();

View File

@@ -1,4 +1,4 @@
import type { AdminSdkCredentials } from "./getGoogleAuthToken"; import type { AdminSdkCredentials } from "./getAdminSdkCredentials";
import { sendFcmMessage } from "./sendFcmMessage"; import { sendFcmMessage } from "./sendFcmMessage";
export async function verifyFcmToken( export async function verifyFcmToken(

View File

@@ -2,7 +2,7 @@ import type { TokenOptions } from "gtoken";
import { mock } from "bun:test"; import { mock } from "bun:test";
import type { AdminSdkCredentials } from "~/libs/gcloud/getGoogleAuthToken"; import type { AdminSdkCredentials } from "~/libs/gcloud/getAdminSdkCredentials";
const emailRegex = 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,}))$/; /^(([^<>()[\]\\.,;:\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,}))$/;