feat(v3): Adding baseline for API v3
This commit is contained in:
@@ -6,6 +6,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node src/",
|
"start": "node src/",
|
||||||
"dev": "nodemon src/",
|
"dev": "nodemon src/",
|
||||||
|
"dev3": "nodemon server/src/",
|
||||||
"test": "mocha test/lib/handlers/proposals"
|
"test": "mocha test/lib/handlers/proposals"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
@@ -38,10 +39,11 @@
|
|||||||
"mongodb-core": "^3.2.7",
|
"mongodb-core": "^3.2.7",
|
||||||
"mongoose": "^7.5.4",
|
"mongoose": "^7.5.4",
|
||||||
"morgan": "^1.10.0",
|
"morgan": "^1.10.0",
|
||||||
|
"mysql": "^2.18.1",
|
||||||
"nodemailer": "^6.9.5",
|
"nodemailer": "^6.9.5",
|
||||||
"nodemailer-sendgrid": "^1.0.3",
|
"nodemailer-sendgrid": "^1.0.3",
|
||||||
"nodemon": "^3.0.1",
|
"nodemon": "^3.0.1",
|
||||||
"objection": "^3.1.2",
|
"objection": "^3.1.4",
|
||||||
"uuid": "^9.0.1"
|
"uuid": "^9.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
5
server/README.md
Normal file
5
server/README.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# REST API Framework
|
||||||
|
|
||||||
|
## Architecture Design
|
||||||
|
|
||||||
|

