From 6979c455efa257a1deca1acd5e327566bae7c614 Mon Sep 17 00:00:00 2001 From: David Ball Date: Mon, 24 Jun 2024 00:57:28 -0400 Subject: [PATCH 1/3] Removed console log message from config startup. --- app/config.mts | 406 ++++++++++++++++++++++++------------------------- 1 file changed, 202 insertions(+), 204 deletions(-) diff --git a/app/config.mts b/app/config.mts index 3ab4eedd..9ff45f88 100644 --- a/app/config.mts +++ b/app/config.mts @@ -2,188 +2,186 @@ * The `ProcessEnv` interface represents the imported environment variables to input from `process.env` dictionary. */ export interface ProcessEnv { - /** - * `APP_HTTP_LISTEN_HOST` is the host for the HTTP web app. - */ - APP_HTTP_HOST?: string; - /** - * `APP_HTTP_LISTEN_PORT` is the TCP port used to access the Node application's HTTP interface (usually by a reverse proxy). - */ - APP_HTTP_PORT?: string; - /** - * `APP_URL` is the URL used to access the Node application (usually by a reverse proxy). - */ - APP_HTTP_URL?: string; - /** - * `SITE_NAME` is used for page generation. - */ - SITE_NAME?: string; - /** - * `SITE_HOST` is used for generating links for the search index. (If you leave this blank it should work using relative paths.) - */ - SITE_WELCOME_MESSAGE?: string; - /** - * `SITE_URL` is used for generating links for the search index. (If you leave this blank it should work using relative paths.) - */ - SITE_HOST?: string; - /** - * `WELCOME_MESSAGE` is used for the homepage instead of `"Welcome to ${SITE_NAME}!"` - */ - SITE_URL?: string; - /** - * `PUBLIC_PATH` is the relative path to the directory to this project root for the public files. - */ - PUBLIC_PATH?: string; - /** - * `PAGES_PATH` is the relative path to the directory to this project root for the pages rather than public files. - */ - PAGES_PATH?: string; - /** - * `ASSETS_PATH` is the relative path to the directory to this project root for the static asset files. - */ - ASSETS_PATH?: string; - /** - * `SOLR_DOCS_HOST` is the host for Apache Solr's core for indexed documents. - */ - SOLR_DOCS_HOST?: string; - /** - * `SOLR_DOCS_PORT` is the port for Apache Solr's core for indexed documents. - */ - SOLR_DOCS_PORT?: string; - /** - * `SOLR_DOCS_CORE` is the core name for Apache Solr's core for indexed documents. - */ - SOLR_DOCS_CORE?: string; - /** - * `SOLR_DOCS_URL` is the URL to access Apache Solr's core for indexed documents. It is used by Gulp and the Search feature. - */ - SOLR_DOCS_URL?: string; - /** - * `SOLR_LAW_HOST` is the host for Apache Solr's core for indexed laws. - */ - SOLR_LAW_HOST?: string; - /** - * `SOLR_LAW_PORT` is the port for Apache Solr's core for indexed laws. - */ - SOLR_LAW_PORT?: string; - /** - * `SOLR_LAW_CORE` is the core name for Apache Solr's core for indexed laws. - */ - SOLR_LAW_CORE?: string; - /** - * `SOLR_LAW_URL` is the URL to access Apache Solr's core for indexed laws. It is used by Gulp and the Search feature. - */ - SOLR_LAW_URL?: string; - /** - * `TIKA_HOST` is the host to access the Apache Tika app. - */ - TIKA_HOST?: string; - /** - * `TIKA_PORT` is the port to access the Apache Tika app. - */ - TIKA_PORT?: string; - /** - * `TIKA_URL` is the URL to access the Apache Tika app. - */ - TIKA_URL?: string; + /** + * `APP_HTTP_LISTEN_HOST` is the host for the HTTP web app. + */ + APP_HTTP_HOST?: string; + /** + * `APP_HTTP_LISTEN_PORT` is the TCP port used to access the Node application's HTTP interface (usually by a reverse proxy). + */ + APP_HTTP_PORT?: string; + /** + * `APP_URL` is the URL used to access the Node application (usually by a reverse proxy). + */ + APP_HTTP_URL?: string; + /** + * `SITE_NAME` is used for page generation. + */ + SITE_NAME?: string; + /** + * `SITE_HOST` is used for generating links for the search index. (If you leave this blank it should work using relative paths.) + */ + SITE_WELCOME_MESSAGE?: string; + /** + * `SITE_URL` is used for generating links for the search index. (If you leave this blank it should work using relative paths.) + */ + SITE_HOST?: string; + /** + * `WELCOME_MESSAGE` is used for the homepage instead of `"Welcome to ${SITE_NAME}!"` + */ + SITE_URL?: string; + /** + * `PUBLIC_PATH` is the relative path to the directory to this project root for the public files. + */ + PUBLIC_PATH?: string; + /** + * `PAGES_PATH` is the relative path to the directory to this project root for the pages rather than public files. + */ + PAGES_PATH?: string; + /** + * `ASSETS_PATH` is the relative path to the directory to this project root for the static asset files. + */ + ASSETS_PATH?: string; + /** + * `SOLR_DOCS_HOST` is the host for Apache Solr's core for indexed documents. + */ + SOLR_DOCS_HOST?: string; + /** + * `SOLR_DOCS_PORT` is the port for Apache Solr's core for indexed documents. + */ + SOLR_DOCS_PORT?: string; + /** + * `SOLR_DOCS_CORE` is the core name for Apache Solr's core for indexed documents. + */ + SOLR_DOCS_CORE?: string; + /** + * `SOLR_DOCS_URL` is the URL to access Apache Solr's core for indexed documents. It is used by Gulp and the Search feature. + */ + SOLR_DOCS_URL?: string; + /** + * `SOLR_LAW_HOST` is the host for Apache Solr's core for indexed laws. + */ + SOLR_LAW_HOST?: string; + /** + * `SOLR_LAW_PORT` is the port for Apache Solr's core for indexed laws. + */ + SOLR_LAW_PORT?: string; + /** + * `SOLR_LAW_CORE` is the core name for Apache Solr's core for indexed laws. + */ + SOLR_LAW_CORE?: string; + /** + * `SOLR_LAW_URL` is the URL to access Apache Solr's core for indexed laws. It is used by Gulp and the Search feature. + */ + SOLR_LAW_URL?: string; + /** + * `TIKA_HOST` is the host to access the Apache Tika app. + */ + TIKA_HOST?: string; + /** + * `TIKA_PORT` is the port to access the Apache Tika app. + */ + TIKA_PORT?: string; + /** + * `TIKA_URL` is the URL to access the Apache Tika app. + */ + TIKA_URL?: string; } /** * The `Config` interface represents the imported environment variables after imported from `process.env` dictionary. */ export interface Config { - /** - * `appHttpHost` is the host for the HTTP web app. - */ - appHttpHost: string; - /** - * `appHttpPort` is the TCP port used to access the Node application's HTTP interface (usually by a reverse proxy). - */ - appHttpPort: number|string; - /** - * `appHttpUrl` is the URL used to access the Node application (usually by a reverse proxy). - */ - appHttpUrl: string; - /** - * `siteName` is used for page generation. - */ - siteName: string; - /** - * `siteWelcomeMessage` is used for the homepage instead of `"Welcome to ${process.env['SITE_NAME']}!"` - */ - siteWelcomeMessage: string; - /** - * `siteHost` is used for generating links for the search index. (If you leave this blank it should work using relative paths.) - */ - siteHost: string; - /** - * `siteUrl` is used for generating links for the search index. (If you leave this blank it should work using relative paths.) - */ - siteUrl: string; - /** - * `publicPath` is the relative path to the directory to this project root for the public files. - */ - publicPath: string; - /** - * `pagesPath` is the relative path to the directory to this project root for the pages rather than public files. - */ - pagesPath: string; - /** - * `assetsPath` is the relative path to the directory to this project root for the static asset files. - */ - assetsPath: string; - /** - * `viewsPath' is the relative path to the directory to this project root for the view templates. - */ - viewsPath: string; - /** - * `solrDocsHost` is the host for Apache Solr's core for indexed documents. - */ - solrDocsHost: string; - /** - * `solrDocsPort` is the port for Apache Solr's core for indexed documents. - */ - solrDocsPort: number|string; - /** - * `solrDocsCore` is the core name for Apache Solr's core for indexed documents. - */ - solrDocsCore: string; - /** - * `solrDocsUrl` is the URL to access Apache Solr's core for indexed documents. It is used by Gulp and the Search feature. - */ - solrDocsUrl: string; - /** - * `solrLawHost` is the host for Apache Solr's core for indexed laws. - */ - solrLawHost: string; - /** - * `solrLawPort` is the port for Apache Solr's core for indexed laws. - */ - solrLawPort: number|string; - /** - * `solrLawCore` is the core name for Apache Solr's core for indexed laws. - */ - solrLawCore: string; - /** - * `solrLawUrl` is the URL to access Apache Solr's core for indexed laws. It is used by Gulp and the Search feature. - */ - solrLawUrl: string; - /** - * `tikaHost` is the host to access the Apache Tika app. - */ - tikaHost: string; - /** - * `tikaPort` is the port to access the Apache Tika app. - */ - tikaPort: string|number; - /** - * `tikaUrl` is the URL to access the Apache Tika app. - */ - tikaUrl: string; + /** + * `appHttpHost` is the host for the HTTP web app. + */ + appHttpHost: string; + /** + * `appHttpPort` is the TCP port used to access the Node application's HTTP interface (usually by a reverse proxy). + */ + appHttpPort: number|string; + /** + * `appHttpUrl` is the URL used to access the Node application (usually by a reverse proxy). + */ + appHttpUrl: string; + /** + * `siteName` is used for page generation. + */ + siteName: string; + /** + * `siteWelcomeMessage` is used for the homepage instead of `"Welcome to ${process.env['SITE_NAME']}!"` + */ + siteWelcomeMessage: string; + /** + * `siteHost` is used for generating links for the search index. (If you leave this blank it should work using relative paths.) + */ + siteHost: string; + /** + * `siteUrl` is used for generating links for the search index. (If you leave this blank it should work using relative paths.) + */ + siteUrl: string; + /** + * `publicPath` is the relative path to the directory to this project root for the public files. + */ + publicPath: string; + /** + * `pagesPath` is the relative path to the directory to this project root for the pages rather than public files. + */ + pagesPath: string; + /** + * `assetsPath` is the relative path to the directory to this project root for the static asset files. + */ + assetsPath: string; + /** + * `viewsPath' is the relative path to the directory to this project root for the view templates. + */ + viewsPath: string; + /** + * `solrDocsHost` is the host for Apache Solr's core for indexed documents. + */ + solrDocsHost: string; + /** + * `solrDocsPort` is the port for Apache Solr's core for indexed documents. + */ + solrDocsPort: number|string; + /** + * `solrDocsCore` is the core name for Apache Solr's core for indexed documents. + */ + solrDocsCore: string; + /** + * `solrDocsUrl` is the URL to access Apache Solr's core for indexed documents. It is used by Gulp and the Search feature. + */ + solrDocsUrl: string; + /** + * `solrLawHost` is the host for Apache Solr's core for indexed laws. + */ + solrLawHost: string; + /** + * `solrLawPort` is the port for Apache Solr's core for indexed laws. + */ + solrLawPort: number|string; + /** + * `solrLawCore` is the core name for Apache Solr's core for indexed laws. + */ + solrLawCore: string; + /** + * `solrLawUrl` is the URL to access Apache Solr's core for indexed laws. It is used by Gulp and the Search feature. + */ + solrLawUrl: string; + /** + * `tikaHost` is the host to access the Apache Tika app. + */ + tikaHost: string; + /** + * `tikaPort` is the port to access the Apache Tika app. + */ + tikaPort: string|number; + /** + * `tikaUrl` is the URL to access the Apache Tika app. + */ + tikaUrl: string; } -console.log(`Configuring .env and expanding .env to include environment variable references.`); - import path from 'path'; import dotenv from 'dotenv'; import dotenvExpand from 'dotenv-expand'; @@ -195,20 +193,20 @@ const __dirname = path.dirname(__filename); const env: ProcessEnv = {}; let dotEnvConfig = dotenv.config({ - path: path.join(__dirname, '.env'), - processEnv: dotenv.config({ - path: path.join(__dirname, '..', '..', '.env'), - processEnv: env as dotenv.DotenvPopulateInput}) as dotenv.DotenvPopulateInput - }); + path: path.join(__dirname, '.env'), + processEnv: dotenv.config({ + path: path.join(__dirname, '..', '..', '.env'), + processEnv: env as dotenv.DotenvPopulateInput}) as dotenv.DotenvPopulateInput + }); dotEnvConfig = dotenvExpand.expand({ - parsed: env as dotenvExpand.DotenvParseInput, - processEnv: process.env as dotenvExpand.DotenvParseInput + parsed: env as dotenvExpand.DotenvParseInput, + processEnv: process.env as dotenvExpand.DotenvParseInput }); export const getAppHttpHost = () => env.APP_HTTP_HOST||'nm3clol-express-app'; export const getAppHttpPort = () => process.env.PORT||env.APP_HTTP_PORT||3000; export const getAppHttpUrl = () => { - return env.APP_HTTP_URL || `http://${getAppHttpHost() + ((getAppHttpPort() == '80') ? '' : ':' + getAppHttpPort())}` + return env.APP_HTTP_URL || `http://${getAppHttpHost() + ((getAppHttpPort() == '80') ? '' : ':' + getAppHttpPort())}` }; export const getSiteName = () => env.SITE_NAME||"(dev) No Moss 3 Carbo Landfill Online Localhost"; @@ -237,31 +235,31 @@ export const getTikaPort = () => parseInt(env.TIKA_PORT||'9998'); export const getTikaUrl = () => env.TIKA_URL||`http://${getTikaHost()}:${getTikaPort()}`; export const config: Config = { - appHttpHost: getAppHttpHost(), - appHttpPort: getAppHttpPort(), - appHttpUrl: getAppHttpUrl(), + appHttpHost: getAppHttpHost(), + appHttpPort: getAppHttpPort(), + appHttpUrl: getAppHttpUrl(), - siteName: getSiteName(), - siteWelcomeMessage: getSiteWelcomeMessage(), - siteHost: getSiteHost(), - siteUrl: getSiteUrl(), + siteName: getSiteName(), + siteWelcomeMessage: getSiteWelcomeMessage(), + siteHost: getSiteHost(), + siteUrl: getSiteUrl(), - publicPath: getPublicPath(), - pagesPath: getPagesPath(), - assetsPath: getAssetsPath(), - viewsPath: getViewsPath(), + publicPath: getPublicPath(), + pagesPath: getPagesPath(), + assetsPath: getAssetsPath(), + viewsPath: getViewsPath(), - solrDocsHost: getSolrDocsHost(), - solrDocsPort: getSolrDocsPort(), - solrDocsCore: getSolrDocsCore(), - solrDocsUrl: getSolrDocsUrl(), + solrDocsHost: getSolrDocsHost(), + solrDocsPort: getSolrDocsPort(), + solrDocsCore: getSolrDocsCore(), + solrDocsUrl: getSolrDocsUrl(), - solrLawHost: getSolrLawHost(), - solrLawPort: getSolrLawPort(), - solrLawCore: getSolrLawCore(), - solrLawUrl: getSolrLawCore(), + solrLawHost: getSolrLawHost(), + solrLawPort: getSolrLawPort(), + solrLawCore: getSolrLawCore(), + solrLawUrl: getSolrLawCore(), - tikaHost: getTikaHost(), - tikaPort: getTikaPort(), - tikaUrl: getTikaUrl(), + tikaHost: getTikaHost(), + tikaPort: getTikaPort(), + tikaUrl: getTikaUrl(), }; From e0b93cf3558a64c20dbfcf101f8dbb05e8affac1 Mon Sep 17 00:00:00 2001 From: David Ball Date: Mon, 24 Jun 2024 01:00:18 -0400 Subject: [PATCH 2/3] Cleanup a lot of tab stops from 4 spaces to 2 and adjust other whitespace. --- app/helpers/breadcrumbs.mts | 6 +- app/page/glob-slash.mts | 2 +- app/search/solr-doc.mts | 28 ++-- app/server.mts | 4 +- app/tika/client.mts | 10 +- app/tika/types.mts | 160 ++++++++++----------- app/views/error.ejs | 199 ++++++++++++--------------- app/views/includes/bottom-navbar.ejs | 2 +- app/views/includes/breadcrumbs.ejs | 2 +- app/views/includes/no-trash-svg.ejs | 30 ++-- app/views/includes/top-navbar.ejs | 2 +- app/views/page.ejs | 7 - app/views/search-error.ejs | 63 +++++---- app/views/search-results.ejs | 139 ++++++++++--------- app/views/video-player.ejs | 7 - 15 files changed, 314 insertions(+), 347 deletions(-) diff --git a/app/helpers/breadcrumbs.mts b/app/helpers/breadcrumbs.mts index 3580bdc4..f2586fea 100644 --- a/app/helpers/breadcrumbs.mts +++ b/app/helpers/breadcrumbs.mts @@ -1,4 +1,4 @@ export interface Breadcrumb { - title: string; - url: string; -} + title: string; + url: string; +} \ No newline at end of file diff --git a/app/page/glob-slash.mts b/app/page/glob-slash.mts index 6491d648..ac29d935 100644 --- a/app/page/glob-slash.mts +++ b/app/page/glob-slash.mts @@ -5,4 +5,4 @@ import path from 'path'; export const normalize = (value: string) => path.posix.normalize(path.posix.join('/', value));; -export default (value: string) => (value.charAt(0) === '!' ? `!${normalize(value.substr(1))}` : normalize(value)); +export default (value: string) => (value.charAt(0) === '!' ? `!${normalize(value.substr(1))}` : normalize(value)); \ No newline at end of file diff --git a/app/search/solr-doc.mts b/app/search/solr-doc.mts index 7c10e40a..f7f4de23 100644 --- a/app/search/solr-doc.mts +++ b/app/search/solr-doc.mts @@ -2,24 +2,24 @@ * Needed until the conversion is completed. */ export interface IncorrectStyleSolrDocument { - id: string; - sha256sum: string[]; - url: string[]; - content_length: number[]; - content_type: string[]; - text: string[]; - _version_?: number; + id: string; + sha256sum: string[]; + url: string[]; + content_length: number[]; + content_type: string[]; + text: string[]; + _version_?: number; } /** * Describes Solr full-text search properties for a document file in the public repository. */ export interface SolrDocument { - id: string; - sha256sum: string; - url: string; - content_length: number; - content_type: string; - text: string; - _version_?: number; + id: string; + sha256sum: string; + url: string; + content_length: number; + content_type: string; + text: string; + _version_?: number; } diff --git a/app/server.mts b/app/server.mts index 782ac3db..b90eaccf 100644 --- a/app/server.mts +++ b/app/server.mts @@ -38,5 +38,5 @@ app.listen(config.appHttpPort, () => { console.log(`To access your app, you can use the 127.0.0.1 host, http://127.0.0.1:${config.appHttpPort}.`); console.log(`To access your app, you can use the ::1 host, http://[::1]:${config.appHttpPort}.`); console.log(`To access your app, you might can use the app host name, ${config.appHttpUrl}.`); - console.log(`This app is configured to use the web site URL, ${config.siteUrl}.`); -}); + console.log(`This app is configured to use the web site URL for URL generation, as needed, ${config.siteUrl}. Certain site features won't work correctly unless this is on a publicly accessible URL.`); +}); \ No newline at end of file diff --git a/app/tika/client.mts b/app/tika/client.mts index 378d722d..80305f55 100644 --- a/app/tika/client.mts +++ b/app/tika/client.mts @@ -1,11 +1,11 @@ import { ReadStream } from 'fs' import fetch from 'node-fetch' let join = (...args: String[]) => { - let output = ""; - args.forEach((arg) => { - output += arg; - }) - return output; + let output = ""; + args.forEach((arg) => { + output += arg; + }) + return output; }; import { ContentResource, MetadataResource } from './types.mjs' import { Writable } from 'stream'; diff --git a/app/tika/types.mts b/app/tika/types.mts index 1ad11bb8..2b3ce2d4 100644 --- a/app/tika/types.mts +++ b/app/tika/types.mts @@ -1,81 +1,81 @@ export interface MetadataResource { - 'pdf:unmappedUnicodeCharsPerPage': string[] - 'pdf:PDFVersion': string - 'xmp:CreatorTool': string - 'pdf:hasXFA': string - 'access_permission:modify_annotations': string - 'access_permission:can_print_degraded': string - 'X-TIKA:Parsed-By-Full-Set': string[] - 'pdf:num3DAnnotations': string - 'dcterms:created': string - 'language': string - 'dcterms:modified': string - 'dc:format': string - 'pdf:docinfo:creator_tool': string - 'pdf:overallPercentageUnmappedUnicodeChars': string - 'access_permission:fill_in_form': string - 'pdf:docinfo:modified': string - 'pdf:hasCollection': string - 'pdf:encrypted': string - 'pdf:containsNonEmbeddedFont': string - 'Content-Length': string - 'pdf:hasMarkedContent': string - 'Content-Type': string - 'pdf:producer': string - 'pdf:totalUnmappedUnicodeChars': string - 'access_permission:extract_for_accessibility': string - 'access_permission:assemble_document': string - 'xmpTPg:NPages': string - 'pdf:hasXMP': string - 'pdf:charsPerPage': string[] - 'access_permission:extract_content': string - 'access_permission:can_print': string - 'X-TIKA:Parsed-By': string[] - 'pdf:annotationTypes': string - 'access_permission:can_modify': string - 'pdf:docinfo:producer': string - 'pdf:docinfo:created': string - 'pdf:annotationSubtypes': string - 'pdf:containsDamagedFont': string - } - - export interface ContentResource { - 'pdf:unmappedUnicodeCharsPerPage': string[] - 'pdf:PDFVersion': string - 'xmp:CreatorTool': string - 'pdf:hasXFA': string - 'access_permission:modify_annotations': string - 'access_permission:can_print_degraded': string - 'X-TIKA:Parsed-By-Full-Set': string[] - 'pdf:num3DAnnotations': string - 'dcterms:created': string - 'dcterms:modified': string - 'dc:format': string - 'pdf:docinfo:creator_tool': string - 'pdf:overallPercentageUnmappedUnicodeChars': string - 'access_permission:fill_in_form': string - 'pdf:docinfo:modified': string - 'pdf:hasCollection': string - 'pdf:encrypted': string - 'pdf:containsNonEmbeddedFont': string - 'Content-Length': string - 'pdf:hasMarkedContent': string - 'Content-Type': string - 'pdf:producer': string - 'pdf:totalUnmappedUnicodeChars': string - 'access_permission:extract_for_accessibility': string - 'access_permission:assemble_document': string - 'xmpTPg:NPages': string - 'pdf:hasXMP': string - 'pdf:charsPerPage': string[] - 'access_permission:extract_content': string - 'access_permission:can_print': string - 'X-TIKA:Parsed-By': string[] - 'X-TIKA:content': string - 'pdf:annotationTypes': string - 'access_permission:can_modify': string - 'pdf:docinfo:producer': string - 'pdf:docinfo:created': string - 'pdf:annotationSubtypes': string - 'pdf:containsDamagedFont': string - } \ No newline at end of file + 'pdf:unmappedUnicodeCharsPerPage': string[] + 'pdf:PDFVersion': string + 'xmp:CreatorTool': string + 'pdf:hasXFA': string + 'access_permission:modify_annotations': string + 'access_permission:can_print_degraded': string + 'X-TIKA:Parsed-By-Full-Set': string[] + 'pdf:num3DAnnotations': string + 'dcterms:created': string + 'language': string + 'dcterms:modified': string + 'dc:format': string + 'pdf:docinfo:creator_tool': string + 'pdf:overallPercentageUnmappedUnicodeChars': string + 'access_permission:fill_in_form': string + 'pdf:docinfo:modified': string + 'pdf:hasCollection': string + 'pdf:encrypted': string + 'pdf:containsNonEmbeddedFont': string + 'Content-Length': string + 'pdf:hasMarkedContent': string + 'Content-Type': string + 'pdf:producer': string + 'pdf:totalUnmappedUnicodeChars': string + 'access_permission:extract_for_accessibility': string + 'access_permission:assemble_document': string + 'xmpTPg:NPages': string + 'pdf:hasXMP': string + 'pdf:charsPerPage': string[] + 'access_permission:extract_content': string + 'access_permission:can_print': string + 'X-TIKA:Parsed-By': string[] + 'pdf:annotationTypes': string + 'access_permission:can_modify': string + 'pdf:docinfo:producer': string + 'pdf:docinfo:created': string + 'pdf:annotationSubtypes': string + 'pdf:containsDamagedFont': string +} + +export interface ContentResource { + 'pdf:unmappedUnicodeCharsPerPage': string[] + 'pdf:PDFVersion': string + 'xmp:CreatorTool': string + 'pdf:hasXFA': string + 'access_permission:modify_annotations': string + 'access_permission:can_print_degraded': string + 'X-TIKA:Parsed-By-Full-Set': string[] + 'pdf:num3DAnnotations': string + 'dcterms:created': string + 'dcterms:modified': string + 'dc:format': string + 'pdf:docinfo:creator_tool': string + 'pdf:overallPercentageUnmappedUnicodeChars': string + 'access_permission:fill_in_form': string + 'pdf:docinfo:modified': string + 'pdf:hasCollection': string + 'pdf:encrypted': string + 'pdf:containsNonEmbeddedFont': string + 'Content-Length': string + 'pdf:hasMarkedContent': string + 'Content-Type': string + 'pdf:producer': string + 'pdf:totalUnmappedUnicodeChars': string + 'access_permission:extract_for_accessibility': string + 'access_permission:assemble_document': string + 'xmpTPg:NPages': string + 'pdf:hasXMP': string + 'pdf:charsPerPage': string[] + 'access_permission:extract_content': string + 'access_permission:can_print': string + 'X-TIKA:Parsed-By': string[] + 'X-TIKA:content': string + 'pdf:annotationTypes': string + 'access_permission:can_modify': string + 'pdf:docinfo:producer': string + 'pdf:docinfo:created': string + 'pdf:annotationSubtypes': string + 'pdf:containsDamagedFont': string +} \ No newline at end of file diff --git a/app/views/error.ejs b/app/views/error.ejs index 91181817..4b9af003 100644 --- a/app/views/error.ejs +++ b/app/views/error.ejs @@ -1,122 +1,105 @@ - - + - - - + +
-
- <% if (typeof statusCode !== 'undefined') { %><%= statusCode %><% } %> -

