feat: Split v1 and v2 apis
This commit is contained in:
123
v1/src/lib/Handlers/Account/index.js
Normal file
123
v1/src/lib/Handlers/Account/index.js
Normal 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 };
|
||||
111
v1/src/lib/Handlers/Generic.handler.js
Normal file
111
v1/src/lib/Handlers/Generic.handler.js
Normal 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 };
|
||||
85
v1/src/lib/Handlers/MailClient/SendGrid.handler.js
Normal file
85
v1/src/lib/Handlers/MailClient/SendGrid.handler.js
Normal 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 };
|
||||
24
v1/src/lib/Handlers/MailClient/StandAlone.handler.js
Normal file
24
v1/src/lib/Handlers/MailClient/StandAlone.handler.js
Normal 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 };
|
||||
50
v1/src/lib/Handlers/MailClient/index.js
Normal file
50
v1/src/lib/Handlers/MailClient/index.js
Normal 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 };
|
||||
52
v1/src/lib/Handlers/Proposals.handler.js
Normal file
52
v1/src/lib/Handlers/Proposals.handler.js
Normal 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 };
|
||||
187
v1/src/lib/Handlers/Users.handler.js
Normal file
187
v1/src/lib/Handlers/Users.handler.js
Normal 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
87
v1/src/lib/Middlewares.js
Normal file
@@ -0,0 +1,87 @@
|
||||
'use strict';
|
||||
/**
|
||||
* HASH
|
||||
*****************************************************
|
||||
* DEPENDENCIES
|
||||
*****************************************************
|
||||
* Based on Express Framework
|
||||
* System
|
||||
*****************************************************
|
||||
* PUBLIC METHODS
|
||||
*****************************************************
|
||||
* Auth( req, res, next)
|
||||
* Extract JWT or BasicAuth data
|
||||
* errorJSON( error , request , response , next )
|
||||
* Generate error response on bad JSON format
|
||||
* error404( request , response , next )
|
||||
* Generate error 404 response
|
||||
* apiKey( request , response , next )
|
||||
* Generate error on invalid apikey
|
||||
**/
|
||||
|
||||
/// Extract JWT or BasicAuth
|
||||
function Auth( req, res , next ){
|
||||
///
|
||||
/// Try to extract the authorization data from headers
|
||||
///
|
||||
let auth;
|
||||
if( req.headers.hasOwnProperty( "authorization" ) ){
|
||||
auth = req.headers.authorization;
|
||||
auth = auth.split(" ")[1];
|
||||
if( !auth ){ console.log( "NO HEADER AUTH available" ); return next(); }
|
||||
//console.log( auth );
|
||||
/// Try BasicAuth {
|
||||
try{
|
||||
let ba = Buffer.from( auth , 'base64' ).toString()
|
||||
//const [user,pass] = ba.split(':');
|
||||
ba = ba.split(':');
|
||||
if( ba.length == 2 ){
|
||||
req.basicAuth = { user : ba[0] , password : ba[1] };
|
||||
}
|
||||
}catch(error){
|
||||
console.log("MIDDLEWARE_AUTH_ERR_BA",error);
|
||||
}
|
||||
/// Try BasicAuth }
|
||||
}else if( req.query.access_token ){
|
||||
auth = req.query.access_token;
|
||||
if( !auth ){ console.log( "NO QUERY AUTH available" ); return next(); }
|
||||
}
|
||||
if( auth ){
|
||||
/// Try JWT {
|
||||
try{
|
||||
let jwt = auth.split(".");
|
||||
if( jwt.length == 3 ){
|
||||
req.JWT = {};
|
||||
req.JWT.raw = auth;
|
||||
}
|
||||
}catch( error ){
|
||||
console.log("MIDDLEWARE_AUTH_ERR_JWT",error);
|
||||
}
|
||||
/// Try JWT }
|
||||
}
|
||||
next();
|
||||
}
|
||||
|
||||
function errorJSON( error , request , response , next ){
|
||||
console.log(error);
|
||||
if( error !== null ){
|
||||
/// For body-parser errors
|
||||
if( error instanceof SyntaxError && error.status === 400 && 'body' in error ){
|
||||
return response.status(400).json({ error : 'Invalid json' , code : 400 });
|
||||
}
|
||||
/// For any error
|
||||
return response.status(500).send( { error: "Internal server error" , code : 500 } );
|
||||
}else{
|
||||
return next();
|
||||
}
|
||||
}
|
||||
|
||||
function error404( request , response , next ){
|
||||
return response.status(404).send( { error : "Page not found", code : 404 } );
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
Auth,
|
||||
errorJSON,
|
||||
error404,
|
||||
};
|
||||
105
v1/src/lib/Misc.js
Normal file
105
v1/src/lib/Misc.js
Normal 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};
|
||||
16
v1/src/lib/Models/branches.model.js
Normal file
16
v1/src/lib/Models/branches.model.js
Normal 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 );
|
||||
33
v1/src/lib/Models/budgets.model.js
Normal file
33
v1/src/lib/Models/budgets.model.js
Normal 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 );
|
||||
11
v1/src/lib/Models/cities.model.js
Normal file
11
v1/src/lib/Models/cities.model.js
Normal 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 );
|
||||
65
v1/src/lib/Models/companies.model.js
Normal file
65
v1/src/lib/Models/companies.model.js
Normal 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 );
|
||||
10
v1/src/lib/Models/countries.model.js
Normal file
10
v1/src/lib/Models/countries.model.js
Normal 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 );
|
||||
73
v1/src/lib/Models/index.js
Normal file
73
v1/src/lib/Models/index.js
Normal 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
|
||||
};
|
||||
19
v1/src/lib/Models/load-attachments.model.js
Normal file
19
v1/src/lib/Models/load-attachments.model.js
Normal 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 );
|
||||
|
||||
91
v1/src/lib/Models/loads.model.js
Normal file
91
v1/src/lib/Models/loads.model.js
Normal 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 );
|
||||
8
v1/src/lib/Models/mailer.model.js
Normal file
8
v1/src/lib/Models/mailer.model.js
Normal 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 );
|
||||
10
v1/src/lib/Models/memberships.model.js
Normal file
10
v1/src/lib/Models/memberships.model.js
Normal 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 );
|
||||
10
v1/src/lib/Models/meta-data.model.js
Normal file
10
v1/src/lib/Models/meta-data.model.js
Normal 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 );
|
||||
11
v1/src/lib/Models/meta-groups.model.js
Normal file
11
v1/src/lib/Models/meta-groups.model.js
Normal 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 );
|
||||
26
v1/src/lib/Models/news.model.js
Normal file
26
v1/src/lib/Models/news.model.js
Normal 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 );
|
||||
11
v1/src/lib/Models/orders.model.js
Normal file
11
v1/src/lib/Models/orders.model.js
Normal 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 );
|
||||
8
v1/src/lib/Models/product-categories.model.js
Normal file
8
v1/src/lib/Models/product-categories.model.js
Normal 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 );
|
||||
9
v1/src/lib/Models/products.model.js
Normal file
9
v1/src/lib/Models/products.model.js
Normal 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 );
|
||||
22
v1/src/lib/Models/proposals.model.js
Normal file
22
v1/src/lib/Models/proposals.model.js
Normal 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 );
|
||||
12
v1/src/lib/Models/states.model.js
Normal file
12
v1/src/lib/Models/states.model.js
Normal 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 );
|
||||
|
||||
12
v1/src/lib/Models/trackings.model.js
Normal file
12
v1/src/lib/Models/trackings.model.js
Normal 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 );
|
||||
62
v1/src/lib/Models/users.model.js
Normal file
62
v1/src/lib/Models/users.model.js
Normal 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 );
|
||||
57
v1/src/lib/Models/vehicles.model.js
Normal file
57
v1/src/lib/Models/vehicles.model.js
Normal 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 );
|
||||
29
v1/src/lib/jwtValidator.js
Normal file
29
v1/src/lib/jwtValidator.js
Normal 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
|
||||
};
|
||||
Reference in New Issue
Block a user