Initial Commit
This commit is contained in:
10
routes/about.js
Normal file
10
routes/about.js
Normal file
@@ -0,0 +1,10 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const path = require('path');
|
||||
|
||||
// Serve about.html
|
||||
router.get('/', (req, res) => {
|
||||
res.sendFile(path.join(__dirname, '../views/about.html'));
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
10
routes/art.js
Normal file
10
routes/art.js
Normal file
@@ -0,0 +1,10 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const path = require('path');
|
||||
|
||||
// Route to serve the art page
|
||||
router.get('/', (req, res) => {
|
||||
res.sendFile(path.join(__dirname, '../views/art.html'));
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
107
routes/blog.js
Normal file
107
routes/blog.js
Normal file
@@ -0,0 +1,107 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const { marked } = require('marked');
|
||||
const fm = require('front-matter'); // For parsing front matter
|
||||
const RSS = require('rss'); // Import RSS package
|
||||
|
||||
// Directory containing Markdown blog posts
|
||||
const blogDirectory = path.join(__dirname, '../blog');
|
||||
|
||||
// Function to get all Markdown files in the blog directory
|
||||
function getBlogPosts() {
|
||||
const files = fs.readdirSync(blogDirectory);
|
||||
return files.filter(file => file.endsWith('.md')).map(file => {
|
||||
const content = fs.readFileSync(path.join(blogDirectory, file), 'utf-8');
|
||||
|
||||
// Parse front matter
|
||||
const parsed = fm(content);
|
||||
const { title, date, preview } = parsed.attributes; // Get title, date, and preview from front matter
|
||||
|
||||
// Remove Markdown formatting by converting to HTML and stripping the tags
|
||||
const htmlContent = marked(parsed.body);
|
||||
const plainText = htmlContent.replace(/<\/?[^>]+(>|$)/g, ""); // Strip HTML tags from Markdown-converted content
|
||||
|
||||
// Truncate the plain text to create the preview
|
||||
const generatedPreview = plainText.split(' ').slice(0, 30).join(' ').substring(0, 150); // First 150 characters
|
||||
|
||||
// Use the preview from front matter if available, otherwise use the generated plain-text preview
|
||||
const finalPreview = preview || generatedPreview;
|
||||
|
||||
const slug = file.replace('.md', ''); // Remove file extension for slug
|
||||
|
||||
console.log(`Preview for ${title}: ${finalPreview}`); // Log the preview to verify
|
||||
|
||||
return {
|
||||
title,
|
||||
date,
|
||||
preview: finalPreview, // Ensure the correct preview is sent
|
||||
slug
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// New Route to generate RSS feed - put this before the dynamic slug route
|
||||
router.get('/rss.xml', (req, res) => {
|
||||
const feed = new RSS({
|
||||
title: 'The Klein Blog',
|
||||
description: 'Latest updates from The Klein Blog',
|
||||
feed_url: `${req.protocol}://${req.get('host')}/rss.xml`,
|
||||
site_url: `${req.protocol}://${req.get('host')}`,
|
||||
language: 'en',
|
||||
pubDate: new Date().toUTCString(),
|
||||
});
|
||||
|
||||
// Add each blog post to the RSS feed
|
||||
const posts = getBlogPosts();
|
||||
posts.forEach(post => {
|
||||
feed.item({
|
||||
title: post.title,
|
||||
description: post.preview, // Short preview for the RSS feed
|
||||
url: `${req.protocol}://${req.get('host')}/blog/${post.slug}`, // Link to the blog post
|
||||
date: post.date, // Published date
|
||||
});
|
||||
});
|
||||
|
||||
// Set the content type to XML and send the RSS feed
|
||||
res.set('Content-Type', 'application/rss+xml');
|
||||
res.send(feed.xml());
|
||||
});
|
||||
|
||||
// Route to serve the blog posts as JSON
|
||||
router.get('/blog-posts', (req, res) => {
|
||||
const posts = getBlogPosts(); // Get all blog posts
|
||||
res.json(posts); // Return posts as JSON to be fetched by the client-side JS
|
||||
});
|
||||
|
||||
// Route to serve the main blog page (serve blog.html)
|
||||
router.get('/', (req, res) => {
|
||||
// Render the blog.html file from the views directory
|
||||
res.sendFile(path.join(__dirname, '../views/blog.html'));
|
||||
});
|
||||
|
||||
marked.setOptions({
|
||||
gfm: true, // GitHub-flavored Markdown
|
||||
breaks: true, // Enable line breaks
|
||||
smartypants: true, // Use smart quotes, dashes, etc.
|
||||
sanitize: false, // This is the important option to allow HTML tags
|
||||
});
|
||||
|
||||
// Route to serve individual blog posts dynamically
|
||||
router.get('/:slug', (req, res) => {
|
||||
const { slug } = req.params;
|
||||
const filePath = path.join(blogDirectory, `${slug}.md`);
|
||||
|
||||
if (fs.existsSync(filePath)) {
|
||||
const content = fs.readFileSync(filePath, 'utf-8');
|
||||
const parsed = fm(content); // Parse front matter
|
||||
const htmlContent = marked(parsed.body); // Convert markdown body to HTML
|
||||
res.render('post', { content: htmlContent, title: parsed.attributes.title, date: parsed.attributes.date }); // Render post view
|
||||
} else {
|
||||
res.status(404).send('Blog post not found');
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
78
routes/contact.js
Normal file
78
routes/contact.js
Normal file
@@ -0,0 +1,78 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const path = require('path');
|
||||
const nodemailer = require('nodemailer');
|
||||
const rateLimit = require('express-rate-limit');
|
||||
const fs = require('fs');
|
||||
require('dotenv').config(); // Load environment variables
|
||||
|
||||
// Define the log file path
|
||||
const logFilePath = path.join(__dirname, '../stderr.log');
|
||||
|
||||
// Helper function to log errors to stderr.log
|
||||
function logError(message) {
|
||||
const logMessage = `${new Date().toISOString()} - ${message}\n`;
|
||||
fs.appendFile(logFilePath, logMessage, (err) => {
|
||||
if (err) {
|
||||
console.error('Error writing to stderr.log:', err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Nodemailer setup using environment variables
|
||||
const transporter = nodemailer.createTransport({
|
||||
service: 'gmail', // Use your email service (like Gmail, Outlook, etc.)
|
||||
auth: {
|
||||
user: process.env.EMAIL_USER, // Fetch email from environment variable
|
||||
pass: process.env.EMAIL_PASSWORD // Fetch password from environment variable
|
||||
}
|
||||
});
|
||||
|
||||
// Rate limiter to allow only one submission per 24 hours per IP
|
||||
const contactFormLimiter = rateLimit({
|
||||
windowMs: 24 * 60 * 60 * 1000, // 24 hours
|
||||
max: 1, // Limit each IP to 1 request per window
|
||||
message: 'You have already submitted a message. Please try again after 24 hours.'
|
||||
});
|
||||
|
||||
// Route to serve the contact page
|
||||
router.get('/', (req, res) => {
|
||||
res.sendFile(path.join(__dirname, '../views/contact.html'));
|
||||
});
|
||||
|
||||
// Route to handle form submissions
|
||||
router.post('/submit-contact-form', contactFormLimiter, (req, res) => {
|
||||
const { name, email, message } = req.body;
|
||||
|
||||
// Backend validation for the form fields
|
||||
if (!name || !email || !message) {
|
||||
logError('Form submission failed: Missing fields.');
|
||||
return res.status(400).json({ success: false, message: 'All fields are required.' });
|
||||
}
|
||||
|
||||
// Check if environment variables are set
|
||||
if (!process.env.EMAIL_USER || !process.env.EMAIL_PASSWORD) {
|
||||
logError('Error: EMAIL_USER or EMAIL_PASSWORD environment variables not set.');
|
||||
return res.status(500).json({ success: false, message: 'Server configuration error: Environment variables not set.' });
|
||||
}
|
||||
|
||||
// Email options for sending the message
|
||||
const mailOptions = {
|
||||
from: email, // Sender's email
|
||||
to: process.env.EMAIL_USER, // Your email where you'll receive messages
|
||||
subject: `New Contact Form Submission from ${name}`,
|
||||
text: `You have received a new message from ${name} (${email}):\n\n${message}`
|
||||
};
|
||||
|
||||
// Send the email
|
||||
transporter.sendMail(mailOptions, (error, info) => {
|
||||
if (error) {
|
||||
logError(`Error sending email: ${error.message}`);
|
||||
return res.status(500).json({ success: false, message: 'Error sending email.' });
|
||||
}
|
||||
logError(`Email sent successfully: ${info.response}`);
|
||||
res.json({ success: true, message: 'Your message has been sent successfully.' });
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
44
routes/index.js
Normal file
44
routes/index.js
Normal file
@@ -0,0 +1,44 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const path = require('path');
|
||||
|
||||
// Function to detect curl requests
|
||||
function isCurl(req) {
|
||||
const userAgent = req.headers['user-agent'];
|
||||
return userAgent && userAgent.includes('curl');
|
||||
}
|
||||
|
||||
// Serve index.html for browser requests or plain text for curl
|
||||
router.get('/', (req, res) => {
|
||||
if (isCurl(req)) {
|
||||
res.type('text/plain');
|
||||
res.send(`
|
||||
_ ___ _ _____ _
|
||||
| |/ / | (_) | __ \\ (_)
|
||||
| ' /| | ___ _ _ __ | |__) |_ _ _ __ _ ___
|
||||
| < | |/ _ \\ | '_ \\| ___/ _\` | '_ \\| |/ __|
|
||||
| . \\| | __/ | | | | | | (_| | | | | | (__
|
||||
|_|\\_\\_|\\___|_|_| |_|_| \\__,_|_| |_|_|\\___|
|
||||
|
||||
My Awesome Website
|
||||
|
||||
Source: https://github.com/your-username/your-repo
|
||||
|
||||
+ ------------------------- + -------------------------------------- + -------------------- +
|
||||
| TITLE | DESCRIPTION | VIDEO |
|
||||
+ ------------------------- + -------------------------------------- + -------------------- +
|
||||
| | | |
|
||||
| | | |
|
||||
| | | |
|
||||
| | | |
|
||||
+ ------------------------- + -------------------------------------- + -------------------- +
|
||||
|
||||
last updated: ${new Date().toUTCString()}
|
||||
`);
|
||||
} else {
|
||||
// Render HTML for normal browser requests
|
||||
res.sendFile(path.join(__dirname, '../views/index.html'));
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
9
routes/monitor.js
Normal file
9
routes/monitor.js
Normal file
@@ -0,0 +1,9 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const path = require('path');
|
||||
|
||||
router.get('/', (req, res) => {
|
||||
res.sendFile(path.join(__dirname, '../views/monitor.html'));
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
31
routes/projects.js
Normal file
31
routes/projects.js
Normal file
@@ -0,0 +1,31 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const axios = require('axios');
|
||||
const path = require('path');
|
||||
|
||||
// Route for /projects page
|
||||
router.get('/', (req, res) => {
|
||||
res.sendFile(path.join(__dirname, '../views/projects.html'));
|
||||
});
|
||||
|
||||
// Route for fetching GitHub projects dynamically via JavaScript
|
||||
router.get('/fetch', async (req, res) => {
|
||||
const page = req.query.page || 1;
|
||||
const per_page = req.query.per_page || 100; // Maximum is 100 items per page
|
||||
|
||||
try {
|
||||
// Fetch user's GitHub repositories with pagination
|
||||
const response = await axios.get(`https://api.github.com/users/kleinpanic/repos`, {
|
||||
params: {
|
||||
page,
|
||||
per_page,
|
||||
},
|
||||
});
|
||||
|
||||
res.json(response.data);
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: 'Unable to fetch GitHub repositories.' });
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
Reference in New Issue
Block a user