This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
# Public site origin used for SEO metadata, sitemap, and robots.txt.
|
||||
BASE_URL=https://guide.sudloh.com
|
||||
|
||||
# Public AdSense publisher client ID. Leave unset to disable ads locally.
|
||||
NEXT_PUBLIC_GOOGLE_ADSENSE_CLIENT_ID=ca-pub-9687404323559597
|
||||
|
||||
# Local-only demo mode serves sanitized fixtures and bypasses external services.
|
||||
# Keep this false in every deployed environment.
|
||||
BUZZ_DEMO_MODE=false
|
||||
|
||||
@@ -10,6 +10,7 @@ on:
|
||||
|
||||
env:
|
||||
BASE_URL: https://guide.sudloh.com
|
||||
NEXT_PUBLIC_GOOGLE_ADSENSE_CLIENT_ID: ca-pub-9687404323559597
|
||||
REGISTRY_IMAGE: registry.neko-piranha.ts.net/astral/buzz-sheet
|
||||
DEPLOY_NAMESPACE: buzz-sheet
|
||||
KUBE_API_SERVER: https://100.112.189.33:6443/
|
||||
@@ -32,6 +33,7 @@ jobs:
|
||||
docker build \
|
||||
--target app \
|
||||
--build-arg BASE_URL="$BASE_URL" \
|
||||
--build-arg NEXT_PUBLIC_GOOGLE_ADSENSE_CLIENT_ID="$NEXT_PUBLIC_GOOGLE_ADSENSE_CLIENT_ID" \
|
||||
--build-arg NEXT_DEPLOYMENT_ID=${{ gitea.sha }} \
|
||||
--build-arg VCS_REF=${{ gitea.sha }} \
|
||||
--tag ${{ env.REGISTRY_IMAGE }}:${{ gitea.sha }} \
|
||||
|
||||
@@ -23,8 +23,10 @@ FROM node:22-bookworm-slim AS next-builder
|
||||
WORKDIR /app
|
||||
ARG NEXT_DEPLOYMENT_ID=container-build
|
||||
ARG BASE_URL
|
||||
ARG NEXT_PUBLIC_GOOGLE_ADSENSE_CLIENT_ID
|
||||
ENV BASE_URL=${BASE_URL}
|
||||
ENV NEXT_DEPLOYMENT_ID=${NEXT_DEPLOYMENT_ID}
|
||||
ENV NEXT_PUBLIC_GOOGLE_ADSENSE_CLIENT_ID=${NEXT_PUBLIC_GOOGLE_ADSENSE_CLIENT_ID}
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
COPY --from=dependencies /app/node_modules ./node_modules
|
||||
COPY . .
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
google.com, pub-9687404323559597, DIRECT, f08c47fec0942fa0
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { Metadata } from "next";
|
||||
import { notFound } from "next/navigation";
|
||||
|
||||
import { GoogleAdsense } from "@/components/public/google-adsense";
|
||||
import { publicSections, StructuredGuideShell } from "@/components/public/structured-guide";
|
||||
import { getCachedPublicGuide } from "@/lib/cache/public";
|
||||
|
||||
@@ -25,5 +26,10 @@ export default async function GuideSectionPage({ params }: { params: Params }) {
|
||||
const { character, page } = await params;
|
||||
const guide = await getCachedPublicGuide(character);
|
||||
if (!guide || !publicSections(guide).some((section) => section.slug === page)) notFound();
|
||||
return <StructuredGuideShell guide={guide} section={page} />;
|
||||
return (
|
||||
<>
|
||||
<GoogleAdsense />
|
||||
<StructuredGuideShell guide={guide} section={page} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { Metadata } from "next";
|
||||
import { notFound } from "next/navigation";
|
||||
|
||||
import { GoogleAdsense } from "@/components/public/google-adsense";
|
||||
import { StructuredGuideShell } from "@/components/public/structured-guide";
|
||||
import { getCachedPublicGuide } from "@/lib/cache/public";
|
||||
|
||||
@@ -31,5 +32,10 @@ export default async function GuideOverviewPage({
|
||||
}) {
|
||||
const guide = await getCachedPublicGuide((await params).character);
|
||||
if (!guide) notFound();
|
||||
return <StructuredGuideShell guide={guide} />;
|
||||
return (
|
||||
<>
|
||||
<GoogleAdsense />
|
||||
<StructuredGuideShell guide={guide} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { connection } from "next/server";
|
||||
import { Suspense } from "react";
|
||||
|
||||
import { LiveRefresh } from "@/components/live-refresh";
|
||||
import { GoogleAdsense } from "@/components/public/google-adsense";
|
||||
import { SiteFooter } from "@/components/public/site-footer";
|
||||
import { StructuredDirectory } from "@/components/public/structured-directory";
|
||||
import { SiteHeader } from "@/components/public/site-header";
|
||||
@@ -16,6 +17,7 @@ async function DirectoryContent() {
|
||||
export default function HomePage() {
|
||||
return (
|
||||
<div className="flex min-h-svh flex-col bg-background">
|
||||
<GoogleAdsense />
|
||||
<LiveRefresh endpoint="/api/events/directory" />
|
||||
<SiteHeader />
|
||||
<main className="mx-auto flex w-full max-w-7xl flex-col gap-8 px-4 py-10 sm:px-6 sm:py-14">
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
"use client";
|
||||
|
||||
import Script from "next/script";
|
||||
|
||||
import { authClient } from "@/lib/auth/client";
|
||||
|
||||
const clientId = process.env.NEXT_PUBLIC_GOOGLE_ADSENSE_CLIENT_ID?.trim();
|
||||
|
||||
export function GoogleAdsense() {
|
||||
const { data: session, error, isPending } = authClient.useSession();
|
||||
|
||||
if (
|
||||
process.env.NODE_ENV !== "production" ||
|
||||
!clientId ||
|
||||
isPending ||
|
||||
error ||
|
||||
session
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Script
|
||||
id="google-adsense"
|
||||
src={`https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=${encodeURIComponent(clientId)}`}
|
||||
strategy="afterInteractive"
|
||||
crossOrigin="anonymous"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
google.com, pub-9687404323559597, DIRECT, f08c47fec0942fa0
|
||||
@@ -91,7 +91,12 @@ describe("production deployment contract", () => {
|
||||
expect(dockerfile.match(/^USER 1000:1000$/gmu)).toHaveLength(2);
|
||||
expect(dockerfile).toContain('ENTRYPOINT ["bun", "scripts/migrate.ts"]');
|
||||
expect(dockerfile).toContain('CMD ["bun", "server.js"]');
|
||||
expect(dockerfile).toContain("ARG BASE_URL\nENV BASE_URL=${BASE_URL}");
|
||||
expect(dockerfile).toContain("ARG BASE_URL");
|
||||
expect(dockerfile).toContain("ENV BASE_URL=${BASE_URL}");
|
||||
expect(dockerfile).toContain("ARG NEXT_PUBLIC_GOOGLE_ADSENSE_CLIENT_ID");
|
||||
expect(dockerfile).toContain(
|
||||
"ENV NEXT_PUBLIC_GOOGLE_ADSENSE_CLIENT_ID=${NEXT_PUBLIC_GOOGLE_ADSENSE_CLIENT_ID}",
|
||||
);
|
||||
expect(dockerfile).toContain("backend/discord.ts");
|
||||
expect(dockerfile).toContain("./worker/discord.js");
|
||||
});
|
||||
@@ -106,6 +111,9 @@ describe("production deployment contract", () => {
|
||||
expect(workflow).toContain("kubectl kustomize k8s/");
|
||||
expect(workflow).toContain("--target app");
|
||||
expect(workflow).toContain('--build-arg BASE_URL="$BASE_URL"');
|
||||
expect(workflow).toContain(
|
||||
'--build-arg NEXT_PUBLIC_GOOGLE_ADSENSE_CLIENT_ID="$NEXT_PUBLIC_GOOGLE_ADSENSE_CLIENT_ID"',
|
||||
);
|
||||
expect(workflow).toContain('\\"BASE_URL\\":\\"$BASE_URL\\"');
|
||||
expect(workflow).toContain("--target migration");
|
||||
expect(workflow).not.toContain("platforms: linux/arm64");
|
||||
@@ -167,6 +175,9 @@ describe("environment template contract", () => {
|
||||
expect(environmentExample).toMatch(new RegExp(`^${key}=`, "mu"));
|
||||
}
|
||||
expect(environmentExample).toContain("BUZZ_DEMO_MODE=false");
|
||||
expect(environmentExample).toContain(
|
||||
"NEXT_PUBLIC_GOOGLE_ADSENSE_CLIENT_ID=ca-pub-9687404323559597",
|
||||
);
|
||||
});
|
||||
|
||||
it("runs Discord catalog sync as an isolated worker", async () => {
|
||||
|
||||
@@ -55,4 +55,25 @@ describe("public rendering performance", () => {
|
||||
sitemap: "https://guide.example.test/sitemap.xml",
|
||||
});
|
||||
});
|
||||
|
||||
it("loads AdSense only after confirming the visitor is signed out", async () => {
|
||||
const [adsense, home, guide, guideSection, adsTxt] = await Promise.all([
|
||||
repositoryFile("components/public/google-adsense.tsx"),
|
||||
repositoryFile("app/page.tsx"),
|
||||
repositoryFile("app/[character]/page.tsx"),
|
||||
repositoryFile("app/[character]/[page]/page.tsx"),
|
||||
repositoryFile("public/ads.txt"),
|
||||
]);
|
||||
|
||||
expect(adsense).toContain("authClient.useSession()");
|
||||
expect(adsense).toContain('process.env.NODE_ENV !== "production"');
|
||||
expect(adsense).toMatch(/isPending \|\|\s+error \|\|\s+session/u);
|
||||
expect(adsense).toContain("pagead2.googlesyndication.com");
|
||||
expect(home).toContain("<GoogleAdsense />");
|
||||
expect(guide).toContain("<GoogleAdsense />");
|
||||
expect(guideSection).toContain("<GoogleAdsense />");
|
||||
expect(adsTxt.trim()).toBe(
|
||||
"google.com, pub-9687404323559597, DIRECT, f08c47fec0942fa0",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user