feat: Split v1 and v2 apis

This commit is contained in:
Josepablo C
2024-08-05 15:33:23 -06:00
parent 49ee7d7b5a
commit c3f0b08cb7
149 changed files with 284 additions and 33 deletions

10
v1/src/apps/index.js Normal file
View File

@@ -0,0 +1,10 @@
const express = require('express');
const app = express();
const private = require('./private');
const public = require('./public');
app.use( public );
app.use( private );
module.exports = app;

View File

@@ -0,0 +1,7 @@
'use strict';
const router = require('express').Router();
const services= require('./services.js');
router.post('/register', services.register);
module.exports = router;

View File

@@ -0,0 +1,15 @@
"use strict";
const { ROOT_PATH, HANDLERS_PATH } = process.env;
const { complete_register } = require( `${ROOT_PATH}/${HANDLERS_PATH}/Account` );
const register = async( req, res ) => {
try{
const result = await complete_register( req.context.userId , req.body );
return res.send( result );
}catch( error ){
console.error( error );
return res.status( 500 ).send({ error });
}
}
module.exports = { register };

View File

@@ -0,0 +1,12 @@
'use strict';
const router = require('express').Router();
const services= require('./services.js');
router.get('/find', services.findList);
router.post('/new', services.postBranch);
router.patch('/:id', services.patchBranch);
router.delete('/:id', services.deleteBranch);
router.get('/:id', services.getById);
module.exports = router;

View File

