// // brokenURLReport.js // // Created by Alezia Kurdis on February 22, 2021. // Copyright 2021 Vircadia contributors. // // This script reports broken URLs to the Create Application. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // var brokenURLReportHttpRequest; var brokenURLReportUrlList = []; var brokenURLReportInvalideUrlList = []; var brokenURLReportProcessedUrlNo = 0; var brokenURLReportUrlEntry; var brokenURLReportMessageBox; var brokenURLReportOverlayWebWindow; var BROKEN_URL_REPORT_YES_BUTTON = 0x4000; var BROKEN_URL_REPORT_NO_BUTTON = 0x10000; var MAX_URL_BEFORE_WARNING_FOR_LONG_PROCESS = 20; function brokenURLReportRequestUrlValidityCheck(no) { brokenURLReportHttpRequest = new XMLHttpRequest(); brokenURLReportHttpRequest.requestComplete.connect(brokenURLReportGetResponseStatus); brokenURLReportHttpRequest.open("GET", brokenURLReportUrlList[no].url); brokenURLReportHttpRequest.send(); } function brokenURLReportGetResponseStatus() { if (brokenURLReportHttpRequest.status === 0 || brokenURLReportHttpRequest.status > 299) { if (brokenURLReportHttpRequest.status === 0) { brokenURLReportUrlList[brokenURLReportProcessedUrlNo].validity = "0 - Server not found"; } else { brokenURLReportUrlList[brokenURLReportProcessedUrlNo].validity = brokenURLReportHttpRequest.status + " - " + brokenURLReportHttpRequest.statusText; } brokenURLReportInvalideUrlList.push(brokenURLReportUrlList[brokenURLReportProcessedUrlNo]); } brokenURLReportHttpRequest.requestComplete.disconnect(brokenURLReportGetResponseStatus); brokenURLReportHttpRequest = null; brokenURLReportProcessedUrlNo = brokenURLReportProcessedUrlNo + 1; if (brokenURLReportProcessedUrlNo === brokenURLReportUrlList.length) { brokenURLReportGenerateFormatedReport(brokenURLReportInvalideUrlList); brokenURLReportUrlList = []; brokenURLReportInvalideUrlList = []; brokenURLReportProcessedUrlNo = 0; } else { brokenURLReportRequestUrlValidityCheck(brokenURLReportProcessedUrlNo); } } function brokenURLReportGenerateFormatedReport(brokenURLReportInvalideUrlList) { var brokenURLReportContent = ""; if (brokenURLReportInvalideUrlList.length === 0) { brokenURLReportContent = "

Broken URL Report

" + brokenURLReportUrlList.length + " URL tested.
NO ISSUES HAVE BEEN FOUND.




"; brokenURLReportContent += "