|
||||||
55
server/config/apiConfig.json
Normal file
55
server/config/apiConfig.json
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
{
|
||||||
|
"authentication": {
|
||||||
|
"pwdSecret":"Nx2g_IWo2Zt_LS$+",
|
||||||
|
"jwtSecret":"9o3BBz0EsrwXliwEJ/SFuywZoN8=",
|
||||||
|
"jwtTimeout":24,
|
||||||
|
"jwtRenewalTimeout":720,
|
||||||
|
"tokenSecret":"9Z'jMt|(h_f(&/S+zv.K",
|
||||||
|
"jwtOptions": {
|
||||||
|
"header": {
|
||||||
|
"typ": "access"
|
||||||
|
},
|
||||||
|
"audience": "https://www.etaviaporte.com",
|
||||||
|
"issuer": "etaviaporte",
|
||||||
|
"algorithm": "HS256",
|
||||||
|
"expiresIn": "1d"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"version" : {
|
||||||
|
"version" : "1.1.1",
|
||||||
|
"name": "ETA Beta",
|
||||||
|
"date":"03/2024"
|
||||||
|
},
|
||||||
|
"S3" : {
|
||||||
|
"accessKeyId": "AKIAXTQEUF6MLCHTUIKW",
|
||||||
|
"secretAccessKey": "QhM8gQ5O3hVDIf41YeO5/A6Wo58D1xQz8pzxBB2W",
|
||||||
|
"bucket": "enruta",
|
||||||
|
"load_attachments_key":"loadattachments",
|
||||||
|
"news_key":"news",
|
||||||
|
"region": "us-west-1"
|
||||||
|
},
|
||||||
|
"sendgrid" : {
|
||||||
|
"HOST": "smtp.sendgrid.net",
|
||||||
|
"PORT": "465",
|
||||||
|
"username": "apikey",
|
||||||
|
"API_KEY": "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",
|
||||||
|
"FROM": "noreply@etaviaporte.com"
|
||||||
|
},
|
||||||
|
"email_standalone" : {
|
||||||
|
"host": "smtp.hostinger.com",
|
||||||
|
"port": "465",
|
||||||
|
"secure": true,
|
||||||
|
"auth": {
|
||||||
|
"user": "noreply@etaviaporte.com",
|
||||||
|
"pass": "-)WJt[oP~P$`76Q4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mongodb": "mongodb+srv://enruta_admin:NeptFx4RUZG8OsfA@enruta.vwofshy.mongodb.net/enrutaviaporte?retryWrites=true&w=majority",
|
||||||
|
"sql":{
|
||||||
|
"host":"srv765.hstgr.io",
|
||||||
|
"port":3306,
|
||||||
|
"user":"u947463964_sysadmin",
|
||||||
|
"password":"3^K/47^h5pP",
|
||||||
|
"database":"u947463964_etaviaporte"
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
server/docs/assets/APIDesign.png
Normal file
BIN
server/docs/assets/APIDesign.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 60 KiB |
60
server/src/Apps/Account/Controller/index.js
Normal file
60
server/src/Apps/Account/Controller/index.js
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
'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" });
|
||||||
|
}
|
||||||
|
|
||||||
|
router.post('/register', dummy_middleware );
|
||||||
|
|
||||||
|
router.post('/authorize', dummy_middleware );
|
||||||
|
|
||||||
|
router.get('/authorize/:session_token', dummy_middleware );
|
||||||
|
|
||||||
|
router.get('/check-account/:email', async( req, res ) => {
|
||||||
|
try{
|
||||||
|
const email = req.params.email;
|
||||||
|
const data = await Application.check_account( email );
|
||||||
|
return res.send( data );
|
||||||
|
}catch(error){
|
||||||
|
console.error( error );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
router.post('/signup', async(req,res) => {
|
||||||
|
try{
|
||||||
|
const email = req.body.email;
|
||||||
|
const password = req.body.password;
|
||||||
|
const data = await Application.getVerifyChecksum( 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 );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
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 );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
router.post('/recover', dummy_middleware );
|
||||||
|
router.patch('/recover', dummy_middleware );
|
||||||
|
|
||||||
|
module.exports = router;
|
||||||
133
server/src/Apps/Account/Domain/index.js
Normal file
133
server/src/Apps/Account/Domain/index.js
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const Repository = require('../Repository');
|
||||||
|
const jsonwebtoken = require('jsonwebtoken');
|
||||||
|
const { toSha256,
|
||||||
|
publishEvent,
|
||||||
|
jwtRenewalTimeout,
|
||||||
|
jwtTimeout,
|
||||||
|
jwtOptions,
|
||||||
|
jwtSecret,
|
||||||
|
tokenSecret,
|
||||||
|
pwdSecret,
|
||||||
|
genErrorResponse } = require('../Ports/Interfaces');
|
||||||
|
|
||||||
|
class ApplicationLogic {
|
||||||
|
constructor(){
|
||||||
|
}
|
||||||
|
|
||||||
|
genOTP( email ){
|
||||||
|
const len = 5;
|
||||||
|
const shacode = toSha256( email + new Date() + tokenSecret );
|
||||||
|
const otp_hex = shacode.slice(0 , len );
|
||||||
|
const otp_dec = Number.parseInt( otp_hex , 16 );
|
||||||
|
return ""+otp_dec;
|
||||||
|
}
|
||||||
|
|
||||||
|
genSafePassword( password ){
|
||||||
|
return toSha256( password + pwdSecret );
|
||||||
|
}
|
||||||
|
|
||||||
|
async check_account( email ){
|
||||||
|
const projection = ["id","email","password","company_id"];
|
||||||
|
const user = await Repository.getByEmail( email , projection );
|
||||||
|
const retVal = {
|
||||||
|
has_account:false,
|
||||||
|
isVerified:false,
|
||||||
|
has_password:false
|
||||||
|
};
|
||||||
|
|
||||||
|
if( !user ){
|
||||||
|
retVal.has_account = false;
|
||||||
|
retVal.isVerified = false;
|
||||||
|
retVal.has_password = false;
|
||||||
|
}else{
|
||||||
|
retVal.has_account = true;
|
||||||
|
retVal.isVerified = user.isVerified;
|
||||||
|
retVal.has_password = ( !user.password )? false : true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getVerifyChecksum( email , password ){
|
||||||
|
const otp = this.genOTP( email );
|
||||||
|
const it_exists = await Repository.getByEmail( email );
|
||||||
|
|
||||||
|
if( it_exists ){
|
||||||
|
return genErrorResponse( "Email already exists" );
|
||||||
|
}
|
||||||
|
const content = { OTP : otp, user_name : email, email };
|
||||||
|
|
||||||
|
const checksum_entry = {
|
||||||
|
email,
|
||||||
|
password,
|
||||||
|
otp
|
||||||
|
};
|
||||||
|
|
||||||
|
const checksum = toSha256( JSON.stringify(checksum_entry)).slice(0, 32);
|
||||||
|
publishEvent( "getchecksum" , content );
|
||||||
|
return { checksum };
|
||||||
|
}
|
||||||
|
|
||||||
|
async signup( email, password, otp, checksum ){
|
||||||
|
const it_exists = await Repository.getByEmail( email );
|
||||||
|
|
||||||
|
if( it_exists ){
|
||||||
|
return genErrorResponse( "User already registered!" );
|
||||||
|
}
|
||||||
|
|
||||||
|
const checksum_entry = {email, password, otp};
|
||||||
|
const recomputed_checksum = toSha256( JSON.stringify(checksum_entry)).slice(0, 32);
|
||||||
|
|
||||||
|
if( recomputed_checksum != checksum ){
|
||||||
|
return genErrorResponse( "Wrong OTP" );
|
||||||
|
}
|
||||||
|
|
||||||
|
await Repository.createOne( email, this.genSafePassword( password ) );
|
||||||
|
|
||||||
|
const content = { user_name : email, email };
|
||||||
|
|
||||||
|
publishEvent( "signupconfirmed" , content );
|
||||||
|
|
||||||
|
return await this.authorize_credentials( email, password );
|
||||||
|
}
|
||||||
|
|
||||||
|
async authorize_credentials( email, password ){
|
||||||
|
const user = await Repository.findByEmailPassword( email, this.genSafePassword( password ) );
|
||||||
|
|
||||||
|
if( !user ){
|
||||||
|
return genErrorResponse( "Not able to log in", 401 );
|
||||||
|
}
|
||||||
|
const current_date = new Date();
|
||||||
|
const iat = Math.floor( (current_date.getTime())/1000 );
|
||||||
|
const renewal_exp = ( iat + 3600*jwtRenewalTimeout ) * 1000;
|
||||||
|
/**
|
||||||
|
* Renew session token on every login event.
|
||||||
|
* Previous session token is lost
|
||||||
|
*/
|
||||||
|
const session_token = toSha256( `${new Date()}` );
|
||||||
|
const session_token_exp = new Date( renewal_exp );
|
||||||
|
|
||||||
|
await Repository.addSessionToken( user.id, session_token, session_token_exp );
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
iat: iat,
|
||||||
|
exp: iat + jwtTimeout * 3600,
|
||||||
|
aud: jwtOptions.audience,
|
||||||
|
iss: jwtOptions.audience,
|
||||||
|
sub: user.id,
|
||||||
|
};
|
||||||
|
const jwt = jsonwebtoken.sign( payload , jwtSecret );
|
||||||
|
return {
|
||||||
|
accessToken : jwt,
|
||||||
|
payload : payload,
|
||||||
|
session_token,
|
||||||
|
session_token_exp,
|
||||||
|
user : user
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = new ApplicationLogic();
|
||||||
9
server/src/Apps/Account/Ports/Events/index.js
Normal file
9
server/src/Apps/Account/Ports/Events/index.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
'use strict';
|
||||||
|
const App = require('../../App');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dictionary of event ids and handlers
|
||||||
|
*/
|
||||||
|
module.exports = {
|
||||||
|
// "event_id" : App.onEvent
|
||||||
|
};
|
||||||
38
server/src/Apps/Account/Ports/Interfaces/index.js
Normal file
38
server/src/Apps/Account/Ports/Interfaces/index.js
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const { toSha256 } = require('../../../../Shared/ShaUtils');
|
||||||
|
|
||||||
|
const { authentication } = require('../../../../../config/apiConfig.json');
|
||||||
|
|
||||||
|
const { genErrorResponse } = require('../../../../Shared/ErrorResponse');
|
||||||
|
|
||||||
|
const SharedResources = require('../../../../Shared/Resources');
|
||||||
|
|
||||||
|
function publishEvent( event , data = null ){
|
||||||
|
const EventBus = SharedResources.get("SysS:EventManager");
|
||||||
|
const AppEventDomain = "App:Account:"
|
||||||
|
const event_id = AppEventDomain + event;
|
||||||
|
|
||||||
|
console.log( event_id );
|
||||||
|
EventBus.publishEvent( event_id , data );
|
||||||
|
}
|
||||||
|
|
||||||
|
const tokenSecret = authentication.tokenSecret;
|
||||||
|
const jwtRenewalTimeout = authentication.jwtRenewalTimeout;
|
||||||
|
const jwtTimeout = authentication.jwtTimeout;
|
||||||
|
const jwtOptions = authentication.jwtOptions;
|
||||||
|
const jwtSecret = authentication.jwtSecret;
|
||||||
|
|
||||||
|
const pwdSecret = authentication.pwdSecret;
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
toSha256,
|
||||||
|
tokenSecret,
|
||||||
|
jwtRenewalTimeout,
|
||||||
|
jwtTimeout,
|
||||||
|
jwtOptions,
|
||||||
|
jwtSecret,
|
||||||
|
pwdSecret,
|
||||||
|
genErrorResponse,
|
||||||
|
publishEvent
|
||||||
|
};
|
||||||
3
server/src/Apps/Account/Ports/Public/index.js
Normal file
3
server/src/Apps/Account/Ports/Public/index.js
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.export = {};
|
||||||
76
server/src/Apps/Account/Repository/Objection/index.js
Normal file
76
server/src/Apps/Account/Repository/Objection/index.js
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const { getModel } = require('../../../../Shared/Models/Objection');
|
||||||
|
const Model = getModel('users');
|
||||||
|
const Sessions = getModel('users_sessions');
|
||||||
|
const Companies = getModel('companies');
|
||||||
|
|
||||||
|
class SpecificModelRepository{
|
||||||
|
constructor(){}
|
||||||
|
|
||||||
|
async populateCompany( user ){
|
||||||
|
if( user.company_id ){
|
||||||
|
const company = await Companies.query().findById( user.company_id );
|
||||||
|
user.company = company;
|
||||||
|
}else{
|
||||||
|
user.company = null;
|
||||||
|
}
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getByEmail( email ){
|
||||||
|
const user = await Model.query()
|
||||||
|
.select( "*" )
|
||||||
|
.where("email","=",email).first();
|
||||||
|
}
|
||||||
|
|
||||||
|
async createOne( email, safe_password ){
|
||||||
|
const user = await Model.query().insert({
|
||||||
|
email,
|
||||||
|
password : safe_password,
|
||||||
|
"name":"No name",
|
||||||
|
"last_name":"No lastname",
|
||||||
|
"createdAt" : new Date().toISOString()
|
||||||
|
});
|
||||||
|
return this.populateCompany( user );
|
||||||
|
}
|
||||||
|
|
||||||
|
async findByEmailPassword( email, safe_password ){
|
||||||
|
const user = await Model.query().select('*')
|
||||||
|
.where("email","=",email)
|
||||||
|
.where("password","=",safe_password)
|
||||||
|
.first();
|
||||||
|
return this.populateCompany( user );
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateSessionToken( old_token, token, expiration ){
|
||||||
|
const entry = await Sessions.query().select('*').where('token','=',old_token).first();
|
||||||
|
const data = {
|
||||||
|
token,
|
||||||
|
expiration,
|
||||||
|
};
|
||||||
|
if( entry ){
|
||||||
|
return await Sessions.query().patch( data ).where('token','=',old_token).first();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async addSessionToken( userId , token, expiration ){
|
||||||
|
const entry = await Sessions.query().select('*').where("user_id",'=',userId).first();
|
||||||
|
const data = {
|
||||||
|
token,
|
||||||
|
expiration : expiration.toISOString(),
|
||||||
|
};
|
||||||
|
if( entry ){
|
||||||
|
return await Sessions.query()
|
||||||
|
.findById( entry.id )
|
||||||
|
.patch(data);
|
||||||
|
}else{
|
||||||
|
data.user_id = userId;
|
||||||
|
return await Sessions.query().insert( data );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new SpecificModelRepository();
|
||||||
5
server/src/Apps/Account/Repository/index.js
Normal file
5
server/src/Apps/Account/Repository/index.js
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const SpecificModelRepository = require('./Objection');
|
||||||
|
|
||||||
|
module.exports = SpecificModelRepository;
|
||||||
8
server/src/Controller/index.js
Normal file
8
server/src/Controller/index.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
const express = require('express');
|
||||||
|
const app = express();
|
||||||
|
|
||||||
|
const account = require('../Apps/Account/Controller');
|
||||||
|
|
||||||
|
app.use('/account',account);
|
||||||
|
|
||||||
|
module.exports = app;
|
||||||
12
server/src/Shared/ErrorResponse.js
Normal file
12
server/src/Shared/ErrorResponse.js
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
function genErrorResponse( msg , code = 400 ){
|
||||||
|
return {
|
||||||
|
error : {
|
||||||
|
code,
|
||||||
|
msg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { genErrorResponse };
|
||||||
24
server/src/Shared/Models/Objection/companies.model.js
Normal file
24
server/src/Shared/Models/Objection/companies.model.js
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
'use strict';
|
||||||
|
const { Model } = require('objection');
|
||||||
|
|
||||||
|
class Companies extends Model {
|
||||||
|
static get tableName() { return 'companies'; }
|
||||||
|
static get idColumn() { return 'id'; }
|
||||||
|
static get jsonSchema() {
|
||||||
|
return {
|
||||||
|
type : 'object',
|
||||||
|
required : ['owner_id','type','is_hidden','is_active','name','description','createdAt'],
|
||||||
|
properties : {
|
||||||
|
owner_id : { type : 'integer', minimum : 0 },
|
||||||
|
type : { type : 'string' , enum : ['carrier', 'shipper'] },
|
||||||
|
is_hidden : { type : 'boolean', default : true },
|
||||||
|
is_active : { type : 'boolean', default : true },
|
||||||
|
name : { type : 'string', maxLength : 100 },
|
||||||
|
description : { type : 'string', maxLength : 256 },
|
||||||
|
createdAt : { type : 'date-time' }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Companies;
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
'use strict';
|
||||||
|
const { Model } = require('objection');
|
||||||
|
|
||||||
|
class CompanyCategories extends Model {
|
||||||
|
static get tableName() { return 'company_categories'; }
|
||||||
|
static get idColumn() { return 'id'; }
|
||||||
|
static get jsonSchema() {
|
||||||
|
return {
|
||||||
|
type : 'object',
|
||||||
|
required : ['company_id','category'],
|
||||||
|
properties : {
|
||||||
|
company_id : { type : 'integer', minimum : 0 },
|
||||||
|
category : { type : 'string', maxLength : 100 },
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = CompanyCategories;
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
'use strict';
|
||||||
|
const { Model } = require('objection');
|
||||||
|
|
||||||
|
class CompanyTruckTypes extends Model {
|
||||||
|
static get tableName() { return 'company_truck_types'; }
|
||||||
|
static get idColumn() { return 'id'; }
|
||||||
|
static get jsonSchema() {
|
||||||
|
return {
|
||||||
|
type : 'object',
|
||||||
|
required : ['company_id','truck_type'],
|
||||||
|
properties : {
|
||||||
|
company_id : { type : 'integer', minimum : 0 },
|
||||||
|
truck_type : { type : 'string', maxLength : 100 },
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = CompanyTruckTypes;
|
||||||
22
server/src/Shared/Models/Objection/index.js
Normal file
22
server/src/Shared/Models/Objection/index.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
const users = require('./users.model');
|
||||||
|
const user_sessions = require('./user_sessions.model');
|
||||||
|
const companies = require('./companies.model');
|
||||||
|
|
||||||
|
function getModel( name ){
|
||||||
|
switch( name ){
|
||||||
|
case 'users':
|
||||||
|
return users;
|
||||||
|
case 'users_sessions':
|
||||||
|
return user_sessions;
|
||||||
|
case 'companies':
|
||||||
|
return companies;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getModel
|
||||||
|
};
|
||||||
32
server/src/Shared/Models/Objection/load_attachments.model.js
Normal file
32
server/src/Shared/Models/Objection/load_attachments.model.js
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
'use strict';
|
||||||
|
const { Model } = require('objection');
|
||||||
|
|
||||||
|
class LoadAttachments extends Model {
|
||||||
|
static get tableName() { return 'load_attachments'; }
|
||||||
|
static get idColumn() { return 'id'; }
|
||||||
|
static get jsonSchema() {
|
||||||
|
return {
|
||||||
|
type : 'object',
|
||||||
|
required : [
|
||||||
|
'status',
|
||||||
|
'type',
|
||||||
|
'createdAt',
|
||||||
|
'updatedAt',
|
||||||
|
'doneAt'
|
||||||
|
],
|
||||||
|
properties : {
|
||||||
|
load_id : { type : 'integer' , minimum : 0 },
|
||||||
|
shipper_id : { type : 'integer' , minimum : 0 },
|
||||||
|
carrier_id : { type : 'integer' , minimum : 0 },
|
||||||
|
author_id : { type : 'integer' , minimum : 0 },
|
||||||
|
status : { type : 'string' , default : 'Draft', enum: ['Draft', 'Done'] },
|
||||||
|
type : { type : 'string' , enum: ['Draft', 'Done'] },
|
||||||
|
createdAt : { type : 'date-time' },
|
||||||
|
updatedAt : { type : 'date-time' },
|
||||||
|
doneAt : { type : 'date-time' }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = LoadAttachments;
|
||||||
19
server/src/Shared/Models/Objection/load_categories.model.js
Normal file
19
server/src/Shared/Models/Objection/load_categories.model.js
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
'use strict';
|
||||||
|
const { Model } = require('objection');
|
||||||
|
|
||||||
|
class LoadCategories extends Model {
|
||||||
|
static get tableName() { return 'load_categories'; }
|
||||||
|
static get idColumn() { return 'id'; }
|
||||||
|
static get jsonSchema() {
|
||||||
|
return {
|
||||||
|
type : 'object',
|
||||||
|
required : ['load_id','category_id'],
|
||||||
|
properties : {
|
||||||
|
load_id : { type : 'integer', minimum : 0 },
|
||||||
|
category_id : { type : 'integer', minimum : 0 },
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = LoadCategories;
|
||||||
60
server/src/Shared/Models/Objection/loads.model.js
Normal file
60
server/src/Shared/Models/Objection/loads.model.js
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
'use strict';
|
||||||
|
const { Model } = require('objection');
|
||||||
|
|
||||||
|
class Loads extends Model {
|
||||||
|
static get tableName() { return 'loads'; }
|
||||||
|
static get idColumn() { return 'id'; }
|
||||||
|
static get jsonSchema() {
|
||||||
|
return {
|
||||||
|
type : 'object',
|
||||||
|
required : [
|
||||||
|
'company_id',
|
||||||
|
'responsible_id',
|
||||||
|
'origin_country',
|
||||||
|
'origin_state',
|
||||||
|
'origin_city',
|
||||||
|
'origin_zipcode',
|
||||||
|
'origin_address_line1',
|
||||||
|
'destination_address_line1',
|
||||||
|
'updatedAt',
|
||||||
|
'createdAt',
|
||||||
|
'publication_status'
|
||||||
|
],
|
||||||
|
properties : {
|
||||||
|
company_id : { type : 'integer' , minimum : 0 },
|
||||||
|
responsible_id : { type : 'integer' , minimum : 0 },
|
||||||
|
truck_type : { type : 'string' , maxLength : 100 },
|
||||||
|
origin_country : { type : 'string' , default : 'Mexico', maxLength : 45 },
|
||||||
|
origin_state : { type : 'string' , maxLength : 45 },
|
||||||
|
origin_city : { type : 'string' , maxLength : 45 },
|
||||||
|
origin_zipcode : { type : 'string' , maxLength : 10 },
|
||||||
|
origin_lat : { type : 'string' , maxLength : 45 },
|
||||||
|
origin_lng : { type : 'string' , maxLength : 45 },
|
||||||
|
origin_address_line1 : { type : 'string' , maxLength : 100 },
|
||||||
|
origin_address_line2 : { type : 'string' , maxLength : 100 },
|
||||||
|
destination_country : { type : 'string' , maxLength : 45 },
|
||||||
|
destination_state : { type : 'string' , maxLength : 45 },
|
||||||
|
destination_city : { type : 'string' , maxLength : 45 },
|
||||||
|
destination_zipcode : { type : 'string' , maxLength : 10 },
|
||||||
|
destination_lat : { type : 'string' , maxLength : 45 },
|
||||||
|
destination_lng : { type : 'string' , maxLength : 45 },
|
||||||
|
destination_address_line1 : { type : 'string' , maxLength : 100 },
|
||||||
|
destination_address_line2 : { type : 'string' , maxLength : 100 },
|
||||||
|
weight : { type : 'number' , minimum : 0.0 },
|
||||||
|
est_loading_date : { type : 'date-time' },
|
||||||
|
est_unloading_date : { type : 'date-time' },
|
||||||
|
notes : { type : 'string', maxLength : 256 },
|
||||||
|
updatedAt : { type : 'date-time' },
|
||||||
|
createdAt : { type : 'date-time' },
|
||||||
|
publishedAt : { type : 'date-time' },
|
||||||
|
loadedAt : { type : 'date-time' },
|
||||||
|
transitAt : { type : 'date-time' },
|
||||||
|
deliveredAt : { type : 'date-time' },
|
||||||
|
publication_status : { type : 'string' , default : 'Draft', enum : ['Draft', 'Published', 'Completed', 'Closed'] },
|
||||||
|
status : { type : 'string', enum : ['Published', 'Loading', 'Transit', 'Downloading', 'Delivered'] }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Loads;
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
'use strict';
|
||||||
|
const { Model } = require('objection');
|
||||||
|
|
||||||
|
class LocationCategories extends Model {
|
||||||
|
static get tableName() { return 'location_categories'; }
|
||||||
|
static get idColumn() { return 'id'; }
|
||||||
|
static get jsonSchema() {
|
||||||
|
return {
|
||||||
|
type : 'object',
|
||||||
|
required : ['location_id','category_id'],
|
||||||
|
properties : {
|
||||||
|
location_id : { type : 'integer', minimum : 0 },
|
||||||
|
category_id : { type : 'integer', minimum : 0 },
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = LocationCategories;
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
'use strict';
|
||||||
|
const { Model } = require('objection');
|
||||||
|
|
||||||
|
class LocationTruckTypes extends Model {
|
||||||
|
static get tableName() { return 'location_truck_types'; }
|
||||||
|
static get idColumn() { return 'id'; }
|
||||||
|
static get jsonSchema() {
|
||||||
|
return {
|
||||||
|
type : 'object',
|
||||||
|
required : ['location_id','truck_type_id'],
|
||||||
|
properties : {
|
||||||
|
location_id : { type : 'integer', minimum : 0 },
|
||||||
|
truck_type_id : { type : 'integer', minimum : 0 },
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = LocationTruckTypes;
|
||||||
25
server/src/Shared/Models/Objection/locations.model.js
Normal file
25
server/src/Shared/Models/Objection/locations.model.js
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
'use strict';
|
||||||
|
const { Model } = require('objection');
|
||||||
|
|
||||||
|
class Locations extends Model {
|
||||||
|
static get tableName() { return 'locations'; }
|
||||||
|
static get idColumn() { return 'id'; }
|
||||||
|
static get jsonSchema() {
|
||||||
|
return {
|
||||||
|
type : 'object',
|
||||||
|
required : ['company_id','type','state','city','country','zipcode','address_line1'],
|
||||||
|
properties : {
|
||||||
|
company_id : { type : 'integer', minimum : 0 },
|
||||||
|
type : { type : 'string' , enum : ['loading', 'unloading', 'both'] },
|
||||||
|
state : { type : 'string', maxLength : 45 },
|
||||||
|
city : { type : 'string', maxLength : 45 },
|
||||||
|
country : { type : 'string', maxLength : 45 },
|
||||||
|
zipcode : { type : 'string', maxLength : 10 },
|
||||||
|
address_line1 : { type : 'string', maxLength : 100 },
|
||||||
|
address_line2 : { type : 'string', maxLength : 100 }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Users;
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use strict';
|
||||||
|
const { Model } = require('objection');
|
||||||
|
|
||||||
|
class MetadataCategories extends Model {
|
||||||
|
static get tableName() { return 'metadata_categories'; }
|
||||||
|
static get idColumn() { return 'id'; }
|
||||||
|
static get jsonSchema() {
|
||||||
|
return {
|
||||||
|
type : 'object',
|
||||||
|
required : ['category'],
|
||||||
|
properties : {
|
||||||
|
category: { type: 'string', maxLength: 100 },
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = MetadataCategories;
|
||||||
21
server/src/Shared/Models/Objection/metadata_cities.model.js
Normal file
21
server/src/Shared/Models/Objection/metadata_cities.model.js
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
'use strict';
|
||||||
|
const { Model } = require('objection');
|
||||||
|
|
||||||
|
class MetadataCities extends Model {
|
||||||
|
static get tableName() { return 'metadata_cities'; }
|
||||||
|
static get idColumn() { return 'id'; }
|
||||||
|
static get jsonSchema() {
|
||||||
|
return {
|
||||||
|
type : 'object',
|
||||||
|
required : ['city','state','country'],
|
||||||
|
properties : {
|
||||||
|
city: { type: 'string', maxLength: 100 },
|
||||||
|
state: { type: 'string', maxLength: 100 },
|
||||||
|
country: { type: 'string', maxLength: 100 },
|
||||||
|
zipcode: { type: 'string', maxLength: 100 },
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = MetadataCities;
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use strict';
|
||||||
|
const { Model } = require('objection');
|
||||||
|
|
||||||
|
class MetadataProducts extends Model {
|
||||||
|
static get tableName() { return 'metadata_products'; }
|
||||||
|
static get idColumn() { return 'id'; }
|
||||||
|
static get jsonSchema() {
|
||||||
|
return {
|
||||||
|
type : 'object',
|
||||||
|
required : ['type'],
|
||||||
|
properties : {
|
||||||
|
product: { type: 'string', maxLength: 100 },
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = MetadataProducts;
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use strict';
|
||||||
|
const { Model } = require('objection');
|
||||||
|
|
||||||
|
class MetadataTruckTypes extends Model {
|
||||||
|
static get tableName() { return 'metadata_truck_types'; }
|
||||||
|
static get idColumn() { return 'id'; }
|
||||||
|
static get jsonSchema() {
|
||||||
|
return {
|
||||||
|
type : 'object',
|
||||||
|
required : ['type'],
|
||||||
|
properties : {
|
||||||
|
truck_type: { type: 'string', maxLength: 100 },
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = MetadataTruckTypes;
|
||||||
36
server/src/Shared/Models/Objection/user_locations.model.js
Normal file
36
server/src/Shared/Models/Objection/user_locations.model.js
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
'use strict';
|
||||||
|
const { Model } = require('objection');
|
||||||
|
|
||||||
|
class Users extends Model {
|
||||||
|
static get tableName() { return 'users'; }
|
||||||
|
static get idColumn() { return 'id'; }
|
||||||
|
static get jsonSchema() {
|
||||||
|
return {
|
||||||
|
type : 'object',
|
||||||
|
required : [
|
||||||
|
'email',
|
||||||
|
'password',
|
||||||
|
'name',
|
||||||
|
'last_name',
|
||||||
|
'job_role',
|
||||||
|
'permissions',
|
||||||
|
'createdAt',
|
||||||
|
'is_active'
|
||||||
|
],
|
||||||
|
properties : {
|
||||||
|
company_id : { type : 'integer' , minimum : 0 },
|
||||||
|
phone: { type: 'string' , maxLength : 45 },
|
||||||
|
email : { type : 'string' , maxLength : 254 },
|
||||||
|
password : { type : 'string' , maxLength : 64 },
|
||||||
|
name : { type : 'string' , maxLength : 45 },
|
||||||
|
last_name : { type : 'string', maxLength : 100 },
|
||||||
|
job_role: { type: 'string', default : 'limited', enum : ['owner', 'manager', 'staff', 'driver', 'limited'] },
|
||||||
|
permissions: { type: 'string', default: 'limited', enum : ['carrier', 'shipper', 'limited'] },
|
||||||
|
createdAt: { type : 'date-time' },
|
||||||
|
is_active : { type : 'boolean', default : true }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Users;
|
||||||
20
server/src/Shared/Models/Objection/user_sessions.model.js
Normal file
20
server/src/Shared/Models/Objection/user_sessions.model.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
'use strict';
|
||||||
|
const { Model } = require('objection');
|
||||||
|
|
||||||
|
class UserSessions extends Model {
|
||||||
|
static get tableName() { return 'user_sessions'; }
|
||||||
|
static get idColumn() { return 'id'; }
|
||||||
|
static get jsonSchema() {
|
||||||
|
return {
|
||||||
|
type : 'object',
|
||||||
|
required : ['user_id','token','expiration'],
|
||||||
|
properties : {
|
||||||
|
user_id : { type : 'integer' , minimum : 0 },
|
||||||
|
token: { type: 'string' , maxLength : 256 },
|
||||||
|
expiration: { type: 'string' },
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = UserSessions;
|
||||||
36
server/src/Shared/Models/Objection/users.model.js
Normal file
36
server/src/Shared/Models/Objection/users.model.js
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
'use strict';
|
||||||
|
const { Model } = require('objection');
|
||||||
|
|
||||||
|
class Users extends Model {
|
||||||
|
static get tableName() { return 'users'; }
|
||||||
|
static get idColumn() { return 'id'; }
|
||||||
|
static get jsonSchema() {
|
||||||
|
return {
|
||||||
|
type : 'object',
|
||||||
|
required : [
|
||||||
|
'email',
|
||||||
|
'password',
|
||||||
|
'name',
|
||||||
|
'last_name',
|
||||||
|
'job_role',
|
||||||
|
'permissions',
|
||||||
|
'createdAt',
|
||||||
|
'is_active'
|
||||||
|
],
|
||||||
|
properties : {
|
||||||
|
company_id : { type : 'integer' , minimum : 0 },
|
||||||
|
phone: { type: 'string' , maxLength : 45 },
|
||||||
|
email : { type : 'string' , maxLength : 254 },
|
||||||
|
password : { type : 'string' , maxLength : 64 },
|
||||||
|
name : { type : 'string' , maxLength : 45 },
|
||||||
|
last_name : { type : 'string', maxLength : 100 },
|
||||||
|
job_role: { type: 'string', default : 'limited', enum : ['owner', 'manager', 'staff', 'driver', 'limited'] },
|
||||||
|
permissions: { type: 'string', default: 'limited', enum : ['carrier', 'shipper', 'limited'] },
|
||||||
|
createdAt: { type: "string" },
|
||||||
|
is_active : { type : 'boolean', default : true }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Users;
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
'use strict';
|
||||||
|
const { Model } = require('objection');
|
||||||
|
|
||||||
|
class VehiclePublications extends Model {
|
||||||
|
static get tableName() { return 'vehicle_publications'; }
|
||||||
|
static get idColumn() { return 'id'; }
|
||||||
|
static get jsonSchema() {
|
||||||
|
return {
|
||||||
|
type : 'object',
|
||||||
|
required : [
|
||||||
|
'vehicle_id',
|
||||||
|
'published_by',
|
||||||
|
'published_date',
|
||||||
|
'destination',
|
||||||
|
'is_available',
|
||||||
|
'is_hidden',
|
||||||
|
],
|
||||||
|
properties : {
|
||||||
|
vehicle_id : { type : 'integer' , minimum : 0 },
|
||||||
|
published_by : { type : 'integer' , minimum : 0 },
|
||||||
|
published_date : { type : 'date-time' },
|
||||||
|
destination : { type : 'string' , maxLength : 45 },
|
||||||
|
is_available : { type: 'boolean' , default : false },
|
||||||
|
is_hidden : { type: 'boolean' , default : true },
|
||||||
|
available_date : { type : 'date-time' },
|
||||||
|
notes : { type: 'string' , maxLength : 256 },
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = VehiclePublications;
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
'use strict';
|
||||||
|
const { Model } = require('objection');
|
||||||
|
|
||||||
|
class LoadCategories extends Model {
|
||||||
|
static get tableName() { return 'vehicle_categories'; }
|
||||||
|
static get idColumn() { return 'id'; }
|
||||||
|
static get jsonSchema() {
|
||||||
|
return {
|
||||||
|
type : 'object',
|
||||||
|
required : ['vehicle_id','category_id'],
|
||||||
|
properties : {
|
||||||
|
vehicle_id : { type : 'integer', minimum : 0 },
|
||||||
|
category_id : { type : 'integer', minimum : 0 },
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = LoadCategories;
|
||||||
34
server/src/Shared/Models/Objection/vehicles.model.js
Normal file
34
server/src/Shared/Models/Objection/vehicles.model.js
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
'use strict';
|
||||||
|
const { Model } = require('objection');
|
||||||
|
|
||||||
|
class Vehicles extends Model {
|
||||||
|
static get tableName() { return 'vehicles'; }
|
||||||
|
static get idColumn() { return 'id'; }
|
||||||
|
static get jsonSchema() {
|
||||||
|
return {
|
||||||
|
type : 'object',
|
||||||
|
required : [
|
||||||
|
'company_id',
|
||||||
|
'background_tracking',
|
||||||
|
'status',
|
||||||
|
'createdAt'
|
||||||
|
],
|
||||||
|
properties : {
|
||||||
|
company_id : { type : 'integer' , minimum : 0 },
|
||||||
|
VIN : { type: 'string', maxLength : 20 },
|
||||||
|
circulation_serial_number : { type: 'string', maxLength : 100 },
|
||||||
|
truck_type : { type: 'string', maxLength : 100 },
|
||||||
|
background_tracking: { type: 'boolean' , default : false },
|
||||||
|
status: { type: 'string', default : 'Free', enum : ['Free', 'Loading', 'Transit', 'Downloading'] },
|
||||||
|
last_location_lat : { type: 'string', maxLength : 45 },
|
||||||
|
last_location_lng : { type: 'string', maxLength : 45 },
|
||||||
|
last_location_time : { type : 'date-time' },
|
||||||
|
active_load : { type : 'integer' , minimum : 0 },
|
||||||
|
active_driver : { type : 'integer' , minimum : 0 },
|
||||||
|
createdAt: { type : 'date-time' },
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Vehicles;
|
||||||
38
server/src/Shared/Resources/index.js
Normal file
38
server/src/Shared/Resources/index.js
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
class SharedResources{
|
||||||
|
constructor(){
|
||||||
|
this.dictionary = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
set( key , val ){
|
||||||
|
this.dictionary[ key ] = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
exists( key ){
|
||||||
|
return ( this.dictionary[ key ] != undefined );
|
||||||
|
}
|
||||||
|
|
||||||
|
get( key ){
|
||||||
|
if( ! this.exists( key ) ){
|
||||||
|
throw new Error( `Key [${key}] not defined!` );
|
||||||
|
}
|
||||||
|
return this.dictionary[ key ];
|
||||||
|
}
|
||||||
|
|
||||||
|
try_get( key ){
|
||||||
|
if( ! this.exists( key ) ){
|
||||||
|
return null;
|
||||||
|
}else{
|
||||||
|
return this.dictionary[ key ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
remove( key ){
|
||||||
|
if( this.exists(key) ){
|
||||||
|
delete this.dictionary[ key ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new SharedResources();
|
||||||
12
server/src/Shared/ShaUtils.js
Normal file
12
server/src/Shared/ShaUtils.js
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
"use strict";
|
||||||
|
const crypto = require('crypto');
|
||||||
|
/**
|
||||||
|
* Convert string to sha256 string in hex
|
||||||
|
* @param {*} text
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
function toSha256( text ){
|
||||||
|
return crypto.createHmac( "sha256" , "" ).update( text ).digest( 'hex' );
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { toSha256 };
|
||||||
68
server/src/SysS/Connections/index.js
Normal file
68
server/src/SysS/Connections/index.js
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
'use strict';
|
||||||
|
const apiConfig = require( '../../../config/apiConfig.json' );
|
||||||
|
const Knex = require('knex');
|
||||||
|
const { Model } = require('objection');
|
||||||
|
|
||||||
|
const UNINIT = 0;
|
||||||
|
const INIT = 1;
|
||||||
|
const ONLINE = 2;
|
||||||
|
const OFFLINE = 3;
|
||||||
|
|
||||||
|
class SystemServices {
|
||||||
|
constructor(){
|
||||||
|
this.SystemServiceState = UNINIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
async setup(){
|
||||||
|
this.SystemServiceState = UNINIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
async init(){
|
||||||
|
this.SystemServiceState = INIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
async connect(){
|
||||||
|
const knex = Knex({
|
||||||
|
client: 'mysql',
|
||||||
|
useNullAsDefault: true,
|
||||||
|
connection: {
|
||||||
|
host: apiConfig.sql.host,
|
||||||
|
port: apiConfig.sql.port,
|
||||||
|
user: apiConfig.sql.user,
|
||||||
|
password: apiConfig.sql.password,
|
||||||
|
database: apiConfig.sql.database,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Model.knex(knex);
|
||||||
|
this.knex = knex;
|
||||||
|
console.log("Connected to SQL");
|
||||||
|
this.SystemServiceState = ONLINE;
|
||||||
|
}
|
||||||
|
|
||||||
|
async disconnect(){
|
||||||
|
this.knex.destroy();
|
||||||
|
|
||||||
|
this.SystemServiceState = OFFLINE;
|
||||||
|
}
|
||||||
|
|
||||||
|
async deinit(){
|
||||||
|
this.SystemServiceState = UNINIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getState(){
|
||||||
|
switch( this.SystemServiceState ){
|
||||||
|
case UNINIT:
|
||||||
|
return "UNINIT";
|
||||||
|
case INIT:
|
||||||
|
return "INIT";
|
||||||
|
case ONLINE:
|
||||||
|
return "ONLINE";
|
||||||
|
case OFFLINE:
|
||||||
|
return "OFFLINE";
|
||||||
|
default:
|
||||||
|
return "UNINIT";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new SystemServices();
|
||||||
132
server/src/SysS/Controller/index.js
Normal file
132
server/src/SysS/Controller/index.js
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
'use strict';
|
||||||
|
/**
|
||||||
|
* ExpressJS Controller
|
||||||
|
*/
|
||||||
|
require('dotenv').config();
|
||||||
|
const express = require('express');
|
||||||
|
const cors = require('cors');
|
||||||
|
const compression = require('compression');
|
||||||
|
const morgan = require('morgan');
|
||||||
|
const helmet = require('helmet');
|
||||||
|
const bodyParser = require('body-parser');
|
||||||
|
const fileUpload = require('express-fileupload');
|
||||||
|
|
||||||
|
/// Import Applications to serve
|
||||||
|
const AppsController = require('../../Controller');
|
||||||
|
const middlewares = require('./middlewares');
|
||||||
|
|
||||||
|
const UNINIT = 0;
|
||||||
|
const INIT = 1;
|
||||||
|
const ONLINE = 2;
|
||||||
|
const OFFLINE = 3;
|
||||||
|
|
||||||
|
class ExpressJSServices {
|
||||||
|
constructor(){
|
||||||
|
this.SystemServiceState = UNINIT;
|
||||||
|
this.serverPort = process.env.SERVER_PORT || 3000;
|
||||||
|
this.app = express();
|
||||||
|
}
|
||||||
|
|
||||||
|
async setup(){
|
||||||
|
const app = this.app;
|
||||||
|
|
||||||
|
app.use( middlewares.Auth );
|
||||||
|
|
||||||
|
app.use(
|
||||||
|
fileUpload({
|
||||||
|
limits: { fileSize: 4 * 1024 * 1024 },
|
||||||
|
abortOnLimit: true,
|
||||||
|
limitHandler: (req,res,next) => {
|
||||||
|
req.limitSize = true;
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
app.use((req, res, next) => {
|
||||||
|
if (req.limitSize) {
|
||||||
|
res.status(413).send({message:"File size limit has been reached",status:"PAYLOAD_TOO_LARGE"});
|
||||||
|
}else{
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
app.use(bodyParser.urlencoded({ extended: true, limit: '50mb' }));
|
||||||
|
app.use(bodyParser.json({ limit: '50mb' }));
|
||||||
|
app.use(morgan('dev'));
|
||||||
|
|
||||||
|
app.use(helmet({
|
||||||
|
crossOriginResourcePolicy: false
|
||||||
|
}));
|
||||||
|
|
||||||
|
app.use(compression());
|
||||||
|
|
||||||
|
app.use(cors({
|
||||||
|
origin: '*',
|
||||||
|
methods: [
|
||||||
|
'GET',
|
||||||
|
'POST',
|
||||||
|
'PATCH',
|
||||||
|
'PUT',
|
||||||
|
'DELETE'
|
||||||
|
],
|
||||||
|
allowedHeaders: ['Content-Type', 'Authorization']
|
||||||
|
}));
|
||||||
|
|
||||||
|
this.SystemServiceState = UNINIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
async init(){
|
||||||
|
const app = this.app;
|
||||||
|
|
||||||
|
app.use( middlewares.errorJSON );
|
||||||
|
app.use( AppsController );
|
||||||
|
app.use( middlewares.error404 );
|
||||||
|
|
||||||
|
this.SystemServiceState = INIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
async connect(){
|
||||||
|
const app = this.app;
|
||||||
|
const serverPort = this.serverPort;
|
||||||
|
|
||||||
|
const server = app.listen( serverPort , function(err){
|
||||||
|
if( !err ){
|
||||||
|
console.log('API listen on port', serverPort );
|
||||||
|
}else{
|
||||||
|
console.log( err );
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.server = server;
|
||||||
|
|
||||||
|
this.SystemServiceState = ONLINE;
|
||||||
|
}
|
||||||
|
|
||||||
|
async disconnect(){
|
||||||
|
this.server.close();
|
||||||
|
|
||||||
|
this.SystemServiceState = OFFLINE;
|
||||||
|
}
|
||||||
|
|
||||||
|
async deinit(){
|
||||||
|
this.SystemServiceState = UNINIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getState(){
|
||||||
|
switch( this.SystemServiceState ){
|
||||||
|
case UNINIT:
|
||||||
|
return "UNINIT";
|
||||||
|
case INIT:
|
||||||
|
return "INIT";
|
||||||
|
case ONLINE:
|
||||||
|
return "ONLINE";
|
||||||
|
case OFFLINE:
|
||||||
|
return "OFFLINE";
|
||||||
|
default:
|
||||||
|
return "UNINIT";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new ExpressJSServices();
|
||||||
87
server/src/SysS/Controller/middlewares.js
Normal file
87
server/src/SysS/Controller/middlewares.js
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
'use strict';
|
||||||
|
/**
|
||||||
|
* HASH
|
||||||
|
*****************************************************
|
||||||
|
* DEPENDENCIES
|
||||||
|
*****************************************************
|
||||||
|
* Based on Express Framework
|
||||||
|
* System
|
||||||
|
*****************************************************
|
||||||
|
* PUBLIC METHODS
|
||||||
|
*****************************************************
|
||||||
|
* Auth( req, res, next)
|
||||||
|
* Extract JWT or BasicAuth data
|
||||||
|
* errorJSON( error , request , response , next )
|
||||||
|
* Generate error response on bad JSON format
|
||||||
|
* error404( request , response , next )
|
||||||
|
* Generate error 404 response
|
||||||
|
* apiKey( request , response , next )
|
||||||
|
* Generate error on invalid apikey
|
||||||
|
**/
|
||||||
|
|
||||||
|
/// Extract JWT or BasicAuth
|
||||||
|
function Auth( req, res , next ){
|
||||||
|
///
|
||||||
|
/// Try to extract the authorization data from headers
|
||||||
|
///
|
||||||
|
let auth;
|
||||||
|
if( req.headers.hasOwnProperty( "authorization" ) ){
|
||||||
|
auth = req.headers.authorization;
|
||||||
|
auth = auth.split(" ")[1];
|
||||||
|
if( !auth ){ console.log( "NO HEADER AUTH available" ); return next(); }
|
||||||
|
//console.log( auth );
|
||||||
|
/// Try BasicAuth {
|
||||||
|
try{
|
||||||
|
let ba = Buffer.from( auth , 'base64' ).toString()
|
||||||
|
//const [user,pass] = ba.split(':');
|
||||||
|
ba = ba.split(':');
|
||||||
|
if( ba.length == 2 ){
|
||||||
|
req.basicAuth = { user : ba[0] , password : ba[1] };
|
||||||
|
}
|
||||||
|
}catch(error){
|
||||||
|
console.log("MIDDLEWARE_AUTH_ERR_BA",error);
|
||||||
|
}
|
||||||
|
/// Try BasicAuth }
|
||||||
|
}else if( req.query.access_token ){
|
||||||
|
auth = req.query.access_token;
|
||||||
|
if( !auth ){ console.log( "NO QUERY AUTH available" ); return next(); }
|
||||||
|
}
|
||||||
|
if( auth ){
|
||||||
|
/// Try JWT {
|
||||||
|
try{
|
||||||
|
let jwt = auth.split(".");
|
||||||
|
if( jwt.length == 3 ){
|
||||||
|
req.JWT = {};
|
||||||
|
req.JWT.raw = auth;
|
||||||
|
}
|
||||||
|
}catch( error ){
|
||||||
|
console.log("MIDDLEWARE_AUTH_ERR_JWT",error);
|
||||||
|
}
|
||||||
|
/// Try JWT }
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
|
||||||
|
function errorJSON( error , request , response , next ){
|
||||||
|
console.log(error);
|
||||||
|
if( error !== null ){
|
||||||
|
/// For body-parser errors
|
||||||
|
if( error instanceof SyntaxError && error.status === 400 && 'body' in error ){
|
||||||
|
return response.status(400).json({ error : 'Invalid json' , code : 400 });
|
||||||
|
}
|
||||||
|
/// For any error
|
||||||
|
return response.status(500).send( { error: "Internal server error" , code : 500 } );
|
||||||
|
}else{
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function error404( request , response , next ){
|
||||||
|
return response.status(404).send( { error : "Page not found", code : 404 } );
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Auth,
|
||||||
|
errorJSON,
|
||||||
|
error404,
|
||||||
|
};
|
||||||
84
server/src/SysS/EventManager/EmailEvents/SendGrid.handler.js
Normal file
84
server/src/SysS/EventManager/EmailEvents/SendGrid.handler.js
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
'user strict';
|
||||||
|
const apiConfig = require( '../../../../config/apiConfig.json' );
|
||||||
|
const nodemailer = require("nodemailer");
|
||||||
|
const SendGrid = require("nodemailer-sendgrid");
|
||||||
|
|
||||||
|
const SiteName = "ETA Viaporte";
|
||||||
|
|
||||||
|
const sendgridConfig = apiConfig.sendgrid;
|
||||||
|
|
||||||
|
const transporter = nodemailer.createTransport(
|
||||||
|
SendGrid({
|
||||||
|
host: sendgridConfig.HOST,
|
||||||
|
apiKey: sendgridConfig.API_KEY
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
async function sendMailTemplate( templateId, receiver, subject, content ){
|
||||||
|
/**TODO: Remove in production */
|
||||||
|
const default_mail_list = [
|
||||||
|
{pattern:"testing@etaviaporte.com",redirect:"testing@etaviaporte.com"},
|
||||||
|
{pattern:"alex@etaviaporte.com",redirect:"alexandro_uribe@outlook.com"},
|
||||||
|
{pattern:"pablo@etaviaporte.com",redirect:"josepablo134@gmail.com"}
|
||||||
|
];
|
||||||
|
for( let i=0; i< default_mail_list.length; i++ ){
|
||||||
|
if( receiver.indexOf( default_mail_list[i].pattern ) >= 0 ){
|
||||||
|
receiver = default_mail_list[i].redirect;
|
||||||
|
break;/** Set only the first match */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return await transporter.sendMail({
|
||||||
|
from: sendgridConfig.FROM,
|
||||||
|
to: receiver,
|
||||||
|
subject: subject,
|
||||||
|
templateId: templateId,
|
||||||
|
dynamic_template_data: content
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function AccountVerifyEmail( receiver , content ){
|
||||||
|
const templateId = "d-e9b7966303694964a64b6e4954e9715d";
|
||||||
|
const subject = "[ETA] Account Verification";
|
||||||
|
const content_to_send = {
|
||||||
|
project_name: SiteName,
|
||||||
|
user_name: content.user_name,
|
||||||
|
user_email: receiver,
|
||||||
|
OTP : content.OTP
|
||||||
|
};
|
||||||
|
return await sendMailTemplate( templateId, receiver, subject, content_to_send );
|
||||||
|
}
|
||||||
|
|
||||||
|
async function AccountConfirmed( receiver, content ){
|
||||||
|
const templateId = "d-4daaab1b85d443ceba38826f606e9931";
|
||||||
|
const subject = "[ETA] Welcome to ETA";
|
||||||
|
const content_to_send = {
|
||||||
|
user_name: content.user_name,
|
||||||
|
};
|
||||||
|
return await sendMailTemplate( templateId, receiver, subject, content_to_send );
|
||||||
|
}
|
||||||
|
|
||||||
|
async function AccountPwdResetEmail( receiver, content ){
|
||||||
|
const templateId = "d-e9b7966303694964a64b6e4954e9715d";
|
||||||
|
const subject = "[ETA] Password Reset";
|
||||||
|
const content_to_send = {
|
||||||
|
project_name: SiteName,
|
||||||
|
user_name: content.user_name,
|
||||||
|
user_email: receiver,
|
||||||
|
OTP : content.OTP
|
||||||
|
};
|
||||||
|
return await sendMailTemplate( templateId, receiver, subject, content_to_send );
|
||||||
|
}
|
||||||
|
|
||||||
|
async function ContactEmail( receiver, content ){
|
||||||
|
const templateId = "d-1090dda1091442f3a75ee8ab39ad0f10";
|
||||||
|
const subject = "[ETA] Contact Email";
|
||||||
|
const content_to_send = {
|
||||||
|
project_name: SiteName,
|
||||||
|
user_name: content.name,
|
||||||
|
user_email: receiver
|
||||||
|
};
|
||||||
|
return await sendMailTemplate( templateId, receiver, subject, content_to_send );
|
||||||
|
}
|
||||||
|
//ContactEmail( "josepablo134@gmail.com", { email : "josepablo134@gmail.com", name:"Josepablo C.", message: "This is an example" } ).then().catch();
|
||||||
|
|
||||||
|
module.exports = { AccountVerifyEmail, AccountConfirmed, AccountPwdResetEmail, ContactEmail };
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
'user strict';
|
||||||
|
const nodemailer = require("nodemailer");
|
||||||
|
const apiConfig = require( '../../../../config/apiConfig.json' );
|
||||||
|
|
||||||
|
const transporter = nodemailer.createTransport(
|
||||||
|
apiConfig.email_standalone
|
||||||
|
);
|
||||||
|
|
||||||
|
async function StandAloneContactEmail( content ){
|
||||||
|
const default_from = apiConfig.email_standalone.auth.user;
|
||||||
|
const receiver = "support@etaviaporte.com";
|
||||||
|
const {name, email, message } = content;
|
||||||
|
return await transporter.sendMail({
|
||||||
|
from: `${name} <${default_from}>`,
|
||||||
|
to: receiver,
|
||||||
|
subject: "Contact Email From Landing Page",
|
||||||
|
text: `\n\n The following is an email from : ${email}\n\n\n` + message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//StandAloneContactEmail( { email : "josepablo134@gmail.com", name:"Josepablo C.", message: "This is an example" } ).then().catch();
|
||||||
|
|
||||||
|
module.exports = { StandAloneContactEmail };
|
||||||
36
server/src/SysS/EventManager/EmailEvents/index.js
Normal file
36
server/src/SysS/EventManager/EmailEvents/index.js
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const { StandAloneContactEmail } = require('./StandAlone.handler');
|
||||||
|
const { AccountVerifyEmail, AccountConfirmed, AccountPwdResetEmail, ContactEmail } = require('./SendGrid.handler');
|
||||||
|
|
||||||
|
async function onChecksumGeneration( data ){
|
||||||
|
console.log( data );
|
||||||
|
const receiver = data.email;
|
||||||
|
await AccountVerifyEmail( receiver, data );
|
||||||
|
}
|
||||||
|
|
||||||
|
async function onAccountConfirmed( data ){
|
||||||
|
const receiver = data.email;
|
||||||
|
await AccountConfirmed( receiver, data );
|
||||||
|
}
|
||||||
|
|
||||||
|
async function onPasswordReset( data ){
|
||||||
|
const receiver = data.email;
|
||||||
|
await AccountPwdResetEmail( receiver, data );
|
||||||
|
}
|
||||||
|
|
||||||
|
async function onContactFromWebPage( data ){
|
||||||
|
const receiver = data.email;
|
||||||
|
await StandAloneContactEmail( data );
|
||||||
|
await ContactEmail( receiver, data );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dictionary of event ids and handlers
|
||||||
|
*/
|
||||||
|
module.exports = {
|
||||||
|
"App:Account:getchecksum" : onChecksumGeneration,
|
||||||
|
"App:Account:signupconfirmed":onAccountConfirmed,
|
||||||
|
"App:Account:getchecksum:pwdreset":onPasswordReset,
|
||||||
|
"App:ContactEmail:getchecksum":onContactFromWebPage,
|
||||||
|
};
|
||||||
71
server/src/SysS/EventManager/index.js
Normal file
71
server/src/SysS/EventManager/index.js
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
'use strict';
|
||||||
|
const events = require('events');
|
||||||
|
const SharedResources = require('../../Shared/Resources');
|
||||||
|
|
||||||
|
const resources_list = require('./resources');
|
||||||
|
|
||||||
|
const UNINIT = 0;
|
||||||
|
const INIT = 1;
|
||||||
|
const ONLINE = 2;
|
||||||
|
const OFFLINE = 3;
|
||||||
|
|
||||||
|
class SystemServices {
|
||||||
|
constructor(){
|
||||||
|
this.resources = resources_list;
|
||||||
|
this.eventEmitter = new events.EventEmitter();
|
||||||
|
|
||||||
|
this.SystemServiceState = UNINIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
addEvent( event_id , callback ){
|
||||||
|
this.eventEmitter.on( event_id , callback );
|
||||||
|
}
|
||||||
|
|
||||||
|
publishEvent( event_id , data ){
|
||||||
|
this.eventEmitter.emit( event_id , data );
|
||||||
|
}
|
||||||
|
|
||||||
|
async setup(){
|
||||||
|
for ( const resource of this.resources ){
|
||||||
|
for ( const [key, value] of Object.entries( resource ) ) {
|
||||||
|
this.eventEmitter.on( key , value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.SystemServiceState = UNINIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
async init(){
|
||||||
|
SharedResources.set( "SysS:EventManager" , this );
|
||||||
|
this.SystemServiceState = INIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
async connect(){
|
||||||
|
this.SystemServiceState = ONLINE;
|
||||||
|
}
|
||||||
|
|
||||||
|
async disconnect(){
|
||||||
|
this.SystemServiceState = OFFLINE;
|
||||||
|
}
|
||||||
|
|
||||||
|
async deinit(){
|
||||||
|
this.SystemServiceState = UNINIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getState(){
|
||||||
|
switch( this.SystemServiceState ){
|
||||||
|
case UNINIT:
|
||||||
|
return "UNINIT";
|
||||||
|
case INIT:
|
||||||
|
return "INIT";
|
||||||
|
case ONLINE:
|
||||||
|
return "ONLINE";
|
||||||
|
case OFFLINE:
|
||||||
|
return "OFFLINE";
|
||||||
|
default:
|
||||||
|
return "UNINIT";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new SystemServices();
|
||||||
7
server/src/SysS/EventManager/resources.js
Normal file
7
server/src/SysS/EventManager/resources.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const EmailEvents = require('./EmailEvents');
|
||||||
|
|
||||||
|
module.exports = [
|
||||||
|
EmailEvents,
|
||||||
|
];
|
||||||
33
server/src/SysS/Template/index.js
Normal file
33
server/src/SysS/Template/index.js
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
'use strict';
|
||||||
|
const UNINIT = 0;
|
||||||
|
const INIT = 1;
|
||||||
|
const ONLINE = 2;
|
||||||
|
const OFFLINE = 3;
|
||||||
|
|
||||||
|
class SystemServices {
|
||||||
|
constructor(){
|
||||||
|
this.SystemServiceState = UNINIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
async setup(){
|
||||||
|
this.SystemServiceState = UNINIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
async init(){
|
||||||
|
this.SystemServiceState = INIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
async connect(){
|
||||||
|
this.SystemServiceState = ONLINE;
|
||||||
|
}
|
||||||
|
|
||||||
|
async disconnect(){
|
||||||
|
this.SystemServiceState = OFFLINE;
|
||||||
|
}
|
||||||
|
|
||||||
|
async deinit(){
|
||||||
|
this.SystemServiceState = UNINIT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new SystemServices();
|
||||||
78
server/src/SysS/index.js
Normal file
78
server/src/SysS/index.js
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
'use strict';
|
||||||
|
const EventManager = require('./EventManager');
|
||||||
|
const Connections = require('./Connections');
|
||||||
|
const Controller = require('./Controller');
|
||||||
|
|
||||||
|
const UNINIT = 0;
|
||||||
|
const INIT = 1;
|
||||||
|
const ONLINE = 2;
|
||||||
|
const OFFLINE = 3;
|
||||||
|
|
||||||
|
class SystemServices {
|
||||||
|
constructor(){
|
||||||
|
this.resources = [
|
||||||
|
EventManager,
|
||||||
|
Connections,
|
||||||
|
Controller,
|
||||||
|
];
|
||||||
|
|
||||||
|
this.SystemServiceState = UNINIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
async setup(){
|
||||||
|
for ( const service of this.resources ){
|
||||||
|
await service.setup();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.SystemServiceState = UNINIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
async init(){
|
||||||
|
for ( const service of this.resources ){
|
||||||
|
await service.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.SystemServiceState = INIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
async connect(){
|
||||||
|
for ( const service of this.resources ){
|
||||||
|
await service.connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.SystemServiceState = ONLINE;
|
||||||
|
}
|
||||||
|
|
||||||
|
async disconnect(){
|
||||||
|
for ( const service of this.resources ){
|
||||||
|
await service.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.SystemServiceState = OFFLINE;
|
||||||
|
}
|
||||||
|
|
||||||
|
async deinit(){
|
||||||
|
for ( const service of this.resources ){
|
||||||
|
await service.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.SystemServiceState = UNINIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getState(){
|
||||||
|
switch( this.SystemServiceState ){
|
||||||
|
case UNINIT:
|
||||||
|
return "UNINIT";
|
||||||
|
case INIT:
|
||||||
|
return "INIT";
|
||||||
|
case ONLINE:
|
||||||
|
return "ONLINE";
|
||||||
|
case OFFLINE:
|
||||||
|
return "OFFLINE";
|
||||||
|
default:
|
||||||
|
return "UNINIT";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new SystemServices();
|
||||||
32
server/src/index.js
Normal file
32
server/src/index.js
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
'use strict';
|
||||||
|
const process = require('node:process');
|
||||||
|
const SystemServices = require('./SysS');
|
||||||
|
|
||||||
|
async function main(){
|
||||||
|
await SystemServices.setup();
|
||||||
|
await SystemServices.init();
|
||||||
|
await SystemServices.connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
main()
|
||||||
|
.then( ( out ) => { if( out ){ console.log( out ); } } )
|
||||||
|
.catch( ( error ) => { if( error ){ console.error( error ); } } );
|
||||||
|
|
||||||
|
async function disconnect_server( code ){
|
||||||
|
if( await SystemServices.getState() !== "OFFLINE" ){
|
||||||
|
await SystemServices.disconnect();
|
||||||
|
console.log("Server disconnected with exit code : " , code );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
process.on('SIGINT', () => {
|
||||||
|
disconnect_server( "SIGINT" ).then( ()=>{} ).catch((error)=>{
|
||||||
|
console.error("Shutdown error", error);
|
||||||
|
})
|
||||||
|
} );
|
||||||
|
|
||||||
|
process.on('exit', (code) => {
|
||||||
|
disconnect_server( "exit:"+code ).then( ()=>{} ).catch((error)=>{
|
||||||
|
console.error("Shutdown error", error);
|
||||||
|
})
|
||||||
|
} );
|
||||||
18
server/test/index.js
Normal file
18
server/test/index.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
"use strict";
|
||||||
|
/// Unit testing dependences
|
||||||
|
const assert = require("assert");
|
||||||
|
const SharedResources = require('../src/Shared/SharedResources');
|
||||||
|
|
||||||
|
|
||||||
|
describe('Shared Resources' , () => {
|
||||||
|
it('Check key', async () => {
|
||||||
|
assert.equal( SharedResources.exists("test") , false );
|
||||||
|
|
||||||
|
SharedResources.set("test" , "This is a test value ");
|
||||||
|
assert.equal( SharedResources.exists("test") , true );
|
||||||
|
|
||||||
|
SharedResources.remove("test");
|
||||||
|
assert.equal( SharedResources.exists("test") , false );
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
Reference in New Issue
Block a user