Skip to content

Commit

Permalink
seq ui
Browse files Browse the repository at this point in the history
  • Loading branch information
surelle-ha committed Jun 12, 2024
1 parent cab0896 commit da473b9
Show file tree
Hide file tree
Showing 83 changed files with 1,612 additions and 1,709 deletions.
23 changes: 23 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
on:
push:
branches:
- main
workflow_dispatch:

jobs:
run_pull:
name: run pull
runs-on: ubuntu-latest

steps:
- name: install ssh keys
# check this thread to understand why its needed:
# https://stackoverflow.com/a/70447517
run: |
install -m 600 -D /dev/null ~/.ssh/id_rsa
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
ssh-keyscan -H ${{ secrets.SSH_HOST }} > ~/.ssh/known_hosts
- name: connect and pull
run: ssh ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} "cd ${{ secrets.WORK_DIR }} && git checkout ${{ secrets.MAIN_BRANCH }} && git pull && exit"
- name: cleanup
run: rm -rf ~/.ssh
28 changes: 10 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,30 +16,16 @@ Zentinel.JS is a backend framework / boilerplate built on top of Express.JS, str
![NodeJS](https://img.shields.io/badge/Node.JS-black?style=for-the-badge&logo=node.js)
</div>

## Table of Contents
- Features
- Installation
- Environment Variables
- Commands
- Project Structure
- API Documentation
- Error Handling
- Validation
- Authentication
- Authorization
- Logging
- Rate Limit
- Socket / Realtime Data
- Contributing

## Features
Below are the features of Zentinel.JS:
- Zentinel CLI
- Builtin Authentication using JSON Web Token.
- Builtin Role-Based Access Control as Authorization.
- Configured Mongoose for MongoDB
- Configured Sequelize for MySQL
- Configured CORS, Helmet and Securities
- Interconnected MVC Components
- Sequelize UI / ORM Code Generator

## Installation
Installation via CommandLine Interface
Expand Down Expand Up @@ -152,13 +138,14 @@ zentinel --help
zentinel init
zentinel create
```
- [2024/06/12] Sequelize ORM Code Generator is added and can now be accessed on /orm-builder

## Goal Checklist
- [x] Add Rate Limit
- [x] Integrate Mongoose ORM
- [x] Integrate Sequelize ORM
- [ ] Add Socket.io as Native Feature
- [ ] Add Logger Utility
- [x] Add Socket.io as Native Feature
- [x] Add Logger Utility - Pino
- [x] Recreate Zentinel CLI
- [x] Implement Migration and Seeding
- [x] Publish `zentinel-cli` to NPM
Expand All @@ -167,6 +154,11 @@ zentinel create
- [ ] Add Cron Job
- [ ] Add Custom Function
- [ ] Add Storage Driver Support
- [ ] Add Express Validator
- [ ] Add express-response-hooks
- [x] Restructure Directories
- [ ] Typescript Support
- [x] Sequelize ORM Code Generator added

## Developer
As a developer who constantly seeks to improve my development skills, my goal with Zentinel.JS is to create a powerful yet intuitive backend framework that simplifies the development process for fellow developers. I aim to provide a robust toolset that makes backend operations more efficient and enjoyable, ensuring that developers can focus on building great applications without getting bogged down by repetitive tasks.
Expand Down
38 changes: 22 additions & 16 deletions app.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,36 @@
/* Import Server Modules */
const express = require("express");
const helmet = require("helmet");
const cors = require("cors");
const serveIndex = require('serve-index');

/* Import Configurations */
const { connectDB:sql_setup, sequelize} = require('./config/sql.js');
const { connectDB:nosql_setup } = require("./config/nosql.js");
const { RateLimit } = require("./config/ratelimiter.js")
const env_setup = require("./config/environments");
const cors_setup = require("./config/cors");

/* Setup Database */
sql_setup();
nosql_setup();
const { connectDB: sql_setup, sequelize } = require("./config/sql.js");
const { connectDB: nosql_setup } = require("./config/nosql.js");
const { RateLimit } = require("./config/ratelimiter.js");
const { cors, cors_options } = require("./config/cors");
const { helmet } = require("./config/helmet");
const { loggerPino } = require("./config/logger");

/* Setup Express Application */
const app = express();
app.use(RateLimit)
app.use(helmet());
app.use(cors(cors_setup.Options));

if (true) sql_setup();

if (false) nosql_setup();

if (true) app.use(RateLimit);

if (true) app.use(helmet());

if (true) app.use(cors(cors_options));

app.use(loggerPino);
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(express.static('public'));
app.use("/", express.static("public"));
app.use('/storage', express.static('storage'), serveIndex('storage', {'icons': true }));
app.use('/orm-builder', express.static('storage/sequelize-ui'));

/* Routes: Web, API */
app.get("/", (req, res) => { res.status(200).send("ZentinelJS Served"); });
require("./app/utilities/__i.js")(app);
require("./app/services/__i.js")(app);
require("./app/models/__i.js")(app, sequelize);
Expand Down
6 changes: 3 additions & 3 deletions app/controllers/Role.Controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ module.exports = function (app) {
// Retrieve a single role by id
// GET @/api/roles/:id
Controller.getRole = function (req, res) {
Role.findByPk(req.params.id)
Role.findByPk(req.params.role_id)
.then(role => {
if (!role) {
return res.status(404).send({ message: "Role not found" });
Expand Down Expand Up @@ -49,7 +49,7 @@ module.exports = function (app) {
// PATCH @/api/roles/:id
Controller.updateRole = function (req, res) {
Role.update({ name: req.body.name }, {
where: { id: req.params.id },
where: { id: req.params.role_id },
returning: true,
plain: true
})
Expand All @@ -71,7 +71,7 @@ module.exports = function (app) {
// Delete a role
// DELETE @/api/roles/:id
Controller.deleteRole = function (req, res) {
Role.destroy({ where: { id: req.params.id } })
Role.destroy({ where: { id: req.params.role_id } })
.then(deleted => {
if (!deleted) {
return res.status(404).send({ message: "Role not found" });
Expand Down
6 changes: 3 additions & 3 deletions app/controllers/User.Controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ module.exports = function (app) {
// Retrieve a single user by id
// GET @/api/users/:id
Controller.getUser = function (req, res) {
User.findByPk(req.params.id, {
User.findByPk(req.params.user_id, {
include: [{
model: Role,
as: 'Role'
Expand Down Expand Up @@ -72,7 +72,7 @@ module.exports = function (app) {
// PATCH @/api/users/:id
Controller.updateUser = function (req, res) {
User.update(req.body, {
where: { id: req.params.id },
where: { id: req.params.user_id },
returning: true,
plain: true
})
Expand All @@ -94,7 +94,7 @@ module.exports = function (app) {
// Delete a user
// DELETE @/api/users/:id
Controller.deleteUser = function (req, res) {
User.destroy({ where: { id: req.params.id } })
User.destroy({ where: { id: req.params.user_id } })
.then(deleted => {
if (!deleted) {
return res.status(404).send({ message: "User not found" });
Expand Down
4 changes: 0 additions & 4 deletions app/middlewares/Authenticate.Middleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ module.exports = function (app) {
return res.status(401).json({ message: "Authentication Failed: Invalid token.", err: err.message });
}

// Find the session in the database
const session = await Session.findOne({
where: {
token: token,
Expand All @@ -30,9 +29,7 @@ module.exports = function (app) {
return res.status(401).json({ message: "No valid session found." });
}

// Check if the session has expired
if (session.expiresAt < new Date()) {
// If the session has expired, delete it from the database
await Session.destroy({
where: {
token: token,
Expand All @@ -42,7 +39,6 @@ module.exports = function (app) {
return res.status(401).json({ message: "Token expired." });
}

// Set the user ID to req for subsequent middleware
req.userId = decoded.userId;
next();
});
Expand Down
6 changes: 3 additions & 3 deletions app/middlewares/SequelizeGuard.Middleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ module.exports = function (app) {
const user = await User.findByPk(req.userId, {
include: [{
model: Role,
as: 'Role', // Make sure this matches the alias used in your User model's association
as: 'Role',
include: [{
model: Permission,
as: 'Permissions' // And this matches the alias used in your Role model's association
as: 'Permissions'
}]
}]
});
Expand All @@ -28,7 +28,7 @@ module.exports = function (app) {

const permissions = user.Role.Permissions.map(permission => permission.name);
if (permissions.includes(requiredPermission)) {
next(); // Permission is found, continue to the next middleware
next();
} else {
return res.status(403).send({ message: "Access denied. You do not have the required permission." });
}
Expand Down
6 changes: 3 additions & 3 deletions app/routes/v1/Role.Route.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ module.exports = function (app) {
var RoleController = app.controllers.Role;
app.post("/api/v1/roles", [], RoleController.createRole);
app.get("/api/v1/roles", [], RoleController.getAllRoles);
app.get("/api/v1/roles/:id", [], RoleController.getRole);
app.patch("/api/v1/roles/:id", [], RoleController.updateRole);
app.get("/api/v1/roles/:role_id", [], RoleController.getRole);
app.patch("/api/v1/roles/:role_id", [], RoleController.updateRole);
app.delete("/api/v1/roles", [], RoleController.deleteAllRoles);
app.delete("/api/v1/roles/:id", [], RoleController.deleteRole);
app.delete("/api/v1/roles/:role_id", [], RoleController.deleteRole);
};
6 changes: 3 additions & 3 deletions app/routes/v1/User.Route.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ module.exports = function (app) {

app.post("/api/v1/users", [SequelizeGuard.authorize('create-user')], UserController.createUser);
app.get("/api/v1/users", [SequelizeGuard.authorize('fetch-user')], UserController.getAllUsers);
app.get("/api/v1/users/:id", [SequelizeGuard.authorize('fetch-user')], UserController.getUser);
app.patch("/api/v1/users/:id", [SequelizeGuard.authorize('update-user')], UserController.updateUser);
app.get("/api/v1/users/:user_id", [SequelizeGuard.authorize('fetch-user')], UserController.getUser);
app.patch("/api/v1/users/:user_id", [SequelizeGuard.authorize('update-user')], UserController.updateUser);
app.delete("/api/v1/users", [SequelizeGuard.authorize('delete-user')], UserController.deleteAllUsers);
app.delete("/api/v1/users/:id", [SequelizeGuard.authorize('delete-user')], UserController.deleteUser);
app.delete("/api/v1/users/:user_id", [SequelizeGuard.authorize('delete-user')], UserController.deleteUser);
};
3 changes: 3 additions & 0 deletions config/console.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const chalk = require('chalk');

module.exports = chalk;
14 changes: 5 additions & 9 deletions config/cors.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
const cors = require("cors");

/* Only modify this if you know what you're doing. */
let allowedOrigins = [
"http://localhost:5500",
"http://127.0.0.1:5500",
"http://127.0.0.1:8080",
"http://localhost:8080",
"http://localhost:3000",
"http://localhost",
"http://127.0.0.1",
"*"
];

const Options = {
const cors_options = {
origin: function (origin, callback) {
if (!origin) {
return callback(null, true);
Expand All @@ -23,4 +19,4 @@ const Options = {
},
};

module.exports = { Options };
module.exports = { cors, cors_options };
3 changes: 3 additions & 0 deletions config/helmet.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const helmet = require("helmet");

module.exports = { helmet }
57 changes: 57 additions & 0 deletions config/logger.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
const pino = require('pino');
const expressPino = require('express-pino-logger');

const logger = pino({
transport: {
targets: [
{
target: 'pino-pretty',
options: {
colorize: true,
translateTime: 'SYS:standard',
ignore: 'pid,hostname'
},
level: 'info',
},
{
target: 'pino/file',
options: {
destination: './storage/logs/info.log',
},
level: 'info',
},
{
target: 'pino/file',
options: {
destination: './storage/logs/warn.log',
},
level: 'warn',
},
{
target: 'pino/file',
options: {
destination: './storage/logs/error.log',
},
level: 'error',
},
{
target: 'pino/file',
options: {
destination: './storage/logs/fatal.log',
},
level: 'fatal',
}
]
},
serializers: {
req: (req) => ({
method: req.method,
url: req.url,
user: req.raw ? req.raw.user : 'unauthenticated',
}),
}
});

const loggerPino = expressPino({ logger });

module.exports = { loggerPino };
Loading

0 comments on commit da473b9

Please sign in to comment.