diff --git a/data/newsletter-emails.json b/data/newsletter-emails.json new file mode 100644 index 0000000..5b06ffc --- /dev/null +++ b/data/newsletter-emails.json @@ -0,0 +1,4 @@ +[ + "test@email.com", + "tete@hth3.ce" +] \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index df80a10..54b12cc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,7 @@ "nodemailer": "^7.0.3", "nodemon": "^3.1.10", "path": "^0.12.7", + "rss": "^1.2.2", "sqlite3": "^5.1.7" }, "devDependencies": { @@ -4140,6 +4141,37 @@ "node": ">= 18" } }, + "node_modules/rss": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/rss/-/rss-1.2.2.tgz", + "integrity": "sha512-xUhRTgslHeCBeHAqaWSbOYTydN2f0tAzNXvzh3stjz7QDhQMzdgHf3pfgNIngeytQflrFPfy6axHilTETr6gDg==", + "license": "MIT", + "dependencies": { + "mime-types": "2.1.13", + "xml": "1.0.1" + } + }, + "node_modules/rss/node_modules/mime-db": { + "version": "1.25.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.25.0.tgz", + "integrity": "sha512-5k547tI4Cy+Lddr/hdjNbBEWBwSl8EBc5aSdKvedav8DReADgWJzcYiktaRIw3GtGC1jjwldXtTzvqJZmtvC7w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/rss/node_modules/mime-types": { + "version": "2.1.13", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.13.tgz", + "integrity": "sha512-ryBDp1Z/6X90UvjUK3RksH0IBPM137T7cmg4OgD5wQBojlAiUwuok0QeELkim/72EtcYuNlmbkrcGuxj3Kl0YQ==", + "license": "MIT", + "dependencies": { + "mime-db": "~1.25.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/run-series": { "version": "1.1.9", "resolved": "https://registry.npmjs.org/run-series/-/run-series-1.1.9.tgz", @@ -5209,6 +5241,12 @@ } } }, + "node_modules/xml": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", + "integrity": "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==", + "license": "MIT" + }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", diff --git a/package.json b/package.json index 72d7a23..d122e5d 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "nodemailer": "^7.0.3", "nodemon": "^3.1.10", "path": "^0.12.7", + "rss": "^1.2.2", "sqlite3": "^5.1.7" }, "devDependencies": { diff --git a/src/routes/index.js b/src/routes/index.js index 55f4925..a98290c 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -13,12 +13,14 @@ const sitemap = require("./sitemap"); const post = require("./post"); const pages = require("./pages"); +const rssFeed = require("./rssFeed"); router.use(blog_index); router.use(robots); router.use(contact); router.use(sitemap); router.use(pages); +router.use(rssFeed); router.get("/blog/:year/:month/:name", post); diff --git a/src/routes/newsletter.js b/src/routes/newsletter.js index 2afd2e6..435b8c3 100644 --- a/src/routes/newsletter.js +++ b/src/routes/newsletter.js @@ -16,7 +16,7 @@ const context = await getBaseContext({ title: "Thank You", }); - res.render("pages/thankyou.handlebars", context); + res.render("pages/newsletter-success.handlebars", context); }); router.post("/newsletter", async (req, res, next) => { diff --git a/src/routes/pages.js b/src/routes/pages.js index 79ea464..87e4005 100644 --- a/src/routes/pages.js +++ b/src/routes/pages.js @@ -8,21 +8,23 @@ const markdown = new MarkdownRoutes(); if (process.env.NODE_ENV === "production") { - construction.register("/newsletter", "Newsletter"); + // construction.register("/newsletter", "Newsletter"); construction.register("/projects", "Projects"); construction.register("/about/blog", "About this blog"); } else { markdown.register("/about/blog", "about-blog"); markdown.register("/projects", "projects"); - const newsletter = require("./newsletter"); - router.use(newsletter); } +const newsletter = require("./newsletter"); +router.use(newsletter); + construction.register("/changelog", "Changelog"); construction.register("/archive", "Archive"); -construction.register("/rss-feed.xml", "RSS Feed"); +// construction.register("/rss-feed.xml", "RSS Feed"); construction.register("/tags", "Tags"); construction.register("/blog", "Blog"); +construction.register("/about/blog", "About This Blog"); // construction.register("/contact", "Contact Me"); markdown.register("/tools", "tools", "tools"); diff --git a/src/routes/rssFeed.js b/src/routes/rssFeed.js new file mode 100644 index 0000000..255e28a --- /dev/null +++ b/src/routes/rssFeed.js @@ -0,0 +1,13 @@ +// routes/rss.js +const express = require("express"); +const router = express.Router(); +const generateRSSFeed = require("../services/rssFeedService"); + +router.get("/rss-feed.xml", async (req, res) => { + const domain = process.env.DOMAIN; + const xml = await generateRSSFeed("content/posts", `https://${domain}`); + res.set("Content-Type", "application/rss+xml"); + res.send(xml); +}); + +module.exports = router; diff --git a/src/services/rssFeedService.js b/src/services/rssFeedService.js new file mode 100644 index 0000000..00b93cd --- /dev/null +++ b/src/services/rssFeedService.js @@ -0,0 +1,28 @@ +// src/services/rssFeedService.js +const RSS = require("rss"); +const { getAllPosts } = require("../utils/postFileUtils"); + +async function generateRSSFeed(baseDir, siteUrl) { + const allPosts = await getAllPosts(baseDir); + + const feed = new RSS({ + title: "My Blog", + description: "Latest posts from my blog", + feed_url: `${siteUrl}/rss.xml`, + site_url: siteUrl, + language: "en", + }); + + for (const post of allPosts) { + feed.item({ + title: post.title, + description: post.excerpt || "", // optional: add excerpt to post object + url: `${siteUrl}${post.url}`, + date: post.date, + }); + } + + return feed.xml({ indent: true }); +} + +module.exports = generateRSSFeed; diff --git a/src/utils/sendContactMail.js b/src/utils/sendContactMail.js index a9178e1..551ef68 100644 --- a/src/utils/sendContactMail.js +++ b/src/utils/sendContactMail.js @@ -1,21 +1,5 @@ -// src/utils/mailer.js -const nodemailer = require("nodemailer"); -require("dotenv").config(); - -let auth = null; -if (process.env.MAIL_AUTH != "null") { - auth = { - user: process.env.MAIL_USER, - pass: process.env.MAIL_PASS, - }; -} -console.log(process.env.MAIL_PORT); -const transporter = nodemailer.createTransport({ - host: process.env.MAIL_HOST, - port: parseInt(process.env.MAIL_PORT, 10), - secure: process.env.MAIL_SECURE === "true", - auth, -}); +// src/utils/sendContactMail.js +const transporter = require("./transporter"); function sendContactMail({ name, email, subject, message }) { const { DOMAIN: domain } = process.env; diff --git a/src/utils/sendNewsletterSubscriptionMail.js b/src/utils/sendNewsletterSubscriptionMail.js index 5a54b3a..b7f0bce 100644 --- a/src/utils/sendNewsletterSubscriptionMail.js +++ b/src/utils/sendNewsletterSubscriptionMail.js @@ -1,24 +1,5 @@ -// src/utils/mailer.js -const nodemailer = require("nodemailer"); -require("dotenv").config(); - -let auth = null; -if (process.env.MAIL_AUTH !== "null") { - auth = { - user: process.env.MAIL_USER || null, - pass: process.env.MAIL_PASS || null, - }; -} - -const credentials = { - host: process.env.MAIL_HOST, - port: parseInt(process.env.MAIL_PORT, 10), - secure: process.env.MAIL_SECURE === "true", - auth, -}; -console.log(credentials); -const transporter = nodemailer.createTransport(credentials); - +// src/utils/sendNewsletterSubscriptionMail.js +const transporter = require("./transporter"); const sendNewsletterSubscriptionMail = async function ({ email }) { const { DOMAIN: domain } = process.env; const data = { diff --git a/src/utils/transporter.js b/src/utils/transporter.js new file mode 100644 index 0000000..b49466c --- /dev/null +++ b/src/utils/transporter.js @@ -0,0 +1,20 @@ +// src/utils/mailer.js +const nodemailer = require("nodemailer"); +require("dotenv").config(); + +let auth = null; +if (process.env.MAIL_AUTH != "null") { + auth = { + user: process.env.MAIL_USER, + pass: process.env.MAIL_PASS, + }; +} +console.log(process.env.MAIL_PORT); +const transporter = nodemailer.createTransport({ + host: process.env.MAIL_HOST, + port: parseInt(process.env.MAIL_PORT, 10), + secure: process.env.MAIL_SECURE === "true", + auth, +}); + +module.exports = transporter; diff --git a/src/views/pages/home.handlebars b/src/views/pages/home.handlebars index fcf6728..c9bf1ec 100644 --- a/src/views/pages/home.handlebars +++ b/src/views/pages/home.handlebars @@ -1,4 +1,4 @@ - +{{!-- pages/home.handlebars --}}

{{title}}

@@ -7,10 +7,11 @@
- +--}} diff --git a/src/views/pages/newsletter-success.handlebars b/src/views/pages/newsletter-success.handlebars new file mode 100644 index 0000000..02ee8a8 --- /dev/null +++ b/src/views/pages/newsletter-success.handlebars @@ -0,0 +1,6 @@ +{{!-- pages/thankyou.handlebars --}} +
+

Thank You

+
+

You’ve successfully subscribed to my newsletter. Stay tuned for updates.

+
diff --git a/src/views/pages/thankyou.handlebars b/src/views/pages/thankyou.handlebars index 697d946..6976f9f 100644 --- a/src/views/pages/thankyou.handlebars +++ b/src/views/pages/thankyou.handlebars @@ -1,4 +1,4 @@ - +{{!-- pages/thankyou.handlebars --}}

Thank You

diff --git a/yarn.lock b/yarn.lock index 5137829..e686bd9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1480,6 +1480,11 @@ resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz" integrity sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ== +mime-db@~1.25.0: + version "1.25.0" + resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.25.0.tgz" + integrity sha512-5k547tI4Cy+Lddr/hdjNbBEWBwSl8EBc5aSdKvedav8DReADgWJzcYiktaRIw3GtGC1jjwldXtTzvqJZmtvC7w== + mime-types@^3.0.0, mime-types@^3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz" @@ -1487,6 +1492,13 @@ dependencies: mime-db "^1.54.0" +mime-types@2.1.13: + version "2.1.13" + resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.13.tgz" + integrity sha512-ryBDp1Z/6X90UvjUK3RksH0IBPM137T7cmg4OgD5wQBojlAiUwuok0QeELkim/72EtcYuNlmbkrcGuxj3Kl0YQ== + dependencies: + mime-db "~1.25.0" + mimic-response@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz" @@ -2222,6 +2234,14 @@ parseurl "^1.3.3" path-to-regexp "^8.0.0" +rss@^1.2.2: + version "1.2.2" + resolved "https://registry.npmjs.org/rss/-/rss-1.2.2.tgz" + integrity sha512-xUhRTgslHeCBeHAqaWSbOYTydN2f0tAzNXvzh3stjz7QDhQMzdgHf3pfgNIngeytQflrFPfy6axHilTETr6gDg== + dependencies: + mime-types "2.1.13" + xml "1.0.1" + run-series@^1.1.8: version "1.1.9" resolved "https://registry.npmjs.org/run-series/-/run-series-1.1.9.tgz" @@ -2797,6 +2817,11 @@ resolved "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz" integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== +xml@1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz" + integrity sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw== + yallist@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz"