Skip to content

Add PDF streaming viewer and token caching#174

Open
akashroy8210 wants to merge 1 commit into
devfrom
feature/pdf-viewer-streaming
Open

Add PDF streaming viewer and token caching#174
akashroy8210 wants to merge 1 commit into
devfrom
feature/pdf-viewer-streaming

Conversation

@akashroy8210

Copy link
Copy Markdown

Changes

  • Added backend PDF viewing endpoint.
  • Streams PDFs from Microsoft Graph instead of redirecting users to the OneDrive preview page.
  • Eliminates repeated OneDrive authentication prompts.
  • Added access token caching to reduce request latency.
  • Opens PDFs in a new browser tab using the browser's native PDF viewer.

Performance

Observed timings after caching:

  • MongoDB lookup: ~5–15ms
  • Access token retrieval: ~0–5ms (cached)
  • Microsoft Graph fetch: ~700–800ms
  • End-to-end PDF open time: typically under 1 second

User Impact

Users can now open PDFs directly in a new browser tab without being redirected to OneDrive or repeatedly authenticating.

@akashroy8210 akashroy8210 requested a review from DreamBot706 June 19, 2026 06:10
@RsbhThakur RsbhThakur linked an issue Jul 3, 2026 that may be closed by this pull request
@RsbhThakur RsbhThakur self-requested a review July 3, 2026 06:17
import { fetchFolder } from "../../../../api/Folder.js";

const FileDisplay = ({ file, path, code, isMobileView = false }) => {
console.log(file._id);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove these leftover debug logs.

return;
}
window.open(preview_url, "_blank");
window.open(

@RsbhThakur RsbhThakur Jul 3, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Critical Bug: This redirects all file types through the new streaming endpoint, but the backend currently hardcodes the response to PDF. This will break the preview for images, .docx, .pptx, and .jpg files.
Please either add a check here to only use this endpoint if the file is a PDF (falling back to preview_url for others) OR update the backend to dynamically send the correct Content-Type.

@RsbhThakur RsbhThakur left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Many critical issues with this PR. please fix all before merging.


async function GetAllContributions(req, res, next) {
const allContributions = await Contribution.find({});
console.log(allContributions);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove these leftover debug logs

const contributionId = req.headers["contribution-id"];
const files = req.files;

console.log(files.length)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove these leftover debug logs to keep the production logs clean

console.timeEnd("graph request")

console.time("res sent to client")
res.setHeader("Content-Type", "application/pdf")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Critical Bug: Because coursehub accepts all file types (images, word documents, etc.), hardcoding the Content-Type to application/pdf will cause the browser to fail when trying to preview non-PDF files.
Please dynamically set the Content-Type based on the file extension (e.g., using a library like mime-types), or restrict this endpoint to only handle PDFs.

}
}

async function viewFile(req, res, next) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are about 8 leftover console.time, console.timeEnd, and console.log statements throughout this viewFile function. Please remove all performance profiling and debug code before we merge.

cachedAccessToken &&
Date.now() < tokenExpiry
) {
console.log("Using cached token");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove these debug logs to keep the production console clean.

return cachedAccessToken;
}

console.log("Fetching fresh token");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove these debug logs to keep the production console clean.

let data;

if (fs.existsSync("./onedrive-refresh-token.token")) {
data = await refreshAccessToken();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optimization: There is a slight race condition here. If a large class of students all try to view a PDF at the exact moment the token expires, the server will concurrently execute refreshAccessToken() dozens of times. Because that function writes to the .token file on disk, these concurrent writes could corrupt the file or cause Microsoft to revoke the token.
Consider wrapping the refresh call in a Promise lock so that concurrent requests just wait for the first refresh to finish.


async function UploadFile(contributionId, filePath, fileName) {
const folderId = parent_item_id;
console.log("Folder ID:", folderId);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this leftover console logs on line 79 and 80

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

File view (2)

3 participants