From b7de4d96141eb761fa3f06bcb1323d94defd19b8 Mon Sep 17 00:00:00 2001 From: Jo <johannesreckers2006@gmail.com> Date: Tue, 9 Jan 2024 08:28:18 +0100 Subject: [PATCH 1/4] feat: new DatabaseInstance class for universal database management, W.I.P --- Dockerfile | 7 ++-- Structures/Classes/DatabaseInstance.js | 49 +++++++++++++++++++++++++ app.js | 18 ++++----- bun.lockb | Bin 0 -> 81566 bytes entrypoint.sh | 2 +- 5 files changed, 61 insertions(+), 15 deletions(-) create mode 100644 Structures/Classes/DatabaseInstance.js create mode 100755 bun.lockb diff --git a/Dockerfile b/Dockerfile index 8496da5..8bd562b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:21 +FROM oven/bun:latest # Install netcat RUN apt-get update && apt-get install -y netcat-traditional @@ -6,9 +6,10 @@ RUN apt-get update && apt-get install -y netcat-traditional WORKDIR /usr/src/app # Copy package.json and package-lock.json to the working directory -COPY package*.json ./ +COPY package.json ./ +copy bun.lockb ./ -RUN npm install +RUN bun install COPY . . diff --git a/Structures/Classes/DatabaseInstance.js b/Structures/Classes/DatabaseInstance.js new file mode 100644 index 0000000..313e2e2 --- /dev/null +++ b/Structures/Classes/DatabaseInstance.js @@ -0,0 +1,49 @@ +const mysql = require("mysql2"); +const { readdir } = require("fs"); +const path = require("path"); + +/** + * Universal database instance to be used for any database operations + */ +class DatabaseInstance { + /** + * Construct the DatabaseInstance using the database credentials + * + * @param {Object} credentials The database credentils in a standard mysql format + */ + constructor(credentials) { + this.pool = mysql.createPool({ + database: credentials.database, + user: credentials.user, + password: credentials.password, + host: credentials.host, + port: credentials.port, + enableKeepAlive: true, + waitForConnections: true, + connectionLimit: 10 + }); + + console.log("[JET » DatabaseInstance] Successfully initialized database connection") + + this.pool.on("connection", (err) => { + if (err) console.log("[JET » DatabaseInstance] Error occurred during connection"); + else console.log("[JET » DatabaseInstance » client] Successfully created new connection"); + }); + } + + /** + * + * @param {String} query + * @param {Array} values + * @returns + */ + async execute(query, values, callback) { + this.pool.execute(query, values, callback); + } + + async query(query, callback) { + this.pool.query(query, callback); + } +} + +module.exports = { DatabaseInstance }; \ No newline at end of file diff --git a/app.js b/app.js index f76d2f7..792469f 100644 --- a/app.js +++ b/app.js @@ -12,12 +12,17 @@ // Imports //------------------------------------------------> +// Packages const express = require("express"); const bodyParser = require("body-parser"); const cookieParser = require("cookie-parser"); const mysql = require("mysql2"); const path = require("path"); +// Classes +const { DatabaseInstance } = require("./Structures/Classes/DatabaseInstance"); + +// Load environment variables when not using docker if (!process.env.DOCKER) { const dotenv = require("dotenv"); dotenv.config(); @@ -43,11 +48,10 @@ app.use(bodyParser.urlencoded({ extended: false })); app.use(cookieParser()); //------------------------------------------------> -// MySQL connection +// Initialize database //------------------------------------------------> -//! Make extra sure these values are loaded correctly, if you experience any connection issues. -const db = mysql.createConnection({ +const db = new DatabaseInstance({ database: process.env.DB_NAME, user: process.env.DB_USER, password: process.env.DB_PASSWORD, @@ -55,14 +59,6 @@ const db = mysql.createConnection({ port: process.env.DB_PORT }); -db.connect((error) => { - if (error) { - console.error("[JET] Error connecting to MySQL database:", error); - } else { - console.log("[JET] Database connected successfully"); - } -}); - //------------------------------------------------> // Routing //------------------------------------------------> diff --git a/bun.lockb b/bun.lockb new file mode 100755 index 0000000000000000000000000000000000000000..5575077defdcdc9fc64923d102aa0036485215d1 GIT binary patch literal 81566 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 JnEwy{`9BUC1&jay literal 0 HcmV?d00001 diff --git a/entrypoint.sh b/entrypoint.sh index 2f46014..2b76ede 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -14,4 +14,4 @@ check_database() { check_database # Start the Express app -exec npm run start +exec bun run start From a86bddf352cb91f4dcc59194a5356ff32465332c Mon Sep 17 00:00:00 2001 From: Jo <johannesreckers2006@gmail.com> Date: Wed, 10 Jan 2024 17:23:14 +0100 Subject: [PATCH 2/4] feat: add Model and Controller class, improve structure --- Structures/Classes/Controller.js | 25 ++++++++++ Structures/Classes/DatabaseInstance.js | 49 ------------------- Structures/Classes/Model.js | 38 ++++++++++++++ app.js | 26 +++++----- .../{placeholder => indexController.js} | 0 .../userController.js | 0 docker-compose.yml | 12 ++--- model/userModel.js | 19 +++++++ public/placeholder | 0 routes/indexRoutes.js | 8 +++ 10 files changed, 107 insertions(+), 70 deletions(-) create mode 100644 Structures/Classes/Controller.js delete mode 100644 Structures/Classes/DatabaseInstance.js create mode 100644 Structures/Classes/Model.js rename controller/{placeholder => indexController.js} (100%) rename model/placeholder => controller/userController.js (100%) create mode 100644 model/userModel.js delete mode 100644 public/placeholder create mode 100644 routes/indexRoutes.js diff --git a/Structures/Classes/Controller.js b/Structures/Classes/Controller.js new file mode 100644 index 0000000..e9ca7c6 --- /dev/null +++ b/Structures/Classes/Controller.js @@ -0,0 +1,25 @@ +//------------------------------------------------> +// Imports +//------------------------------------------------> + +// None + +//------------------------------------------------> +// Controller class +//------------------------------------------------> + +class Controller { + /** + * Construct the basis of our Controller + */ + constructor() { + this.global = { + pageData: { + name: "The Void", + links: [] + } + } + } +} + +module.exports = { Controller } \ No newline at end of file diff --git a/Structures/Classes/DatabaseInstance.js b/Structures/Classes/DatabaseInstance.js deleted file mode 100644 index 313e2e2..0000000 --- a/Structures/Classes/DatabaseInstance.js +++ /dev/null @@ -1,49 +0,0 @@ -const mysql = require("mysql2"); -const { readdir } = require("fs"); -const path = require("path"); - -/** - * Universal database instance to be used for any database operations - */ -class DatabaseInstance { - /** - * Construct the DatabaseInstance using the database credentials - * - * @param {Object} credentials The database credentils in a standard mysql format - */ - constructor(credentials) { - this.pool = mysql.createPool({ - database: credentials.database, - user: credentials.user, - password: credentials.password, - host: credentials.host, - port: credentials.port, - enableKeepAlive: true, - waitForConnections: true, - connectionLimit: 10 - }); - - console.log("[JET » DatabaseInstance] Successfully initialized database connection") - - this.pool.on("connection", (err) => { - if (err) console.log("[JET » DatabaseInstance] Error occurred during connection"); - else console.log("[JET » DatabaseInstance » client] Successfully created new connection"); - }); - } - - /** - * - * @param {String} query - * @param {Array} values - * @returns - */ - async execute(query, values, callback) { - this.pool.execute(query, values, callback); - } - - async query(query, callback) { - this.pool.query(query, callback); - } -} - -module.exports = { DatabaseInstance }; \ No newline at end of file diff --git a/Structures/Classes/Model.js b/Structures/Classes/Model.js new file mode 100644 index 0000000..fb4c2e0 --- /dev/null +++ b/Structures/Classes/Model.js @@ -0,0 +1,38 @@ +//------------------------------------------------> +// Imports +//------------------------------------------------> + +// Packages +const mysql = require("mysql2"); + +// Config +const { databaseCredentials } = require("../Config/databaseCredentials"); + +//------------------------------------------------> +// Model class +//------------------------------------------------> + +class Model { + /** + * Construct the Model using the database credentials + * + * @param {Object} credentials The database credentials in a standard mysql format + */ + constructor() { + this.pool = mysql.createPool(databaseCredentials); + + this.pool.getConnection(async (err) => { + if (err) console.log(`[JET » Model] Error occurred during connection: ${err}`); + else console.log("[JET » Model » pool] Successfully initialized pool"); + }); + + this.pool.on("connection", async () => { + console.log("[JET » Model » pool] Created new connection"); + }); + + if (!this.initialize) throw new Error("[JET » Model] initialize method not found"); + this.initialize(); + } +} + +module.exports = { Model } \ No newline at end of file diff --git a/app.js b/app.js index 792469f..3092a7d 100644 --- a/app.js +++ b/app.js @@ -15,12 +15,11 @@ // Packages const express = require("express"); const bodyParser = require("body-parser"); -const cookieParser = require("cookie-parser"); const mysql = require("mysql2"); const path = require("path"); -// Classes -const { DatabaseInstance } = require("./Structures/Classes/DatabaseInstance"); +// Config +const { databaseCredentials } = require("./Structures/Config/databaseCredentials"); // Load environment variables when not using docker if (!process.env.DOCKER) { @@ -45,32 +44,29 @@ app.set("view engine", "ejs"); // Use body-parser and cookie-parser app.use(bodyParser.urlencoded({ extended: false })); -app.use(cookieParser()); //------------------------------------------------> // Initialize database //------------------------------------------------> -const db = new DatabaseInstance({ - database: process.env.DB_NAME, - user: process.env.DB_USER, - password: process.env.DB_PASSWORD, - host: process.env.DB_HOST, - port: process.env.DB_PORT +const db = mysql.createConnection(databaseCredentials); + +db.connect((err) => { + if (err) console.log(`[JET] Error occurred during initial connection: ${err}`); + else console.log("[JET] Successfully connected to database"); }); +db.end(); + //------------------------------------------------> // Routing //------------------------------------------------> const apiRouter = require("./routes/apiRoutes"); +const indexRouter = require("./routes/indexRoutes"); app.use("/api", apiRouter); - -// Handle home route -app.get("/", (req, res) => { - res.render("layout"); -}); +app.use("/", indexRouter); //------------------------------------------------> // Start Express diff --git a/controller/placeholder b/controller/indexController.js similarity index 100% rename from controller/placeholder rename to controller/indexController.js diff --git a/model/placeholder b/controller/userController.js similarity index 100% rename from model/placeholder rename to controller/userController.js diff --git a/docker-compose.yml b/docker-compose.yml index aa66a2c..6054fb6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,12 +8,12 @@ services: environment: MYSQL_DATABASE: jet MYSQL_USER: jet - MYSQL_PASSWORD: ghiuwe§825429h§$%ff + MYSQL_PASSWORD: ghiuwe825429hff MYSQL_ROOT_PASSWORD: hgruwhgvuiwrghiuwe§825429h§$%ff ports: - "3306:3306" - volumes: - - mysql:/var/lib/mysql + # volumes: + # - mysql:/var/lib/mysql # Express app service app: @@ -28,10 +28,10 @@ services: DB_HOST: db DB_PORT: 3306 DB_USER: jet - DB_PASSWORD: ghiuwe§825429h§$%ff + DB_PASSWORD: ghiuwe§825429hff DB_NAME: jet DOCKER: true PORT: 4300 -volumes: - mysql: \ No newline at end of file +# volumes: +# mysql: \ No newline at end of file diff --git a/model/userModel.js b/model/userModel.js new file mode 100644 index 0000000..88489d6 --- /dev/null +++ b/model/userModel.js @@ -0,0 +1,19 @@ +//------------------------------------------------> +// Imports +//------------------------------------------------> + +const { Model } = require("../Structures/Classes/Model"); + +//------------------------------------------------> +// UserModel +//------------------------------------------------> + +class UserModel extends Model { + initialize() { + // The initialize method is required in each instance of the Model class!!! + } + + async getUserById() { + // Additional classes are optional and can be used to interact with the DB Pool, this.pool! + } +} \ No newline at end of file diff --git a/public/placeholder b/public/placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/routes/indexRoutes.js b/routes/indexRoutes.js new file mode 100644 index 0000000..c7660a8 --- /dev/null +++ b/routes/indexRoutes.js @@ -0,0 +1,8 @@ +const express = require("express"); +const router = express.Router(); + +router.get("/", (req, res) => { + res.render("layout"); +}); + +module.exports = router; \ No newline at end of file From 022935f14c62e4b643a1b1abfe241180ef59ec46 Mon Sep 17 00:00:00 2001 From: Jo <johannesreckers2006@gmail.com> Date: Wed, 21 Feb 2024 00:11:09 +0100 Subject: [PATCH 3/4] [workflows] rename .gitea to .forgejo, modify .gitignore --- {.gitea => .forgejo}/workflows/build.yml | 0 .gitignore | 5 ++++- 2 files changed, 4 insertions(+), 1 deletion(-) rename {.gitea => .forgejo}/workflows/build.yml (100%) diff --git a/.gitea/workflows/build.yml b/.forgejo/workflows/build.yml similarity index 100% rename from .gitea/workflows/build.yml rename to .forgejo/workflows/build.yml diff --git a/.gitignore b/.gitignore index a00b819..ed70c70 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,7 @@ node_modules # Config files config/config.json -.env \ No newline at end of file +.env + +# Docker +docker-compose.yml \ No newline at end of file From 31d42c8bbbdb324d628ae07c0972640df5e6c802 Mon Sep 17 00:00:00 2001 From: Jo <johannesreckers2006@gmail.com> Date: Wed, 21 Feb 2024 00:13:40 +0100 Subject: [PATCH 4/4] [routes] modify comment --- routes/apiRoutes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routes/apiRoutes.js b/routes/apiRoutes.js index c133f02..1990fe4 100644 --- a/routes/apiRoutes.js +++ b/routes/apiRoutes.js @@ -2,7 +2,7 @@ const express = require("express"); const router = express.Router(); router.get("/", (req, res) => { - // API stuff goes here + // API stuff goes here :3 }); module.exports = router; \ No newline at end of file