diff --git a/.env.example b/.env.example index 3d705e3..d8c914d 100644 --- a/.env.example +++ b/.env.example @@ -4,6 +4,9 @@ SERVER_PORT=3000 # Link to the Registry Repo for redirect handler for /register TEMPLATE_REGISTRY_REPO_URL=https://github.com/code-server-boilerplates/template-registry +# database for storing hit counters +MONGO_URL=mongodb+srv://localhost:5432/test + # for local dev, set this to false unless needed ENABLE_WEBHOOK_ENDPOINT=false # GitHub API token, since we'll use webhooks for handling replied and stuff diff --git a/.gitpod.yml b/.gitpod.yml new file mode 100644 index 0000000..c18ff4f --- /dev/null +++ b/.gitpod.yml @@ -0,0 +1,9 @@ +image: gitpod/workspace-full + +tasks: + - before: yarn install + command: yarn dev + +vscode: + extensions: + - wakatime.vscode-wakatime@4.0.10:30b7a8787b00b019734875064c013473 diff --git a/.theia/settings.json b/.theia/settings.json new file mode 100644 index 0000000..f26f4e5 --- /dev/null +++ b/.theia/settings.json @@ -0,0 +1,3 @@ +{ + "editor.autoSave": "on" +} diff --git a/README.md b/README.md index 19cfa26..249280f 100644 --- a/README.md +++ b/README.md @@ -11,11 +11,12 @@ hosted on Divio. repo path for specific Code Server template, which the server usually handles it through `if-else` magic (e.g. `/railway/nodejs-yarnified` for Yarnified Node.js) * `/heroku/slug-here` - redirects to , where `username/slug-here` (in URL-decoded form) is the GitHub repo path for specific Code Server template, which the server usually handles it through `if-else` magic (e.g. `/heroku/electron-builder` for building Electron apps like VS Code or Theia) -* `/heartbeat` - use this endpoint to check server status (even there's an endpoint specifically for health checking services, +* `/api/heartbeat` - use this endpoint to check server status (even there's an endpoint specifically for health checking services, there's no way to detect issues in the code through this API endpoint unless you're using an modern IDE like VS Code or Atom or even going to every single endpoint listed above * `/register` - redirects to `process.env.TEMPLATE_REGISTRY_REPO_URL + "/issues/new/choose"` (by default, ) +* `/api/webhookHandler` - Reserved for GitHub webhook handling. Will develop an code handling for tnat soon. ## Development diff --git a/lib/visitsModel.js b/lib/visitsModel.js new file mode 100644 index 0000000..30ba3e8 --- /dev/null +++ b/lib/visitsModel.js @@ -0,0 +1,23 @@ +// source file: https://github.com/ahmad-ali14/siteViews-counter/blob/master/models/visits.js + +const mongoose = require('mongoose'); + +const schemaOptions = { + timestamps: { createdAt: 'created_at', updatedAt: 'updated_at' }, +}; + +const visitSchema = new mongoose.Schema({ + + page:{ + type: String, + required: true + }, + counter:{ + type: Number, + required: true + } +}, schemaOptions); + +const visits = mongoose.model('visits', visitSchema); + +module.exports = visits; diff --git a/nodemon.json b/nodemon.json index b6c8d2d..370ac0d 100644 --- a/nodemon.json +++ b/nodemon.json @@ -1,7 +1,8 @@ { "watch": [ "server.js", - ".env" + ".env", + "lib/**.js" ], - "delay": "10" + "delay": 2 } diff --git a/package.json b/package.json index 1f181c4..a7ee500 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,8 @@ "cz-conventional-changelog": "^3.3.0", "dotenv": "^8.2.0", "express": "^4.17.1", + "mongodb": "^3.6.6", + "mongoose": "^5.12.7", "uuid": "^8.3.2" }, "scripts": { diff --git a/server.js b/server.js index a469bd9..e81897d 100644 --- a/server.js +++ b/server.js @@ -1,7 +1,29 @@ +// core server const express = require("express"); const app = express(); require("dotenv").config(); -const { v4: uuidv4 } = require('uuid'); + +const { v4: uuidv4 } = require("uuid"); + +// database logic +const mongoose = require("mongoose"); +const visits = require("./lib/visitsModel"); + +// function for hit counter stuff +countNewVisit = function (collection, slug) { + visits + .findOneAndUpdate( + { page: slug }, + { $inc: { counter: 1 } }, + { new: true }, + ) + .then((data) => { + console.log("server-log-analytics: " + data); + }) + .catch((err) => { + console.log("server-errors: " + err); + }); +}; const registryRepo = process.env.TEMPLATE_REGISTRY_REPO_URL || @@ -37,21 +59,33 @@ app.post("/api/webhookHandler", (req, res) => { }); app.get("/api/webhookHandler", (req, res) => { - res.status(405).json({ ok: false, description: "Method not supported", code: 405 }) -}) + res + .status(405) + .json({ ok: false, description: "Method not supported", code: 405 }); +}); app.get("/heroku/:boilerplateSlug", (req, res) => { // TODO: better handle hig counting in the future - const ip = req.headers['x-forwarded-for'] || req.socket.remoteAddress; + const ip = req.headers["x-forwarded-for"] || req.socket.remoteAddress; console.log( - "server-log-analytics: Requested slug: " + req.params.boilerplateSlug + " | Request type: heroku.com/deploy | Request ID: " + uuidv4() + " | IP Address: " + ip); + "server-log-analytics: Requested slug: " + + req.params.boilerplateSlug + + " | Request type: heroku.com/deploy | Request ID: " + + uuidv4() + + " | IP Address: " + + ip, + ); + var slugVisitName = "heroku-" + req.params.boilerplateSlug; + countNewVisit(slugVisitName); // if it's example-project, use the starter-pack repo. if (req.params.boilerplateSlug == "example-project") { res.redirect( "https://heroku.com/deploy?template=https://github.com/code-server-boilerplate/starter-pack", ); } else if (req.params.boilerplateSlug == "deploy-code-server-upstream") { - res.redirect("https://heroku.com/deploy?template=https://github.com/cdr/deploy-code-server") + res.redirect( + "https://heroku.com/deploy?template=https://github.com/cdr/deploy-code-server", + ); } else { res.redirect( "https://heroku.com/deploy?template=https://github.com/code-server-boilerplate/" + @@ -62,9 +96,17 @@ app.get("/heroku/:boilerplateSlug", (req, res) => { app.get("/railway/:boilerplateSlug", (req, res) => { // implement better hit counting handler here - const ip = req.headers['x-forwarded-for'] || req.socket.remoteAddress; + const ip = req.headers["x-forwarded-for"] || req.socket.remoteAddress; console.log( - "server-log-analytics: Requested slug: " + req.params.boilerplateSlug + " | Request type: railway.app | Request ID: " + uuidv4() + " | IP Address: " + ip); + "server-log-analytics: Requested slug: " + + req.params.boilerplateSlug + + " | Request type: railway.app | Request ID: " + + uuidv4() + + " | IP Address: " + + ip, + ); + var slugVisitName = "heroku-" + req.params.boilerplateSlug; + countNewVisit(slugVisitName); // if it's example-project, use the starter-pack repo. if (req.params.boilerplateSlug == "example-project") { res.redirect( @@ -101,6 +143,17 @@ app.get("/bootstrapper/:boilerplateSlug", (req, res) => { }); const port = process.env.SERVER_PORT || 8080; -app.listen(port, () => { - console.log(`server-up: Now listening at port ${port}`); -}); +mongoose + .connect(process.env.MONGO_URI, { + useNewUrlParser: true, + useUnifiedTopology: true, + useCreateIndex: true, + useFindAndModify: false, + retryWrites: true, + }) + .then(() => { + console.log(`server-log-analytics: Conncted to MongoDB`); + app.listen(port, () => + console.log(`server-up: Now listening at port ${port}`), + ); + }); diff --git a/yarn.lock b/yarn.lock index 661eb3e..1b98876 100644 --- a/yarn.lock +++ b/yarn.lock @@ -223,6 +223,8 @@ __metadata: cz-conventional-changelog: ^3.3.0 dotenv: ^8.2.0 express: ^4.17.1 + mongodb: ^3.6.6 + mongoose: ^5.12.7 nodemon: ^2.0.7 prettier: ^2.2.1 uuid: ^8.3.2 @@ -252,6 +254,15 @@ __metadata: languageName: node linkType: hard +"@types/bson@npm:*": + version: 4.0.3 + resolution: "@types/bson@npm:4.0.3" + dependencies: + "@types/node": "*" + checksum: 73c0179851f02bd43f010db65c465b09f7c495b35b0e3820a79d36f4bb209c84a512121c1af4c1d2512e5f13cd27cc74fa8aa6f3df9b17b7cca9d37d59ece3ce + languageName: node + linkType: hard + "@types/keyv@npm:^3.1.1": version: 3.1.1 resolution: "@types/keyv@npm:3.1.1" @@ -268,6 +279,16 @@ __metadata: languageName: node linkType: hard +"@types/mongodb@npm:^3.5.27": + version: 3.6.12 + resolution: "@types/mongodb@npm:3.6.12" + dependencies: + "@types/bson": "*" + "@types/node": "*" + checksum: 7e41e42a941a5c07cc45f83722e617f1e96942b27cabae8f06dd253ae86b420c1ca5c75e1de7bfbce787bb703714bc297bef45215ef1275815e8d355e03bc27c + languageName: node + linkType: hard + "@types/node@npm:*": version: 15.0.1 resolution: "@types/node@npm:15.0.1" @@ -547,6 +568,23 @@ __metadata: languageName: node linkType: hard +"bl@npm:^2.2.1": + version: 2.2.1 + resolution: "bl@npm:2.2.1" + dependencies: + readable-stream: ^2.3.5 + safe-buffer: ^5.1.1 + checksum: 438c510aa211ec4398819ad1cb4ef1617b0ffeb0f1946c2b359fc5aefbe6f8e22dc2f6788e8746509779fabee89f1c3b34ec87ff30fb7b3d95654d8cd51e3b70 + languageName: node + linkType: hard + +"bluebird@npm:3.5.1": + version: 3.5.1 + resolution: "bluebird@npm:3.5.1" + checksum: 11347ec6d59fdb2aca5f2507bbc5f7127bf5a7bb978da30f83469ad43a3fa6b533b24544a9b31e21fd730b77b93b0526e65c73d8fdb11b3b633f4269d75e420a + languageName: node + linkType: hard + "body-parser@npm:1.19.0": version: 1.19.0 resolution: "body-parser@npm:1.19.0" @@ -618,6 +656,13 @@ __metadata: languageName: node linkType: hard +"bson@npm:^1.1.4": + version: 1.1.6 + resolution: "bson@npm:1.1.6" + checksum: d9e9e65dd4a980e7b035b71fa946d3c6d80910529b082e5aee731c5c3293d5570958255bd4316724128aa2e58a0dc374272e7e71865e44b7d5354e1d40acd53d + languageName: node + linkType: hard + "bytes@npm:3.1.0": version: 3.1.0 resolution: "bytes@npm:3.1.0" @@ -1128,6 +1173,15 @@ __metadata: languageName: node linkType: hard +"debug@npm:3.1.0": + version: 3.1.0 + resolution: "debug@npm:3.1.0" + dependencies: + ms: 2.0.0 + checksum: 1295acd5e0531761255661d325cd0a80ac8c5f6de8942a53bb23c2197ccb97526972de662ed0e5d9393be83f3428a298a6e7185ecb02f0da6282019cd2ffb4a8 + languageName: node + linkType: hard + "debug@npm:4, debug@npm:^4.1.0": version: 4.3.2 resolution: "debug@npm:4.3.2" @@ -1238,6 +1292,13 @@ __metadata: languageName: node linkType: hard +"denque@npm:^1.4.1": + version: 1.5.0 + resolution: "denque@npm:1.5.0" + checksum: 3564778cda60c7dee3f1d71e397e50e6b39a8c06118aab9843b9396cb621b3191ab56d13de5237b8beee2b87bec485e8239c58ca3133472d2d1eaa3d2d518022 + languageName: node + linkType: hard + "depd@npm:^1.1.2, depd@npm:~1.1.2": version: 1.1.2 resolution: "depd@npm:1.1.2" @@ -2510,6 +2571,13 @@ fsevents@~2.3.1: languageName: node linkType: hard +"kareem@npm:2.3.2": + version: 2.3.2 + resolution: "kareem@npm:2.3.2" + checksum: de7225607b86280e5c39c00d564e1cb4daee9f0a75076fa0c096af75069681ca9a97ea39d8d48ce58ff8dd4d3a738942b1b43101aa95982c4599284ec36e02b4 + languageName: node + linkType: hard + "keyv@npm:^3.0.0": version: 3.1.0 resolution: "keyv@npm:3.1.0" @@ -2698,6 +2766,13 @@ fsevents@~2.3.1: languageName: node linkType: hard +"memory-pager@npm:^1.0.2": + version: 1.5.0 + resolution: "memory-pager@npm:1.5.0" + checksum: 6812af8165a31e729df25af125ba91b7ea7f3cacaf73a1c139b755be640cab9dfa4bb05b9acfc5d5f1f540b334203f26dac0662576033dd351e0a798abc4d72a + languageName: node + linkType: hard + "meow@npm:^8.0.0": version: 8.1.2 resolution: "meow@npm:8.1.2" @@ -2921,6 +2996,85 @@ fsevents@~2.3.1: languageName: node linkType: hard +"mongodb@npm:3.6.6, mongodb@npm:^3.6.6": + version: 3.6.6 + resolution: "mongodb@npm:3.6.6" + dependencies: + bl: ^2.2.1 + bson: ^1.1.4 + denque: ^1.4.1 + optional-require: ^1.0.2 + safe-buffer: ^5.1.2 + saslprep: ^1.0.0 + dependenciesMeta: + saslprep: + optional: true + peerDependenciesMeta: + aws4: + optional: true + bson-ext: + optional: true + kerberos: + optional: true + mongodb-client-encryption: + optional: true + mongodb-extjson: + optional: true + snappy: + optional: true + checksum: 7c711f82269a98fc331e5d52d3ba02167446d7a44c54f0ab26072d708a804c5082e201abae85dcf01154ac73572e4e7f80f32c0b632b72e92e8e65857f553062 + languageName: node + linkType: hard + +"mongoose-legacy-pluralize@npm:1.0.2": + version: 1.0.2 + resolution: "mongoose-legacy-pluralize@npm:1.0.2" + peerDependencies: + mongoose: "*" + checksum: a1f86450b3540a1883cfb093001846806d14cd3a8b80f6681fdac13afcfd4a1f57875fb79009aceacf2e80e3ffd2d5ab7e289ba873c586958ce536eff270dc0a + languageName: node + linkType: hard + +"mongoose@npm:5.12.7, mongoose@npm:^5.12.7": + version: 5.12.7 + resolution: "mongoose@npm:5.12.7" + dependencies: + "@types/mongodb": ^3.5.27 + bson: ^1.1.4 + kareem: 2.3.2 + mongodb: 3.6.6 + mongoose-legacy-pluralize: 1.0.2 + mpath: 0.8.3 + mquery: 3.2.5 + ms: 2.1.2 + regexp-clone: 1.0.0 + safe-buffer: 5.2.1 + sift: 13.5.2 + sliced: 1.0.1 + checksum: 0f9403ac8fc773e29373bb184a291dbbe2162144e0d2ed8a1ad351947943b343bc4214fce528e503298b1663030273332a13b945811fbd46fc988480997162f6 + languageName: node + linkType: hard + +"mpath@npm:0.8.3": + version: 0.8.3 + resolution: "mpath@npm:0.8.3" + checksum: 6c129da222169bcf2eb28ae73abca2a8a32c3c659748efd496308aed21c7dca7a9a923de53a5a1df3d898f5eba74c704fdf352ca68e5ecb602d2352a9d5ab90e + languageName: node + linkType: hard + +"mquery@npm:3.2.5": + version: 3.2.5 + resolution: "mquery@npm:3.2.5" + dependencies: + bluebird: 3.5.1 + debug: 3.1.0 + regexp-clone: ^1.0.0 + safe-buffer: 5.1.2 + sliced: 1.0.1 + checksum: d7d611b3eed531f4ebb4a0d58bd5704712b5b0fb88c058e9ed433bb25f3dda72a5fbbcac8026c9c11a56a8d3983c039abd90d329ff91137f31fdea93ee7ce5d1 + languageName: node + linkType: hard + "ms@npm:2.0.0": version: 2.0.0 resolution: "ms@npm:2.0.0" @@ -3164,6 +3318,13 @@ fsevents@~2.3.1: languageName: node linkType: hard +"optional-require@npm:^1.0.2": + version: 1.0.3 + resolution: "optional-require@npm:1.0.3" + checksum: be8556c35b0f6f76ac3b34587f010ad8fc17f69d1afbd5198fb338c785ebbe8e3c96b5f5222a0853b2c8ab7bfe8127a4f4c795e8795d5656e31c8fd693780ba9 + languageName: node + linkType: hard + "os-tmpdir@npm:~1.0.2": version: 1.0.2 resolution: "os-tmpdir@npm:1.0.2" @@ -3497,7 +3658,7 @@ fsevents@~2.3.1: languageName: node linkType: hard -"readable-stream@npm:^2.0.6": +"readable-stream@npm:^2.0.6, readable-stream@npm:^2.3.5": version: 2.3.7 resolution: "readable-stream@npm:2.3.7" dependencies: @@ -3541,6 +3702,13 @@ fsevents@~2.3.1: languageName: node linkType: hard +"regexp-clone@npm:1.0.0, regexp-clone@npm:^1.0.0": + version: 1.0.0 + resolution: "regexp-clone@npm:1.0.0" + checksum: 0cb16b8806a0a4e3e0f8887c1465d03ff25371fde03d03ab3b2fe7bc521faaabaac36feabcdcdf63bcbce05a7d0eca113eb5b4d3b9a9efc77dc1c0fa87a2811d + languageName: node + linkType: hard + "registry-auth-token@npm:^4.0.0": version: 4.2.1 resolution: "registry-auth-token@npm:4.2.1" @@ -3707,7 +3875,7 @@ fsevents@~2.3.1: languageName: node linkType: hard -"safe-buffer@npm:~5.2.0": +"safe-buffer@npm:5.2.1, safe-buffer@npm:^5.1.1, safe-buffer@npm:^5.1.2, safe-buffer@npm:~5.2.0": version: 5.2.1 resolution: "safe-buffer@npm:5.2.1" checksum: 0bb57f0d8f9d1fa4fe35ad8a2db1f83a027d48f2822d59ede88fd5cd4ddad83c0b497213feb7a70fbf90597a70c5217f735b0eb1850df40ce9b4ae81dd22b3f9 @@ -3730,6 +3898,15 @@ fsevents@~2.3.1: languageName: node linkType: hard +"saslprep@npm:^1.0.0": + version: 1.0.3 + resolution: "saslprep@npm:1.0.3" + dependencies: + sparse-bitfield: ^3.0.3 + checksum: d007f50fe6578814d7b6c06f528cf7b08f1e12292b1c7d671a29a7a709cec29527d85352d1de3e020b3ee30017a9abd58252ff27b5042b889acd4a67b089c38c + languageName: node + linkType: hard + "semver-diff@npm:^3.1.1": version: 3.1.1 resolution: "semver-diff@npm:3.1.1" @@ -3827,6 +4004,13 @@ fsevents@~2.3.1: languageName: node linkType: hard +"sift@npm:13.5.2": + version: 13.5.2 + resolution: "sift@npm:13.5.2" + checksum: 5c005114f85f6bacea5b21265c87b7a366f15eed992b24f6d4468056d241d072309e118795900f5e883c9952692d47ac35f92fcce9cc68c34c9eba9828dd4e1d + languageName: node + linkType: hard + "signal-exit@npm:^3.0.0, signal-exit@npm:^3.0.2": version: 3.0.3 resolution: "signal-exit@npm:3.0.3" @@ -3834,6 +4018,13 @@ fsevents@~2.3.1: languageName: node linkType: hard +"sliced@npm:1.0.1": + version: 1.0.1 + resolution: "sliced@npm:1.0.1" + checksum: af6bd9d9116298828d84a0c4ad417f941c61b72ed16cc289b97ad3669c2c41d13763b79385f3ac44c40a1e82f8c0774d18587b3b7125034fa6f80d10363a234c + languageName: node + linkType: hard + "smart-buffer@npm:^4.1.0": version: 4.1.0 resolution: "smart-buffer@npm:4.1.0" @@ -3925,6 +4116,15 @@ fsevents@~2.3.1: languageName: node linkType: hard +"sparse-bitfield@npm:^3.0.3": + version: 3.0.3 + resolution: "sparse-bitfield@npm:3.0.3" + dependencies: + memory-pager: ^1.0.2 + checksum: 3d7ea483df832df45c1a9b4905b2e2ffb9107b6b43db664ffaf03371000f9ec0db664c8d94600443e344c91be36c52a299ba627f2d15c7f2bcd2c2b7ded6f3b0 + languageName: node + linkType: hard + "spdx-correct@npm:^3.0.0": version: 3.1.1 resolution: "spdx-correct@npm:3.1.1"