Question / Problem
I am trying to use a plugin to show attachments under their respective modals as a preview, as such I am using the Excel example that is ubiquitous.
However, if I try to use it to load a PDF file, I get an authorization denied request.
I am assuming this is because I am referencing the file via a plug-in and not via an API token.
I tried adding authorization headers. But, it seems that the issue is not so much accessing the file as it is displaying the file on the modal.
Error Message
{"code":"CB_JH01","id":"6Qyv9HItzZvqRbjGAow3","message":"Authentication failed. X-Requested-With header is required for session authentication."}
Note: I have tried sending the headers manually, but they seem to be lost between the file download and the modal loading.
Current Situation
How is your Kintone App configured?
Developer account
What are you trying to do?
Previewing a PDF file inside a modal, that is button triggered, rather than clicked attachment.
Code / Attempts
Here is the code:
// Check File Extension (Excel or PDF)
function checkFileExtension(file) {
let reg = /\.xl(s[xmb]|t[xm]|am|s)$/g; // Excel file extension regex
let pdfReg = /\.pdf$/g; // PDF file extension regex
return reg.test(file) || pdfReg.test(file);
}
// Check if the file is an Excel file (cut before finishing)
function checkXls(file) {
let reg = /\.xl(s[xmb]|t[xm]|am|s)$/g;
return reg.test(file);
}
// Load Preview
function loadModal(fileInfo) {
let previewElement;
if (window.innerWidth > 768) {
// Desktop preview
jQuery(".file-image-container-gaia").each(function (i, e) {
let fileName = jQuery(e).children("a:eq(0)").text();
if (
fileName == fileInfo.name &&
jQuery(e).children("button").length == 0
) {
previewElement = jQuery(e);
return false;
}
});
} else {
// Mobile preview
jQuery(".control-showlayout-file-gaia .control-value-gaia div").each(
function (index, e) {
let fileName = jQuery(e).find("a:eq(0)").text();
if (fileName == fileInfo.name && jQuery(e).find("button").length == 0) {
previewElement = jQuery(e);
return false;
}
}
);
}
if (!previewElement) return;
let modalId = "myModal" + fileInfo.fileKey;
let tabId = "myTab" + fileInfo.fileKey;
let tabContentId = "tab-content" + fileInfo.fileKey;
let $button = $(
'<button type="button" class="btn btn-default" data-toggle="modal" data-target="#' +
modalId +
'"><span class="fa fa-search"></span></button>'
);
let myModal =
'<style type="text/css">td{word-break: keep-all;white-space:nowrap;}</style>' +
'<div class="modal fade tab-pane active" id="' +
modalId +
'" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">' +
'<div class="modal-dialog ' +
(window.innerWidth > 768 ? "modal-xl" : "modal-dialog-scrollable") +
'" style="border-radius:5px" role="document">' +
'<div class="modal-content">' +
'<div class="modal-header">' +
'<h5 class="modal-title">' +
fileInfo.name +
"</h5>" +
'<button type="button" class="close" data-dismiss="modal" aria-label="Close">' +
'<span aria-hidden="true">×</span>' +
"</button>" +
"</div>" +
'<ul class="nav nav-tabs" id=' +
tabId +
">" +
"</ul>" +
"<div id=" +
tabContentId +
' class="tab-content">' +
'<div class="d-flex justify-content-center">' +
'<div class="spinner-border" role="status">' +
'<span class="sr-only">Loading...</span>' +
"</div>" +
"</div>" +
"</div>" +
'<div class="modal-footer">' +
'<button type="button" class="btn btn-secondary" data-dismiss="modal">CLOSE</button>' +
"</div>" +
"</div>" +
"</div>" +
"</div>";
previewElement.append($button);
$("body").prepend(myModal);
$("#" + modalId).on("shown.bs.modal", function (e) {
if (checkXls(fileInfo.name)) {
loadExcelFile(fileInfo);
} else {
loadPDFFile(fileInfo);
}
});
}
// Download and load Excel file into modal
function loadExcelFile(fileInfo) {
let fileUrl = "/k/v1/file.json?fileKey=" + fileInfo.fileKey;
readWorkbookFromRemoteFile(fileUrl, function (workbook) {
readWorkbook(workbook, fileInfo);
});
}
// Load PDF file into modal
function loadPDFFile(fileInfo) {
let fileUrl = "/k/v1/file.json?fileKey=" + fileInfo.fileKey;
let loginName = "***";
let password = "***";
let authString = btoa(loginName + ":" + password); // Base64 encode login name and password
fileUrl += "&X-Cybozu-Authorization=" + authString;
let xhr = new XMLHttpRequest();
xhr.open("GET", fileUrl, true);
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
xhr.setRequestHeader("X-Cybozu-Authorization", authString); // Set the X-Cybozu-Authorization header again
xhr.onload = function () {
if (xhr.status === 200) {
let pdfHtml =
'<embed src="' +
fileUrl +
'" type="application/pdf" width="100%" height="600px" />';
let tabContentId = "tab-content" + fileInfo.fileKey;
jQuery("#" + tabContentId).html(pdfHtml);
console.log("PDF file loaded successfully.");
} else {
console.log("Failed to load PDF file. Status code: " + xhr.status);
}
};
// Log the secondary authorization header
console.log("Secondary Authorization Header: " + xhr.getAllResponseHeaders());
xhr.send();
}
// Read workbook from remote file (Excel)
function readWorkbookFromRemoteFile(url, callback) {
let xhr = new XMLHttpRequest();
xhr.open("get", url, true);
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
xhr.responseType = "arraybuffer";
xhr.onload = function (e) {
if (xhr.status == 200) {
let data = new Uint8Array(xhr.response);
let workbook = XLSX.read(data, { type: "array" });
if (callback) callback(workbook);
}
};
xhr.send();
}
// Read workbook (Excel)
function readWorkbook(workbook, fileInfo) {
let sheetNames = workbook.SheetNames;
let navHtml = "";
let tabHtml = "";
let myTabId = "myTab" + fileInfo.fileKey;
let tabContentId = "tab-content" + fileInfo.fileKey;
for (let index = 0; index < sheetNames.length; index++) {
let sheetName = sheetNames[index];
let worksheet = workbook.Sheets[sheetName];
let sheetHtml = XLSX.utils.sheet_to_html(worksheet);
let tabid = "tab" + fileInfo.fileKey + "-" + index;
let xlsid = "xlsid" + fileInfo.fileKey + "-" + index;
let active = index == 0 ? "active" : "";
navHtml +=
'<li class="nav-item"><a class="nav-link ' +
active +
'" href="#" data-target="#' +
tabid +
'" data-toggle="tab">' +
sheetName +
"</a></li>";
tabHtml +=
'<div id="' +
tabid +
'" class="tab-pane ' +
active +
'" style="padding:10px;overflow:auto;height:600px" >' +
'<div id="' +
xlsid +
'">' +
sheetHtml +
" </div></div>";
}
jQuery("#" + myTabId).html(navHtml);
jQuery("#" + tabContentId).html(tabHtml);
jQuery("#" + tabContentId + " table").addClass(
"table table-bordered table-hover"
);
}
// Build Kintone
kintone.events.on("app.record.detail.show", function (event) {
let record = event.record;
for (let index in record) {
let field = record[index];
if (field.type === "FILE") {
let fieldValue = field.value;
fieldValue.forEach(function (file) {
if (checkFileExtension(file.name)) {
loadModal(file);
}
});
}
}
});
Error Message
Screenshot of the Kintone App:
- A pop-up modal is opened to a PDF file
- Instead of displaying the PDF preview, the Authentication failed error is displayed
Screenshot of the browser console:
Secondary Authorization Header:
PDF file loaded successfully.
GET https://***.kintone.com/k/v1/file.json?fileKey=***&X-Cybozu-Authorization=***== 520
Desired Outcome / Expected Behavior
For the PDF to be loaded into the modal.