Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions localstack/init/ready.d/init.sh
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
#!/bin/sh
set -eu

bucket_prefix="${EXPORT_BUCKET_PREFIX:-gbt-exports}"
bucket_name="${bucket_prefix}-local"

bucket_name="${STATIC_ASSET_BUCKET:gbt-static-assets}"
if ! awslocal s3api head-bucket --bucket "$bucket_name" >/dev/null 2>&1; then
awslocal s3 mb "s3://${bucket_name}" >/dev/null
fi
Expand Down
81 changes: 0 additions & 81 deletions src/modules/export/data-access/ExportStorageRepository.ts

This file was deleted.

47 changes: 47 additions & 0 deletions src/modules/export/data-access/exportStorageRepository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { Upload } from "@aws-sdk/lib-storage";
import { Readable } from "stream";
import { createLogger } from "@/logging";
import { getS3Client } from "@/shared/s3";

const EXPORT_BUCKET = process.env.STATIC_ASSET_BUCKET ?? "gbt-static-assets";

const s3Client = getS3Client();

export const exportStorageRepository = {
async upload({
key,
source,
type,
}: {
key: string;
source: Readable | Buffer;
type: string;
}): Promise<string> {
const logger = createLogger({ bucket: EXPORT_BUCKET, key });

const upload = new Upload({
client: s3Client,
params: {
Bucket: EXPORT_BUCKET,
Key: key,
Body: source,
ContentType: type,
},
});

await upload.done();

const location = `s3://${EXPORT_BUCKET}/${key}`;
logger.info(`Export PDF uploaded to ${location}`);

return location;
},

publicUrl({ key }: { key: string }): string {
if (process.env.NODE_ENV === "production") {
return `https://assets.globalbibletools.com/${key}`;
} else {
return `${process.env.EXPORT_PUBLIC_S3_ENDPOINT}/${EXPORT_BUCKET}/${key}`;
}
},
};
18 changes: 7 additions & 11 deletions src/modules/export/jobs/exportInterlinearPdfHandler.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { logger } from "@/logging";
import jobRepo from "@/shared/jobs/data-access/jobRepository";
import { getStorageEnvironment } from "@/shared/storageEnvironment";
import exportStorageRepository from "../data-access/ExportStorageRepository";
import { exportStorageRepository } from "../data-access/exportStorageRepository";
import { detectScript } from "@/shared/scriptDetection";
import interlinearQueryService from "../data-access/InterlinearQueryService";
import {
Expand All @@ -15,11 +14,9 @@ export async function exportInterlinearPdfHandler(
) {
const jobLogger = logger.child({ jobId: job.id, jobType: job.type });

const environment = getStorageEnvironment();

const { languageCode, languageId } = job.payload;

const exportKey = `interlinear/${languageCode}/${job.id}.pdf`;
const exportKey = `interlinear-pdf/${languageCode}.pdf`;

try {
const books =
Expand Down Expand Up @@ -61,14 +58,13 @@ export async function exportInterlinearPdfHandler(
},
});

await exportStorageRepository.uploadPdf({
environment,
await exportStorageRepository.upload({
key: exportKey,
stream,
source: stream,
type: "application/pdf",
});

const downloadUrl = exportStorageRepository.publicPdfUrl({
environment,
const downloadUrl = exportStorageRepository.publicUrl({
key: exportKey,
});

Expand Down Expand Up @@ -114,4 +110,4 @@ function formatChapterLabel(chapters: number[]): string {

function formatChapterRange(start: number, end: number): string {
return start === end ? `${start}` : `${start}-${end}`;
}
}
55 changes: 26 additions & 29 deletions src/modules/export/jobs/exportInterlinearPdfHandler.unit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ import jobRepository from "@/shared/jobs/data-access/jobRepository";

const {
mockFetchBooksWithApprovedGlossChapters,
mockUploadPdf,
mockPublicPdfUrl,
mockUpload,
mockPublicUrl,
mockGenerateInterlinearPdfDocument,
} = vi.hoisted(() => {
return {
mockFetchBooksWithApprovedGlossChapters: vi.fn(),
mockUploadPdf: vi.fn(),
mockPublicPdfUrl: vi.fn(),
mockUpload: vi.fn(),
mockPublicUrl: vi.fn(),
mockGenerateInterlinearPdfDocument: vi.fn(),
};
});
Expand All @@ -29,12 +29,12 @@ vi.mock("@/modules/export/data-access/InterlinearQueryService", () => {
},
};
});
vi.mock("@/modules/export/data-access/ExportStorageRepository", () => {
vi.mock("@/modules/export/data-access/exportStorageRepository", () => {
const repo = {
uploadPdf: mockUploadPdf,
publicPdfUrl: mockPublicPdfUrl,
upload: mockUpload,
publicUrl: mockPublicUrl,
};
return { __esModule: true, exportStorageRepository: repo, default: repo };
return { __esModule: true, exportStorageRepository: repo };
});
vi.mock("@/modules/export/pdf/InterlinearPdfGenerator", () => ({
generateInterlinearPdfDocument: mockGenerateInterlinearPdfDocument,
Expand All @@ -59,8 +59,8 @@ describe("exportInterlinearPdfHandler", () => {
beforeEach(() => {
vi.useFakeTimers();
mockFetchBooksWithApprovedGlossChapters.mockReset();
mockUploadPdf.mockReset();
mockPublicPdfUrl.mockReset();
mockUpload.mockReset();
mockPublicUrl.mockReset();
mockGenerateInterlinearPdfDocument.mockReset();
mockJobRepoCommit.mockReset();

Expand Down Expand Up @@ -116,7 +116,7 @@ describe("exportInterlinearPdfHandler", () => {
stream: Readable.from(["pdf"]),
pageCount: 3,
}));
mockPublicPdfUrl.mockReturnValue("https://exports.example.com/final.pdf");
mockPublicUrl.mockReturnValue("https://exports.example.com/final.pdf");
});

afterEach(() => {
Expand Down Expand Up @@ -149,21 +149,19 @@ describe("exportInterlinearPdfHandler", () => {
}),
}),
);
expect(mockUploadPdf).toHaveBeenCalledExactlyOnceWith(
expect.objectContaining({
environment: "local",
key: "interlinear/spa/job-1.pdf",
}),
);
expect(mockPublicPdfUrl).toHaveBeenCalledExactlyOnceWith({
environment: "local",
key: "interlinear/spa/job-1.pdf",
expect(mockUpload).toHaveBeenCalledExactlyOnceWith({
key: "interlinear-pdf/spa.pdf",
source: expect.anything(),
type: "application/pdf",
});
expect(mockPublicUrl).toHaveBeenCalledExactlyOnceWith({
key: "interlinear-pdf/spa.pdf",
});
expect(mockJobRepoCommit).toHaveBeenCalledExactlyOnceWith(
expect.objectContaining({
id: "job-1",
data: {
exportKey: "interlinear/spa/job-1.pdf",
exportKey: "interlinear-pdf/spa.pdf",
downloadUrl: "https://exports.example.com/final.pdf",
pages: 3,
},
Expand Down Expand Up @@ -216,20 +214,19 @@ describe("exportInterlinearPdfHandler", () => {
});

it("does not record job data when final URL generation fails", async () => {
mockPublicPdfUrl.mockImplementationOnce(() => {
mockPublicUrl.mockImplementationOnce(() => {
throw new Error("public URL failed");
});

await expect(exportInterlinearPdfHandler(baseJob)).rejects.toThrow(
/public URL failed/,
);

expect(mockUploadPdf).toHaveBeenCalledExactlyOnceWith(
expect.objectContaining({
environment: "local",
key: "interlinear/spa/job-1.pdf",
}),
);
expect(mockUpload).toHaveBeenCalledExactlyOnceWith({
key: "interlinear-pdf/spa.pdf",
source: expect.anything(),
type: "application/pdf",
});
expect(mockJobRepoCommit).not.toHaveBeenCalled();
});

Expand All @@ -241,6 +238,6 @@ describe("exportInterlinearPdfHandler", () => {
);

expect(mockGenerateInterlinearPdfDocument).not.toHaveBeenCalled();
expect(mockUploadPdf).not.toHaveBeenCalled();
expect(mockUpload).not.toHaveBeenCalled();
});
});
4 changes: 2 additions & 2 deletions src/shared/jobs/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export function createJobModel<
id: ulid(),
parentJobId: options?.parentJobId,
status: JobStatus.Pending,
payload: payloadSchema.parse(payload ?? {}),
payload: payloadSchema.parse(payload),
data: undefined as Data | undefined,
createdAt: now,
updatedAt: now,
Expand All @@ -90,7 +90,7 @@ export function createJobModel<
id: raw.id,
parentJobId: raw.parentJobId,
status: raw.status,
payload: payloadSchema.parse(raw.payload ?? {}),
payload: payloadSchema.parse(raw.payload),
data: raw.data != null ? resolvedDataSchema.parse(raw.data) : undefined,
createdAt: raw.createdAt,
updatedAt: raw.updatedAt,
Expand Down
5 changes: 0 additions & 5 deletions src/shared/storageEnvironment.ts

This file was deleted.

Loading