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
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public interface IFileUploader
/// Uploads a local file to remote storage at the specified key.
/// </summary>
/// <param name="localFilePath">Absolute path to the local file to upload.</param>
/// <param name="key">The storage key (e.g., "handouts/factorization/factorization.sk.pdf").</param>
/// <param name="key">The storage key (e.g., "handouts/pdfs/factorization.sk.pdf").</param>
/// <returns>A task representing the asynchronous upload operation.</returns>
Task UploadAsync(string localFilePath, string key);
}
8 changes: 4 additions & 4 deletions backend/src/Tools/MathComps.Cli.Handouts/BuildCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -451,8 +451,8 @@ private static void CompileTexFile(
}

/// <summary>
/// Uploads a compiled handout PDF (main or skeleton) to remote storage, nesting it
/// under the handout's slug folder so every artefact for one handout sits together.
/// Uploads a compiled handout PDF (main or skeleton) to remote storage under
/// the flat <c>handouts/pdfs/</c> folder shared by every handout.
/// </summary>
/// <param name="texFile">The .tex file whose corresponding PDF should be uploaded.</param>
/// <param name="sourceDirectory">The directory containing the compiled PDFs.</param>
Expand All @@ -471,8 +471,8 @@ private static async Task UploadHandoutPdfAsync(FileInfo texFile, DirectoryInfo
return;
}

// Build the R2 key so every artefact for one handout lands in the same folder
var r2Key = ToHandoutR2Key($"{ToHandoutSlug(texFile.Name)}/{pdfFileName}");
// All handout PDFs share the flat handouts/pdfs/ folder
var r2Key = ToHandoutR2Key($"pdfs/{pdfFileName}");
await fileUploader.UploadAsync(sourcePdfPath, r2Key);
AnsiConsole.MarkupLine($" [green]✓ PDF uploaded:[/] {Markup.Escape(pdfFileName)}");
}
Expand Down
2 changes: 1 addition & 1 deletion backend/src/Tools/MathComps.Cli.Handouts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ For each matched `.tex` file, the tool runs these steps in order:
2. **Compile TeX** — runs the configured compiler (2 passes) on both main + skeleton files
3. **Parse to JSON** — converts the TeX document structure into `RawContentBlock[]` JSON (saved locally to `web/src/content/handouts/`)
4. **Upload images** — processes SVG images and uploads them to R2 under `handouts/<slug>/<image>.svg`, where `<slug>` is the language-stripped handout id (so all language variants share one image set)
5. **Upload PDFs** — uploads compiled main + skeleton PDFs to R2 under `handouts/<slug>/<file>.pdf` (same folder as the images)
5. **Upload PDFs** — uploads compiled main + skeleton PDFs to R2 under `handouts/pdfs/<file>.pdf` (flat layout; every handout's PDFs share one folder)

## Prerequisites

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,14 @@ export function getProblemImageUrl(contentId: string, type: ImageType): string {
}

/**
* Builds a public URL to a handout PDF by its filename. The handout's
* language-stripped slug is derived from the filename — both `<slug>.<lang>.pdf`
* and `<slug>.<lang>-skeleton.pdf` collapse to the same slug so every artefact
* lives in one folder on R2.
* Builds a public URL to a handout PDF by its filename. All handout PDFs live
* together in the flat `handouts/pdfs/` folder on R2.
*
* @param filename - The PDF filename (e.g., "factorization.sk.pdf")
* @returns The public URL to the PDF on R2
*/
export function getHandoutPdfUrl(filename: string): string {
const slug = filename.replace(/\.[a-z]{2}(-skeleton)?\.pdf$/i, '')
return `${getR2BaseUrl()}/handouts/${slug}/${filename}`
return `${getR2BaseUrl()}/handouts/pdfs/${filename}`
}

/**
Expand Down
Loading