<% if (typeof message !== 'undefined') { %><%= message %><% } %>

-
+
+ <% if (typeof statusCode !== 'undefined') { %><%= statusCode %><% } %> +

<% if (typeof message !== 'undefined') { %><%= message %><% } %>

+
- - - + + \ No newline at end of file diff --git a/app/views/includes/bottom-navbar.ejs b/app/views/includes/bottom-navbar.ejs index 5d2df91c..ae233c08 100644 --- a/app/views/includes/bottom-navbar.ejs +++ b/app/views/includes/bottom-navbar.ejs @@ -9,4 +9,4 @@ Your use of this search feature constitutes your agreement with the Search Policy.

- + \ No newline at end of file diff --git a/app/views/includes/breadcrumbs.ejs b/app/views/includes/breadcrumbs.ejs index 06e8165d..267d8d2a 100644 --- a/app/views/includes/breadcrumbs.ejs +++ b/app/views/includes/breadcrumbs.ejs @@ -9,4 +9,4 @@ <%=breadcrumb.title%> <% } %> <% }) %> - + \ No newline at end of file diff --git a/app/views/includes/no-trash-svg.ejs b/app/views/includes/no-trash-svg.ejs index 8a32995e..e333a91d 100644 --- a/app/views/includes/no-trash-svg.ejs +++ b/app/views/includes/no-trash-svg.ejs @@ -1,18 +1,18 @@ \ No newline at end of file diff --git a/app/views/includes/top-navbar.ejs b/app/views/includes/top-navbar.ejs index e2430a77..fcba03bd 100644 --- a/app/views/includes/top-navbar.ejs +++ b/app/views/includes/top-navbar.ejs @@ -13,4 +13,4 @@ - + \ No newline at end of file diff --git a/app/views/page.ejs b/app/views/page.ejs index be4d05d1..6fc892a9 100644 --- a/app/views/page.ejs +++ b/app/views/page.ejs @@ -4,18 +4,13 @@ <%= (typeof fm.title !== 'undefined') ? `${fm.title} - ${h.getSiteName()}` : h.getSiteName() %> <%- include('./includes/common-head.ejs') %> - - <%- include('./includes/top-navbar.ejs') %> - <%- include('./includes/no-trash-svg.ejs') %> -
<%- include('./includes/breadcrumbs.ejs') %>
- <% if (typeof content !== 'undefined') {%>
@@ -29,7 +24,6 @@
<% } %> -
    <% if (typeof files !== 'undefined') files.forEach(function(value, index) { %>
  • @@ -40,7 +34,6 @@ <% }) %>