@@ -0,0 +1,147 @@
"use strict";
const { ROOT_PATH, LIB_PATH, MODELS_PATH, HANDLERS_PATH } = process.env;
const { getModel } = require( `${ROOT_PATH}/${MODELS_PATH}` );
const { getPagination } = require( `${ROOT_PATH}/${LIB_PATH}/Misc.js` );
const { GenericHandler } = require( `${ROOT_PATH}/${HANDLERS_PATH}/Generic.handler.js` );
const Model = getModel('branches');
const populate_list = ['company', 'categories'];
const generic = new GenericHandler( Model, null, populate_list );
function getAndFilterList( query ){
const filter_list = [];
const { categories, branch_name, phone, city, state, truck_type } = query;
if( categories ) { filter_list.push({ categories }); }
if( branch_name ) { filter_list.push({ branch_name }); }
if( phone ) { filter_list.push({ phone }); }
if( city ) { filter_list.push({ city }); }
if( state ) { filter_list.push({ state }); }
if( truck_type ) { filter_list.push({ truck_type }); }
if( filter_list.length == 0 ){
return null;
}
return filter_list;
}
async function findElements( companyId , query ){
const { page, elements } = getPagination( query );
const andFilterList = getAndFilterList( query );
let filter;
if( andFilterList ){
andFilterList.push({ company : companyId });
filter = { $and : andFilterList };
}else{
filter = { company : companyId };
}
const { total , limit, skip, data } = await generic.getList( page , elements, filter );
const list_elements = data;
// for(let i=0; i<list_elements.length; i++){
// const item = list_elements[i].toObject();
// if (item.categories) {
// let categories = item.categories.map((c) => c.name);
// item._categories = categories.join(", ");
// }
// if (item.truck_type) {
// item._truck_types = item.truck_type.join(", ");
// }
// list_elements[i] = item;
// }
return {
total,
limit,
skip,
data:list_elements
};
}
async function findElementById( elementId , companyId ){
const filter = {
$and : [
{ _id : elementId },
{ company : companyId }
]
};
let retVal = await Model.findOne( filter ).populate( populate_list ) || {};
return retVal;
}
const findList = async(req, res) => {
try{
const query = req.query || {};
const companyId = req.context.companyId;
const retVal = await findElements( companyId , query );
res.send( retVal );
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
};
const getById = async(req, res) => {
try{
const companyId = req.context.companyId;
const elementId = req.params.id;
res.send( await findElementById( elementId , companyId ) );
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
};
const patchBranch = async(req, res) => {
try{
const companyId = req.context.companyId;
const elementId = req.params.id;
const data = req.body;
const branch = await findElementById( elementId , companyId );
if( !branch ){
throw "You can't modify this branch";
}
if( !data ){
throw "load data not sent";
}
data.company = companyId;
await Model.findByIdAndUpdate( elementId , data );
return res.send( await Model.findById( elementId ) );
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
};
const postBranch = async(req, res) => {
try{
const companyId = req.context.companyId;
const data = req.body;
if( !data ){
throw "Branch data not sent";
}
data.company = companyId;
const branch = new Model( data );
await branch.save();
return res.send( branch );
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
};
const deleteBranch = async(req, res) => {
try{
const companyId = req.context.companyId;
const elementId = req.params.id;
const element = await findElementById( elementId , companyId );
if(!element){
throw "You can't delete this branch";
}
await Model.findByIdAndDelete( elementId );
return res.send(element);
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
};
module.exports = { findList, getById, patchBranch, postBranch, deleteBranch };

View File

@@ -0,0 +1,12 @@
'use strict';
const router = require('express').Router();
const services= require('./services.js');
router.get('/find', services.findList);
router.post('/new', services.postBudget);
router.patch('/:id', services.patchBudget);
router.delete('/:id', services.deleteBudget);
router.get('/:id', services.getById);
module.exports = router;

View File

@@ -0,0 +1,178 @@
"use strict";
const { ROOT_PATH, LIB_PATH, MODELS_PATH, HANDLERS_PATH } = process.env;
const { getModel } = require( '../../../lib/Models' );
const { getPagination } = require( `${ROOT_PATH}/${LIB_PATH}/Misc.js` );
const { GenericHandler } = require( `${ROOT_PATH}/${HANDLERS_PATH}/Generic.handler.js` );
const Model = getModel('budgets');
const populate_list = ['company'];
const generic = new GenericHandler( Model, null, populate_list );
function getAndFilterList( query ){
const filter_list = [];
const {
client,
material,
origin,
destination,
truck_type,
num_tons,
price_per_ton,
tonnage,
pickup_distance,
delivery_distance,
warehouse_distance,
total_km_travel,
cost_per_liter,
fuel_price_per_liter,
other_fuel_expenses,
total_fuel_consumed,
total_cost_fuel,
driver_salary,
accomadation_allowance,
other_administrative_expenses,
total_before_tax,
total_utility_per_km,
total_profit,
profit_percentage,
total_administrative_expenses,
} = query;
if( client ) { filter_list.push({ client }); }
if( material ) { filter_list.push({ material }); }
if( origin ) { filter_list.push({ origin }); }
if( destination ) { filter_list.push({ destination }); }
if( truck_type ) { filter_list.push({ truck_type }); }
if( num_tons ) { filter_list.push({ num_tons }); }
if( price_per_ton ) { filter_list.push({ price_per_ton }); }
if( tonnage ) { filter_list.push({ tonnage }); }
if( pickup_distance ) { filter_list.push({ pickup_distance }); }
if( delivery_distance ) { filter_list.push({ delivery_distance }); }
if( warehouse_distance ) { filter_list.push({ warehouse_distance }); }
if( total_km_travel ) { filter_list.push({ total_km_travel }); }
if( cost_per_liter ) { filter_list.push({ cost_per_liter }); }
if( fuel_price_per_liter ) { filter_list.push({ fuel_price_per_liter }); }
if( other_fuel_expenses ) { filter_list.push({ other_fuel_expenses }); }
if( total_fuel_consumed ) { filter_list.push({ total_fuel_consumed }); }
if( total_cost_fuel ) { filter_list.push({ total_cost_fuel }); }
if( driver_salary ) { filter_list.push({ driver_salary }); }
if( accomadation_allowance ) { filter_list.push({ accomadation_allowance }); }
if( other_administrative_expenses ) { filter_list.push({ other_administrative_expenses }); }
if( total_before_tax ) { filter_list.push({ total_before_tax }); }
if( total_utility_per_km ) { filter_list.push({ total_utility_per_km }); }
if( total_profit ) { filter_list.push({ total_profit }); }
if( profit_percentage ) { filter_list.push({ profit_percentage }); }
if( total_administrative_expenses ) { filter_list.push({ total_administrative_expenses }); }
if( filter_list.length == 0 ){
return null;
}
return filter_list;
}
async function findElements( companyId , query ){
const { page, elements } = getPagination( query );
const andFilterList = getAndFilterList( query );
let filter;
if( andFilterList ){
andFilterList.push({ company : companyId });
filter = { $and : andFilterList };
}else{
filter = { company : companyId };
}
const { total , limit, skip, data } = await generic.getList( page , elements, filter );
return {
total,
limit,
skip,
data:data
};
}
async function findElementById( elementId , companyId ){
const filter = {
$and : [
{ _id : elementId },
{ company : companyId }
]
};
let retVal = await Model.findOne( filter ).populate( populate_list ) || {};
return retVal;
}
const findList = async(req, res) => {
try{
const query = req.query || {};
const companyId = req.context.companyId;
const retVal = await findElements( companyId , query );
res.send( retVal );
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
};
const getById = async(req, res) => {
try{
const companyId = req.context.companyId;
const elementId = req.params.id;
res.send( await findElementById( elementId , companyId ) );
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
};
const patchBudget = async(req, res) => {
try{
const elementId = req.params.id;
const budget = await Model.findById( elementId );
const data = req.body;
if( !budget ){
throw "You can't modify this budget";
}
if( !data ){
throw "budget data not sent";
}
await Model.findByIdAndUpdate( elementId , data );
return res.send( await Model.findById( elementId ) );
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
};
const postBudget = async(req, res) => {
try{
const companyId = req.context.companyId;
const data = req.body;
if( !data ){
throw "budget data not sent";
}
data.company = companyId;
const budget = new Model( data );
await budget.save();
return res.send( budget );
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
};
const deleteBudget = async(req, res) => {
try{
const elementId = req.params.id;
const budget = await Model.findById( elementId );
if(!budget){
throw "You can't delete this budget";
}
await Model.findByIdAndDelete( elementId );
return res.send(budget);
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
};
module.exports = { findList, getById, patchBudget, postBudget, deleteBudget };

View File

@@ -0,0 +1,15 @@
'use strict';
const router = require('express').Router();
const services= require('./services.js');
router.get('/own', services.getOwnCompany);
router.patch('/own', services.patchOwnCompany);
router.get('/shipper', services.getListShippers);
router.get('/carrier', services.getListCarriers);
router.get('/users/:companyId', services.getUserLists);
router.get('/:id', services.getCompanyById);
module.exports = router;

View File

@@ -0,0 +1,229 @@
"use strict";
const { ROOT_PATH, MODELS_PATH, HANDLERS_PATH, LIB_PATH } = process.env;
const { getModel } = require( `${ROOT_PATH}/${MODELS_PATH}` );
const { GenericHandler } = require( '../../../lib/Handlers/Generic.handler.js' );
const { getPagination } = require( `${ROOT_PATH}/${LIB_PATH}/Misc.js` );
const usersModel = getModel('users');
const companiesModel = getModel('companies');
const branchesModel = getModel('branches');
const vehiclesModel = getModel('vehicles');
const loadsModel = getModel('loads');
const productCategoriesModel = getModel('product_categories');
const populate_select = {
categories:"-_id name",
};
const generic = new GenericHandler( companiesModel, null, null , populate_select );
const user_generic = new GenericHandler( usersModel );
function join_field_list( obj_with_fields , list_of_fields )
{
for(let field_idx=0; field_idx < list_of_fields.length; field_idx++){
const field_name = list_of_fields[ field_idx ];
const new_field_name = "_" + list_of_fields[ field_idx ];
if( obj_with_fields[ field_name ] ){
obj_with_fields[ new_field_name ] = obj_with_fields[field_name].join(", ");
}
}
return obj_with_fields;
}
function getAndFilterList( query ){
const filter_list = [];
const { company_type, company_name, truck_type, categories, company_state, company_city } = query;
if( company_name ){ filter_list.push( { company_name } ); }
if( company_type ){ filter_list.push( { company_type } ); }
if( company_state ){ filter_list.push( { company_state } ); }
if( company_city ){ filter_list.push( { company_city } ); }
if( truck_type ){ filter_list.push( { truck_type } ); }
if( categories ){ filter_list.push( { categories } ); }
if( filter_list.length == 0 ){
return null;
}
return filter_list;
}
async function getListByType( type , req ){
const filter = { "company_type" : type , "is_hidden" : false };
const select = [
"rfc",
"company_name",
"company_type",
"company_code",
"company_city",
"company_state",
"createdAt",
"membership",
"categories",
"truck_type",
"company_description"
];
const { $sort } = req.query;
const { elements , page } = getPagination( req.query );
let query_elements;
if( elements >= 100 ){
query_elements = 100;// Never return more than 100 elements
}else{
query_elements = elements;
}
const andFilterList = getAndFilterList( req.query );
if( andFilterList ){
filter.$and = andFilterList;
}
const queryVal = await generic.getList(page , query_elements, filter, select, $sort );
const data_list = queryVal.data;
for(let i=0; i<data_list.length; i++){
data_list[i] = data_list[i].toObject();
data_list[i] = join_field_list( data_list[i] , ["company_city","company_state","truck_type"] );
let categories = data_list[i].categories.map( ( c ) => c.name);
data_list[i]._truck_types = data_list[i]._truck_type;
data_list[i]._categories = categories.join(", ");
/** Remove not requried fields */
delete data_list[i].categories;
delete data_list[i].company_city;
delete data_list[i].company_state;
delete data_list[i].truck_type;
delete data_list[i]._truck_type;
}
const retVal = {
total : queryVal.total,
limit : queryVal.limit,
skip : queryVal.skip,
data : data_list
};
return retVal;
}
async function getOwnCompany( req , res ) {
try{
const companyId = req.context.companyId;
const result = await companiesModel.findById( companyId )
.populate("categories" , "_id name")
.populate("company_city", "-_id name")
.populate("company_state", "-_id name")
.populate("truck_type", "-_id name");
return res.send( result );
}catch( error ){
console.error( error );
return res.status( 500 ).send({ error });
}
}
async function patchOwnCompany( req , res ) {
try{
const companyId = req.context.companyId;
const data = req.body;
if( data.company_type ){ delete data.company_type; }
await companiesModel.findByIdAndUpdate( companyId , data );
const result = await companiesModel.findById( companyId );
return res.send( result );
}catch( error ){
console.error( error );
return res.status( 500 ).send({ error });
}
}
async function getCompanyById( req , res ) {
try{
const companyId = req.params.id;
const result = await companiesModel.findById( companyId );
return res.send( result );
}catch( error ){
console.error( error );
return res.status( 500 ).send({ error });
}
}
async function getListShippers( req , res ) {
try{
const retVal = await getListByType( "Shipper" , req );
res.send( retVal );
}catch( error ){
console.error( error );
return res.status( 500 ).send({ error });
}
}
async function getListCarriers( req , res ) {
try{
const retVal = await getListByType( "Carrier" , req );
res.send( retVal );
}catch( error ){
console.error( error );
return res.status( 500 ).send({ error });
}
}
const getUserLists = async(req, res) => {
try{
const companyId = req.params.companyId;
const { elements, page } = getPagination( req.query );
let query_elements;
if( elements >= 100 ){
query_elements = 100;// Never return more than 100 elements
}else{
query_elements = elements;
}
const select = [
"first_name",
"middle_name",
"last_name",
"company",
"employe_id",
"phone",
"phone2",
"email",
"categories",
"user_city",
"user_state",
"truck_type"
];
const queryVal = await user_generic.getList(page , query_elements, { company : companyId }, select );
const data_list = queryVal.data;
for(let i=0; i<data_list.length; i++){
data_list[i] = data_list[i].toObject();
let name;
name = ( !data_list[i].first_name )? "" : data_list[i].first_name;
name += ( !data_list[i].middle_name )? "": " " + data_list[i].middle_name;
name += ( !data_list[i].last_name )? "": " " + data_list[i].last_name;
data_list[i].name = name;
data_list[i] = join_field_list( data_list[i] , ["categories","user_city","user_state","truck_type"] );
// let categories = data_list[i].categories.map( ( c ) => c.name);
/** Remove not requried fields */
delete data_list[i].categories;
delete data_list[i].user_city;
delete data_list[i].user_state;
delete data_list[i].truck_type;
}
const retVal = {
total : queryVal.total,
limit : queryVal.limit,
skip : queryVal.skip,
data : data_list
};
return res.status(200).send( retVal );
} catch ( err ){
console.error( err );
return res.status(500).send({ error : "Companies: Internal error" });
}
};
module.exports = {
getOwnCompany,
patchOwnCompany,
getCompanyById,
getListShippers,
getListCarriers,
getUserLists
};

View File

@@ -0,0 +1,45 @@
'use strict';
const { ROOT_PATH , LIB_PATH } = process.env;
/// Router instance
const router = require('express').Router();
const jwtValidator = require( `${ROOT_PATH}/${LIB_PATH}/jwtValidator.js` );
const context = require( './lib/context' );
const account = require('./account/routes.js');
const budgets = require('./budgets/routes.js')
const branches = require('./branches/routes.js');
const companies = require('./companies/routes.js');
const loadAttachments = require('./load-attachments/routes.js');
const loads = require('./loads/routes.js');
const proposals = require('./proposals/routes.js');
const users = require('./users/routes.js');
const vehicles = require('./vehicles/routes.js');
router.use( jwtValidator.middleware );
router.use( context.middleware );
router.use('/account', account);
router.use('/budgets', budgets);
router.use('/branches', branches);
router.use('/companies', companies);
router.use('/load-attachments', loadAttachments );
router.use('/loads', loads);
router.use('/proposals', proposals);
router.use('/users', users);
router.use('/vehicles', vehicles);
/*
router.use('/orders', test);
router.use('/mailer', test);
router.use('/memberships', test);
router.use('/bootresolvers', test);
router.use('/news', test);
router.use('/branches', test);
router.use('/trackings', test);
router.use('/upload', test);
router.use('/calendars', test);
router.use('/dashboard', test);
*/
module.exports = router;

View File

@@ -0,0 +1,23 @@
'use strict';
const { ROOT_PATH, MODELS_PATH } = process.env;
const { getModel } = require( `${ROOT_PATH}/${MODELS_PATH}` );
const usersModel = getModel('users');
async function middleware( req, res, next ){
if( ! req.JWT?.isValid ){
return res.status(401).send({error:"Unauthorized",code:401});
}
const userID = req.JWT.payload.sub;
req.context = {
user : await usersModel.findById( userID , { password : 0 , session_token : 0 , session_token_exp : 0 } ).populate('company')
}
req.context.userId = req.context.user.id;
req.context.companyId = req.context.user.company.id || null;
req.context.job_role = req.context.user.job_role || null;
req.context.permissions = req.context.user.permissions || null;
next();
}
module.exports = {
middleware
};

View File

@@ -0,0 +1,11 @@
'use strict';
const router = require('express').Router();
const services= require('./services.js');
router.post('/loading/:id', services.postLoadingAttachment );
router.post('/downloading/:id', services.postDownloadingAttachment );
router.get('/load/:id', services.getLoadAttachmentList );
router.get('/:id', services.getAttachment );
router.get('/', services.getAttachmentList );
module.exports = router;

View File

@@ -0,0 +1,164 @@
"use strict";
const { ROOT_PATH, LIB_PATH, MODELS_PATH, API_CONFIG } = process.env;
const { getPagination , getPage } = require( `${ROOT_PATH}/${LIB_PATH}/Misc.js` );
const apiConfig = require( `${ROOT_PATH}/${API_CONFIG}` );
const { S3Client, PutObjectCommand } = require('@aws-sdk/client-s3');
const s3Client = new S3Client({
region : apiConfig.S3.region,
credentials : {
accessKeyId : apiConfig.S3.accessKeyId,
secretAccessKey : apiConfig.S3.secretAccessKey
}
});
const s3Bucket = apiConfig.S3.bucket;
const s3BucketKey = apiConfig.S3.load_attachments_key;
const Model = require( `${ROOT_PATH}/${MODELS_PATH}/load-attachments.model.js` );
const UserModel = require( `${ROOT_PATH}/${MODELS_PATH}/users.model.js` );
const LoadsModel = require( `${ROOT_PATH}/${MODELS_PATH}/loads.model.js` );
async function getAuthorizationFilter( userId ){
const user = await UserModel.findById( userId );
const companyId = user.company.toString();
return {
$or: [
{ company : companyId },
{ carrier : companyId },
]
};
}
const getAttachment = async(req, res) => {
try{
const attachmentId = req.params.id;
const CompanyAccessFilter = await getAuthorizationFilter( req.JWT.payload.sub );
const filter = {
$and : [
{ _id : attachmentId },
CompanyAccessFilter
]
};
const retVal = await Model.findOne( filter ) || {};
res.send( retVal );
}catch( err ){
res.send( {} );
}
};
const getAttachmentList = async(req, res) => {
const filter = await getAuthorizationFilter( req.JWT.payload.sub );
const { page , elements } = getPagination( req.query );
const retVal = await getPage( page, elements, Model, filter );
res.send( retVal );
};
const getLoadAttachmentList = async(req, res) => {
const { page , elements } = getPagination( req.query );
const loadId = req.params.id;
try{
const CompanyAccessFilter = await getAuthorizationFilter( req.JWT.payload.sub );
const filter = {
$and : [
{ load : loadId },
CompanyAccessFilter
]
};
const retVal = await getPage( page, elements, Model, filter );
return res.send( retVal );
}catch( error ){
console.log( error );
return res.send({
total: 0,
limit: elements,
skip: page*elements,
data : []
});
}
};
async function getLoadById( loadId , companyId ){
const filter = {
$and : [
{ _id : loadId },
{
$or: [
{ company : companyId },
{ carrier : companyId },
]
}
]
};
return await LoadsModel.findOne( filter ) || null;
}
async function createLoadAttachment( type , userId , loadId ){
const user = await UserModel.findById( userId );
const companyId = user.company.toString();
const load = await getLoadById( loadId , companyId );
const prevAttachment = (load)? await Model.findOne({ load : loadId , type : type }) : null;
let attachment = null;
if( load && !prevAttachment ){
attachment = new Model({
type : type,
carrier : companyId,
company : load.company,
load : loadId,
author : userId
});
await attachment.save();
}
else if( load && prevAttachment ){
prevAttachment.updatedAt = Date.now();
await prevAttachment.save();
attachment = prevAttachment;
}else{
/**
* load is not valid => I don't have access to this load!
*/
attachment = null;
}
return attachment;
}
async function uploadFile( bucket, key, file , obj_id ){
const params = {
Bucket: bucket,
Key : `${key}/${obj_id}`,
ContentType : file.mimetype,
Body : file.data
};
const s3resp = await s3Client.send( new PutObjectCommand( params ) );
return s3resp;
}
const postLoadingAttachment = async(req, res) => {
const loadId = req.params.id;
const attachment = await createLoadAttachment( "Loading", req.JWT.payload.sub , loadId );
const file = req.files.attachment;
if( attachment && file ){
const s3resp = await uploadFile( s3Bucket, s3BucketKey, file , attachment._id );
res.send( attachment );
}else if( !file ){
res.status(400).send({ error : "attachment file not found" , code: 400 });
}else{
res.status(401).send({error:"Unauthorized",code:401});
}
};
const postDownloadingAttachment = async(req, res) => {
const loadId = req.params.id;
const attachment = await createLoadAttachment( "Downloading", req.JWT.payload.sub , loadId );
const file = req.files.attachment;
if( attachment && file ){
const s3resp = await uploadFile( s3Bucket, s3BucketKey, file , attachment._id );
res.send( attachment );
}else if( !file ){
res.status(400).send({ error : "attachment file not found" , code: 400 });
}else{
res.status(401).send({error:"Unauthorized",code:401});
}
};
module.exports = { getAttachment, getAttachmentList, getLoadAttachmentList, postLoadingAttachment, postDownloadingAttachment };

View File

@@ -0,0 +1,13 @@
'use strict';
const router = require('express').Router();
const services= require('./services.js');
router.get('/find', services.findList);
router.get('/calendar', services.findCalendarList);
router.post('/new', services.postLoad);
router.patch('/:id', services.patchLoad);
router.delete('/:id', services.deleteLoad);
router.get('/:id', services.getById);
module.exports = router;

View File

@@ -0,0 +1,294 @@
"use strict";
const { ROOT_PATH, LIB_PATH } = process.env;
const { getModel } = require( '../../../lib/Models' );
const { getPagination } = require( `${ROOT_PATH}/${LIB_PATH}/Misc.js` );
const { GenericHandler } = require( '../../../lib/Handlers/Generic.handler.js' );
const Model = getModel('loads');
const CompanyModel = getModel('companies');
const ProposalsModel = getModel('proposals');
const populate_list = ['product', 'company', 'carrier', 'vehicle', 'categories'];
const generic = new GenericHandler( Model, null, populate_list );
function getAndFilterList( query ){
const filter_list = [];
const {
companyId,
carrier,
vehicle,
driver,
status,
posted_by,
posted_by_name,
load_status,
published_date,
loaded_date,
transit_date,
categories,
product,
shipment_code
} = query;
if( companyId ){ filter_list.push( { company : companyId } ); }
if( carrier ){ filter_list.push( { carrier } ); }
if( vehicle ){ filter_list.push( { vehicle } ); }
if( driver ){ filter_list.push( { driver } ); }
if( status ){ filter_list.push( { status } ); }
if( posted_by ) { filter_list.push({ posted_by }); }
if( posted_by_name ) { filter_list.push({ posted_by_name }); }
if( load_status ) { filter_list.push({ load_status }); }
if( published_date ) { filter_list.push({ published_date }); }
if( loaded_date ) { filter_list.push({ loaded_date }); }
if( transit_date ) { filter_list.push({ transit_date }); }
if( categories ) { filter_list.push({ categories }); }
if( product ) { filter_list.push({ product }); }
if( shipment_code ) { filter_list.push({ shipment_code }); }
if( filter_list.length == 0 ){
return null;
}
return filter_list;
}
async function findLoads( query ){
const { $sort, company_name } = query;
const { page, elements } = getPagination( query );
const andFilterList = getAndFilterList( query ) || [];
let filter;
if( company_name ){
/* Populate list of company ids with match on the company_name */
const company_list = await CompanyModel.find( { company_name }, [ "id" ] );
const or_company_list = []
company_list.forEach( (item) =>{
or_company_list.push({"company" : item.id});
})
andFilterList.push({
$or : or_company_list
});
}
if( andFilterList.length > 0 ){
filter = { $and : andFilterList };
}else{
filter = null;
}
const { total , limit, skip, data } = await generic.getList( page , elements, filter, null, $sort );
const load_list = data;
for(let i=0; i<load_list.length; i++){
const load_id = load_list[ i ].id;
load_list[i] = load_list[i].toObject();
const no_of_proposals = await ProposalsModel.count({ load : load_id });
load_list[i].no_of_proposals = no_of_proposals;
}
return {
total,
limit,
skip,
data : load_list
};
}
async function findCalendarLoads( userId, companyId, query ){
const select = [
"company",
"carrier",
"posted_by",
"bidder",
"status",
"load_status",
"published_date",
"load_status_updated",
"loaded_date",
"transit_date",
"delivered_date",
"createdAt",
"shipment_code",
"est_loading_date",
"est_unloading_date"
];
const { date, load_status , $sort } = query;
const { global } = query;
if( ! date ){
throw "Date field is required";
}
const { page, elements } = getPagination( query );
const orFilterList = [
{"company" : companyId},
{"carrier" : companyId}
]
const andFilterList = [
{
"est_loading_date" : {
$gte : new Date( date["gte"] ),
$lte : new Date( date["lte"] )
}
},
{
$or : orFilterList
}
]
if( !(global) || (global == 0) ){
andFilterList.push( {
$or : [
{"bidder" : userId},
{"posted_by" : userId},
]
} );
}
if( load_status ){
andFilterList.push( { load_status } )
}
const filter = {
$and : andFilterList,
};
const {
total,
limit,
skip,
query : model_query,
} = await generic.getListQuery( page , elements, filter , select );
if( $sort ){
model_query.sort( $sort );
}
const data = await model_query.exec();
return {
total,
limit,
skip,
data
};
}
async function findElementById( elementId ){
let retVal = await Model.findById( elementId ).populate( populate_list );
if( retVal ){
retVal = retVal.toObject();
const no_of_proposals = await ProposalsModel.count({ load : elementId });
retVal.no_of_proposals = no_of_proposals;
}else{
retVal = {};
}
return retVal;
}
const findCalendarList = async(req, res) => {
try{
const query = req.query || {};
const companyId = req.context.companyId;
const userId = req.context.userId;
const retVal = await findCalendarLoads( userId, companyId, query );
res.send( retVal );
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
}
const findList = async(req, res) => {
try{
const query = req.query || {};
const retVal = await findLoads( query );
res.send( retVal );
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
};
const getById = async(req, res) => {
try{
const elementId = req.params.id;
res.send( await findElementById( elementId ) );
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
};
const patchLoad = async(req, res) => {
try{
const elementId = req.params.id;
const permissions = req.context.permissions;
const data = req.body;
const load = await findElementById( elementId );
if( !load ){
throw "You can't modify this load";
}
if( !data ){
throw "load data not sent";
}
await Model.findByIdAndUpdate( elementId , data );
return res.send( await Model.findById( elementId ) );
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
};
const postLoad = async(req, res) => {
try{
const companyId = req.context.companyId;
const userId = req.context.userId;
const user_name = req.context.user.first_name;
const permissions = req.context.permissions;
const data = req.body;
if( !data ){
throw "Load data not sent";
}
if(permissions !== "role_shipper" ){
throw "You can't create loads";
}
data.company = companyId;
data.posted_by = userId;
data.name = user_name;
const load = new Model( data );
await load.save();
const id = "" + load._id;
const shipment_code = "ETA-" + id.substring( 0 , 6 );
await Model.findByIdAndUpdate( id , {
shipment_code
});
return res.send( load );
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
};
const deleteLoad = async(req, res) => {
try{
const companyId = req.context.companyId;
const elementId = req.params.id;
const permissions = req.context.permissions;
const load = await findElementById( elementId , companyId );
if(!load){
throw "You can't delete this load";
}
if(permissions !== "role_shipper" ){
throw "You can't delete loads";
}
await Model.findByIdAndDelete( elementId );
return res.send(load);
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
};
module.exports = { findCalendarList, findList, getById, patchLoad, postLoad, deleteLoad };

View File

@@ -0,0 +1,12 @@
'use strict';
const router = require('express').Router();
const services= require('./services.js');
router.get('/find', services.findList);
router.post('/new', services.postProposal);
router.patch('/:id', services.patchProposal);
router.delete('/:id', services.deleteProposal);
router.get('/:id', services.getById);
module.exports = router;

View File

@@ -0,0 +1,142 @@
"use strict";
const { getModel } = require( '../../../lib/Models' );
const { getPagination } = require( '../../../lib/Misc' );
const { GenericHandler } = require( '../../../lib/Handlers/Generic.handler' );
const { onPatchEvent } = require('../../../lib/Handlers/Proposals.handler');
const Model = getModel('proposals');
const populate_list = [
{ path:'load' , populate : { path : 'categories' } },
{ path:'load' , populate : { path : 'company' } },
'shipper',
'carrier',
'vehicle',
'bidder',
'accepted_by'
];
const generic = new GenericHandler( Model, null, populate_list );
function getAndFilterList( query ){
const filter_list = [];
const { load, categories, branch_name, phone, city, state, truck_type } = query;
if( load ) { filter_list.push({ load }); }
if( categories ) { filter_list.push({ categories }); }
if( branch_name ) { filter_list.push({ branch_name }); }
if( phone ) { filter_list.push({ phone }); }
if( city ) { filter_list.push({ city }); }
if( state ) { filter_list.push({ state }); }
if( truck_type ) { filter_list.push({ truck_type }); }
if( filter_list.length == 0 ){
return null;
}
return filter_list;
}
async function findElements( query ){
const { page, elements } = getPagination( query );
const andFilterList = getAndFilterList( query );
let filter;
if( andFilterList ){
filter = { $and : andFilterList };
}else{
filter = null;
}
const { total , limit, skip, data } = await generic.getList( page , elements, filter );
return {
total,
limit,
skip,
data:data
};
}
async function findElementById( elementId , companyId ){
const filter = {
$and : [
{ _id : elementId },
{ $or :[
{ shipper : companyId },
{ carrier : companyId }
]}
]
};
let retVal = await Model.findOne( filter ).populate( populate_list ) || {};
return retVal;
}
const findList = async(req, res) => {
try{
const query = req.query || {};
const retVal = await findElements( query );
res.send( retVal );
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
};
const getById = async(req, res) => {
try{
const companyId = req.context.companyId;
const elementId = req.params.id;
res.send( await findElementById( elementId , companyId ) );
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
};
const patchProposal = async(req, res) => {
try{
const elementId = req.params.id;
const proposal = await Model.findById( elementId );
const data = req.body;
if( !proposal ){
throw "You can't modify this proposal";
}
if( !data ){
throw "proposal data not sent";
}
await Model.findByIdAndUpdate( elementId , data );
await onPatchEvent( elementId , data );
return res.send( await Model.findById( elementId ) );
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
};
const postProposal = async(req, res) => {
try{
const data = req.body;
if( !data ){
throw "proposal data not sent";
}
const proposal = new Model( data );
await proposal.save();
return res.send( proposal );
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
};
const deleteProposal = async(req, res) => {
try{
const elementId = req.params.id;
const proposal = await Model.findById( elementId );
if(!proposal){
throw "You can't delete this proposal";
}
await Model.findByIdAndDelete( elementId );
return res.send(proposal);
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
};
module.exports = { findList, getById, patchProposal, postProposal, deleteProposal };

View File

@@ -0,0 +1,16 @@
'use strict';
const router = require('express').Router();
const services= require('./services.js');
router.get('/find', services.findList);
router.post('/member', services.postTeamMemberData);
router.patch('/member/:id', services.patchTeamMemberProfileData);
router.delete('/member/:id', services.deleteTeamMember);
router.get('/profile', services.getProfileData);
router.patch('/profile', services.patchProfileData);
router.get('/:id', services.getById);
module.exports = router;

View File

@@ -0,0 +1,177 @@
"use strict";
const { ROOT_PATH, HANDLERS_PATH } = process.env;
const { getUserById, findUsers, patchUserData, createUserWithinCompany, deleteUserWithinCompany } = require( "../../../lib/Handlers/Users.handler" );
const findList = async(req, res) => {
try{
const {
total,
limit,
skip,
data
} = await findUsers( req.query );
return res.send({
total,
limit,
skip,
data});
}catch( error ){
console.error( error );
return res.status( 500 ).send( { error } );
}
};
const getById = async(req, res) => {
try{
const id = req.params.id;
const user = await getUserById( id );
res.send({ user });
}catch( error ){
console.error( error );
return res.status( 500 ).send( { error } );
}
};
const getProfileData = async(req, res) => {
res.send( req.context.user );
};
const patchProfileData = async(req, res) => {
try{
const data = req.body;
if( (data.email) && (data.email === req.context.user.email ) ){
delete data.email;
}
if( req.body.job_role ){
/// You can't change your own role
delete data.job_role;
}
const user = await patchUserData( req.context.user.id , data );
res.send( user );
}catch( error ){
console.error( error );
return res.status( 500 ).send( { error } );
}
};
function job_role_change_allowance( change_author_job_role , affected_job_role ){
try{
if( (change_author_job_role !== "owner") && (change_author_job_role !== "manager") ){
return false;
}
if( affected_job_role === "owner" ){
return false;
}
switch( affected_job_role ){
case 'manager':
case 'driver':
case 'staff':
return true;
default:
return false;
}
}catch( error ){
console.error( error );
return res.status( 500 ).send( { error } );
}
}
const patchTeamMemberProfileData = async(req, res) => {
try{
const id = req.params.id;
if( id === req.context.userId ){
return await patchProfileData( req, res);
}
const companyId = req.context.companyId;
if( !companyId ){
return res.status(400).send( { error : "Not authorized to modify this user" } );
}
/// If a job_role change is requested, validate with rules.
if( ( req.body.job_role ) &&
( !job_role_change_allowance( req.context.job_role , req.body.job_role ) )
){
return res.status(400).send( { error : "Not authorized to upgrade the role as requested" } );
}
if( ( req.body.job_role ) && ( req.body.job_role === "driver" ) && (req.context.permissions !== "role_carrier" ) ){
return res.status(400).send( { error : "Your company can not create drivers" } );
}
if( (req.context.job_role !== "owner") && (req.context.job_role !== "manager") ){
/// Only an owner or manager can modify a team member.
return res.status(400).send( { error : "Your role does not allow to modify this user" } );
}
/// No one can modify an "owner".
const teamMember = await getUserById( id , { company : companyId , job_role : { $ne: "owner" } } );
if( !teamMember ){
return res.status(400).send( { error : "You can't modify users outside of your company" } );
}
/// Apply change to user.
const user_patch_result = await patchUserData( id , req.body );
return res.send( user_patch_result );
}catch( error ){
console.error( error );
return res.status( 500 ).send( { error } );
}
};
const postTeamMemberData = async(req, res) => {
try{
const companyId = req.context.companyId;
if( !companyId ){
return res.status(400).send( { error : "Not authorized to create users" } );
}
if( !req.body.job_role ){
return res.status(400).send( { error : "job_role is mandatory!" } );
}
if( ( req.body.job_role ) &&
( !job_role_change_allowance( req.context.job_role , req.body.job_role ) )
){
return res.status(400).send( { error : "Not authorized to create the role as requested" } );
}
if( (req.context.job_role !== "owner") && (req.context.job_role !== "manager") ){
return res.status(400).send( { error : "Not authorized to create users" } );
}
if( ( req.body.job_role ) && ( req.body.job_role === "driver" ) && (req.context.permissions !== "role_carrier" ) ){
return res.status(400).send( { error : "Your company can not create drivers" } );
}
if( !req.body.email ){
return res.status(400).send( { error : "email is mandatory to create a new user" } );
}
/// Only an owner or manager can create a new user
const teamMember = await createUserWithinCompany( companyId , req.body );
return res.send( teamMember );
}catch( error ){
console.error( error );
return res.status( 500 ).send( { error } );
}
}
const deleteTeamMember = async(req, res) => {
try{
const user_to_remove_id = req.params.id;
const manager_id = req.context.userId;
if( (req.context.job_role !== "owner") && (req.context.job_role !== "manager") ){
return res.status(400).send( { error : "Not authorized to delete this user" } );
}
const teamMember = await deleteUserWithinCompany( manager_id, user_to_remove_id );
return res.send( teamMember );
}catch( error ){
console.error( error );
return res.status( 500 ).send( { error } );
}
}
module.exports = { findList , getById , getProfileData, patchProfileData, patchTeamMemberProfileData, postTeamMemberData , deleteTeamMember };

View File

@@ -0,0 +1,12 @@
'use strict';
const router = require('express').Router();
const services= require('./services.js');
router.get('/find', services.findList);
router.post('/new', services.postVehicle);
router.patch('/:id', services.patchVehicle);
router.delete('/:id', services.deleteVehicle);
router.get('/:id', services.getById);
module.exports = router;

View File

@@ -0,0 +1,168 @@
"use strict";
const { ROOT_PATH, LIB_PATH, MODELS_PATH, HANDLERS_PATH } = process.env;
const { getModel } = require( `${ROOT_PATH}/${MODELS_PATH}` );
const { getPagination } = require( `${ROOT_PATH}/${LIB_PATH}/Misc.js` );
const { GenericHandler } = require( `${ROOT_PATH}/${HANDLERS_PATH}/Generic.handler.js` );
const Model = getModel('vehicles');
const populate_list = ['categories', 'active_load','load_shipper','driver'];
const generic = new GenericHandler( Model, null, populate_list );
function getAndFilterList( query ){
const filter_list = [];
const {
categories,
active_load,
load_shipper,
driver,
vehicle_code,
vehicle_name,
vehicle_number,
circulation_serial_number,
truck_type,
tyre_type,
city,
state,
status,
destino
} = query;
if( categories ) { filter_list.push({ categories }); }
if( active_load ) { filter_list.push({ active_load }); }
if( load_shipper ) { filter_list.push({ load_shipper }); }
if( driver ) { filter_list.push({ driver }); }
if( vehicle_code ) { filter_list.push({ vehicle_code }); }
if( vehicle_name ) { filter_list.push({ vehicle_name }); }
if( vehicle_number ) { filter_list.push({ vehicle_number }); }
if( circulation_serial_number ) { filter_list.push({ circulation_serial_number }); }
if( truck_type ) { filter_list.push({ truck_type }); }
if( tyre_type ) { filter_list.push({ tyre_type }); }
if( city ) { filter_list.push({ city }); }
if( state ) { filter_list.push({ state }); }
if( status ) { filter_list.push({ status }); }
if( destino ) { filter_list.push({ destino }); }
if( filter_list.length == 0 ){
return null;
}
return filter_list;
}
async function findElements( companyId , query ){
const { page, elements } = getPagination( query );
const andFilterList = getAndFilterList( query );
let filter;
if( andFilterList ){
andFilterList.push({ company : companyId });
filter = { $and : andFilterList };
}else{
filter = { company : companyId };
}
const { total , limit, skip, data } = await generic.getList( page , elements, filter );
return {
total,
limit,
skip,
data:data
};
}
async function findElementById( elementId , companyId ){
let retVal = await Model.findById( elementId ).populate( populate_list ) || {};
return retVal;
}
const findList = async(req, res) => {
try{
const query = req.query || {};
const companyId = req.context.companyId;
const retVal = await findElements( companyId , query );
res.send( retVal );
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
};
const getById = async(req, res) => {
try{
const companyId = req.context.companyId;
const elementId = req.params.id;
res.send( await findElementById( elementId , companyId ) );
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
};
const patchVehicle = async(req, res) => {
try{
const companyId = req.context.companyId;
const elementId = req.params.id;
const permissions = req.context.permissions;
const vehicle = await findElementById( elementId , companyId );
const data = req.body;
if( !vehicle ){
throw "You can't modify this vehicle";
}
if( !data ){
throw "Vehicle data not sent";
}
if( permissions !== "role_carrier" ){
throw "You can't modify vehicles";
}
data.company = companyId;
await Model.findByIdAndUpdate( elementId , data );
return res.send( await Model.findById( elementId ) );
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
};
const postVehicle = async(req, res) => {
try{
const userId = req.context.userId;
const companyId = req.context.companyId;
const permissions = req.context.permissions;
const data = req.body;
if( !data ){
throw "Vehicle data not sent";
}
if(permissions !== "role_carrier" ){
throw "You can't create vehicles";
}
data.company = companyId;
data.status = "Free";
data.is_available = false;
data.posted_by = userId;
const vehicle = new Model( data );
await vehicle.save();
return res.send( vehicle );
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
};
const deleteVehicle = async(req, res) => {
try{
const companyId = req.context.companyId;
const elementId = req.params.id;
const permissions = req.context.permissions;
const vehicle = await findElementById( elementId , companyId );
if( !vehicle ){
throw "You can't delete this vehicle";
}
if(permissions !== "role_carrier" ){
throw "You can't delete vehicles";
}
await Model.findByIdAndDelete( elementId );
return res.send(vehicle);
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
};
module.exports = { findList, getById, patchVehicle, postVehicle, deleteVehicle };

View File

@@ -0,0 +1,16 @@
'use strict';
const router = require('express').Router();
const services= require('./services.js');
router.post('/authorize', services.AuthorizeJWT);
router.get('/authorize/:session_token', services.RenewJWT);
router.get('/check-account/:email', services.checkAccount );
router.post('/signup', services.TryCreateAccount);
router.patch('/signup', services.ConfirmAccount);
router.post('/recover', services.RecoverPwd);
router.patch('/recover', services.ConfirmRecoverPwd);
module.exports = router;

View File

@@ -0,0 +1,279 @@
"use strict";
const jsonwebtoken = require('jsonwebtoken');
const { API_CONFIG, ROOT_PATH, LIB_PATH, HANDLERS_PATH } = process.env;
const apiConfig = require( `${ROOT_PATH}/${API_CONFIG}` );
const { genKey, toSha256 } = require( `${ROOT_PATH}/${LIB_PATH}/Misc.js` );
const { emailEvent , EMAIL_EVENTS } = require( '../../../lib/Handlers/MailClient' );
const { create_account, already_exists, verify_driver_account, login, login_with_session_token, reset_password } = require( '../../../lib/Handlers/Account' );
const { Validator } = require( "jsonschema" );
const jwtSecret = apiConfig.authentication.jwtSecret;
const jwtTimeout = apiConfig.authentication.jwtTimeout;//Timeout in hours
const jwtRenewalTimeout = apiConfig.authentication.jwtRenewalTimeout;//Timeout in hours
const jwtOptions = apiConfig.authentication.jwtOptions;
const validator = new Validator();
const create_account_schema = {
type : 'object',
properties : {
email : { type : 'string' , maxLength : 256 },
password : { type : 'string', maxLength : 256},
otp : { type : 'string', maxLength : 6 },
checksum : { type : 'string', maxLength : 32 }
},
required : [ 'email', 'password' ]
};
const confirm_account_schema = {
type : 'object',
properties : create_account_schema.properties,//Same properties
required : [ 'email', 'password', 'otp', 'checksum' ]//Different requirements
};
const login_account_schema = {
type : 'object',
properties : create_account_schema.properties,//Same properties
required : [ 'email', 'password' ]//Different requirements
};
const password_recover_schema = create_account_schema;
const confirm_password_recover_schema = {
type : 'object',
properties : create_account_schema.properties,//Same properties
required : [ 'email', 'password', 'otp', 'checksum' ]//Different requirements
};
async function AuthorizeJWT_email_pwd( email , password ){
const user = await login( email, password );
if( !user ){
return null;
}
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 );
user.session_token = session_token;
user.session_token_exp = session_token_exp;
await user.save();
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
};
}
const AuthorizeJWT = async(req, res) => {
try{
if( validator.validate( req.body , login_account_schema ).valid ){
const { email, password } = req.body;
const retVal = await AuthorizeJWT_email_pwd( email , password );
if( !retVal ){
return res.status(401).send( { error : "Invalid credentials" } );
}
return res.send( retVal );
}else{
return res.status(400).send( { error : "Invalid request" } );
}
}catch( err ){
console.error( err );
res.status(500).send({ error : "Login: Internal error" });
}
};
const RenewJWT = async(req, res) => {
try{
const login_session_token = req.params.session_token;
const user = await login_with_session_token( login_session_token );
if( !user ){
return res.status(401).send( { error : "Invalid or Expired Session Token" } );
}
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 );
user.session_token = session_token;
user.session_token_exp = session_token_exp;
await user.save();
const payload = {
iat: iat,
exp: iat + jwtTimeout * 3600,
aud: jwtOptions.audience,
iss: jwtOptions.audience,
sub: user.id,
};
const jwt = jsonwebtoken.sign( payload , jwtSecret );
return res.status(200).send( {
accessToken : jwt,
payload : payload,
session_token,
session_token_exp,
user : user
} );
}catch( err ){
console.error( err );
res.status(500).send({ error : "Renew: Internal error" });
}
};
const TryCreateAccount = async(req, res) => {
try{
if( validator.validate( req.body , create_account_schema ).valid ){
const otp = genKey();
const { email : receiver , password } = req.body;
const email = receiver;
const it_exists = await already_exists( email );
if( it_exists ){
return res.status(400).send({ error : "Email already exists" });
}
const content = { OTP : otp, user_name : email };
const checksum_entry = {
email : receiver,
password,
otp
};
const checksum = toSha256( JSON.stringify(checksum_entry)).substr(0, 32);
await emailEvent( EMAIL_EVENTS.ACCOUNT_VERIFY , receiver , content );
console.log(
content
);
res.status(200).send( { checksum } );
}else{
res.status(400).send( { error : "Invalid request" } );
}
}catch( err ){
console.error( err );
res.status(500).send({ error : "Account creation: Internal error" });
}
};
const ConfirmAccount = async(req, res) => {
try{
if( validator.validate( req.body , confirm_account_schema ).valid ){
const { email, password, otp, checksum } = req.body;
const it_exists = await already_exists( email );
if( it_exists ){
return res.status(400).send({ error : "User already registered!" });
}
const checksum_entry = {email, password, otp};
const recomputed_checksum = toSha256( JSON.stringify(checksum_entry)).substr(0, 32);
if( recomputed_checksum != checksum ){
return res.status(400).send({ error : "Wrong OTP" });
}
await create_account( email, password );
const content = { user_name : email };
const receiver = email;
await emailEvent( EMAIL_EVENTS.ACCOUNT_CONFIRMED , receiver , content );
const retVal = await AuthorizeJWT_email_pwd( email , password );
return res.send( retVal );
}else{
return res.status(400).send( { error : "Invalid request" } );
}
}catch( err ){
console.error( err );
return res.status(500).send({ error : "Account creation: Internal error" });
}
};
const RecoverPwd = async(req, res) => {
try{
if( validator.validate( req.body , password_recover_schema ).valid ){
const otp = genKey();
const { email : receiver , password } = req.body;
const email = receiver;
const it_exists = await already_exists( email );
if( !it_exists ){
return res.status(400).send({ error : "Email is not registered!" });
}
const content = { OTP : otp, user_name : email };
const checksum_entry = {
email : receiver,
password,
otp
};
const checksum = toSha256( JSON.stringify(checksum_entry)).substr(0, 32);
await emailEvent( EMAIL_EVENTS.ACCOUNT_VERIFY , receiver , content );
console.log(
content
);
res.status(200).send( { checksum } );
}else{
res.status(400).send( { error : "Invalid request" } );
}
}catch( err ){
console.error( err );
res.status(500).send({ error : "Password Recover: Internal error" });
}
};
const ConfirmRecoverPwd = async(req, res) => {
try{
if( validator.validate( req.body , confirm_password_recover_schema ).valid ){
const { email, password, otp, checksum } = req.body;
const it_exists = await already_exists( email );
if( !it_exists ){
return res.status(400).send({ error : "Email is not registered!" });
}
const checksum_entry = {email, password, otp};
const recomputed_checksum = toSha256( JSON.stringify(checksum_entry)).substr(0, 32);
if( recomputed_checksum != checksum ){
return res.status(400).send({ error : "Wrong OTP" });
}
await reset_password( email, password );
return res.status(200).send( { msg : "Password is reset!" } );
}else{
return res.status(400).send( { error : "Invalid request" } );
}
}catch( err ){
console.error( err );
return res.status(500).send({ error : "Password Recover Confirmation: Internal error" });
}
};
const checkAccount = async(req, res) => {
try{
const email = req.params.email;
const driver_account_val = await verify_driver_account( email );
return res.status(200).send( driver_account_val );
} catch ( err ){
console.error( err );
return res.status(500).send({ error : "AuthManagement: Internal error" });
}
};
module.exports = { AuthorizeJWT, RenewJWT, TryCreateAccount, ConfirmAccount, RecoverPwd, ConfirmRecoverPwd, checkAccount};

View File

@@ -0,0 +1,9 @@
'use strict';
const router = require('express').Router();
const services= require('./services.js');
router.get('/', services.getList);
router.get('/find', services.findList);
router.get('/:id', services.getById);
module.exports = router;

View File

@@ -0,0 +1,33 @@
"use strict";
const { ROOT_PATH, LIB_PATH, MODELS_PATH, HANDLERS_PATH } = process.env;
const { getPagination } = require( `${ROOT_PATH}/${LIB_PATH}/Misc.js` );
const { GenericHandler } = require( `${ROOT_PATH}/${HANDLERS_PATH}/Generic.handler.js` );
const Model = require( `${ROOT_PATH}/${MODELS_PATH}/cities.model.js` );
const generic = new GenericHandler( Model, "city_name" );
const getList = async(req, res) => {
const { page , elements } = getPagination( req.query );
const retVal = await generic.getList(page , elements);
res.send( retVal );
};
const findList = async(req, res) => {
const findString = req.query.regex || null;
const { page , elements } = getPagination( req.query );
let retVal;
if( findString ){
retVal = await generic.findList( findString, page, elements );
}else{
retVal = await generic.getList(page , elements);
}
res.send( retVal );
};
const getById = async(req, res) => {
const id=req.params.id;
const retVal = await generic.getById( id );
res.send( retVal );
};
module.exports = { getList , findList , getById };

View File

@@ -0,0 +1,7 @@
'use strict';
const router = require('express').Router();
const services= require('./services.js');
router.post('/', services.postSendConactEMail);
module.exports = router;

View File

@@ -0,0 +1,38 @@
"use strict";
const { ROOT_PATH, HANDLERS_PATH } = process.env;
const { emailEvent , EMAIL_EVENTS } = require( `${ROOT_PATH}/${HANDLERS_PATH}/MailClient` );
const { Validator } = require( "jsonschema" );
const validator = new Validator();
const conact_email = {
type : 'object',
properties : {
name : { type : 'string' , maxLength : 256 },
email : { type : 'string' , maxLength : 256 },
message : { type : 'string', maxLength : 1024 }
},
required : [ 'name', 'email', 'message' ]
};
const postSendConactEMail = async(req, res) => {
try{
if( validator.validate( req.body , conact_email ).valid ){
const receiver = req.body.email;
const content = {
name : req.body.name,
email : req.body.email,
message : req.body.message
}
await emailEvent( EMAIL_EVENTS.CONTACT_EMAIL , receiver , content );
}else{
res.status(400).send( { error : "Invalid request" } );
}
return res.status(200).send({ msg : "Email sent!"});
} catch ( err ){
console.error( err );
return res.status(500).send({ error : "Contact-Email: Internal error" });
}
};
module.exports = { postSendConactEMail };

View File

@@ -0,0 +1,9 @@
'use strict';
const router = require('express').Router();
const services= require('./services.js');
router.get('/', services.getList);
router.get('/find', services.findList);
router.get('/:id', services.getById);
module.exports = router;

View File

@@ -0,0 +1,33 @@
"use strict";
const { ROOT_PATH, LIB_PATH, MODELS_PATH, HANDLERS_PATH } = process.env;
const { getPagination } = require( `${ROOT_PATH}/${LIB_PATH}/Misc.js` );
const { GenericHandler } = require( `${ROOT_PATH}/${HANDLERS_PATH}/Generic.handler.js` );
const Model = require( `${ROOT_PATH}/${MODELS_PATH}/countries.model.js` );
const generic = new GenericHandler( Model, "country_name" );
const getList = async(req, res) => {
const { page , elements } = getPagination( req.query );
const retVal = await generic.getList(page , elements);
res.send( retVal );
};
const findList = async(req, res) => {
const findString = req.query.regex || null;
const { page , elements } = getPagination( req.query );
let retVal;
if( findString ){
retVal = await generic.findList( findString, page, elements );
}else{
retVal = await generic.getList(page , elements);
}
res.send( retVal );
};
const getById = async(req, res) => {
const id=req.params.id;
const retVal = await generic.getById( id );
res.send( retVal );
};
module.exports = { getList , findList , getById };

View File

@@ -0,0 +1,42 @@
'use strict';
const { ROOT_PATH , LIB_PATH } = process.env;
/// Router instance
const router = require('express').Router();
const account = require('./account/routes.js');
const cities = require('./cities/routes.js');
const contactEmail = require('./contact-email/routes.js');
const countries = require('./countries/routes.js');
const metaData = require('./meta-data/routes.js');
const metaGroups = require('./meta-groups/routes.js');
const news = require('./news/routes.js');
const productCategories = require('./product-categories/routes.js');
const products = require('./products/routes.js');
const publicCompanies = require('./public-companies/routes.js');
const publicVehicles = require('./public-vehicles/routes.js');
const publicLoads = require('./public-loads/routes.js');
const publicLoadAttachments = require('./public-load-attachments/routes.js');
const publicLoadsTracking = require('./public-load-tracking/routes.js');
const states = require('./states/routes.js');
const test = require('./test/routes.js');
router.use('/account', account);
router.use('/cities', cities);
router.use('/contact-email', contactEmail);
router.use('/countries', countries);
router.use('/meta-data', metaData);
router.use('/meta-groups', metaGroups);
router.use('/news', news);
router.use('/product-categories', productCategories);
router.use('/products', products);
router.use("/public-companies", publicCompanies);
router.use("/public-vehicles", publicVehicles);
router.use('/public-loads', publicLoads );
router.use('/public-load-attachments', publicLoadAttachments );
router.use('/public-load-tracking', publicLoadsTracking );
router.use('/states', states);
router.use("/test", test);
module.exports = router;

View File

@@ -0,0 +1,9 @@
'use strict';
const router = require('express').Router();
const services= require('./services.js');
router.get('/', services.getList);
router.get('/find', services.findList);
router.get('/:id', services.getById);
module.exports = router;

View File

@@ -0,0 +1,33 @@
"use strict";
const { ROOT_PATH, LIB_PATH, MODELS_PATH, HANDLERS_PATH } = process.env;
const { getPagination } = require( `${ROOT_PATH}/${LIB_PATH}/Misc.js` );
const { GenericHandler } = require( `${ROOT_PATH}/${HANDLERS_PATH}/Generic.handler.js` );
const Model = require( `${ROOT_PATH}/${MODELS_PATH}/meta-data.model.js` );
const generic = new GenericHandler( Model, "meta_value" );
const getList = async(req, res) => {
const { page , elements } = getPagination( req.query );
const retVal = await generic.getList(page , elements);
res.send( retVal );
};
const findList = async(req, res) => {
const findString = req.query.regex || null;
const { page , elements } = getPagination( req.query );
let retVal;
if( findString ){
retVal = await generic.findList( findString, page, elements );
}else{
retVal = await generic.getList(page , elements);
}
res.send( retVal );
};
const getById = async(req, res) => {
const id=req.params.id;
const retVal = await generic.getById( id );
res.send( retVal );
};
module.exports = { getList , findList , getById };

View File

@@ -0,0 +1,9 @@
'use strict';
const router = require('express').Router();
const services= require('./services.js');
router.get('/', services.getList);
router.get('/find', services.findList);
router.get('/:id', services.getById);
module.exports = router;

View File

@@ -0,0 +1,33 @@
"use strict";
const { ROOT_PATH, LIB_PATH, MODELS_PATH, HANDLERS_PATH } = process.env;
const { getPagination } = require( `${ROOT_PATH}/${LIB_PATH}/Misc.js` );
const { GenericHandler } = require( `${ROOT_PATH}/${HANDLERS_PATH}/Generic.handler.js` );
const Model = require( `${ROOT_PATH}/${MODELS_PATH}/meta-groups.model.js` );
const generic = new GenericHandler( Model, "group_label" );
const getList = async(req, res) => {
const { page , elements } = getPagination( req.query );
const retVal = await generic.getList(page , elements);
res.send( retVal );
};
const findList = async(req, res) => {
const findString = req.query.regex || null;
const { page , elements } = getPagination( req.query );
let retVal;
if( findString ){
retVal = await generic.findList( findString, page, elements );
}else{
retVal = await generic.getList(page , elements);
}
res.send( retVal );
};
const getById = async(req, res) => {
const id=req.params.id;
const retVal = await generic.getById( id );
res.send( retVal );
};
module.exports = { getList , findList , getById };

View File

@@ -0,0 +1,10 @@
'use strict';
const router = require('express').Router();
const services= require('./services.js');
router.get('/', services.getList);
router.get('/find', services.findList);
router.get('/:id', services.getById);
router.get('/download/:image_name', services.getImageByNewId);
module.exports = router;

View File

@@ -0,0 +1,52 @@
"use strict";
const { API_CONFIG, ROOT_PATH, LIB_PATH, MODELS_PATH, HANDLERS_PATH } = process.env;
const { getPagination } = require( `${ROOT_PATH}/${LIB_PATH}/Misc.js` );
const { GenericHandler } = require( `${ROOT_PATH}/${HANDLERS_PATH}/Generic.handler.js` );
const { downloadFile } = require(`${ROOT_PATH}/${LIB_PATH}/Misc`);
const apiConfig = require( `${ROOT_PATH}/${API_CONFIG}` );
const s3Bucket = apiConfig.S3.bucket;
const s3BucketKey = apiConfig.S3.news_key;
const Model = require( `${ROOT_PATH}/${MODELS_PATH}/news.model.js` );
const generic = new GenericHandler( Model );
const getList = async(req, res) => {
const { page , elements } = getPagination( req.query );
const retVal = await generic.getList(page , elements);
res.send( retVal );
};
const findList = async(req, res) => {
const findString = req.query.regex || null;
const { page , elements } = getPagination( req.query );
let retVal;
if( findString ){
retVal = await generic.findList( findString, page, elements );
}else{
retVal = await generic.getList(page , elements);
}
res.send( retVal );
};
const getById = async(req, res) => {
const id=req.params.id;
const retVal = await generic.getById( id );
res.send( retVal );
};
const getImageByNewId = async(req, res) => {
try{
const image_name = req.params.image_name;
const file = await downloadFile( s3Bucket, s3BucketKey, image_name );
res.attachment( image_name );
res.setHeader('Content-Type', file.ContentType );
res.send( file.Body );
} catch ( err ){
console.error( err );
return res.status(500).send({ error : "News: Internal error" });
}
};
module.exports = { getList , findList , getById, getImageByNewId };

View File

@@ -0,0 +1,9 @@
'use strict';
const router = require('express').Router();
const services= require('./services.js');
router.get('/', services.getList);
router.get('/find', services.findList);
router.get('/:id', services.getById);
module.exports = router;

View File

@@ -0,0 +1,33 @@
"use strict";
const { ROOT_PATH, LIB_PATH, MODELS_PATH, HANDLERS_PATH } = process.env;
const { getPagination } = require( `${ROOT_PATH}/${LIB_PATH}/Misc.js` );
const { GenericHandler } = require( `${ROOT_PATH}/${HANDLERS_PATH}/Generic.handler.js` );
const Model = require( `${ROOT_PATH}/${MODELS_PATH}/product-categories.model.js` );
const generic = new GenericHandler( Model, "name" );
const getList = async(req, res) => {
const { page , elements } = getPagination( req.query );
const retVal = await generic.getList(page , elements);
res.send( retVal );
};
const findList = async(req, res) => {
const findString = req.query.regex || null;
const { page , elements } = getPagination( req.query );
let retVal;
if( findString ){
retVal = await generic.findList( findString, page, elements );
}else{
retVal = await generic.getList(page , elements);
}
res.send( retVal );
};
const getById = async(req, res) => {
const id=req.params.id;
const retVal = await generic.getById( id );
res.send( retVal );
};
module.exports = { getList , findList , getById };

View File

@@ -0,0 +1,9 @@
'use strict';
const router = require('express').Router();
const services= require('./services.js');
router.get('/', services.getList);
router.get('/find', services.findList);
router.get('/:id', services.getById);
module.exports = router;

View File

@@ -0,0 +1,33 @@
"use strict";
const { ROOT_PATH, LIB_PATH, MODELS_PATH, HANDLERS_PATH } = process.env;
const { getPagination } = require( `${ROOT_PATH}/${LIB_PATH}/Misc.js` );
const { GenericHandler } = require( `${ROOT_PATH}/${HANDLERS_PATH}/Generic.handler.js` );
const Model = require( `${ROOT_PATH}/${MODELS_PATH}/products.model.js` );
const generic = new GenericHandler( Model, "name" );
const getList = async(req, res) => {
const { page , elements } = getPagination( req.query );
const retVal = await generic.getList(page , elements);
res.send( retVal );
};
const findList = async(req, res) => {
const findString = req.query.regex || null;
const { page , elements } = getPagination( req.query );
let retVal;
if( findString ){
retVal = await generic.findList( findString, page, elements );
}else{
retVal = await generic.getList(page , elements);
}
res.send( retVal );
};
const getById = async(req, res) => {
const id=req.params.id;
const retVal = await generic.getById( id );
res.send( retVal );
};
module.exports = { getList , findList , getById };

View File

@@ -0,0 +1,9 @@
'use strict';
const router = require('express').Router();
const services= require('./services.js');
router.get('/shipper', services.getListShippers);
router.get('/carrier', services.getListCarriers);
router.get('/users/:companyId', services.getUserLists);
module.exports = router;

View File

@@ -0,0 +1,182 @@
"use strict";
const { query } = require("express");
const { ROOT_PATH, LIB_PATH, MODELS_PATH, HANDLERS_PATH } = process.env;
const { getPagination , getPage } = require( `${ROOT_PATH}/${LIB_PATH}/Misc.js` );
const { GenericHandler } = require( `${ROOT_PATH}/${HANDLERS_PATH}/Generic.handler.js` );
const Model = require( `${ROOT_PATH}/${MODELS_PATH}/companies.model.js` );
const categoriesModel = require( `${ROOT_PATH}/${MODELS_PATH}/product-categories.model.js` );
const usersModel = require( `${ROOT_PATH}/${MODELS_PATH}/users.model.js` );
const populate_select = {
categories:"-_id name",
};
const generic = new GenericHandler( Model, null, null , populate_select );
const user_generic = new GenericHandler( usersModel );
function join_field_list( obj_with_fields , list_of_fields )
{
for(let field_idx=0; field_idx < list_of_fields.length; field_idx++){
const field_name = list_of_fields[ field_idx ];
const new_field_name = "_" + list_of_fields[ field_idx ];
if( obj_with_fields[ field_name ] ){
obj_with_fields[ new_field_name ] = obj_with_fields[field_name].join(", ");
}
}
return obj_with_fields;
}
function getAndFilterList( query ){
const filter_list = [];
const { company_type, company_name, truck_type, categories, company_state, company_city } = query;
if( company_name ){ filter_list.push( { company_name } ); }
if( company_type ){ filter_list.push( { company_type } ); }
if( company_state ){ filter_list.push( { company_state } ); }
if( company_city ){ filter_list.push( { company_city } ); }
if( truck_type ){ filter_list.push( { truck_type } ); }
if( categories ){ filter_list.push( { categories } ); }
if( filter_list.length == 0 ){
return null;
}
return filter_list;
}
async function getListByType( type , req ){
const filter = { "company_type" : type , "is_hidden" : false };
const select = [
"rfc",
"company_name",
"company_type",
"company_code",
"company_city",
"company_state",
"createdAt",
"membership",
"categories",
"truck_type",
"company_description"
];
const { elements } = getPagination( req.query );
const page = 0;// No pagination allowed to this endpoint
let query_elements;
if( elements >= 100 ){
query_elements = 100;// Never return more than 100 elements
}else{
query_elements = elements;
}
const andFilterList = getAndFilterList( req.query );
if( andFilterList ){
filter.$and = andFilterList;
}
const queryVal = await generic.getList(page , query_elements, filter, select );
const data_list = queryVal.data;
for(let i=0; i<data_list.length; i++){
data_list[i] = data_list[i].toObject();
data_list[i] = join_field_list( data_list[i] , ["company_city","company_state","truck_type"] );
let categories = data_list[i].categories.map( ( c ) => c.name);
data_list[i]._truck_types = data_list[i]._truck_type;
data_list[i]._categories = categories.join(", ");
/** Remove not requried fields */
delete data_list[i].categories;
delete data_list[i].company_city;
delete data_list[i].company_state;
delete data_list[i].truck_type;
delete data_list[i]._truck_type;
}
const retVal = {
total : queryVal.total,
limit : queryVal.limit,
skip : queryVal.skip,
data : data_list
};
return retVal;
}
const getListShippers = async(req, res) => {
try{
const retVal = await getListByType( "Shipper" , req );
res.send( retVal );
} catch ( err ){
console.error( err );
return res.status(500).send({ error : "Public-Companies(Carriers): Internal error" });
}
};
const getListCarriers = async(req, res) => {
try{
const retVal = await getListByType( "Carrier" , req );
res.send( retVal );
} catch ( err ){
console.error( err );
return res.status(500).send({ error : "Public-Companies(Carriers): Internal error" });
}
};
const getUserLists = async(req, res) => {
try{
const companyId = req.params.companyId;
const { elements } = getPagination( req.query );
const page = 0;// No pagination allowed to this endpoint
let query_elements;
if( elements >= 100 ){
query_elements = 100;// Never return more than 100 elements
}else{
query_elements = elements;
}
const select = [
"first_name",
"middle_name",
"last_name",
"company",
"employe_id",
"phone",
"phone2",
"email",
"categories",
"user_city",
"user_state",
"truck_type"
];
const queryVal = await user_generic.getList(page , query_elements, { company : companyId }, select );
const data_list = queryVal.data;
for(let i=0; i<data_list.length; i++){
data_list[i] = data_list[i].toObject();
let name;
name = ( !data_list[i].first_name )? "" : data_list[i].first_name;
name += ( !data_list[i].middle_name )? "": " " + data_list[i].middle_name;
name += ( !data_list[i].last_name )? "": " " + data_list[i].last_name;
data_list[i].name = name;
data_list[i] = join_field_list( data_list[i] , ["categories","user_city","user_state","truck_type"] );
let categories = data_list[i].categories.map( ( c ) => c.name);
/** Remove not requried fields */
delete data_list[i].categories;
delete data_list[i].user_city;
delete data_list[i].user_state;
delete data_list[i].truck_type;
}
const retVal = {
total : queryVal.total,
limit : queryVal.limit,
skip : queryVal.skip,
data : data_list
};
return res.status(200).send( retVal );
} catch ( err ){
console.error( err );
return res.status(500).send({ error : "Public-Companies: Internal error" });
}
};
module.exports = { getListShippers, getListCarriers, getUserLists };

View File

@@ -0,0 +1,7 @@
'use strict';
const router = require('express').Router();
const services= require('./services.js');
router.get('/download/:id', services.getAttachmentFile );
module.exports = router;

View File

@@ -0,0 +1,22 @@
"use strict";
const { ROOT_PATH, LIB_PATH, MODELS_PATH, API_CONFIG } = process.env;
const { downloadFile } = require(`${ROOT_PATH}/${LIB_PATH}/Misc`);
const apiConfig = require( `${ROOT_PATH}/${API_CONFIG}` );
const s3Bucket = apiConfig.S3.bucket;
const s3BucketKey = apiConfig.S3.load_attachments_key;
const getAttachmentFile = async(req, res) => {
try{
const attachmentId = req.params.id;
const file = await downloadFile( s3Bucket, s3BucketKey, attachmentId );
res.attachment( attachmentId );
res.setHeader('Content-Type', file.ContentType );
res.send( file.Body );
}catch( error ){
console.error( error );
res.status(500).send({ error });
}
}
module.exports = { getAttachmentFile };

View File

@@ -0,0 +1,7 @@
'use strict';
const router = require('express').Router();
const services= require('./services.js');
router.get('/:id', services.getById);
module.exports = router;

View File

@@ -0,0 +1,55 @@
"use strict";
const { getModel } = require( '../../../lib/Models' );
const Model = getModel('loads');
const vehicle_projection = ['background_tracking','status','last_location_lat',
'last_location_lng','last_location_geo','last_location_time']
const user_projection = ['first_name','last_name','middle_name']
const company_projection = ["company_name"]
const populate_list = [
{path:'posted_by',select: user_projection },
{path:'vehicle',select: vehicle_projection },
{path:'company',select: company_projection },
'posted_by_name',
'categories'
];
const getById = async(req, res) => {
try{
const elementId = req.params.id;
const select = [
"categories",
"truck_type",
"published_date",
"createdAt",
"status",
"load_status",
"weight",
"est_loading_date",
"est_unloading_date",
"origin.city",
"origin_geo",
"origin.state",
"destination.city",
"destination.state",
"destination_geo",
];
// const load = await Model.findOne( { _id : elementId , load_status : "Transit" } , select ).populate( populate_list );
const load = await Model.findById( elementId , select ).populate( populate_list );
if( load ){
return res.send( load );
}else{
return res.status(400).send({
error : `Load [${elementId}] not found!`
})
}
}catch(error){
console.error( error );
return res.status( 500 ).send({ error });
}
};
module.exports = { getById };

View File

@@ -0,0 +1,7 @@
'use strict';
const router = require('express').Router();
const services= require('./services.js');
router.get('/', services.getList);
module.exports = router;

View File

@@ -0,0 +1,32 @@
"use strict";
const { ROOT_PATH, LIB_PATH, MODELS_PATH, HANDLERS_PATH } = process.env;
const { getPagination , getPage } = require( `${ROOT_PATH}/${LIB_PATH}/Misc.js` );
const { GenericHandler } = require( `${ROOT_PATH}/${HANDLERS_PATH}/Generic.handler.js` );
const Model = require( `${ROOT_PATH}/${MODELS_PATH}/loads.model.js` );
const categoriesModel = require( `${ROOT_PATH}/${MODELS_PATH}/product-categories.model.js` );
const populate_list = ['categories'];
const generic = new GenericHandler( Model, null, populate_list );
const getList = async(req, res) => {
const filter = { status : "Published" };
const select = [
"categories",
"truck_type",
"published_date",
"createdAt",
"status",
"weight",
"est_loading_date",
"est_unloading_date",
"origin.city",
"origin.state",
"destination.city",
"destination.state",
];
const { page , elements } = getPagination( req.query );
const retVal = await generic.getList(page , elements, filter, select );
res.send( retVal );
};
module.exports = { getList };

View File

@@ -0,0 +1,8 @@
'use strict';
const router = require('express').Router();
const services= require('./services.js');
router.get('/published', services.getListPublished);
router.get('/location', services.getListLocations);
module.exports = router;

View File

@@ -0,0 +1,71 @@
"use strict";
const { ROOT_PATH, LIB_PATH, MODELS_PATH, HANDLERS_PATH } = process.env;
const { getPagination , getPage } = require( `${ROOT_PATH}/${LIB_PATH}/Misc.js` );
const { GenericHandler } = require( `${ROOT_PATH}/${HANDLERS_PATH}/Generic.handler.js` );
const Model = require( `${ROOT_PATH}/${MODELS_PATH}/vehicles.model.js` );
const categoriesModel = require( `${ROOT_PATH}/${MODELS_PATH}/product-categories.model.js` );
const populate_list = ['categories'];
const generic = new GenericHandler( Model, null, populate_list );
const getListPublished = async(req, res) => {
const filter = { is_available : true };
const select = [
"city",
"state",
"truck_type",
"tyre_type",
"destino",
"available_in",
"available_date",
"createdAt",
"updatedAt",
"published_date",
"status",
"is_available",
"categories"
];
const { elements } = getPagination( req.query );
const page = 0;// No pagination allowed to this endpoint
let query_elements;
if( elements >= 100 ){
query_elements = 100;// Never return more than 100 elements
}else{
query_elements = elements;
}
const retVal = await generic.getList(page , query_elements, filter, select );
res.send( retVal );
};
const getListLocations = async(req, res) => {
const filter = { status : "Free" };
const select = [
"last_location_geo",
"driver",
"updatedAt",
"status",
"categories"
];
const { elements } = getPagination( req.query );
const page = 0;// No pagination allowed to this endpoint
let query_elements;
if( elements >= 100 ){
query_elements = 100;// Never return more than 100 elements
}else{
query_elements = elements;
}
const objQuery = await generic.getListQuery( page , query_elements, filter, select );
const data = await objQuery.query.sort("field -updatedAt").populate("categories").exec();
const retVal = {
total : objQuery.total,
limit : objQuery.limit,
skip : objQuery.skip,
data : data
};
res.send( retVal );
};
module.exports = { getListPublished, getListLocations };

View File

@@ -0,0 +1,9 @@
'use strict';
const router = require('express').Router();
const services= require('./services.js');
router.get('/', services.getList);
router.get('/find', services.findList);
router.get('/:id', services.getById);
module.exports = router;

View File

@@ -0,0 +1,33 @@
"use strict";
const { ROOT_PATH, LIB_PATH, MODELS_PATH, HANDLERS_PATH } = process.env;
const { getPagination , getPage } = require( `${ROOT_PATH}/${LIB_PATH}/Misc.js` );
const { GenericHandler } = require( `${ROOT_PATH}/${HANDLERS_PATH}/Generic.handler.js` );
const Model = require( `${ROOT_PATH}/${MODELS_PATH}/states.model.js` );
const generic = new GenericHandler( Model, "state_name" );
const getList = async(req, res) => {
const { page , elements } = getPagination( req.query );
const retVal = await generic.getList(page , elements);
res.send( retVal );
};
const findList = async(req, res) => {
const findString = req.query.regex || null;
const { page , elements } = getPagination( req.query );
let retVal;
if( findString ){
retVal = await generic.findList( findString, page, elements );
}else{
retVal = await generic.getList(page , elements);
}
res.send( retVal );
};
const getById = async(req, res) => {
const id=req.params.id;
const retVal = await generic.getById( id );
res.send( retVal );
};
module.exports = { getList , findList , getById };

View File

@@ -0,0 +1,8 @@
'use strict';
const router = require('express').Router();
const services= require('./services.js');
router.post('/apitest', services.postTest);
router.get('/version', services.getVersion);
module.exports = router;

View File

@@ -0,0 +1,20 @@
"use strict";
const { ROOT_PATH, LIB_PATH, API_CONFIG } = process.env;
const apiConfig = require( `${ROOT_PATH}/${API_CONFIG}` );
const postTest = async(req, res) => {
res.send({
msg:"Hello world!",
data:{
apiQuery:req.query,
apiParams:req.params.params,
body:req.body,
}
});
};
const getVersion = async(req, res) => {
res.send( apiConfig.version );
};
module.exports = { postTest , getVersion };

View File

@@ -0,0 +1,48 @@
{
"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": "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",
"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"
}

View File

@@ -0,0 +1,48 @@
{
"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": "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",
"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://localhost/etaviaporte?retryWrites=true&w=majority"
}

73
v1/src/index.js Normal file
View File

@@ -0,0 +1,73 @@
'use strict';
require('dotenv').config();
const { ROOT_PATH, LIB_PATH, API_CONFIG } = process.env;
const apiConfig = require( `${ROOT_PATH}/${API_CONFIG}` );
const apps = require('./apps');
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');
const middlewares = require( `${ROOT_PATH}/${LIB_PATH}/Middlewares.js` );
const mongoose = require('mongoose');
mongoose.connect(
apiConfig.mongodb,
{ useNewUrlParser: true }
).then( ( val ) => {
console.log( `MongoDB Connected : ${ apiConfig.mongodb }` );
});//catch throw error so service stops!
const app = express();
const serverPort = process.env.SERVER_PORT || 3000;
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']
}));
app.use( middlewares.errorJSON );
app.use( apps );
app.use( middlewares.error404 );
app.listen( serverPort , function(err){
if( !err ){
console.log('API listen on port', serverPort );
}else{
console.log( err );
}
});

View File

@@ -0,0 +1,123 @@
'user strict';
const { ROOT_PATH, API_CONFIG, MODELS_PATH, LIB_PATH } = process.env;
const { getModel } = require( `${ROOT_PATH}/${MODELS_PATH}` );
const apiConfig = require( `${ROOT_PATH}/${API_CONFIG}` );
const { toSha256 } = require( `${ROOT_PATH}/${LIB_PATH}/Misc.js` );
const UserModel = getModel('users');
const companiesModels = getModel('companies');
const pwd_secret = apiConfig.authentication.pwdSecret;
async function create_account( email, password ){
let safe_password = toSha256( password + pwd_secret );
const user = new UserModel({
email,
password : safe_password,
job_role : 'owner',//Always a new user created from signup is owner
isVerified : true,
has_password : true
});
await user.save();
// Create user code
const id = "" + user._id;
const employee_id = "E-" + id.substring( 0 , 6 );
await UserModel.findByIdAndUpdate( id , {
employee_id
});
}
async function reset_password( email, password ){
let safe_password = toSha256( password + pwd_secret );
const user = await UserModel.findOne({ email });
user.password = safe_password;
user.isVerified = true;
user.has_password = true;
await user.save();
return user;
}
async function already_exists( email ){
const user = await UserModel.findOne( { email } );
if( !user ){
return false;
}else{
return true;
}
}
async function verify_driver_account( email ){
const user = await UserModel.findOne( { email } );
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 function login( email , password ){
let safe_password = toSha256( password + pwd_secret );
const user = await UserModel.findOne({
email , password : safe_password
},{ password : 0 , session_token : 0 , session_token_exp : 0 }).populate('company');
return user;
}
async function login_with_session_token( session_token ){
const user = await UserModel.findOne({
session_token,
session_token_exp : { $gte: new Date() }
},{ password : 0 , session_token : 0 , session_token_exp : 0 }).populate('company');
return user;
}
async function complete_register( userId , data ){
let {
company_type
} = data;
let permissions;
if( company_type.toLowerCase() === "shipper" ){
company_type = "Shipper";
permissions = "role_shipper";
}else if( company_type.toLowerCase() === "carrier" ){
company_type = "Carrier";
permissions = "role_carrier";
}else{
throw "Invalid company type";
}
data.company_type = company_type;
const user = await UserModel.findById( userId , { password : 0 , session_token : 0 , session_token_exp : 0 } );
if( user.company ){
throw "User already register";
}
const company = new companiesModels( data );
await company.save();
user.company = company;
user.job_role = "owner";
user.permissions = permissions;
user.isVerified = true;
await user.save();
return company;
}
module.exports = { create_account, already_exists, verify_driver_account, login, login_with_session_token, reset_password, complete_register };

View File

@@ -0,0 +1,111 @@
"use strict";
const { ROOT_PATH, LIB_PATH, MODELS_PATH, HANDLERS_PATH } = process.env;
async function getPage( page, elements, Model, filter=null, projection=null){
const skip = elements * page;
const total = await Model.count( filter );
const list = await Model.find( filter , projection, { skip : skip , limit : elements } );
return {
total : total,
limit : elements,
skip : skip,
data : list
}
}
async function getPageQuery(page, elements, Model, filter=null, projection=null){
const skip = elements * page;
const total = await Model.count( filter );
return {
query : Model.find( filter , projection, { skip : skip , limit : elements } ),
total : total,
skip : skip
};
}
class GenericHandler{
constructor( Model, search_param=null, populate_list=null, populate_select=null ) {
this.Model = Model;
this.search_param = search_param || null;
this.populate_list = populate_list || [];
this.populate_select = populate_select || null;
}
async populateQuery( query ){
if( this.populate_list.length > 0 ){
query.populate( this.populate_list );
}
else
if( this.populate_select != null ){
for( const [key,value] of Object.entries(this.populate_select) ){
query.populate( key , value );
}
}
return await query.exec();
}
async getList( page, elements, filter=null, projection=null, sort=null ){
const { query , total, skip } = await getPageQuery( page , elements, this.Model, filter, projection );
if( sort ){
query.sort( sort );
}
const list = await this.populateQuery( query );
return {
total : total,
limit : elements,
skip : skip,
data : list
};
}
/**
* Not populated query.
*
* Typical usage:
* @code{js}
* const queryObj = await generic.getListQuery(page, elements, filter, projection );
* queryObj.query.SOME_ACTIONS();
* const data = await generic.populateQuery( queryObj.query );
* @endcode
* @param {*} page
* @param {*} elements
* @param {*} filter
* @param {*} projection
* @returns { total , limit, skip, query}
*/
async getListQuery( page, elements , filter=null, projection=null, sort=null ){
const { query , total, skip } = await getPageQuery( page , elements, this.Model, filter, projection );
if( sort ){
query.sort( sort );
}
return {
total : total,
limit : elements,
skip : skip,
query : query
};
}
async findList( find_string, page, elements, projection=null ){
if( !this.search_param ){
throw new Error( "No search parameter setted up" );
}
const search_param = this.search_param;
const re = new RegExp( find_string );
const filter = {};
filter[ search_param ] = { $regex: re, $options: 'i' };
return await this.getList( page, elements, filter, projection );
}
async getById( id, projection=null ){
const query = Model.findById( id, projection );
return await this.populateQuery( query );
}
};
module.exports = { getPage, getPageQuery, GenericHandler };

View File

@@ -0,0 +1,85 @@
'user strict';
const { ROOT_PATH, API_CONFIG } = process.env;
const apiConfig = require( `${ROOT_PATH}/${API_CONFIG}` );
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 };

View File

@@ -0,0 +1,24 @@
'user strict';
const { ROOT_PATH, API_CONFIG } = process.env;
const nodemailer = require("nodemailer");
const apiConfig = require( `${ROOT_PATH}/${API_CONFIG}` );
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 };

View File

@@ -0,0 +1,50 @@
'user strict';
const { ROOT_PATH, HANDLERS_PATH, MODELS_PATH, API_CONFIG } = process.env;
const { StandAloneContactEmail } = require('./StandAlone.handler');
const { AccountVerifyEmail, AccountConfirmed, AccountPwdResetEmail, ContactEmail } = require('./SendGrid.handler');
const EMAIL_EVENTS={
ACCOUNT_VERIFY:1,
ACCOUNT_CONFIRMED:2,
ACCOUNT_PWD_RESET:3,
CONTACT_EMAIL:4,
}
/**
* Send an email according to the event.
* @param eventId : string
* @param email_content : { string receiver, {*} content }
* @returns
*/
async function emailEvent( eventId, receiver , content ){
switch( eventId ){
case EMAIL_EVENTS.ACCOUNT_VERIFY:
{
return await AccountVerifyEmail( receiver, content );
}
break;
case EMAIL_EVENTS.ACCOUNT_CONFIRMED:
{
return await AccountConfirmed( receiver, content );
}
break;
case EMAIL_EVENTS.ACCOUNT_PWD_RESET:
{
return await AccountPwdResetEmail( receiver, content );
}
break;
case EMAIL_EVENTS.CONTACT_EMAIL:
{
await StandAloneContactEmail( content );
return await ContactEmail( receiver, content );
}
break;
default:
{
throw new Error(`Email event not defined ${eventId}`);
}
break;
}
}
module.exports = { emailEvent , EMAIL_EVENTS };

View File

@@ -0,0 +1,52 @@
'user strict';
const { getModel } = require( '../Models' );
const vehiclesModel = require('../Models/vehicles.model');
const proposalsModel = getModel('proposals');
const loadsModel = getModel('loads');
const usersModel = getModel('users');
const companiesModel = getModel('companies');
/**
* When the proposal is accepted then the load should be updated to have the
* @param {*} id
* @param {*} newProposalData
* @returns
*/
async function onPatchEvent( id , newProposalData ){
const proposal = await proposalsModel.findById( id );
if( !newProposalData.is_accepted ){
/// Update Proposal:
/// Remove shipper
await proposalsModel.findByIdAndUpdate( id , {
shipper : null
} );
/// Update Load:
/// Remove carrier, driver and vehicle
await loadsModel.findByIdAndUpdate( proposal.load, {
carrier : null,
driver : null,
vehicle : null,
} );
}else{
const shipper_user = await usersModel.findById( proposal.accepted_by );
const shipper = await companiesModel.findById( shipper_user.company );
const vehicle = await vehiclesModel.findById( proposal.vehicle );
/// Update Proposal:
/// Adding shipper to proposal
await proposalsModel.findByIdAndUpdate( id , {
shipper : shipper.id
} );
/// Update Load:
/// Add carrier, driver and vehicle
await loadsModel.findByIdAndUpdate( proposal.load, {
carrier : proposal.carrier,
driver : vehicle.driver,
vehicle : proposal.vehicle,
} );
}
}
module.exports = { onPatchEvent };

View File

@@ -0,0 +1,187 @@
'user strict';
const { ROOT_PATH, HANDLERS_PATH, LIB_PATH } = process.env;
const { getModel } = require( '../Models' );
const { GenericHandler } = require( `${ROOT_PATH}/${HANDLERS_PATH}/Generic.handler.js` );
const { getPagination } = require( `${ROOT_PATH}/${LIB_PATH}/Misc.js` );
const usersModel = getModel('users');
const companiesModel = getModel('companies');
const populate_list = ['company','branch','vehicle','active_load','categories'];
const generic = new GenericHandler( usersModel, "first_name", populate_list );
async function getUserById( id , filter ){
if( filter ){
filter._id = id;
const user = await usersModel.findOne( filter , { password : 0 , session_token : 0 , session_token_exp : 0 } );
return user;
}else{
return await usersModel.findById( id , { password : 0 , session_token : 0 , session_token_exp : 0 } ).populate('company');
}
}
function getAndFilterList( query ){
const filter_list = [];
const { email, permissions, gender, job_role, employee_id, company, branch, vehicle, active_load, categories } = query;
if( email ){ filter_list.push( { email } ); }
if( permissions ){ filter_list.push( { permissions } ); }
if( gender ){ filter_list.push( { gender } ); }
if( job_role ){ filter_list.push( { job_role } ); }
if( employee_id ){ filter_list.push( { employee_id } ); }
if( company ){ filter_list.push( { company } ); }
if( branch ){ filter_list.push( { branch } ); }
if( vehicle ){ filter_list.push( { vehicle } ); }
if( active_load ){ filter_list.push( { active_load } ); }
if( categories ){ filter_list.push( { categories } ); }
if( filter_list.length == 0 ){
return null;
}
return filter_list;
}
async function findUsers( query ){
const filter = { "is_hidden" : false , "is_deleted" : false };
const { page, elements } = getPagination( query );
const andFilterList = getAndFilterList( query );
if( andFilterList ){
filter.$and = andFilterList;
}
let search_param;
let search_value;
if( query.first_name ){
search_param = "first_name";
search_value = query.first_name;
}
else if( query.last_name ){
search_param = "last_name";
search_value = query.last_name;
}
else if( query.middle_name ){
search_param = "middle_name";
search_value = query.middle_name;
}
else if( query.email ){
search_param = "email";
search_value = query.email;
}
else if( query.phone ){
search_param = "phone";
search_value = query.phone;
}
else if( query.phone2 ){
search_param = "phone2";
search_value = query.phone2;
}
if( search_param ){
const re = new RegExp( search_value );
filter[ search_param ] = { $regex: re, $options: 'i' };
}
const queryVal = await generic.getList(page , elements, filter, { password : 0 , session_token : 0 , session_token_exp : 0 } );
return {
total : queryVal.total,
limit : queryVal.limit,
skip : queryVal.skip,
data : queryVal.data
};
}
function clean_user_data( data , company ){
/// Avoid modifying sensitive fields.
if( data.password ){ delete data.password; }
if( data.company ){ delete data.company; }
if( data.job_role ){
/// System can only create manager,driver or staff.
if( (data.job_role !== "manager") && (data.job_role !== "driver") && (data.job_role !== "staff") ){
data.job_role = "staff";
}
}
if( data.permissions ){ delete data.permissions; }
if( company ){
if( company.company_type === 'Shipper' ){
data.permissions = "role_shipper";
}else
if( company.company_type === 'Carrier' ){
data.permissions = "role_carrier";
}
}
if( data.session_token ){ delete data.session_token; }
if( data.session_token_exp ){ delete data.session_token_exp; }
if( data.is_deleted ){ delete data.is_deleted; }
return data;
}
async function patchUserData( id , data ){
/// Avoid modifying sensitive fields.
data = clean_user_data( data , null );
const user = await usersModel.findById( id , { password : 0 , session_token : 0 , session_token_exp : 0 } );
if( (data.email) && (data.email !== user.email) ){
const user_already_exists = await usersModel.findOne({ email : data.email });
if( user_already_exists ){
throw "email already exists, please choose other";
}
/// Changing the email requires a password recovery in order to verify the email!!
data.password = "reset your password please";
}else{
delete data.email;
}
await usersModel.findByIdAndUpdate( id , data );
return await usersModel.findById( id , { password : 0 , session_token : 0 , session_token_exp : 0 } ).populate('company');
}
async function createUserWithinCompany( companyId , data ){
const company = await companiesModel.findById( companyId );
/// Avoid modifying sensitive fields.
data = clean_user_data( data , company );
data.company = companyId;
if( data.email ){
const user_already_exists = await usersModel.findOne({ email : data.email });
if( user_already_exists ){
throw "email already exists";
}
}else{
throw "email is required";
}
data.isVerified = false;
const user = new usersModel( data );
await user.save();
// Create user code
const id = "" + user._id;
const employee_id = "E-" + id.substring( 0 , 6 );
await usersModel.findByIdAndUpdate( id , {
employee_id
});
user.employee_id = employee_id;
return user;
}
async function deleteUserWithinCompany( manager_id , user_to_remove_id ){
if( manager_id === user_to_remove_id ){ throw "Manager can not remove it self"; }
const manager = await usersModel.findById( manager_id ).populate( "company" );
const company = manager.company;
if( !manager ){ throw "Invalid manager or owner"; }
if( !company ){ throw "Invalid company"; }
const user = await usersModel.findOne( {
_id : user_to_remove_id ,
company : manager.company.id
} );
if( !user ){ throw "User is invalid"; }
await usersModel.findOneAndDelete( {
_id : user_to_remove_id ,
company : manager.company.id
} );
return user;
}
module.exports = { getUserById , findUsers , patchUserData , createUserWithinCompany , deleteUserWithinCompany };

87
v1/src/lib/Middlewares.js Normal file
View 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,
};

105
v1/src/lib/Misc.js Normal file
View File

@@ -0,0 +1,105 @@
"use strict";
const { ROOT_PATH, API_CONFIG } = process.env;
const apiConfig = require( `${ROOT_PATH}/${API_CONFIG}` );
const crypto = require('crypto');
const { S3Client, GetObjectCommand } = require('@aws-sdk/client-s3');
const s3Client = new S3Client({
region : apiConfig.S3.region,
credentials : {
accessKeyId : apiConfig.S3.accessKeyId,
secretAccessKey : apiConfig.S3.secretAccessKey
}
});
const secret = apiConfig.authentication.jwtSecret;
const tokenSecret = apiConfig.authentication.tokenSecret;
/**
* Convert string to sha256 string in hex
* @param {*} text
* @returns
*/
function toSha256( text ){
return crypto.createHmac( "sha256" , "" ).update( text ).digest( 'hex' );
}
/**
* Generate string with fixed length with random content.
* Length is limited to 64 characters.
* @param {*} text
* @returns
*/
function genKey( len = 5 , key="" ){
if( len >= 64 ){
throw "invalid key len";
}
const shacode = toSha256( key + new Date() + tokenSecret );
const otp_hex = shacode.slice(0 , len );
const otp_dec = Number.parseInt( otp_hex , 16 );
return ""+otp_dec;
}
function getPagination( query ){
let limit = {
page : 0,
elements : 10
};
if( query.page ){
limit.page = parseInt( query.page ) || 0;
if( limit.page < 0 ){
limit.page = 0;
}
}
if( query.elements ){
limit.elements = parseInt( query.elements ) || 10;
/** Safe pagination limit */
if( limit.elements > 1000 ){
limit.elements = 1000;
}
else if( limit.elements < 0 ){
limit.elements = 10;
}
}
return limit;
}
async function getPage( page, elements, model, filter=null, projection=null){
const skip = elements * page;
const total = await model.count( filter );
const list = await model.find( filter , projection, { skip : skip , limit : elements } );
return {
total : total,
limit : elements,
skip : skip,
data : list
}
}
async function queryPage(page, elements, model, filter=null, projection=null){
const skip = elements * page;
const total = await model.count( filter );
return {
query : model.find( filter , projection, { skip : skip , limit : elements } ),
total : total,
skip : skip
};
}
async function downloadFile( bucket, key, obj_id ){
const params = {
Bucket: bucket,
Key : `${key}/${obj_id}`
};
const s3resp = await s3Client.send( new GetObjectCommand( params ) );
const chunks = []
for await (const chunk of s3resp.Body) {
chunks.push(chunk)
}
const body = Buffer.concat(chunks);
s3resp.Body = body;
return s3resp;
}
module.exports = { genKey , toSha256, getPagination, getPage, queryPage, downloadFile};

View File

@@ -0,0 +1,16 @@
const mongoose = require('mongoose');
const { Schema } = mongoose;
const schema = new Schema({
categories: [{ type: Schema.Types.ObjectId, ref: 'productcategories' }],
company: { type: Schema.Types.ObjectId, ref: 'companies' },
branch_name: { type: String },
phone: { type: String },
city: { type: String },
state: { type: String },
truck_type: [{ type: String }],
description:{type: String},
address : { type: String }
});
module.exports = mongoose.model( "branches", schema );

View File

@@ -0,0 +1,33 @@
const mongoose = require('mongoose');
const { Schema } = mongoose;
const schema = new Schema({
company: { type: Schema.Types.ObjectId, ref: 'companies', required: true},
client: { type: String, required: true },
material: { type: String },
origin: { type: String },
destination: { type: String },
truck_type: { type: String },
num_tons: { type: Number },
price_per_ton: { type: Number },
tonnage: { type: String },
pickup_distance: { type: Number },
delivery_distance: { type: Number },
warehouse_distance: { type: Number },
total_km_travel: { type: Number },
cost_per_liter: { type: Number },
fuel_price_per_liter: { type: Number },
other_fuel_expenses: { type: Number },
total_fuel_consumed: { type: Number },
total_cost_fuel: { type: Number },
driver_salary: { type: Number },
accomadation_allowance: { type: Number },
other_administrative_expenses: { type: Number },
total_before_tax: { type: Number },
total_utility_per_km: { type: Number },
total_profit: { type: Number },
profit_percentage: { type: Number },
total_administrative_expenses: { type: Number }
});
module.exports = mongoose.model( "budgets", schema );

View File

@@ -0,0 +1,11 @@
const mongoose = require('mongoose');
const { Schema } = mongoose;
const schema = new Schema({
country_name: { type: String },
country_code: { type: String },
state_name: { type: String },
city_name: { type: String, required: true }
});
module.exports = mongoose.model( "cities", schema );

View File

@@ -0,0 +1,65 @@
const mongoose = require('mongoose');
const { Schema } = mongoose;
const meta_data = new Schema({
meta_group: { type: String },
meta_key: { type: String },
meta_value: { type: String },
});
const company_contacts = new Schema({
meta_key: { type: String },
meta_value: { type: String },
});
const address = new Schema({
street_address1: { type: String },
street_address2: { type: String },
city: { type: String },
state: { type: String },
country: { type: String },
zipcode: { type: String },
landmark: { type: String },
lat: { type: String },
lng: { type: String },
});
const schema = new Schema({
company_serial_number: { type: String },
company_code: { type: String },
is_company: { type: String }, //1000
company_name: { type: String, required: true },
company_legal_name: { type: String },
company_description: { type: String },
rfc: { type: String },
company_type: { type: String, enum : [ 'Shipper', 'Carrier' ] },
is_broker: { type: Boolean, default: false },
membership: { type: String },
membership_start_at: { type: Date },
meta_data: [meta_data],
categories: [{ type: Schema.Types.ObjectId, ref: 'productcategories' }],
products: { type: Schema.Types.ObjectId, ref: 'products' },
branches: [{ type: Schema.Types.ObjectId, ref: 'branches' }],
company_city: [{ type: String }],
company_state: [{ type: String }],
truck_type: [{ type: String }],
street_address1: { type: String },
street_address2: { type: String },
city: { type: String },
state: { type: String },
country: { type: String },
zipcode: { type: String },
landmark: { type: String },
lat: { type: String },
lng: { type: String },
is_hidden: { type: Boolean, default: false },
createdAt: { type : Date, required : true, default : () => { return Date.now(); } }
});
module.exports = mongoose.model( "companies", schema );

View File

@@ -0,0 +1,10 @@
const mongoose = require('mongoose');
const { Schema } = mongoose;
const schema = new Schema({
country_name: { type: String, required: true },
country_code: { type: String, required: true },
phone_code: { type: String, required: true }
});
module.exports = mongoose.model( "countries", schema );

View File

@@ -0,0 +1,73 @@
"use strict";
const branches = require('./branches.model.js');
const budgets = require('./budgets.model.js');
const cities = require('./cities.model.js');
const companies = require('./companies.model.js');
const countries = require('./countries.model.js');
const load_attachments = require('./load-attachments.model.js');
const loads = require('./loads.model.js');
const mailer = require('./mailer.model.js');
const memberships = require('./memberships.model.js');
const meta_data = require('./meta-data.model.js');
const meta_groups = require('./meta-groups.model.js');
const news = require('./news.model.js');
const orders = require('./orders.model.js');
const product_categories = require('./product-categories.model.js');
const products = require('./products.model.js');
const proposals = require('./proposals.model.js');
const states = require('./states.model.js');
const trackings = require('./trackings.model.js');
const users = require('./users.model.js');
const vehicles = require('./vehicles.model.js');
function getModel( name ){
switch( name ){
case 'branches':
return branches;
case 'budgets':
return budgets;
case 'cities':
return cities;
case 'companies':
return companies;
case 'countries':
return countries;
case 'load_attachments':
return load_attachments;
case 'loads':
return loads;
case 'mailer':
return mailer;
case 'memberships':
return memberships;
case 'meta_data':
return meta_data;
case 'meta_groups':
return meta_groups;
case 'news':
return news;
case 'orders':
return orders;
case 'product_categories':
return product_categories;
case 'products':
return products;
case 'proposals':
return proposals;
case 'states':
return states;
case 'trackings':
return trackings;
case 'users':
return users;
case 'vehicles':
return vehicles;
default:
return null;
}
}
module.exports = {
getModel
};

View File

@@ -0,0 +1,19 @@
const mongoose = require('mongoose');
const { Schema } = mongoose;
const schema = new Schema({
status: { type: String, default: 'Draft', enum: ['Draft', 'Done'] },/*Once in Done state, no changes are allowed.*/
updatedAt: {
type: Date,
default : () => Date.now()
},
type: { type: String, enum: ['Loading', 'Downloading'], required : true },
company: { type: Schema.Types.ObjectId, ref: 'companies', required: true }, //shipper
carrier: { type: Schema.Types.ObjectId, ref: 'companies', required: true }, // carrier
load: { type: Schema.Types.ObjectId, ref: 'loads', required: true },
author: { type: Schema.Types.ObjectId, ref: 'users', required: true },
doneAt: { type: Date }
});
module.exports = mongoose.model( "loadattachments", schema );

View File

@@ -0,0 +1,91 @@
const mongoose = require('mongoose');
const { Schema } = mongoose;
const address = new Schema({
company_name: { type: String },
street_address1: { type: String },
street_address2: { type: String },
city: { type: String },
state: { type: String },
country: { type: String },
zipcode: { type: String },
landmark: { type: String },
lat: { type: String },
lng: { type: String },
});
const pointSchema = new Schema({
type: {
type: String,
enum: ['Point'],
required: true
},
coordinates: {
type: [Number],
required: true
}
});
const schema = new Schema({
shipment_code: { type: String },
company: { type: Schema.Types.ObjectId, ref: 'companies', required: true }, //shipper
carrier: { type: Schema.Types.ObjectId, ref: 'companies' }, // carrier
vehicle: { type: Schema.Types.ObjectId, ref: 'vehicles' },
driver: { type: Schema.Types.ObjectId, ref: 'users' },
posted_by: { type: Schema.Types.ObjectId, ref: 'users' }, // shipper
posted_by_name: { type: String }, // search purpose
bidder: { type: Schema.Types.ObjectId, ref: 'users' },
origin: address,
origin_geo: {
type: pointSchema,
},
destination: address,
destination_geo: {
type: pointSchema,
},
categories: [{ type: Schema.Types.ObjectId, ref: 'productcategories' }],
product: { type: Schema.Types.ObjectId, ref: 'products' },
truck_type: { type: String },
tyre_type: { type: String },
weight: { type: Number },
estimated_cost: { type: Number },
distance: { type: Number },
actual_cost: { type: Number },
// 1. Posted Shipments (Posted)
// 2. Shipments Loading (Loading)
// 3. Enroute Shipments (In Transit)
// 4. Shipments in Unloading (Unloading)
// 5. Shipments pending finding truck
status: { type: String, default: 'Draft', enum: ['Draft', 'Published', 'Completed', 'Closed'] },
load_status: { type: String, enum: ['Published', 'Loading', 'Transit', 'Downloading', 'Delivered'] },
contract_start_date: { type: Date },
contract_end_date: { type: Date },
est_loading_date: { type: Date },
est_unloading_date: { type: Date },
published_date: { type: Date },
loaded_date: { type: Date },
transit_date: { type: Date },
delivered_date: { type: Date },
load_status_updated: { type: Date, default: () => Date.now() },
notes: { type: String },
payment_term: { type: String },
terms_and_conditions: { type: String },
createdAt: { type : Date, required : true, default : () => { return Date.now(); } }
});
module.exports = mongoose.model( "loads", schema );

View File

@@ -0,0 +1,8 @@
const mongoose = require('mongoose');
const { Schema } = mongoose;
const schema = new Schema({
text: { type: String, required: true }
});
module.exports = mongoose.model( "mailer", schema );

View File

@@ -0,0 +1,10 @@
const mongoose = require('mongoose');
const { Schema } = mongoose;
const schema = new Schema({
name: { type: String, required: true }, // free, pro
price: { type: Number },
validity : { type: Number }, // number 0f days
});
module.exports = mongoose.model( "memberships", schema );

View File

@@ -0,0 +1,10 @@
const mongoose = require('mongoose');
const { Schema } = mongoose;
const schema = new Schema({
meta_group: { type: Schema.Types.ObjectId, ref: 'metagroups'},// settings, terms, collaborator
meta_key: { type: String, required: true }, // collaborator
meta_value: { type: String }
});
module.exports = mongoose.model( "metadatas", schema );

View File

@@ -0,0 +1,11 @@
const mongoose = require('mongoose');
const { Schema } = mongoose;
const schema = new Schema({
group_label: { type: String, required: true },
group_key: { type: String, required: true },
group_field_type: { type: String,default:'text' }, // text, textarea, html, select
group_options: [{ type: String }]
});
module.exports = mongoose.model( "metagroups", schema );

View File

@@ -0,0 +1,26 @@
const mongoose = require('mongoose');
const { Schema } = mongoose;
const attachFile = new Schema({
file:{ type: String },
originalname:{ type: String },
mimetype:{ type: String },
focus_point:[{
thumbnail:{ type: String, default:"main" },
x:{ type: Number },
y:{ type: Number },
w:{ type: Number },
h:{ type: Number },
s:{ type: Number }
}]
});
const schema = new Schema({
title : { type: String, required: true },
description : { type: String, required: true },
link_text : { type: String, required: true },
link_url : { type: String, required: true },
news_image: attachFile,
});
module.exports = mongoose.model( "news", schema );

View File

@@ -0,0 +1,11 @@
const mongoose = require('mongoose');
const { Schema } = mongoose;
const schema = new Schema({
load: { type: Schema.Types.ObjectId, ref: 'loads' },
shipper: { type: Schema.Types.ObjectId, ref: 'companies' }, // how offers load
carrier: { type: Schema.Types.ObjectId, ref: 'companies' }, // how transport the load
vehicle: { type: Schema.Types.ObjectId, ref: 'vehicles' },
});
module.exports = mongoose.model( "orders", schema );

View File

@@ -0,0 +1,8 @@
const mongoose = require('mongoose');
const { Schema } = mongoose;
const schema = new Schema({
name: { type: String, required: true } // fruit, boxes, wood
});
module.exports = mongoose.model( "productcategories", schema );

View File

@@ -0,0 +1,9 @@
const mongoose = require('mongoose');
const { Schema } = mongoose;
const schema = new Schema({
name: { type: String, required: true },
segment: { type: String},
});
module.exports = mongoose.model( "products", schema );

View File

@@ -0,0 +1,22 @@
const mongoose = require('mongoose');
const { Schema } = mongoose;
const schema = new Schema({
load: { type: Schema.Types.ObjectId, ref: 'loads' },
shipper: { type: Schema.Types.ObjectId, ref: 'companies' }, // who offers load
carrier: { type: Schema.Types.ObjectId, ref: 'companies' }, // who transport the load
vehicle: { type: Schema.Types.ObjectId, ref: 'vehicles' },
bidder: { type: Schema.Types.ObjectId, ref: 'users' },
comment: { type: String },
is_withdrawn: { type: Boolean, default: false },
accepted_by: { type: Schema.Types.ObjectId, ref: 'users' },
accepted_date: { type: Date },
is_accepted: { type: Boolean, default: false },
createdAt: { type : Date, required : true, default : () => { return Date.now(); } }
});
module.exports = mongoose.model( "proposals", schema );

View File

@@ -0,0 +1,12 @@
const mongoose = require('mongoose');
const { Schema } = mongoose;
const schema = new Schema({
country_name: { type: String},
country_code: { type: String },
state_name: { type: String, required: true },
state_code: { type: String }
});
module.exports = mongoose.model( "states", schema );

View File

@@ -0,0 +1,12 @@
const mongoose = require('mongoose');
const { Schema } = mongoose;
const schema = new Schema({
lat: { type: String },
lng: { type: String },
user: { type: Schema.Types.ObjectId, ref: 'users' },
load: { type: Schema.Types.ObjectId, ref: 'loads' },
vehicle: { type: Schema.Types.ObjectId, ref: 'vehicles' },
});
module.exports = mongoose.model( "trackings", schema );

View File

@@ -0,0 +1,62 @@
const mongoose = require('mongoose');
const { Schema } = mongoose;
const pointSchema = new Schema({
type: {
type: String,
enum: ['Point'],
required: true
},
coordinates: {
type: [Number],
required: true
}
});
const schema = new Schema({
first_name: { type: String },
last_name: { type: String },
middle_name: { type: String },
email: { type: String, unique: true, lowercase: true },
password: { type: String , maxLength : 256 },
phone: { type: String },
phone2: { type: String },
permissions: { type: String, default: 'role_admin', enum : [ 'admin', 'role_admin', 'role_shipper', 'role_carrier', 'role_driver' ] },
gender: { type: String },
address: { type: String },
dob: { type: String },
// vehicle_status: { type: String, enum: ['Free', 'Loading', 'Moving', 'Downloading'] },
job_role: { type: String, enum : [ 'admin', 'owner', 'manager', 'driver', 'staff' ] },
employee_id: { type: String }, //EM-1000-1 EM-1000-2
company: { type: Schema.Types.ObjectId, ref: 'companies' },
branch: { type: Schema.Types.ObjectId, ref: 'branches' },
vehicle: { type: Schema.Types.ObjectId, ref: 'vehicles' },
active_load: { type: Schema.Types.ObjectId, ref: 'loads' },
categories: [{ type: Schema.Types.ObjectId, ref: 'productcategories' }],
user_city: [{ type: String }],
user_state: [{ type: String }],
user_description: { type: String },
truck_type: [{ type: String }],
last_location_lat: { type: String },
last_location_lng: { type: String },
last_location_geo: { type: pointSchema },
last_location_time: { type: Date },
isVerified: { type: Boolean },
session_token : { type : String, maxLength : 256 },
session_token_exp : { type: Date },
is_hidden: { type: Boolean, default: false },
is_deleted: { type: Boolean, default: false },
deleted_at: { type: Date },
createdAt: { type : Date, required : true, default : () => { return Date.now(); } }
});
module.exports = mongoose.model( "users", schema );

View File

@@ -0,0 +1,57 @@
const mongoose = require('mongoose');
const { Schema } = mongoose;
const pointSchema = new Schema({
type: {
type: String,
enum: ['Point'],
required: true
},
coordinates: {
type: [Number],
required: true
}
});
const schema = new Schema({
company: { type: Schema.Types.ObjectId, ref: 'companies', required: true }, // carrier
vehicle_code: { type: String },
vehicle_name: { type: String },
vehicle_number: { type: String }, //camion001 002 etc
circulation_serial_number: { type: String },
trailer_plate_1: { type: String },
trailer_plate_2: { type: String },
truck_type: { type: String },
tyre_type: { type: String },
city: { type: String },
state: { type: String },
background_tracking: { type: Boolean, default: false },
status: { type: String, enum: ['Free', 'Loading', 'Transit', 'Downloading'] },
categories: [{ type: Schema.Types.ObjectId, ref: 'productcategories' }],
posted_by: { type: Schema.Types.ObjectId, ref: 'users', required: true }, // carrier
published_date: { type: Date },
available_date: { type: String },
is_available: { type: Boolean, default: false },
active_load: { type: Schema.Types.ObjectId, ref: 'loads' },
load_shipper: { type: Schema.Types.ObjectId, ref: 'companies' },
available_in: { type: String },
destino: { type: String },
driver: { type: Schema.Types.ObjectId, ref: 'users' },
notes: { type: String },
last_location_lat: { type: String },
last_location_lng: { type: String },
last_location_geo: { type: pointSchema },
last_location_time: { type: Date },
createdAt: { type : Date, required : true, default : () => { return Date.now(); } }
});
module.exports = mongoose.model( "vehicles", schema );

View File

@@ -0,0 +1,29 @@
'user strict';
const { ROOT_PATH, API_CONFIG } = process.env;
const apiConfig = require( `${ROOT_PATH}/${API_CONFIG}` );
const jwt = require('jsonwebtoken');
const jwtSecret = apiConfig.authentication.jwtSecret;
function middleware( req, res, next ){
if( req.JWT ){
req.JWT.isValid = false;
try{
req.JWT.payload = jwt.verify( req.JWT.raw, jwtSecret );
if( !req.JWT.payload ){
return res.status(401).send({error:"Unauthorized",code:401});
}else{
req.JWT.isValid = true;
}
}catch( err ){
console.error( err );
return res.status(401).send({error:"Unauthorized",code:401});
}
next();
}else{
return res.status(401).send({error:"Unauthorized",code:401});
}
}
module.exports = {
middleware
};