From 1681c03a0509c2e8989fe268e7997dbe912770ec Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Sat, 30 May 2020 15:42:07 -0700
Subject: buxton pdf linking implementation

---
 src/client/views/collections/CollectionTreeView.tsx | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

(limited to 'src/client/views/collections/CollectionTreeView.tsx')

diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 87fe79e19..4d67b1e2c 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -717,7 +717,7 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
         }
         ContextMenu.Instance.addItem({
             description: "Buxton Layout", icon: "eye", event: () => {
-                const { ImageDocument } = Docs.Create;
+                const { ImageDocument, PdfDocument } = Docs.Create;
                 const { Document } = this.props;
                 const fallbackImg = "http://www.cs.brown.edu/~bcz/face.gif";
                 const detailView = Cast(Cast(Doc.UserDoc()["template-button-detail"], Doc, null)?.dragFactory, Doc, null);
@@ -726,13 +726,14 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
                 heroView._showTitle = "title";
                 heroView._showTitleHover = "titlehover";
 
-                const doubleClickView = ImageDocument("http://cs.brown.edu/~bcz/face.gif", { _width: 400 });  // replace with desired double click target
+                const fallback = ImageDocument("http://cs.brown.edu/~bcz/face.gif", { _width: 400 });  // replace with desired double click target
+                let pdfContent: string;
                 DocListCast(this.dataDoc[this.props.fieldKey]).map(d => {
                     DocListCast(d.data).map((img, i) => {
                         const caption = (d.captions as any)[i];
                         if (caption) {
                             Doc.GetProto(img).caption = caption;
-                            Doc.GetProto(img).doubleClickView = doubleClickView;
+                            Doc.GetProto(img).doubleClickView = (pdfContent = StrCast(img.additionalMedia_pdfs)) ? PdfDocument(pdfContent) : fallback;
                         }
                     });
                     Doc.GetProto(d).type = "buxton";
-- 
cgit v1.2.3-70-g09d2


From 85721c9ed95b4c026d0a1c7891e1fee311e9f50e Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Sat, 30 May 2020 17:11:23 -0700
Subject: buxton pdf fix

---
 .../views/collections/CollectionTreeView.tsx       |  2 +-
 src/client/views/pdf/PDFViewer.tsx                 | 14 ++++++-
 src/server/ApiManagers/PDFManager.ts               | 43 +++++++++++-----------
 3 files changed, 34 insertions(+), 25 deletions(-)

(limited to 'src/client/views/collections/CollectionTreeView.tsx')

diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 4d67b1e2c..b2e1c0f73 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -733,7 +733,7 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
                         const caption = (d.captions as any)[i];
                         if (caption) {
                             Doc.GetProto(img).caption = caption;
-                            Doc.GetProto(img).doubleClickView = (pdfContent = StrCast(img.additionalMedia_pdfs)) ? PdfDocument(pdfContent) : fallback;
+                            Doc.GetProto(img).doubleClickView = (pdfContent = StrCast(img.additionalMedia_pdfs)) ? PdfDocument(pdfContent, { title: pdfContent }) : fallback;
                         }
                     });
                     Doc.GetProto(d).type = "buxton";
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 217032c1f..5bad248be 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -34,6 +34,7 @@ import React = require("react");
 import { SnappingManager } from "../../util/SnappingManager";
 const PDFJSViewer = require("pdfjs-dist/web/pdf_viewer");
 const pdfjsLib = require("pdfjs-dist");
+import { Networking } from "../../Network";
 
 export const pageSchema = createSchema({
     curPage: "number",
@@ -129,8 +130,17 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
         // change the address to be the file address of the PNG version of each page
         // file address of the pdf
         const { url: { href } } = Cast(this.dataDoc[this.props.fieldKey], PdfField)!;
-        const addr = Utils.prepend(`/thumbnail${this.props.url.substring("files/pdfs/".length, this.props.url.length - ".pdf".length)}-${(this.Document.curPage || 1)}.png`);
-        this._coverPath = href.startsWith(window.location.origin) ? JSON.parse(await rp.get(addr)) : { width: 100, height: 100, path: "" };
+        const { url: relative } = this.props;
+        const pathComponents = relative.split("/pdfs/")[1].split("/");
+        const coreFilename = pathComponents.pop()!.split(".")[0];
+        const params: any = {
+            coreFilename,
+            pageNum: this.Document.curPage || 1,
+        };
+        if (pathComponents.length) {
+            params.subtree = `${pathComponents.join("/")}/`;
+        }
+        this._coverPath = href.startsWith(window.location.origin) ? await Networking.PostToServer("/thumbnail", params) : { width: 100, height: 100, path: "" };
         runInAction(() => this._showWaiting = this._showCover = true);
         this.props.startupLive && this.setupPdfJsViewer();
         this._searchReactionDisposer = reaction(() => this.Document.searchMatch, search => {
diff --git a/src/server/ApiManagers/PDFManager.ts b/src/server/ApiManagers/PDFManager.ts
index 0136b758e..d2a9e9cce 100644
--- a/src/server/ApiManagers/PDFManager.ts
+++ b/src/server/ApiManagers/PDFManager.ts
@@ -7,54 +7,54 @@ import { createCanvas } from "canvas";
 const imageSize = require("probe-image-size");
 import * as express from "express";
 import * as path from "path";
-import { Directory, serverPathToFile, clientPathToFile } from "./UploadManager";
+import { Directory, serverPathToFile, clientPathToFile, pathToDirectory } from "./UploadManager";
 import { red } from "colors";
+import { resolve } from "path";
 
 export default class PDFManager extends ApiManager {
 
     protected initialize(register: Registration): void {
 
         register({
-            method: Method.GET,
-            subscription: new RouteSubscriber("thumbnail").add("filename"),
-            secureHandler: ({ req, res }) => getOrCreateThumbnail(req.params.filename, res)
+            method: Method.POST,
+            subscription: new RouteSubscriber("thumbnail"),
+            secureHandler: async ({ req, res }) => {
+                const { coreFilename, pageNum, subtree } = req.body;
+                return getOrCreateThumbnail(coreFilename, pageNum, res, subtree);
+            }
         });
 
     }
 
 }
 
-async function getOrCreateThumbnail(thumbnailName: string, res: express.Response): Promise<void> {
-    const noExtension = thumbnailName.substring(0, thumbnailName.length - ".png".length);
-    const pageString = noExtension.split('-')[1];
-    const pageNumber = parseInt(pageString);
+async function getOrCreateThumbnail(coreFilename: string, pageNum: number, res: express.Response, subtree?: string): Promise<void> {
+    const resolved = `${coreFilename}-${pageNum}.png`;
     return new Promise<void>(async resolve => {
-        const path = serverPathToFile(Directory.pdf_thumbnails, thumbnailName);
+        const path = serverPathToFile(Directory.pdf_thumbnails, resolved);
         if (existsSync(path)) {
             const existingThumbnail = createReadStream(path);
             const { err, viewport } = await new Promise<any>(resolve => {
                 imageSize(existingThumbnail, (err: any, viewport: any) => resolve({ err, viewport }));
             });
             if (err) {
-                console.log(red(`In PDF thumbnail response, unable to determine dimensions of ${thumbnailName}:`));
+                console.log(red(`In PDF thumbnail response, unable to determine dimensions of ${resolved}:`));
                 console.log(err);
                 return;
             }
-            dispatchThumbnail(res, viewport, thumbnailName);
+            dispatchThumbnail(res, viewport, resolved);
         } else {
-            const offset = thumbnailName.length - pageString.length - 5;
-            const name = thumbnailName.substring(0, offset) + ".pdf";
-            const path = serverPathToFile(Directory.pdfs, name);
-            await CreateThumbnail(path, pageNumber, res);
+            await CreateThumbnail(coreFilename, pageNum, res, subtree);
         }
         resolve();
     });
 }
 
-async function CreateThumbnail(file: string, pageNumber: number, res: express.Response) {
-    const documentProxy = await Pdfjs.getDocument(file).promise;
+async function CreateThumbnail(coreFilename: string, pageNum: number, res: express.Response, subtree?: string) {
+    const sourcePath = resolve(pathToDirectory(Directory.pdfs), `${subtree ?? ""}${coreFilename}.pdf`);
+    const documentProxy = await Pdfjs.getDocument(sourcePath).promise;
     const factory = new NodeCanvasFactory();
-    const page = await documentProxy.getPage(pageNumber);
+    const page = await documentProxy.getPage(pageNum);
     const viewport = page.getViewport(1 as any);
     const { canvas, context } = factory.create(viewport.width, viewport.height);
     const renderContext = {
@@ -64,14 +64,13 @@ async function CreateThumbnail(file: string, pageNumber: number, res: express.Re
     };
     await page.render(renderContext).promise;
     const pngStream = canvas.createPNGStream();
-    const filenames = path.basename(file).split(".");
-    const thumbnailName = `${filenames[0]}-${pageNumber}.png`;
-    const pngFile = serverPathToFile(Directory.pdf_thumbnails, thumbnailName);
+    const resolved = `${coreFilename}-${pageNum}.png`;
+    const pngFile = serverPathToFile(Directory.pdf_thumbnails, resolved);
     const out = createWriteStream(pngFile);
     pngStream.pipe(out);
     return new Promise<void>((resolve, reject) => {
         out.on("finish", () => {
-            dispatchThumbnail(res, viewport, thumbnailName);
+            dispatchThumbnail(res, viewport, resolved);
             resolve();
         });
         out.on("error", error => {
-- 
cgit v1.2.3-70-g09d2