- <%- include('./includes/bottom-navbar.ejs') %> <%- include('./includes/bottom-scripts.ejs') %> diff --git a/app/views/search-error.ejs b/app/views/search-error.ejs index 54adcd00..89578bcd 100644 --- a/app/views/search-error.ejs +++ b/app/views/search-error.ejs @@ -1,35 +1,34 @@ - - Search Error for <%- query %> - <%- h.getSiteName() %> - <%- include('./includes/common-head.ejs') %> - - - <%- include('./includes/top-navbar.ejs') %> - <%- include('./includes/no-trash-svg.ejs') %> -
-
- <%- include('./includes/breadcrumbs.ejs') %> -
-
-

- Disclaimer: Use of the search feature is subject to both the Search - Policy and the Privacy Policy. -

-
-
- <% if (typeof error !== 'undefined') {%> -

An error occurred while attempting to perform a search.

- <% if (typeof query !== 'undefined') {%>

Search Query: <%= query %>

<% } %> - <% if (typeof error.code !== 'undefined') {%>

Error Code: <%= error.code %>

<% } %> - <% if (typeof error.message !== 'undefined') {%>

Error Message: <%= error.message %>

<% } %> - <% if (typeof error.innerError !== 'undefined' && typeof error.innerError.error !== 'undefined') { %> - <% if (typeof error.innerError.error.msg !== 'undefined') {%>

Inner Error Message: <%- error.innerError.error.msg.replaceAll("<", "<").replaceAll(">", ">").replaceAll("\n", '
') %>

<% } %> + + Search Error for <%- query %> - <%- h.getSiteName() %> + <%- include('./includes/common-head.ejs') %> + + + <%- include('./includes/top-navbar.ejs') %> + <%- include('./includes/no-trash-svg.ejs') %> +
+
+ <%- include('./includes/breadcrumbs.ejs') %> +
+
+

+ Disclaimer: Use of the search feature is subject to both the Search + Policy and the Privacy Policy. +

+
+
+ <% if (typeof error !== 'undefined') {%> +

An error occurred while attempting to perform a search.

+ <% if (typeof query !== 'undefined') {%>

Search Query: <%= query %>

<% } %> + <% if (typeof error.code !== 'undefined') {%>

Error Code: <%= error.code %>

<% } %> + <% if (typeof error.message !== 'undefined') {%>

Error Message: <%= error.message %>

<% } %> + <% if (typeof error.innerError !== 'undefined' && typeof error.innerError.error !== 'undefined') { %> + <% if (typeof error.innerError.error.msg !== 'undefined') {%>

Inner Error Message: <%- error.innerError.error.msg.replaceAll("<", "<").replaceAll(">", ">").replaceAll("\n", '
') %>

<% } %> + <% } %> <% } %> - <% } %> -
- - <%- include('./includes/bottom-navbar.ejs') %> - <%- include('./includes/bottom-scripts.ejs') %> - - +
+ <%- include('./includes/bottom-navbar.ejs') %> + <%- include('./includes/bottom-scripts.ejs') %> + + \ No newline at end of file diff --git a/app/views/search-results.ejs b/app/views/search-results.ejs index 0ac46ae9..f3cad141 100644 --- a/app/views/search-results.ejs +++ b/app/views/search-results.ejs @@ -1,73 +1,72 @@ - - Search Results for <%- query %> - <%- h.getSiteName() %> - <%- include('./includes/common-head.ejs') %> - - - <%- include('./includes/top-navbar.ejs') %> - <%- include('./includes/no-trash-svg.ejs') %> -
-
- <%- include('./includes/breadcrumbs.ejs') %> -
-
-

- Disclaimer: Use of the search feature is subject to both the Search - Policy and the Privacy Policy. -

-
- <% if (typeof response !== "undefined" && typeof response.numFound !== "undefined" && typeof response.docs !== "undefined" && typeof highlighting !== "undefined") { %> -
- - <% if (response.numFound == 0) { %> -

No documents found matching the search query.

- <% } else { %> -
    - <% response.docs.forEach(doc => { %> -
  • -
    <%= doc.title %>
    - <% if (highlighting[doc.id] && highlighting[doc.id].text) { %> - <% highlighting[doc.id].text.forEach(snippet => { %> -
    <%- h.stripWebVTT(snippet) %>
    - <% }); %> - <% } else { %> - - <% } %> - <%= doc.url %> -
  • - <% }); %> -
- <% } %> -
+ + Search Results for <%- query %> - <%- h.getSiteName() %> + <%- include('./includes/common-head.ejs') %> + + + <%- include('./includes/top-navbar.ejs') %> + <%- include('./includes/no-trash-svg.ejs') %> +
+
+ <%- include('./includes/breadcrumbs.ejs') %> +
+
+

+ Disclaimer: Use of the search feature is subject to both the Search + Policy and the Privacy Policy. +

- <% } %> - - <% if (typeof totalPages !== "undefined" && totalPages) { %> - -

Page <%= page %> out of <%= totalPages %>. Displaying results <%= (page-1)*pageSize+1 %> through <%= Math.min(page*pageSize, totalResults) %> out of <%= totalResults %> total results.

- <% } %> -
- - <%- include('./includes/bottom-navbar.ejs') %> - <%- include('./includes/bottom-scripts.ejs') %> - - + <% if (typeof response !== "undefined" && typeof response.numFound !== "undefined" && typeof response.docs !== "undefined" && typeof highlighting !== "undefined") { %> +
+ + <% if (response.numFound == 0) { %> +

No documents found matching the search query.

+ <% } else { %> +
    + <% response.docs.forEach(doc => { %> +
  • +
    <%= doc.title %>
    + <% if (highlighting[doc.id] && highlighting[doc.id].text) { %> + <% highlighting[doc.id].text.forEach(snippet => { %> +
    <%- h.stripWebVTT(snippet) %>
    + <% }); %> + <% } else { %> + + <% } %> + <%= doc.url %> +
  • + <% }); %> +
+ <% } %> +
+ + <% } %> + + <% if (typeof totalPages !== "undefined" && totalPages) { %> + +

Page <%= page %> out of <%= totalPages %>. Displaying results <%= (page-1)*pageSize+1 %> through <%= Math.min(page*pageSize, totalResults) %> out of <%= totalResults %> total results.

+ <% } %> +
+ <%- include('./includes/bottom-navbar.ejs') %> + <%- include('./includes/bottom-scripts.ejs') %> + + \ No newline at end of file diff --git a/app/views/video-player.ejs b/app/views/video-player.ejs index fb47e710..1e87e13c 100644 --- a/app/views/video-player.ejs +++ b/app/views/video-player.ejs @@ -4,17 +4,13 @@ <%=h.getDirectoryTitle(directory)%> <%- include('./includes/common-head.ejs') %> - - <%- include('./includes/top-navbar.ejs') %> <%- include('./includes/no-trash-svg.ejs') %> -
<%- include('./includes/breadcrumbs.ejs') %>
- <% if (typeof videoURL !== 'undefined') {%>
@@ -49,7 +45,6 @@
<% } %> - <% if (typeof subtitleVTT !== 'undefined') {%>
@@ -65,9 +60,7 @@
<% } %> -
- <%- include('./includes/bottom-navbar.ejs') %> <%- include('./includes/bottom-scripts.ejs') %> From 1f1071f5a977b87f6051cf8275b6ddaad641dbe3 Mon Sep 17 00:00:00 2001 From: David Ball Date: Mon, 24 Jun 2024 01:02:26 -0400 Subject: [PATCH 3/3] feat: Embedded Microsoft Office Viewer and Google Docs Viewer web services and no longer download as default action when viewer is supported when loading directory with file attachment that doesn't automatically render. --- app/helpers/functions.mts | 10 ++++ app/page/router.mts | 6 +-- app/page/vercel-serve.mts | 60 ++++++++++++------------ app/views/directory.ejs | 67 +++++++++++++++++++++++---- app/views/includes/bottom-scripts.ejs | 3 +- app/views/includes/common-head.ejs | 2 +- 6 files changed, 104 insertions(+), 44 deletions(-) diff --git a/app/helpers/functions.mts b/app/helpers/functions.mts index 13907508..5c6e2000 100644 --- a/app/helpers/functions.mts +++ b/app/helpers/functions.mts @@ -186,6 +186,14 @@ const renderArchive = (html: string, paths: string[]) => { return html; } +const isMsOfficeViewerSupported = (file: string) => { + return path.extname(file).search(/^((?:.pptx)|(?:.docx)|(?:.xlsx)|(?:.ppt)|(?:.doc)|(?:.xls))$/ig) != -1; +} + +const isGoogleDocsViewerSupported = (file: string) => { + return isMsOfficeViewerSupported(file) || path.extname(file).search(/^((?:.pdf))$/ig) != -1; +} + export default { leftTrimFirstDirectory, trimSlashes, @@ -205,4 +213,6 @@ export default { inspect, md, moment, + isMsOfficeViewerSupported, + isGoogleDocsViewerSupported, }; \ No newline at end of file diff --git a/app/page/router.mts b/app/page/router.mts index 65dfb26c..bd072740 100644 --- a/app/page/router.mts +++ b/app/page/router.mts @@ -78,7 +78,7 @@ export default function () { } }); const renderData = { breadcrumbs, content, filePath, fullFilePath, paths, req, route, ...fmData }; - res.render("page", { h: helpers, ...renderData }); + res.render("page", { h: helpers, path, config, ...renderData }); }); }); @@ -122,7 +122,7 @@ export default function () { console.log(`Setting route for ${route}`); pageRouter.get(route, async (req, res) => { const html = fs.readFileSync(fullFilePath).toString(); - const renderData = { route, filePath, fullFilePath, req, paths, html }; + const renderData = { route, filePath, fullFilePath, req, paths, html, path, config }; res.render("archive", { h: helpers, ...renderData }); }); }); @@ -183,7 +183,7 @@ export default function () { } }); const renderData = { breadcrumbs, route, filePath, fullFilePath, req, paths, directory: path.join('public', directory), videoURL, subtitleURL, subtitleVTT, info }; - res.render("video-player", { h: helpers, ...renderData }); + res.render("video-player", { h: helpers, path, config, ...renderData }); } }); }); diff --git a/app/page/vercel-serve.mts b/app/page/vercel-serve.mts index 1308e953..98524f1c 100644 --- a/app/page/vercel-serve.mts +++ b/app/page/vercel-serve.mts @@ -81,15 +81,15 @@ export interface ServeHandlerOptions { * current working directory. * * For example, if serving a Jekyll app, it would look like this: - * { - * "public": "_site" - * } + * { + * "public": "_site" + * } * * Using absolute path: * - * { - * "public": "/path/to/your/_site" - * } + * { + * "public": "/path/to/your/_site" + * } * * NOTE: The path cannot contain globs or regular expressions. */ @@ -101,17 +101,17 @@ export interface ServeHandlerOptions { * with status code 301 to the same path, but with the extension dropped. * * You can disable the feature like follows: - * { - * "cleanUrls": false - * } + * { + * "cleanUrls": false + * } * * However, you can also restrict it to certain paths: - * { - * "cleanUrls": [ - * "/app/**", - * "/!components/**" - * ] - * } + * { + * "cleanUrls": [ + * "/app/**", + * "/!components/**" + * ] + * } * * NOTE: The paths can only contain globs that are matched using minimatch. */ @@ -121,19 +121,19 @@ export interface ServeHandlerOptions { * different one behind the curtains, this option is what you need. * * It's perfect for single page applications (SPAs), for example: - * { - * "rewrites": [ - * { "source": "app/**", "destination": "/index.html" }, - * { "source": "projects/edit", "destination": "/edit-project.html" } - * ] - * } + * { + * "rewrites": [ + * { "source": "app/**", "destination": "/index.html" }, + * { "source": "projects/edit", "destination": "/edit-project.html" } + * ] + * } * * You can also use so-called "routing segments" as follows: - * { - * "rewrites": [ - * { "source": "/projects/:id/edit", "destination": "/edit-project-:id.html" }, - * ] - * } + * { + * "rewrites": [ + * { "source": "/projects/:id/edit", "destination": "/edit-project-:id.html" }, + * ] + * } * * Now, if a visitor accesses /projects/123/edit, it will respond with the file /edit-project-123.html. * @@ -184,8 +184,9 @@ export const directoryTemplate = (vals: ServeDirectoryTemplateParameters) => { }); } return new Promise((resolve, reject) => { - ejs.renderFile(path.join(config.viewsPath, 'directory.ejs'), { breadcrumbs, h: helpers, ...vals }, (err, str) => { + ejs.renderFile(path.join(config.viewsPath, 'directory.ejs'), { h: helpers, path, config, breadcrumbs, ...vals }, (err, str) => { if (err) { + console.error(err); reject(err); } else { resolve(str); @@ -196,8 +197,9 @@ export const directoryTemplate = (vals: ServeDirectoryTemplateParameters) => { export const errorTemplate = (vals: ServeErrorTemplateParameters) => { return new Promise((resolve, reject) => { - ejs.renderFile(path.join(config.viewsPath, 'error.ejs'), { h: helpers, ...vals }, (err, str) => { + ejs.renderFile(path.join(config.viewsPath, 'error.ejs'), { h: helpers, path, config, ...vals }, (err, str) => { if (err) { + console.error(err); reject(err); } else { resolve(str); @@ -1012,4 +1014,4 @@ export default async (request: Request, response: ServerResponse, serveConfig: S response.writeHead(response.statusCode || 200, headers); stream.pipe(response); -}; +}; \ No newline at end of file diff --git a/app/views/directory.ejs b/app/views/directory.ejs index edfe52dd..adb96576 100644 --- a/app/views/directory.ejs +++ b/app/views/directory.ejs @@ -4,18 +4,13 @@ <%=h.getDirectoryTitle(directory)%> <%- include('./includes/common-head.ejs') %> - - <%- include('./includes/top-navbar.ejs') %> - <%- include('./includes/no-trash-svg.ejs') %> -
<%- include('./includes/breadcrumbs.ejs') %>
- <% if (h.directoryContainsReadme(directory)) {%>
@@ -27,13 +22,69 @@ Document Date: <%= h.moment(h.readmeFm(directory).docDate).format('MMMM D, YYYY') %> <% } %> <%if (typeof h.readmeFm(directory).file !== 'undefined') { %> - Attached Document: <%- h.readmeFm(directory).file %> + Document: <%- h.readmeFm(directory).file %> <% } %>

<% } %> <% if (typeof h.readmeFm(directory).file !== 'undefined') { %> - + +
+ <% if (h.isMsOfficeViewerSupported(h.readmeFm(directory).file)) { %> +
+ +
+ <% } %> + <% if (h.isGoogleDocsViewerSupported(h.readmeFm(directory).file)) { %> +
+ +
+ <% } %> +
+ +
+ + <% if (!h.isMsOfficeViewerSupported(h.readmeFm(directory).file) && !h.isGoogleDocsViewerSupported(h.readmeFm(directory).file)) { %> + + <% } %> +
<% } else { %> <%- h.printReadme(directory) %> <% } %> @@ -54,7 +105,6 @@
<% } %> <% } %> -
    <% files.forEach(function(value, index) { %>
  • @@ -65,7 +115,6 @@ <% }); %>
- <%- include('./includes/bottom-navbar.ejs') %> <%- include('./includes/bottom-scripts.ejs') %> diff --git a/app/views/includes/bottom-scripts.ejs b/app/views/includes/bottom-scripts.ejs index c0bfd4da..71577113 100644 --- a/app/views/includes/bottom-scripts.ejs +++ b/app/views/includes/bottom-scripts.ejs @@ -1,6 +1,5 @@ - - + \ No newline at end of file diff --git a/app/views/includes/common-head.ejs b/app/views/includes/common-head.ejs index 7188b755..64a86044 100644 --- a/app/views/includes/common-head.ejs +++ b/app/views/includes/common-head.ejs @@ -10,7 +10,6 @@ - @@ -26,3 +25,4 @@ +