chore: Refactor v2 folder and class structure + Adding Company App (dummy)

This commit is contained in:
Josepablo C
2024-08-07 00:59:50 -06:00
parent f8d41db04d
commit 288fdc10a7
24 changed files with 614 additions and 190 deletions

View File

@@ -0,0 +1,179 @@
'use strict';
const Application = require('../Domain');
function dummy_middleware( req, res, next ){
return res.status(500).send({ error:"Not implemented yet" });
}
/// Block access to the next list of endpoints if JWT is not valid
async function access_control_with_jwt( req, res, next){
if( ! req.JWT?.isValid ){
return res.status(401).send({error:"Unauthorized",code:401});
}
return next();
}
async function authorize(req, res, next) {
try{
const email = req.body.email;
const password = req.body.password;
const data = await Application.authorize_credentials( email , password );
if( data.error ){
const error = data.error;
return res.status( error.code ).send( { error : error.msg } );
}
return res.send( data );
}catch(error){
console.error( error );
return res.status( 500 ).send( { error } );
}
}
async function refresh_session(req, res, next) {
try{
const session_token = req.params.session_token;
const data = await Application.authorize_token( session_token );
if( data.error ){
const error = data.error;
return res.status( error.code ).send( { error : error.msg } );
}
return res.send( data );
}catch(error){
console.error( error );
return res.status( 500 ).send( { error } );
}
}
async function check_account(req, res, next){
try{
const email = req.params.email;
const data = await Application.check_account( email );
if( data.error ){
const error = data.error;
return res.status( error.code ).send( { error : error.msg } );
}
return res.send( data );
}catch(error){
console.error( error );
return res.status( 500 ).send( { error } );
}
}
async function post_signup(req, res, next) {
try{
const email = req.body.email;
const password = req.body.password;
const data = await Application.genOTPChecksum( email, password, "signup" );
if( data.error ){
const error = data.error;
return res.status( error.code ).send( { error : error.msg } );
}
return res.send( data );
}catch(error){
console.error( error );
return res.status( 500 ).send( { error } );
}
}
async function patch_signup(req, res, next) {
try{
const email = req.body.email;
const password = req.body.password;
const otp = req.body.otp;
const checksum = req.body.checksum;
const data = await Application.signup( email , password, otp, checksum);
if( data.error ){
const error = data.error;
return res.status( error.code ).send( { error : error.msg } );
}
return res.send( data );
}catch(error){
console.error( error );
return res.status( 500 ).send( { error } );
}
}
async function post_recover(req, res, next){
try{
const email = req.body.email;
const password = req.body.password;
const data = await Application.genOTPChecksum( email, password, "recover" );
if( data.error ){
const error = data.error;
return res.status( error.code ).send( { error : error.msg } );
}
return res.send( data );
}catch(error){
console.error( error );
return res.status( 500 ).send( { error } );
}
}
async function patch_recover(req, res, next){
try{
const email = req.body.email;
const password = req.body.password;
const otp = req.body.otp;
const checksum = req.body.checksum;
const data = await Application.recover( email , password, otp, checksum);
if( data.error ){
const error = data.error;
return res.status( error.code ).send( { error : error.msg } );
}
return res.send( data );
}catch(error){
console.error( error );
return res.status( 500 ).send( { error } );
}
}
function AppInit(){
Application.init();
}
module.exports = {
AppInit,
hooks : {
before: {
/**Array of middleware functions*/
all : [],
del : [],
get : [],
patch : [],
post : [],
put : []
},
after: {
/**Array of middleware functions*/
all : [],
del : [],
get : [],
patch : [],
post : [],
put : []
},
custom: {
/**Array of objects like { endpoint, middleware }*/
all : [
{ '/register': dummy_middleware }
],
del : [],
get : [
{ '/check-account/:email' : check_account },
{ '/authorize/:session_token': refresh_session }
],
patch : [
{ '/signup' : patch_signup },
{ '/recover' : patch_recover }
],
post : [
{ '/authorize' : authorize },
{ '/signup' : post_signup },
{ '/recover' : post_recover }
],
put : []
}
}
};

View File

