diff options
-rw-r--r-- | Dockerfile | 4 | ||||
-rw-r--r-- | docker-compose-test.yaml | 41 | ||||
-rw-r--r-- | docker-compose.yaml | 39 | ||||
-rw-r--r-- | model.js | 62 | ||||
-rw-r--r-- | package-lock.json | 485 | ||||
-rw-r--r-- | package.json | 1 | ||||
-rw-r--r-- | put_in_db.js | 26 | ||||
-rwxr-xr-x | server.js | 144 | ||||
-rw-r--r-- | static/about.html | 12 | ||||
-rw-r--r-- | views/archive.ejs | 4 | ||||
-rw-r--r-- | views/index.ejs | 13 | ||||
-rw-r--r-- | views/rss_feed.pug | 21 | ||||
-rw-r--r-- | views/rss_feed_v2.pug | 22 |
13 files changed, 818 insertions, 56 deletions
@@ -3,7 +3,7 @@ RUN apk add openssl WORKDIR /certs RUN openssl req -nodes -new -x509 -subj="/C=US/ST=Denial/L=springfield/O=Dis/CN=localhost" -keyout server.key -out server.cert -FROM node:lts-alpine3.13 +FROM node:lts-alpine3.15 COPY --from=certbuilder /certs/ /certs COPY ./package.* /server/ RUN cd /server && npm install --production @@ -11,6 +11,6 @@ COPY ./css /server/css/ COPY ./views /server/views/ COPY ./static /server/static/ COPY ./mds /server/mds/ -COPY ./server.js /server/ +COPY ./*.js /server/ ENTRYPOINT ["/server/server.js"] EXPOSE 9000 diff --git a/docker-compose-test.yaml b/docker-compose-test.yaml index 73981ef..fceb9b9 100644 --- a/docker-compose-test.yaml +++ b/docker-compose-test.yaml @@ -1,11 +1,12 @@ version: "3.7" services: - web: - image: web + blog: + image: blog build: - context: ./ + context: . networks: - - webnet + - blognet + - dbnet ports: - "19009:9000" cap_drop: @@ -13,5 +14,35 @@ services: environment: - SERVER_DEPLOYMENT_TYPE=test - SERVER_LISTEN_PORT=9000 + depends_on: + - mongo + secrets: + - mongo_user + - mongo_pass + mongo: + image: mongo:5.0 + networks: + - dbnet + restart: on-failure + ports: + - "127.0.0.1:27117:27017" + - "127.0.0.1:27118:27018" + - "127.0.0.1:27119:27019" + volumes: + - blog-data:/data/db + environment: + - MONGO_INITDB_ROOT_USERNAME_FILE=/run/secrets/mongo_user + - MONGO_INITDB_ROOT_PASSWORD_FILE=/run/secrets/mongo_pass + secrets: + - mongo_user + - mongo_pass networks: - webnet: + blognet: + dbnet: +volumes: + blog-data: +secrets: + mongo_user: + file: ./mongo_secrets/mongo_user + mongo_pass: + file: ./mongo_secrets/mongo_pass diff --git a/docker-compose.yaml b/docker-compose.yaml index 5f3e217..79e5d0c 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,11 +1,12 @@ version: "3.7" services: - web: - image: web + blog: + image: blog build: context: ./ networks: - - webnet + - blognet + - dbnet restart: unless-stopped ports: - "9000:9000" @@ -16,5 +17,35 @@ services: environment: - SERVER_DEPLOYMENT_TYPE=deployment - SERVER_LISTEN_PORT=9000 + depends_on: + - mongo + secrets: + - mongo_user + - mongo_pass + mongo: + image: mongo:5.0 + networks: + - dbnet + restart: on-failure + ports: + - "127.0.0.1:27117:27017" + - "127.0.0.1:27118:27018" + - "127.0.0.1:27119:27019" + volumes: + - blog-data:/data/db + environment: + - MONGO_INITDB_ROOT_USERNAME_FILE=/run/secrets/mongo_user + - MONGO_INITDB_ROOT_PASSWORD_FILE=/run/secrets/mongo_pass + secrets: + - mongo_user + - mongo_pass networks: - webnet: + blognet: + dbnet: +volumes: + blog-data: +secrets: + mongo_user: + file: ./mongo_secrets/mongo_user + mongo_pass: + file: ./mongo_secrets/mongo_pass diff --git a/model.js b/model.js new file mode 100644 index 0000000..dde3913 --- /dev/null +++ b/model.js @@ -0,0 +1,62 @@ +"use strict"; + +const fs = require("fs"); +const path = require("path"); +const mongoose = require("mongoose"); +const Schema = mongoose.Schema; +mongoose.Promise = global.Promise; +const db = {}; +db.mongoose = mongoose; +const db_pass = fs.readFileSync("/run/secrets/mongo_pass").toString(); +const db_user = fs.readFileSync("/run/secrets/mongo_user").toString(); +db.url = "mongodb://" + db_user + ":" + db_pass + "@mongo:27017"; + +const BlogPostSchema = new Schema({ + title: { type: String, required: true, trim: true }, + slug: { type: String, required: true, lowercase: true, trim: true }, + body: { type: String, required: true }, + teaser: { type: String, required: true }, + keywords: { type: Array, required: true }, + lastUpdatedAt: { type: Number }, +}); + +// a simple hook to update the timestamp(lastUpdatedAt) on update +BlogPostSchema.pre("save", function (next) { + this.lastUpdatedAt = Date.now(); + next(); +}); + +function dbInit() { + db.mongoose + .connect(db.url, { useNewUrlParser: true, useUnifiedTopology: true }) + .then(() => { + console.log("successfully connected to db"); + }) + .catch((err) => { + console.log("cannot connect to the database: ", err); + process.exit(1); + }); +} + +function populateDB(model) { + let filePaths = fs.readdirSync(path.join(__dirname, "mds")); + filePaths.forEach((fileName) => { + let fileContent = fs + .readFileSync(path.join(__dirname, "mds", fileName), "utf-8") + .toString(); + let newBlogPost = new model({ + title: fileName, + slug: fileName, + body: fileContent, + teaser: fileName, + keywords: ["kw1", "kw2"], + }); + newBlogPost.save(); + }); +} + +module.exports = { + blogPost: mongoose.model("BlogPost", BlogPostSchema), + dbInit: dbInit, + populateDB: populateDB, +}; diff --git a/package-lock.json b/package-lock.json index c111ea8..aa9d629 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,7 @@ "markdown-it-highlightjs": "^3.4.0", "markdown-it-multimd-table": "^4.0.2", "markdown-it-texmath": "^0.7.0", + "mongoose": "^6.2.8", "morgan": "^1.10.0", "pug": "^3.0.2", "spdy": "^4.0.2" @@ -176,6 +177,25 @@ "node": ">= 6" } }, + "node_modules/@types/node": { + "version": "17.0.23", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.23.tgz", + "integrity": "sha512-UxDxWn7dl97rKVeVS61vErvw086aCYhDLyvRQZ5Rk65rZKepaFdm53GeqXaKBuOhED4e9uWq34IC3TdSdJJ2Gw==" + }, + "node_modules/@types/webidl-conversions": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-6.1.1.tgz", + "integrity": "sha512-XAahCdThVuCFDQLT7R7Pk/vqeObFNL3YqRyFZg+AqAP/W1/w3xHaIxuW7WszQqTbIBOPRcItYJIou3i/mppu3Q==" + }, + "node_modules/@types/whatwg-url": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.1.tgz", + "integrity": "sha512-2YubE1sjj5ifxievI5Ge1sckb9k/Er66HyR2c+3+I6VDUUg1TLPdYYTEbQ+DjRkS4nTxMJhgWfSfMRD2sl2EYQ==", + "dependencies": { + "@types/node": "*", + "@types/webidl-conversions": "*" + } + }, "node_modules/abab": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", @@ -376,6 +396,25 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/basic-auth": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", @@ -421,6 +460,40 @@ "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==" }, + "node_modules/bson": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/bson/-/bson-4.6.2.tgz", + "integrity": "sha512-VeJKHShcu1b/ugl0QiujlVuBepab714X9nNyBdA1kfekuDGecxgpTA2Z6nYbagrWFeiIyzSWIOzju3lhj+RNyQ==", + "dependencies": { + "buffer": "^5.6.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "node_modules/bytes": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", @@ -625,6 +698,14 @@ "node": ">=0.4.0" } }, + "node_modules/denque": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.0.1.tgz", + "integrity": "sha512-tfiWc6BQLXNLpNiR5iGd0Ocu3P3VpxfzFiqubLgMfhfOw9WyvgJBd46CClNn9k3qfbjvT//0cf7AlYRX/OslMQ==", + "engines": { + "node": ">=0.10" + } + }, "node_modules/depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", @@ -1579,6 +1660,25 @@ "node": ">=0.10.0" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", @@ -1628,6 +1728,11 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, + "node_modules/ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" + }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -1840,6 +1945,11 @@ "promise": "^7.0.1" } }, + "node_modules/kareem": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.4.tgz", + "integrity": "sha512-Vcrt8lcpVl0s8ePx634BxwRqmFo+5DcOhlmNadehxreMTIQi/9hOL/B3hZQQbK5DgMS7Lem3xABXV7/S3jy+7g==" + }, "node_modules/katex": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/katex/-/katex-0.11.1.tgz", @@ -1987,6 +2097,12 @@ "url": "https://github.com/sindresorhus/mem?sponsor=1" } }, + "node_modules/memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", + "optional": true + }, "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -2054,6 +2170,89 @@ "node": "*" } }, + "node_modules/mongodb": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.3.1.tgz", + "integrity": "sha512-sNa8APSIk+r4x31ZwctKjuPSaeKuvUeNb/fu/3B6dRM02HpEgig7hTHM8A/PJQTlxuC/KFWlDlQjhsk/S43tBg==", + "dependencies": { + "bson": "^4.6.1", + "denque": "^2.0.1", + "mongodb-connection-string-url": "^2.4.1", + "socks": "^2.6.1" + }, + "engines": { + "node": ">=12.9.0" + }, + "optionalDependencies": { + "saslprep": "^1.0.3" + } + }, + "node_modules/mongodb-connection-string-url": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.5.2.tgz", + "integrity": "sha512-tWDyIG8cQlI5k3skB6ywaEA5F9f5OntrKKsT/Lteub2zgwSUlhqEN2inGgBTm8bpYJf8QYBdA/5naz65XDpczA==", + "dependencies": { + "@types/whatwg-url": "^8.2.1", + "whatwg-url": "^11.0.0" + } + }, + "node_modules/mongodb-connection-string-url/node_modules/tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/mongodb-connection-string-url/node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "engines": { + "node": ">=12" + } + }, + "node_modules/mongodb-connection-string-url/node_modules/whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "dependencies": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/mongoose": { + "version": "6.2.8", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-6.2.8.tgz", + "integrity": "sha512-Wq6HG0sOJEQHp5YqMlxrnf93vBFwdY2zlAwqI97EPPSt69kiVV21pTv4cDanrCNWi4upG8ajQ/p9jpDjcECjkQ==", + "dependencies": { + "bson": "^4.2.2", + "kareem": "2.3.4", + "mongodb": "4.3.1", + "mpath": "0.8.4", + "mquery": "4.0.2", + "ms": "2.1.3", + "sift": "16.0.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mongoose" + } + }, + "node_modules/mongoose/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, "node_modules/morgan": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", @@ -2077,6 +2276,46 @@ "node": ">= 0.8" } }, + "node_modules/mpath": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.8.4.tgz", + "integrity": "sha512-DTxNZomBcTWlrMW76jy1wvV37X/cNNxPW1y2Jzd4DZkAaC5ZGsm8bfGfNOthcDuRJujXLqiuS6o3Tpy0JEoh7g==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mquery": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/mquery/-/mquery-4.0.2.tgz", + "integrity": "sha512-oAVF0Nil1mT3rxty6Zln4YiD6x6QsUWYz927jZzjMxOK2aqmhEz5JQ7xmrKK7xRFA2dwV+YaOpKU/S+vfNqKxA==", + "dependencies": { + "debug": "4.x" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/mquery/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/mquery/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, "node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -2515,6 +2754,18 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "node_modules/saslprep": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz", + "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==", + "optional": true, + "dependencies": { + "sparse-bitfield": "^3.0.3" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/saxes": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", @@ -2622,6 +2873,11 @@ "node": ">=8" } }, + "node_modules/sift": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/sift/-/sift-16.0.0.tgz", + "integrity": "sha512-ILTjdP2Mv9V1kIxWMXeMTIRbOBrqKc4JAXmFMnFq3fKeyQ2Qwa3Dw1ubcye3vR+Y6ofA0b9gNDr/y2t6eUeIzQ==" + }, "node_modules/slice-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", @@ -2672,6 +2928,28 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.2.tgz", + "integrity": "sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA==", + "dependencies": { + "ip": "^1.1.5", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -2681,6 +2959,15 @@ "node": ">=0.10.0" } }, + "node_modules/sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=", + "optional": true, + "dependencies": { + "memory-pager": "^1.0.2" + } + }, "node_modules/spdy": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", @@ -3297,6 +3584,25 @@ "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==" }, + "@types/node": { + "version": "17.0.23", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.23.tgz", + "integrity": "sha512-UxDxWn7dl97rKVeVS61vErvw086aCYhDLyvRQZ5Rk65rZKepaFdm53GeqXaKBuOhED4e9uWq34IC3TdSdJJ2Gw==" + }, + "@types/webidl-conversions": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-6.1.1.tgz", + "integrity": "sha512-XAahCdThVuCFDQLT7R7Pk/vqeObFNL3YqRyFZg+AqAP/W1/w3xHaIxuW7WszQqTbIBOPRcItYJIou3i/mppu3Q==" + }, + "@types/whatwg-url": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.1.tgz", + "integrity": "sha512-2YubE1sjj5ifxievI5Ge1sckb9k/Er66HyR2c+3+I6VDUUg1TLPdYYTEbQ+DjRkS4nTxMJhgWfSfMRD2sl2EYQ==", + "requires": { + "@types/node": "*", + "@types/webidl-conversions": "*" + } + }, "abab": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", @@ -3451,6 +3757,11 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, "basic-auth": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", @@ -3490,6 +3801,23 @@ "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==" }, + "bson": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/bson/-/bson-4.6.2.tgz", + "integrity": "sha512-VeJKHShcu1b/ugl0QiujlVuBepab714X9nNyBdA1kfekuDGecxgpTA2Z6nYbagrWFeiIyzSWIOzju3lhj+RNyQ==", + "requires": { + "buffer": "^5.6.0" + } + }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "bytes": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", @@ -3660,6 +3988,11 @@ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, + "denque": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.0.1.tgz", + "integrity": "sha512-tfiWc6BQLXNLpNiR5iGd0Ocu3P3VpxfzFiqubLgMfhfOw9WyvgJBd46CClNn9k3qfbjvT//0cf7AlYRX/OslMQ==" + }, "depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", @@ -4375,6 +4708,11 @@ "safer-buffer": ">= 2.1.2 < 3" } }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, "ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", @@ -4412,6 +4750,11 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, + "ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" + }, "ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -4579,6 +4922,11 @@ "promise": "^7.0.1" } }, + "kareem": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.4.tgz", + "integrity": "sha512-Vcrt8lcpVl0s8ePx634BxwRqmFo+5DcOhlmNadehxreMTIQi/9hOL/B3hZQQbK5DgMS7Lem3xABXV7/S3jy+7g==" + }, "katex": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/katex/-/katex-0.11.1.tgz", @@ -4702,6 +5050,12 @@ "mimic-fn": "^3.0.0" } }, + "memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", + "optional": true + }, "merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -4748,6 +5102,72 @@ "brace-expansion": "^1.1.7" } }, + "mongodb": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.3.1.tgz", + "integrity": "sha512-sNa8APSIk+r4x31ZwctKjuPSaeKuvUeNb/fu/3B6dRM02HpEgig7hTHM8A/PJQTlxuC/KFWlDlQjhsk/S43tBg==", + "requires": { + "bson": "^4.6.1", + "denque": "^2.0.1", + "mongodb-connection-string-url": "^2.4.1", + "saslprep": "^1.0.3", + "socks": "^2.6.1" + } + }, + "mongodb-connection-string-url": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.5.2.tgz", + "integrity": "sha512-tWDyIG8cQlI5k3skB6ywaEA5F9f5OntrKKsT/Lteub2zgwSUlhqEN2inGgBTm8bpYJf8QYBdA/5naz65XDpczA==", + "requires": { + "@types/whatwg-url": "^8.2.1", + "whatwg-url": "^11.0.0" + }, + "dependencies": { + "tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "requires": { + "punycode": "^2.1.1" + } + }, + "webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==" + }, + "whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "requires": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + } + } + } + }, + "mongoose": { + "version": "6.2.8", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-6.2.8.tgz", + "integrity": "sha512-Wq6HG0sOJEQHp5YqMlxrnf93vBFwdY2zlAwqI97EPPSt69kiVV21pTv4cDanrCNWi4upG8ajQ/p9jpDjcECjkQ==", + "requires": { + "bson": "^4.2.2", + "kareem": "2.3.4", + "mongodb": "4.3.1", + "mpath": "0.8.4", + "mquery": "4.0.2", + "ms": "2.1.3", + "sift": "16.0.0" + }, + "dependencies": { + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, "morgan": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", @@ -4767,6 +5187,34 @@ } } }, + "mpath": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.8.4.tgz", + "integrity": "sha512-DTxNZomBcTWlrMW76jy1wvV37X/cNNxPW1y2Jzd4DZkAaC5ZGsm8bfGfNOthcDuRJujXLqiuS6o3Tpy0JEoh7g==" + }, + "mquery": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/mquery/-/mquery-4.0.2.tgz", + "integrity": "sha512-oAVF0Nil1mT3rxty6Zln4YiD6x6QsUWYz927jZzjMxOK2aqmhEz5JQ7xmrKK7xRFA2dwV+YaOpKU/S+vfNqKxA==", + "requires": { + "debug": "4.x" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -5121,6 +5569,15 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "saslprep": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz", + "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==", + "optional": true, + "requires": { + "sparse-bitfield": "^3.0.3" + } + }, "saxes": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", @@ -5206,6 +5663,11 @@ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, + "sift": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/sift/-/sift-16.0.0.tgz", + "integrity": "sha512-ILTjdP2Mv9V1kIxWMXeMTIRbOBrqKc4JAXmFMnFq3fKeyQ2Qwa3Dw1ubcye3vR+Y6ofA0b9gNDr/y2t6eUeIzQ==" + }, "slice-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", @@ -5243,12 +5705,35 @@ } } }, + "smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==" + }, + "socks": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.2.tgz", + "integrity": "sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA==", + "requires": { + "ip": "^1.1.5", + "smart-buffer": "^4.2.0" + } + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "optional": true }, + "sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=", + "optional": true, + "requires": { + "memory-pager": "^1.0.2" + } + }, "spdy": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", diff --git a/package.json b/package.json index e7d7a5e..bef37be 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "markdown-it-highlightjs": "^3.4.0", "markdown-it-multimd-table": "^4.0.2", "markdown-it-texmath": "^0.7.0", + "mongoose": "^6.2.8", "morgan": "^1.10.0", "pug": "^3.0.2", "spdy": "^4.0.2" diff --git a/put_in_db.js b/put_in_db.js new file mode 100644 index 0000000..da5a050 --- /dev/null +++ b/put_in_db.js @@ -0,0 +1,26 @@ +"use strict"; +// mongosh --host 127.0.0.1 --port 27117 -u mongo -p mongo -f put_in_db.js + +const fs = require("fs"); +const path = require("path"); +// db = connect("http://mongo:mongo@127.0.0.1:27117"); + +blog_entry_1 = { + title: "Turning C structs into Lua tables", + slug: "c_struct_lua_table", + body: fs.readFileSync(path.join(__dirname) + "/mds/cstruct2luatable.md"), + teaser: "Turning C structures into Lua tables", + keywords: "c,lua", + lastUpdatedAt: Date.now(), +}; + +blog_entry_2 = { + title: "Lazy Makefiles", + slug: "lazy_makefile", + body: fs.readFileSync(path.join(__dirname) + "/mds/lazymakefiles.md"), + teaser: "Lazy Makefiles", + keywords: "makefile,c,c++", + lastUpdatedAt: Date.now(), +}; + +db.blogposts.insertMany([blog_entry_1, blog_entry_2]); @@ -22,42 +22,80 @@ const mit = require("markdown-it")({ html: true }) const spdy = require("spdy"); const helmet = require("helmet"); const morgan = require("morgan"); -const pug = require("pug"); +const model = require("./model"); + +model.dbInit(); const app = express(); +app.disable("x-powered-by"); app.use(express.static(path.join(__dirname, "css"))); app.use(express.static(path.join(__dirname, "static"))); app.set("views", path.join(__dirname, "views")); app.set("view engine", "ejs"); -app.engine("ejs", require("ejs").__express); -app.use(helmet()); +app.set("view engine", "pug"); + +app.use(helmet.crossOriginEmbedderPolicy()); +app.use(helmet.crossOriginOpenerPolicy()); +app.use(helmet.crossOriginResourcePolicy()); +app.use(helmet.dnsPrefetchControl()); +app.use(helmet.expectCt()); +app.use(helmet.frameguard()); +app.use(helmet.hidePoweredBy()); +app.use(helmet.hsts()); +app.use(helmet.ieNoOpen()); +app.use(helmet.noSniff()); +app.use(helmet.originAgentCluster()); +app.use(helmet.permittedCrossDomainPolicies()); +app.use(helmet.referrerPolicy()); +app.use(helmet.xssFilter()); +app.use((req, res, next) => { + res.setHeader( + "Permissions-Policy", + "geolocation=(self),midi=(self),sync-xhr=(self),microphone=(self),camera=(self),magnetometer=(self),gyroscope=(self),fullscreen=(self),payment=(self),usb=(self)" + ); + next(); +}); +app.use( + helmet.contentSecurityPolicy({ + useDefaults: false, + directives: { + baseUri: ["self"], + defaultSrc: ["self"], + scriptSrc: ["none"], + styleSrc: ["self", "https:", "unsafef-inline"], + }, + }) +); + app.use(morgan("combined")); -function renderAndSend(req, res) { - try { - let viewPath; - if (req.path == "/") { - viewPath = "mds/cstruct2luatable.md"; - } else { - viewPath = req.path; - } - let readStream = fs.createReadStream( - path.join(__dirname, viewPath), - "utf-8" - ); - //FIXME-this can obviously fail - readStream.on("data", (chunk) => { - res.render("index", { +async function enumerateDir() { + return await fs.readdirSync(path.join(__dirname, "mds")); +} + +function renderAndSend_v2(req, res, slug) { + model.blogPost + .findOne( + { slug: slug }, + { + projection: { + _id: 0, + title: 0, + teaser: 0, + }, + } + ) + .exec(function (err, blogPost) { + if (err) return err; + return res.render("index.ejs", { cache: true, data: { - blogHttp: mit.render(chunk), - mds: fs.readdirSync(path.join(__dirname, "mds"), "utf-8"), + blogHttp: mit.render(blogPost.body), + lastUpdatedAt: blogPost.lastUpdatedAt, + keywords: blogPost.keywords, }, }); }); - } catch (err) { - console.log(err); - } } app.get("/health", (req, res) => { @@ -73,12 +111,17 @@ app.get("/about", (req, res) => { app.get("/archive", (req, res) => { res.type("text/html"); - res.render("archive", { - cache: true, - data: { - mds: fs.readdirSync(path.join(__dirname, "mds"), "utf-8"), - }, - }); + model.blogPost + .find({}, { _id: 0, body: 0, teaser: 0, keywords: 0, lastUpdatedAt: 0 }) + .exec(function (err, blogPosts) { + if (err) return err; + res.render("archive.ejs", { + cache: true, + data: { + blogPosts: blogPosts, + }, + }); + }); }); app.get("/robots.txt", (req, res) => { @@ -90,25 +133,42 @@ app.get("/robots.txt", (req, res) => { res.send(robots_txt); }); -// app.get("/rss/feed", (req, res) => { -// let html = pug.renderFile("./views/rss_feed.pug", merge(options, localls)); -// res.send(html); -// }); - -app.get("/$", (req, res) => { - renderAndSend(req, res); +app.get("/rss/feed", (req, res) => { + res.type("application/rss+xml"); + model.blogPost + .find({}) + .sort("-lastUpdatedAt") + .select("title slug lastUpdatedAt teaser") + .exec(function (err, posts) { + if (err) return err; + return res.render("rss_feed_v2.pug", { cache: true, posts: posts }); + }); }); -app.get("/mds/:mdname$", (req, res) => { - if (req.params["mdname"] == "") { +app.get("/posts/:postName", (req, res) => { + if (req.params["postName"] == "") { res.write("nothing requested!"); } - renderAndSend(req, res); + renderAndSend_v2(req, res, req.params.postName); }); -async function enumerateDir() { - return await fs.readdirSync(path.join(__dirname, "mds")); -} +app.get("/$", (req, res) => { + model.blogPost + .find({}, { projection: { _id: 0, title: 0, teaser: 0 } }) + .limit(1) + .sort({ $natural: -1 }) + .exec(function (err, blogPost) { + if (err) return err; + return res.render("index.ejs", { + cache: true, + data: { + blogHttp: mit.render(blogPost[0].body), + lastUpdatedAt: blogPost[0].lastUpdatedAt, + keywords: blogPost[0].keywords, + }, + }); + }); +}); app.use(sitemap(enumerateDir, "https://blog.terminaldweller.com")); diff --git a/static/about.html b/static/about.html index ad9ed10..a56ad24 100644 --- a/static/about.html +++ b/static/about.html @@ -18,6 +18,18 @@ <p> You can find my github <a href="https://github.com/terminaldweller">here</a> + . </p> + <p> + Also if the blog is broken please make a new issue + <a href="https://github.com/terminaldweller/web">here</a> + . + </p> + <br /> + <br /> + <hr /> + <br /> + <a href="/" class="left-footer">Home</a> + <br /> </body> </html> diff --git a/views/archive.ejs b/views/archive.ejs index 36191de..72b963d 100644 --- a/views/archive.ejs +++ b/views/archive.ejs @@ -9,9 +9,9 @@ <body> <script>0</script> <div class="article"> - <% data.mds.forEach(function(md) { %> + <% data.blogPosts.forEach(function(blogPost) { %> <ul> - <li><a href=<%= "/mds/"+md %> target="_self" rel="noreferrer noopener" type="text/html"><%= md %></a></li> + <li><a href=<%= "/posts/"+blogPost.slug %> target="_self" rel="noreferrer noopener" type="text/html"><%= blogPost.title %></a></li> </ul> <% }) %> </div> diff --git a/views/index.ejs b/views/index.ejs index 4679e4a..fdd49cc 100644 --- a/views/index.ejs +++ b/views/index.ejs @@ -5,16 +5,27 @@ <meta name="viewport" content="width=device-width"> <title>Blog</title> <link rel="stylesheet" href="/master.css" type="text/css" media="screen" title="no title" charset="utf-8"> + <link rel="alternate" type="application/rss+xml" title="RSS" href="/rss/feed"> + <!-- <link rel="alternate" type="application/atom+xml" title="RSS" href="/feed/rss"> --> </head> <body> - <script>0</script> + <!-- <script>0</script> --> <div class="article"> <%- data.blogHttp %> <br/> <hr/> <br/> + <a class="left-footer">Keywords:</a> + <%- data.keywords %> + <%- data.lastUpdated %> + <br/> + <br/> + <hr/> + <br/> <a href="/archive" class="left-footer">Archive</a> <a href="/about" class="right-footer">About</a> + <a class="right-footer">   </a> + <a href="/rss/feed" class="right-footer">RSS</a> </div> </body> </html> diff --git a/views/rss_feed.pug b/views/rss_feed.pug new file mode 100644 index 0000000..e75225d --- /dev/null +++ b/views/rss_feed.pug @@ -0,0 +1,21 @@ +doctype xml +rss(version='2.0', xmlns:atom='<a href="http://www.w3.org/2005/Atom" rel="nofollow">http://www.w3.org/2005/Atom</a>') + channel + title deviblog + link <a href="https://blog.terminaldweller.com" rel="nofollow">https://blog.terminaldweller.com</a> + atom:link(href='<a href="https://blog.terminaldweller.com/feed/rss" rel="nofollow">https://blog.terminaldweller.com/feed/rss</a>', rel='self', type='application/rss+xml') + description I talk about software here. + language en-US + if posts.length + lastBuildDate= new Date(posts[0].lastUpdatedAt).toUTCString() + each post in posts + item + title= post.title + link <a href="https://blog.terminaldweller.com/blog/#{post.slug}" rel="nofollow">https://terminaldweller.com/blog/#{post.slug}</a> + description + | <![CDATA[ + | !{post.teaser} + p: a(href='<a href="https://blog.terminaldweller.com/blog/#{post.slug} rel="nofollow">https://blog.terminaldweller.com/blog/#{post.slug}</a>') 'Read more »' + | ]]> + pubDate= new Date(post.lastUpdatedAt).toUTCString() + guid(isPermaLink='false') <a href="https://blog.terminaldweller.com/blog/#{post.slug}" rel="nofollow">https://blog.terminaldweller.com/blog/#{post.slug}</a> diff --git a/views/rss_feed_v2.pug b/views/rss_feed_v2.pug new file mode 100644 index 0000000..d04297d --- /dev/null +++ b/views/rss_feed_v2.pug @@ -0,0 +1,22 @@ +doctype xml +rss(version='2.0', xmlns:atom='http://www.w3.org/2005/Atom') + channel + title deviblog + link https://blog.terminaldweller.com + atom:link(href='https://blog.terminaldweller.com/rss/feed', rel='self', type='application/rss+xml') + description I talk about software here. + managingEditor devi@terminaldweller.com (Farzad Sadeghi) + webMaster devi@terminaldweller.com (Farzad Sadeghi) + language en-US + if posts.length + lastBuildDate= new Date(posts[0].lastUpdatedAt).toUTCString() + each post in posts + item + title= post.title + link https://blog.terminaldweller.com/posts/#{post.slug} + description + | <![CDATA[ + | #{post.teaser} + | ]]> + pubDate= new Date(post.lastUpdatedAt).toUTCString() + guid(isPermaLink='false') https://blog.terminaldweller.com/blog/#{post.slug} |