forked from nm3clol/nm3clol-express-app
165 lines
6.0 KiB
JavaScript
165 lines
6.0 KiB
JavaScript
const express = require('express');
|
|
const axios = require('axios');
|
|
const app = express();
|
|
const serve = require('./vercel-serve');
|
|
const path = require('path');
|
|
const glob = require('glob');
|
|
const matter = require('gray-matter');
|
|
const ejs = require('ejs');
|
|
const helpers = require('../views/helpers/functions');
|
|
|
|
// Port number for HTTP server
|
|
const port = process.env.PORT||3000;
|
|
|
|
// Solr instance URL
|
|
const solrUrl = 'http://solr.services.cleveland.daball.me:8983/solr/my_core';
|
|
|
|
// Set EJS as the view engine
|
|
app.set('view engine', 'ejs');
|
|
|
|
// Specify the views directory
|
|
app.set('views', path.join(__dirname, '..', 'views'));
|
|
|
|
// Middleware to parse JSON request body
|
|
app.use(express.json());
|
|
|
|
// Middleware to rewrite requests
|
|
//app.use(rewriter);
|
|
|
|
// // Serve static files (CSS, JavaScript, images, etc.)
|
|
// app.use(serve('../public', {
|
|
// dotfiles: 'ignore',
|
|
// index: false,
|
|
// }));
|
|
|
|
// app.get('/', (req, res) => {
|
|
// res.send('Hello World!');
|
|
// })
|
|
|
|
// Endpoints for all the site's pages.
|
|
glob.globSync('pages/**/*.md', {
|
|
cwd: path.join(__dirname, '..'),
|
|
matchBase: true,
|
|
follow: true,
|
|
}).forEach((filePath) => {
|
|
const expressRoutePathFromFilePath = (filePath) => {
|
|
return filePath.substring('pages'.length, filePath.length - path.extname(filePath).length).replaceAll(path.sep, path.posix.sep);
|
|
};
|
|
const route = expressRoutePathFromFilePath(filePath);
|
|
const fullFilePath = path.join(__dirname, '..', filePath);
|
|
let paths = route.split(path.posix.sep);
|
|
paths[0] = 'public';
|
|
app.get(route, async (req, res) => {
|
|
const fm = matter.read(fullFilePath);
|
|
const fmData = { fm: fm.data, excerpt: fm.excerpt };
|
|
const content = helpers.md.render(fm.content, fmData );
|
|
const renderData = { content, route, filePath, fullFilePath, req, paths, ...fmData };
|
|
res.render("page", { h: helpers, ...renderData });
|
|
});
|
|
});
|
|
|
|
// Search endpoint
|
|
app.get('/search', async (req, res) => {
|
|
// Extract search query from request query parameters
|
|
let { q, page = 1, pageSize = 10 } = req.query;
|
|
pageSize = Math.min(pageSize, 100); // cap at 100
|
|
const query = q;
|
|
// Calculate start offset for pagination
|
|
const start = (page - 1) * pageSize;
|
|
|
|
// Sanitize search query to prevent code injection
|
|
const sanitizedQuery = sanitizeQuery(query);
|
|
try {
|
|
// Validate search query
|
|
if (!query) {
|
|
//return res.status(400).json({ error: 'q parameter is required' });
|
|
res.render('search-error', { h: helpers, query: sanitizedQuery, error: { code: 400, message: 'Search query is required.'} });
|
|
}
|
|
|
|
// Send search query to Solr
|
|
const response = await axios.get(solrUrl + '/select', {
|
|
params: {
|
|
q: `text:${sanitizedQuery}`, // Query string with field name
|
|
hl: 'true',
|
|
'hl.method': 'unified',
|
|
'hl.fl': '*',
|
|
'hl.snippets': 5,
|
|
'hl.tag.pre': '<strong class=\"result-highlight\">',
|
|
'hl.tag.post': '</strong>',
|
|
'hl.usePhraseHighlighter': true,
|
|
start, // Start offset for pagination
|
|
rows: 10, // Number of rows to return
|
|
wt: 'json', // Response format (JSON)
|
|
},
|
|
});
|
|
|
|
// Extract search results from Solr response
|
|
const searchResults = response.data.response.docs;
|
|
const highlightedSnippets = response.data.highlighting;
|
|
|
|
// Calculate total number of results (needed for pagination)
|
|
const totalResults = response.data.response.numFound;
|
|
|
|
// Calculate total number of pages
|
|
const totalPages = Math.ceil(totalResults / pageSize);
|
|
|
|
// Send search results as JSON response
|
|
//res.json('search-results', { query, searchResults, highlightedSnippets, page, pageSize, totalResults, totalPages });
|
|
res.render('search-results', { h: helpers, query: sanitizedQuery, searchResults, highlightedSnippets, page, pageSize, totalResults, totalPages });
|
|
} catch (error) {
|
|
// console.error('Error searching Solr:', error.message);
|
|
// res.status(500).json({ error: 'Internal server error' });
|
|
res.render('search-error', { h: helpers, query: sanitizedQuery, error });
|
|
}
|
|
});
|
|
|
|
// Function to sanitize search query to prevent code injection
|
|
function sanitizeQuery(query) {
|
|
// Remove any characters that are not alphanumeric or whitespace
|
|
return query.replace(/[^\w\s*,."]/gi, '');
|
|
}
|
|
|
|
//app.get('/OCR-Encoded-PDFs/Russell-County-Web-Site_2024-02-13_19_50_Modified-With-OCR-Encoding**', rewriter.rewrite('/Web_Site_Archives/Russell_County_Web_Site-2024-02-13_19_50_Modified_With_OCR_Encoding/$1'));
|
|
|
|
app.get('*', async (req, res) => {
|
|
await serve(req, res, {
|
|
public: path.join(__dirname, '..', 'public'),
|
|
symlinks: true,
|
|
trailingSlash: true,
|
|
cleanUrls: false,
|
|
renderSingle: false,
|
|
unlisted: [
|
|
".DS_Store",
|
|
".git",
|
|
"README*"
|
|
],
|
|
redirects: [
|
|
{
|
|
source: "/:year(\d{4})-:mo(\d{2})-:dd(\d{2})_:hh(\d{2})_:mm(\d{2})/",
|
|
destination: "/Web_Site_Archives/Russell_County_Web_Site-:year-:mo-:dd_:hh_:mm/"
|
|
},
|
|
{
|
|
source: "/OCR-Encoded-PDFs",
|
|
destination: "/Web_Site_Archives"
|
|
},
|
|
{
|
|
source: "/OCR-Encoded-PDFs/Russell-County-Web-Site_2024-02-13_19_50_Modified-With-OCR-Encoding.zip",
|
|
destination: "/Web_Site_Archives/Russell_County_Web_Site-2024-02-13_19_50_Modified_With_OCR_Encoding.zip"
|
|
},
|
|
{
|
|
source: "/OCR-Encoded-PDFs/Russell-County-Web-Site_2024-02-13_19_50_Modified-With-OCR-Encoding/:u(.*)",
|
|
destination: "/Web_Site_Archives/Russell_County_Web_Site-2024-02-13_19_50_Modified_With_OCR_Encoding:u"
|
|
},
|
|
{ source: '/YouTube Channel', destination: '/Russell_County_BOS/YouTube_Channel' },
|
|
{ source: '/YouTube Channel.zip', destination: '/Russell_County_BOS/YouTube_Channel.zip' },
|
|
{ source: '/YouTube Channel/:u?', destination: '/Russell_County_BOS/YouTube_Channel/:u' },
|
|
{ source: '/Project Reclaim [WI19KR9Ogwg].mkv', destination: '/YouTube_Archives/@VADMME/Project Reclaim [WI19KR9Ogwg].mkv' },
|
|
]
|
|
});
|
|
});
|
|
|
|
// Start server
|
|
app.listen(port, () => {
|
|
console.log(`no-moss-3-carbo-landfill-library.online app listening on port ${port}`);
|
|
});
|