@@ -1,132 +1,13 @@
'use strict';
/// Router instance
const router = require('express').Router();
const Application = require('../Domain');
function dummy_middleware( req, res ){
return res.status(500).send({ error:"Not implemented yet" });
const { hooks, AppInit } = require( './hooks' );
const GenericController = require('../../Lib');
class Account extends GenericController {
init(){
super.init();
AppInit();
}
}
router.post('/authorize', async( req, res ) => {
try{
const email = req.body.email;
const password = req.body.password;
const data = await Application.authorize_credentials( email , password );
if( data.error ){
const error = data.error;
return res.status( error.code ).send( { error : error.msg } );
}
return res.send( data );
}catch(error){
console.error( error );
return res.status( 500 ).send( { error } );
}
} );
router.get('/authorize/:session_token', async( req, res ) => {
try{
const session_token = req.params.session_token;
const data = await Application.authorize_token( session_token );
if( data.error ){
const error = data.error;
return res.status( error.code ).send( { error : error.msg } );
}
return res.send( data );
}catch(error){
console.error( error );
return res.status( 500 ).send( { error } );
}
} );
router.get('/check-account/:email', async( req, res ) => {
try{
const email = req.params.email;
const data = await Application.check_account( email );
if( data.error ){
const error = data.error;
return res.status( error.code ).send( { error : error.msg } );
}
return res.send( data );
}catch(error){
console.error( error );
return res.status( 500 ).send( { error } );
}
} );
router.post('/signup', async(req,res) => {
try{
const email = req.body.email;
const password = req.body.password;
const data = await Application.genOTPChecksum( email, password, "signup" );
if( data.error ){
const error = data.error;
return res.status( error.code ).send( { error : error.msg } );
}
return res.send( data );
}catch(error){
console.error( error );
return res.status( 500 ).send( { error } );
}
} );
router.patch('/signup', async(req,res) => {
try{
const email = req.body.email;
const password = req.body.password;
const otp = req.body.otp;
const checksum = req.body.checksum;
const data = await Application.signup( email , password, otp, checksum);
if( data.error ){
const error = data.error;
return res.status( error.code ).send( { error : error.msg } );
}
return res.send( data );
}catch(error){
console.error( error );
return res.status( 500 ).send( { error } );
}
} );
router.post('/recover', async(req,res) => {
try{
const email = req.body.email;
const password = req.body.password;
const data = await Application.genOTPChecksum( email, password, "recover" );
if( data.error ){
const error = data.error;
return res.status( error.code ).send( { error : error.msg } );
}
return res.send( data );
}catch(error){
console.error( error );
return res.status( 500 ).send( { error } );
}
} );
router.patch('/recover', async(req,res) => {
try{
const email = req.body.email;
const password = req.body.password;
const otp = req.body.otp;
const checksum = req.body.checksum;
const data = await Application.recover( email , password, otp, checksum);
if( data.error ){
const error = data.error;
return res.status( error.code ).send( { error : error.msg } );
}
return res.send( data );
}catch(error){
console.error( error );
return res.status( 500 ).send( { error } );
}
} );
/// Block access to the next list of endpoints if JWT is not valid
router.use( async (req, res, next) => {
if( ! req.JWT?.isValid ){
return res.status(401).send({error:"Unauthorized",code:401});
}
return next();
} );
router.use('/register' , dummy_middleware );
module.exports = router;
module.exports = new Account( hooks );

View File

@@ -2,18 +2,33 @@
const Repository = require('../Repository');
const jsonwebtoken = require('jsonwebtoken');
const { toSha256,
const { ModuleName,
toSha256,
publishEvent,
registerEvent,
jwtRenewalTimeout,
jwtTimeout,
jwtOptions,
jwtSecret,
tokenSecret,
pwdSecret,
genErrorResponse } = require('../Ports/Interfaces');
genErrorResponse } = require('../Interfaces');
class Account {
constructor(){
this.Events = {
/** Event_Id : callback */
};
}
init(){
/// Setup application events
const Events = this.Events;
for ( const [event, callback] of Object.entries( Events ) ) {
const event_id = ModuleName + event
Interfaces.registerEvent( event_id , callback );
}
}
genOTP( email ){

View File

@@ -1,16 +1,24 @@
'use strict';
const { toSha256 } = require('../../../../Shared/ShaUtils');
const ModuleName = "App:Account:";
const { authentication } = require('../../../../../config/apiConfig.json');
const { toSha256 } = require('../../../Shared/ShaUtils');
const { genErrorResponse } = require('../../../../Shared/ErrorResponse');
const { authentication } = require('../../../../config/apiConfig.json');
const SharedResources = require('../../../../Shared/Resources');
const { genErrorResponse } = require('../../../Shared/ErrorResponse');
const SharedResources = require('../../../Shared/Resources');
function registerEvent( event_id , callback ){
console.log(`Loading event ${event_id}`);
const EventBus = SharedResources.get("SysS:EventManager");
EventBus.addEvent( event_id , callback );
}
function publishEvent( event , data = null ){
const EventBus = SharedResources.get("SysS:EventManager");
const AppEventDomain = "App:Account:"
const AppEventDomain = ModuleName;
const event_id = AppEventDomain + event;
console.log( event_id );
@@ -34,5 +42,6 @@ module.exports = {
jwtSecret,
pwdSecret,
genErrorResponse,
registerEvent,
publishEvent
};

View File

@@ -1,9 +0,0 @@
'use strict';
const App = require('../../App');
/**
* Dictionary of event ids and handlers
*/
module.exports = {
// "event_id" : App.onEvent
};

View File

@@ -1,3 +0,0 @@
'use strict';
module.export = {};

View File

@@ -0,0 +1,48 @@
'use strict';
const Application = require('../Domain');
function dummy_middleware( req, res, next ){
Application.trigger_example_event( {
example : "This is an example of event data"
} )
return res.status(500).send({ error:"Not implemented yet" });
}
function AppInit(){
Application.init();
}
module.exports = {
AppInit,
hooks : {
before: {
/**Array of middleware functions*/
all : [],
del : [],
get : [],
patch : [],
post : [],
put : []
},
after: {
/**Array of middleware functions*/
all : [],
del : [],
get : [],
patch : [],
post : [],
put : []
},
custom: {
/**Array of objects like { endpoint, middleware }*/
all : [ { "/test" : dummy_middleware } ],
del : [],
get : [],
patch : [],
post : [],
put : []
}
}
};

View File

@@ -0,0 +1,13 @@
'use strict';
const { hooks, AppInit } = require( './hooks' );
const GenericController = require('../../Lib');
class Company extends GenericController {
init(){
super.init();
AppInit();
}
}
module.exports = new Company( hooks );

View File

@@ -0,0 +1,34 @@
'use strict';
const Repository = require('../Repository');
const Interfaces = require('../Interfaces');
class Company {
constructor(){
this.Events = {
/** Event_Id : callback */
"Example" : this.event_handler_example
};
}
init(){
/// Setup application events
const Events = this.Events;
/// Setup application events
for ( const [event, callback] of Object.entries( Events ) ) {
const event_id = Interfaces.ModuleName + event
Interfaces.registerEvent( event_id , callback );
}
}
trigger_example_event( data ){
Interfaces.publishEvent( "Example", data );
}
event_handler_example( data ){
console.log( "CompanyDomain event" );
console.log( data );
}
};
module.exports = new Company();

View File

@@ -0,0 +1,27 @@
'use strict';
const ModuleName = "App:Company:";
const SharedResources = require('../../../Shared/Resources');
function registerEvent( event_id , callback ){
const EventBus = SharedResources.get("SysS:EventManager");
console.log(`Loading event ${event_id}`);
EventBus.addEvent( event_id , callback );
}
function publishEvent( event , data = null ){
const EventBus = SharedResources.get("SysS:EventManager");
const AppEventDomain = ModuleName;
const event_id = AppEventDomain + event;
console.log( event_id );
EventBus.publishEvent( event_id , data );
}
module.exports = {
ModuleName,
registerEvent,
publishEvent
};

View File

@@ -0,0 +1,3 @@
'use strict';
module.exports = {};

View File

@@ -0,0 +1,5 @@
'use strict';
const SpecificModelRepository = require('./Objection');
module.exports = SpecificModelRepository;

View File

@@ -0,0 +1,89 @@
'use strict';
const express = require('express');
class GenericController{
constructor( hooks ){
this.router = express.Router();
this.hooks = hooks;
}
init(){
const { before, after, custom } = this.hooks;
if( before ){
this.populate_hooks( before );
}
if( custom ){
this.populate_custom_hooks( custom );
}
if( after ){
this.populate_hooks( after );
}
return this;
}
populate_hooks( hooks ){
if( (hooks.all) && (hooks.all.length > 0) ){
this.router.use( hooks.all );
}
if( (hooks.delete) && (hooks.delete.length > 0) ){
this.router.delete( hooks.del );
}
if( (hooks.get) && (hooks.get.length > 0) ){
this.router.get( hooks.get );
}
if( (hooks.patch) && (hooks.patch.length > 0) ){
this.router.patch( hooks.patch );
}
if( (hooks.post) && (hooks.post.length > 0) ){
this.router.post( hooks.post );
}
if( (hooks.put) && (hooks.put.length > 0) ){
this.router.put( hooks.put );
}
}
add_custom_hook( http_verb, endpoint, middleware ){
switch( http_verb ){
case 'all':
this.router.use( endpoint , middleware );
break;
case 'del':
this.router.delete(endpoint, middleware);
break;
case 'get':
this.router.get(endpoint, middleware);
break;
case 'patch':
this.router.patch(endpoint, middleware);
break;
case 'post':
this.router.post(endpoint, middleware);
break;
case 'put':
this.router.put(endpoint, middleware);
break;
default:
return;
}
}
populate_custom_hooks( hooks ){
for (let http_verb in hooks ){
for (let custom_hook of hooks[ http_verb ]){
for (let entry of Object.entries(custom_hook) ){
const endpoint = entry[0];
const callback = entry[1];
this.add_custom_hook( http_verb, endpoint, callback );
}
}
}
}
}
module.exports = GenericController;

View File

@@ -0,0 +1,60 @@
'use strict';
const { createHandler } = require("graphql-http/lib/use/express");
/// Include graphql schema and resolvers
const schemaDescription = require('./graphql/schema.js');
const schemaResolvers = require('./graphql/resolvers.js');
const { initEvents } = require('../Domain');
async function test(req, res, next){
console.log( req.requestContext );
res.status(200).send({
msg : "It is alive!"
});
}
module.exports = {
AppInit : initEvents, /// Dummy App Init
hooks : {
before: {
/**Array of middleware functions*/
all : [],
del : [],
get : [ test ],
patch : [],
post : [],
put : []
},
after: {
/**Array of middleware functions*/
all : [],
del : [],
get : [],
patch : [],
post : [],
put : []
},
custom: {
/**Array of objects like { endpoint, middleware }*/
all : [],
del : [],
get : [],
patch : [],
post : [
{ '/graphql' :
createHandler({
schema: schemaDescription,
rootValue : schemaResolvers,
context: async (req, params) => { return { requestContext : req.raw.requestContext }; },
graphiql: true
})
}
],
put : []
}
}
};

View File

@@ -1,26 +1,13 @@
'use strict';
const router = require('express').Router();
const { createHandler } = require("graphql-http/lib/use/express");
const { hooks, AppInit } = require( './hooks' );
const GenericController = require('../../Lib');
/// Include graphql schema and resolvers
const schemaDescription = require('./graphql/schema.js');
const schemaResolvers = require('./graphql/resolvers.js');
class PrivateResources extends GenericController {
init(){
super.init();
AppInit();
}
}
router.get('/test', async (req, res) => {
console.log( req.requestContext );
res.status(200).send({
msg : "It is alive!"
});
} );
router.post( '/graphql',
createHandler({
schema: schemaDescription,
rootValue : schemaResolvers,
context: async (req, params) => { return { requestContext : req.raw.requestContext }; },
graphiql: true
})
);
module.exports = router;
module.exports = new PrivateResources( hooks );

View File

@@ -1,6 +1,7 @@
'use strict';
const Repository = require('../Repository');
const Interfaces = require('../Interfaces');
class TruckType {
constructor( category ){
@@ -356,7 +357,25 @@ async function findCompaniesPage( filters, elements, page ) {
};
}
/**
* List of Events to handle in this App Domain
*/
const Events = {
/** Event_Id : callback */
};
function initEvents(){
console.log("Init GraphQL Events");
/// Setup application events
for ( const [event, callback] of Object.entries( Events ) ) {
const event_id = Interfaces.ModuleName + event
Interfaces.registerEvent( event_id , callback );
}
}
module.exports = {
initEvents,
Account,
User,
Company,

View File

@@ -0,0 +1,27 @@
'use strict';
const ModuleName = "App:PrivateResources:";
const SharedResources = require('../../../Shared/Resources');
function registerEvent( event_id , callback ){
const EventBus = SharedResources.get("SysS:EventManager");
console.log(`Loading event ${event_id}`);
EventBus.addEvent( event_id , callback );
}
function publishEvent( event , data = null ){
const EventBus = SharedResources.get("SysS:EventManager");
const AppEventDomain = ModuleName;
const event_id = AppEventDomain + event;
console.log( event_id );
EventBus.publishEvent( event_id , data );
}
module.exports = {
ModuleName,
registerEvent,
publishEvent
};

View File

@@ -1,3 +0,0 @@
'use strict';
module.exports = {};

View File

@@ -1,3 +0,0 @@
'use strict';
module.exports = {};

View File

@@ -1,3 +0,0 @@
'use strict';
module.exports = {};

View File

@@ -1,16 +1,45 @@
'use strict';
/**
* ExpressJS Controller
*/
const express = require('express');
const app = express();
const SystemService = require('../SysS/Lib');
const middlewares = require('./middlewares');
const Resources = require('./resources');
const account = require('../Apps/Account/Controller');
const privateResources = require('../Apps/PrivateResources/Controller');
class AppLayerController extends SystemService {
constructor(){
super();
this.app = express();
this.resources = Resources;
}
async setup(){
super.setup();
}
async init(){
super.init();
const app = this.app;
/// Populate context from JWT payload
app.use( middlewares.jwtValidator );
app.use( middlewares.contextGenerator );
app.use('/account', account);
app.use('/private', privateResources);
for ( const resource of this.resources ){
for ( const [endpoint, controller] of Object.entries( resource ) ) {
controller.init();
app.use( endpoint, controller.router );
}
}
module.exports = app;
}
app_controller(){
return this.app;
}
}
module.exports = new AppLayerController();

View File

@@ -0,0 +1,12 @@
'use strict';
const Account = require('../Apps/Account/Controller');
const Company = require('../Apps/Company/Controller');
const PrivateResources = require('../Apps/PrivateResources/Controller');
module.exports = [
{ "/account": Account },
{ "/company": Company },
{ "/private": PrivateResources },
];

View File

@@ -30,6 +30,8 @@ class ExpressJSServices {
async setup(){
const app = this.app;
await AppsController.setup();
app.use( middlewares.Auth );
app.use(
@@ -79,8 +81,10 @@ class ExpressJSServices {
async init(){
const app = this.app;
await AppsController.init();
app.use( middlewares.errorJSON );
app.use( AppsController );
app.use( AppsController.app_controller() );
app.use( middlewares.error404 );
this.SystemServiceState = INIT;
@@ -90,6 +94,8 @@ class ExpressJSServices {
const app = this.app;
const serverPort = this.serverPort;
await AppsController.connect();
const server = app.listen( serverPort , function(err){
if( !err ){
console.log('API listen on port', serverPort );
@@ -104,12 +110,14 @@ class ExpressJSServices {
}
async disconnect(){
await AppsController.disconnect();
this.server.close();
this.SystemServiceState = OFFLINE;
}
async deinit(){
await AppsController.deinit();
this.SystemServiceState = UNINIT;
}

View File

@@ -4,7 +4,7 @@ const INIT = 1;
const ONLINE = 2;
const OFFLINE = 3;
class SystemServices {
class SystemService {
constructor(){
this.SystemServiceState = UNINIT;
}
@@ -30,4 +30,4 @@ class SystemServices {
}
}
module.exports = new SystemServices();
module.exports = SystemService;