This report ignores Asset Server URLs (atp://), local drive paths, and any string not starting with 'http'.
"; Script.setTimeout(function () { brokenURLReportOverlayWebWindow.emitScriptEvent(brokenURLReportContent); }, 3000); return; } brokenURLReportContent = "

Broken URL Report

\n"; brokenURLReportContent += " \n"; brokenURLReportContent += " \n"; brokenURLReportContent += " \n"; brokenURLReportContent += " \n"; brokenURLReportContent += " \n"; brokenURLReportContent += " \n"; brokenURLReportContent += " \n"; brokenURLReportContent += " \n"; brokenURLReportContent += " \n"; brokenURLReportContent += " \n"; brokenURLReportContent += " \n"; brokenURLReportContent += " \n"; brokenURLReportContent += " \n"; brokenURLReportContent += " \n"; brokenURLReportContent += " \n"; for (var i = 0; i < brokenURLReportInvalideUrlList.length; i++ ){ brokenURLReportContent += " \n"; brokenURLReportContent += " \n"; brokenURLReportContent += " \n"; brokenURLReportContent += " \n"; brokenURLReportContent += " \n"; brokenURLReportContent += " \n"; brokenURLReportContent += " \n"; brokenURLReportContent += " \n"; brokenURLReportContent += " \n"; } brokenURLReportContent += "
 EntityBroken Url
NoTypeName & ID PropertyStatusCurrent URL
" + (i + 1) + "" + brokenURLReportInvalideUrlList[i].type + "" + brokenURLReportInvalideUrlList[i].name + "
" + brokenURLReportInvalideUrlList[i].id + "
" + brokenURLReportInvalideUrlList[i].urlType + "" + brokenURLReportInvalideUrlList[i].validity + "" + brokenURLReportInvalideUrlList[i].url + "
\n"; brokenURLReportContent += "

" + brokenURLReportUrlList.length + " URL tested.

"; brokenURLReportContent += "
This report ignores Asset Server URLs (atp://), local drive paths, and any string not starting with 'http'.
"; Script.setTimeout(function () { brokenURLReportOverlayWebWindow.emitScriptEvent(brokenURLReportContent); }, 3000); } function brokenURLReportGetUrlTypeColor(urlType) { var color = "#FFFFFF"; switch (urlType) { case "script": color = "#00FF00"; break; case "serverScripts": color = "#FF00FF"; break; case "imageURL": color = "#00FFFF"; break; case "materialURL": color = "#FF6600"; break; case "modelURL": color = "#FFFF00"; break; case "compoundShapeURL": color = "#6666FF"; break; case "animation.url": color = "#6699FF"; break; case "textures": color = "#FF0066"; break; case "xTextureURL": color = "#0000FF"; break; case "yTextureURL": color = "#009966"; break; case "zTextureURL": color = "#993366"; break; case "font": color = "#FFFFFF"; break; case "sourceUrl": color = "#BBFF00"; break; case "scriptURL": color = "#FFBBBB"; break; case "filterURL": color = "#BBBBFF"; break; case "skybox.url": color = "#BBFFFF"; break; case "ambientLight.ambientURL": color = "#FF3300"; } return color; } function brokenURLReport(entityIDs) { if (entityIDs.length === 0) { audioFeedback.rejection(); Window.alert("You have nothing selected."); return; } else { var properties; for (var i = 0; i < entityIDs.length; i++ ){ properties = Entities.getEntityProperties(entityIDs[i]); if (properties.script.toLowerCase().startsWith("http")) { brokenURLReportUrlEntry = { id: entityIDs[i], name: properties.name, type: properties.type, urlType: "script", url: properties.script, validity: "NOT_TESTED" }; brokenURLReportUrlList.push(brokenURLReportUrlEntry); } if (properties.serverScripts.toLowerCase().startsWith("http")) { brokenURLReportUrlEntry = { id: entityIDs[i], name: properties.name, type: properties.type, urlType: "serverScripts", url: properties.serverScripts, validity: "NOT_TESTED" }; brokenURLReportUrlList.push(brokenURLReportUrlEntry); } if (properties.type === "Image" && properties.imageURL.toLowerCase().startsWith("http")) { brokenURLReportUrlEntry = { id: entityIDs[i], name: properties.name, type: properties.type, urlType: "imageURL", url: properties.imageURL, validity: "NOT_TESTED" }; brokenURLReportUrlList.push(brokenURLReportUrlEntry); } if (properties.type === "Material" && properties.materialURL.toLowerCase().startsWith("http")) { brokenURLReportUrlEntry = { id: entityIDs[i], name: properties.name, type: properties.type, urlType: "materialURL", url: properties.materialURL, validity: "NOT_TESTED" }; brokenURLReportUrlList.push(brokenURLReportUrlEntry); } if (properties.type === "Model" && properties.modelURL.toLowerCase().startsWith("http")) { brokenURLReportUrlEntry = { id: entityIDs[i], name: properties.name, type: properties.type, urlType: "modelURL", url: properties.modelURL, validity: "NOT_TESTED" }; brokenURLReportUrlList.push(brokenURLReportUrlEntry); } if ( (properties.type === "Zone" || properties.type === "Model" || properties.type === "ParticleEffect") && properties.compoundShapeURL.toLowerCase().startsWith("http") ) { brokenURLReportUrlEntry = { id: entityIDs[i], name: properties.name, type: properties.type, urlType: "compoundShapeURL", url: properties.compoundShapeURL, validity: "NOT_TESTED" }; brokenURLReportUrlList.push(brokenURLReportUrlEntry); } if (properties.type === "Model" && properties.animation.url.toLowerCase().startsWith("http")) { brokenURLReportUrlEntry = { id: entityIDs[i], name: properties.name, type: properties.type, urlType: "animation.url", url: properties.animation.url, validity: "NOT_TESTED" }; brokenURLReportUrlList.push(brokenURLReportUrlEntry); } if (properties.type === "ParticleEffect" && properties.textures.toLowerCase().startsWith("http")) { brokenURLReportUrlEntry = { id: entityIDs[i], name: properties.name, type: properties.type, urlType: "textures", url: properties.textures, validity: "NOT_TESTED" }; brokenURLReportUrlList.push(brokenURLReportUrlEntry); } if (properties.type === "PolyVox" && properties.xTextureURL.toLowerCase().startsWith("http")) { brokenURLReportUrlEntry = { id: entityIDs[i], name: properties.name, type: properties.type, urlType: "xTextureURL", url: properties.xTextureURL, validity: "NOT_TESTED" }; brokenURLReportUrlList.push(brokenURLReportUrlEntry); } if (properties.type === "PolyVox" && properties.yTextureURL.toLowerCase().startsWith("http")) { brokenURLReportUrlEntry = { id: entityIDs[i], name: properties.name, type: properties.type, urlType: "yTextureURL", url: properties.yTextureURL, validity: "NOT_TESTED" }; brokenURLReportUrlList.push(brokenURLReportUrlEntry); } if (properties.type === "PolyVox" && properties.zTextureURL.toLowerCase().startsWith("http")) { brokenURLReportUrlEntry = { id: entityIDs[i], name: properties.name, type: properties.type, urlType: "zTextureURL", url: properties.zTextureURL, validity: "NOT_TESTED" }; brokenURLReportUrlList.push(brokenURLReportUrlEntry); } if (properties.type === "Text" && properties.font.toLowerCase().startsWith("http")) { brokenURLReportUrlEntry = { id: entityIDs[i], name: properties.name, type: properties.type, urlType: "font", url: properties.font, validity: "NOT_TESTED" }; brokenURLReportUrlList.push(brokenURLReportUrlEntry); } if (properties.type === "Web" && properties.sourceUrl.toLowerCase().startsWith("http")) { brokenURLReportUrlEntry = { id: entityIDs[i], name: properties.name, type: properties.type, urlType: "sourceUrl", url: properties.sourceUrl, validity: "NOT_TESTED" }; brokenURLReportUrlList.push(brokenURLReportUrlEntry); } if (properties.type === "Web" && properties.scriptURL.toLowerCase().startsWith("http")) { brokenURLReportUrlEntry = { id: entityIDs[i], name: properties.name, type: properties.type, urlType: "scriptURL", url: properties.scriptURL, validity: "NOT_TESTED" }; brokenURLReportUrlList.push(brokenURLReportUrlEntry); } if (properties.type === "Zone" && properties.filterURL.toLowerCase().startsWith("http")) { brokenURLReportUrlEntry = { id: entityIDs[i], name: properties.name, type: properties.type, urlType: "filterURL", url: properties.filterURL, validity: "NOT_TESTED" }; brokenURLReportUrlList.push(brokenURLReportUrlEntry); } if (properties.type === "Zone" && properties.skybox.url.toLowerCase().startsWith("http")) { brokenURLReportUrlEntry = { id: entityIDs[i], name: properties.name, type: properties.type, urlType: "skybox.url", url: properties.skybox.url, validity: "NOT_TESTED" }; brokenURLReportUrlList.push(brokenURLReportUrlEntry); } if (properties.type === "Zone" && properties.ambientLight.ambientURL.toLowerCase().startsWith("http")) { brokenURLReportUrlEntry = { id: entityIDs[i], name: properties.name, type: properties.type, urlType: "ambientLight.ambientURL", url: properties.ambientLight.ambientURL, validity: "NOT_TESTED" }; brokenURLReportUrlList.push(brokenURLReportUrlEntry); } } if (brokenURLReportUrlList.length === 0) { audioFeedback.confirmation(); Window.alert("No 'http' URL has been found within the current selection."); return; } else { if (brokenURLReportUrlList.length > MAX_URL_BEFORE_WARNING_FOR_LONG_PROCESS) { var message = "Number of http URLs found: " + brokenURLReportUrlList.length + "\n The analysis may take time. Do you want to proceed?"; var answer = Window.confirm(message); if (!answer) { return; } } if (brokenURLReportOverlayWebWindow !== undefined) { brokenURLReportOverlayWebWindow.close(); } brokenURLReportOverlayWebWindow = new OverlayWebWindow({ title: "Broken URL Report", source: Script.resolvePath("brokenURLReport.html"), width: 1000, height: 600 }); brokenURLReportContent = ""; brokenURLReportRequestUrlValidityCheck(brokenURLReportProcessedUrlNo); } } brokenURLReportOverlayWebWindow.webEventReceived.connect(function (message) { try { var data = JSON.parse(message); } catch(e) { print("brokenURLReport.js: Error parsing JSON"); return; } if (data.action === "select") { selectionManager.setSelections([data.entityID], this); } }); }