feat: Split v1 and v2 apis
This commit is contained in:
19
v1/Dockerfile
Normal file
19
v1/Dockerfile
Normal file
@@ -0,0 +1,19 @@
|
||||
# Use an official Python runtime as a parent image
|
||||
FROM node:18-alpine
|
||||
|
||||
# Set the working directory to /app
|
||||
WORKDIR /app
|
||||
|
||||
# Copy the current directory contents into the container at /app
|
||||
COPY src /app/src
|
||||
COPY package.json /app
|
||||
COPY dotenv /app/.env
|
||||
|
||||
RUN apk add bash bash-completion vim
|
||||
RUN npm install --include=dev
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
ENV ROOT_PATH="/app"
|
||||
|
||||
ENTRYPOINT npm start
|
||||
444
v1/README.md
Normal file
444
v1/README.md
Normal file
@@ -0,0 +1,444 @@
|
||||
# ETA API
|
||||
|
||||
ETA Viaporte API
|
||||
|
||||
# Dependencies
|
||||
|
||||
- NodeJS v18
|
||||
- Docker
|
||||
|
||||
# Endpoints
|
||||
|
||||
All endpoints that return a list of elements is paginable with the following queries:
|
||||
- `elements`: Number of elements for each page.
|
||||
- `page`: Page number (from 0 to n)
|
||||
|
||||
Example:
|
||||
- `/endpoint?elements=50&page=2` : Get page 2 with 50 elements per page.
|
||||
- `/endpoint?page=2` : Get page 2 with default (10) elements per page.
|
||||
- `/endpoint?elements=50` : Get page 0 with 50 elements.
|
||||
|
||||
## Public endpoints
|
||||
|
||||
Read registered resources:
|
||||
|
||||
- `GET /account`: At this location you can: register, login, recover password, renew JWT.
|
||||
- `GET /countries`: List registered countries.
|
||||
- `GET /cities`: List registered cities.
|
||||
- `GET /meta-data`: List registered meta-data.
|
||||
- `GET /meta-groups`: List registered meta-data.
|
||||
- `GET /product-categories`: List registered product-categories.
|
||||
- `GET /public-companies`: List registered companies. Pagination limited to 100 elements and page 0.
|
||||
- `GET /public-loads`: List registered loads.
|
||||
- `GET /public-load-attachments/download/:id`: Downloads the attachment of the load identified by Id.
|
||||
- `GET /public-vehicles`: List registered vehicles.
|
||||
- `GET /states`: List registered states.
|
||||
- `POST /contact-email`: Send an email from the Landing Page.
|
||||
|
||||
All these endpoints support the following parameters (except for those with `public-` as prefix, for example `public-vehicles`):
|
||||
|
||||
- `/` : List registered resources with pagination.
|
||||
- `/:id` : Read specific resource identified by Id.
|
||||
- `/find?regex=xxx` : List resources that matches with regex (support pagination).
|
||||
|
||||
### /account
|
||||
|
||||
This endpoint provides mechanisms to register, login, recover password and renew JWT.
|
||||
|
||||
The __Login__ and __Renew__ process will return 2 tokens, the `accessToken` (JWT) which is used in every further request to authorize access to private endpoints. And the 2nd is the `session_token` (renew token), which should be used after the expiration of the JWT, in order to generate another _JWT_ and _session token_ without the need of use the _email_ and _password__.
|
||||
|
||||
The _session token_ expiration is typically 30 days after its generation. Every renewal replaces the token in the DB and the expiration is reset again to 30 days.
|
||||
|
||||
#### POST /account/authorize
|
||||
|
||||
Login process, returns a JWT and Renew Token
|
||||
|
||||
Expects a body with the following data:
|
||||
```{.json}
|
||||
{
|
||||
"email":"testing@etaviaporte.com",
|
||||
"password":"PasswordExample"
|
||||
}
|
||||
```
|
||||
|
||||
Returns:
|
||||
```{.javascript}
|
||||
{
|
||||
"accessToken" : "JWT",
|
||||
"payload" : "Content in the JWT",
|
||||
"session_token": "Renew token",
|
||||
"session_token_exp": "Expiration of renew token in UNIX epoch format",
|
||||
"user" : { ... }
|
||||
}
|
||||
```
|
||||
|
||||
#### GET /account/authorize/:session_token
|
||||
|
||||
Renewal of JWT with session token, will return the new session token and a new JWT only if the session token is not expired, otherwise the request will fail and the login process should be used instead.
|
||||
|
||||
Example of usage:
|
||||
```
|
||||
GET /account/authorize/"HERE_GOES_THE_SESSION_TOKEN"
|
||||
```
|
||||
|
||||
Returns:
|
||||
```{.json}
|
||||
{
|
||||
"accessToken" : "JWT",
|
||||
"payload" : "Content in the JWT",
|
||||
"session_token": "Renew token",
|
||||
"session_token_exp": "Expiration of renew token in UNIX epoch format",
|
||||
"user" : { ... }
|
||||
}
|
||||
```
|
||||
|
||||
#### POST /account/signup
|
||||
|
||||
Create a new user. This will trigger an email with the OTP (one time password) to verify the email. There is no expiration time, but it is expected that the Fron End removes the checksum from the local storage after an expiration time defined in the Front End.
|
||||
|
||||
This will return a checksum string to be used in the confirmation process.
|
||||
|
||||
Expects a body with the following data:
|
||||
```{.json}
|
||||
{
|
||||
"email":"testing@etaviaporte.com",
|
||||
"password":"PasswordExample"
|
||||
}
|
||||
```
|
||||
|
||||
Returns:
|
||||
```{.javascript}
|
||||
{
|
||||
"checksum" : "JWT"
|
||||
}
|
||||
```
|
||||
|
||||
#### PATCH /account/signup
|
||||
|
||||
Confirms registration of new user. This will trigger a welcome email to the user.
|
||||
There is no timeout to confirm the email, but it is expected that the Fron End removes the checksum from the local storage after an expiration time defined in the Front End.
|
||||
|
||||
If the checksum matches but the user is already registered, then this request will be rejected.
|
||||
|
||||
Expects a body with the same data as the POST request, but adding the OTP received in the email, the company type decided by the user and the checksum generated by the POST request. Here is an example:
|
||||
|
||||
```{.json}
|
||||
{
|
||||
"email":"testing@etaviaporte.com",
|
||||
"password":"PasswordExample",
|
||||
"otp":"OTP string",
|
||||
"checksum":"Checksum generated in the POST request"
|
||||
}
|
||||
```
|
||||
|
||||
Returns:
|
||||
```{.json}
|
||||
{
|
||||
"msg" : "User created successfully!"
|
||||
}
|
||||
```
|
||||
|
||||
#### POST /account/recover
|
||||
|
||||
Reset password request. This will trigger an email with the OTP (one time password) to verify the email. There is no expiration time, but it is expected that the Fron End removes the checksum from the local storage after an expiration time defined in the Front End.
|
||||
|
||||
This will return a checksum string to be used in the confirmation process.
|
||||
|
||||
Expects a body with the following data:
|
||||
```{.json}
|
||||
{
|
||||
"email":"testing@etaviaporte.com",
|
||||
"password":"new password"
|
||||
}
|
||||
```
|
||||
|
||||
Returns:
|
||||
```{.javascript}
|
||||
{
|
||||
"checksum" : "JWT"
|
||||
}
|
||||
```
|
||||
|
||||
#### PATCH /account/recover
|
||||
|
||||
Confirms the email to recover the password.
|
||||
There is no timeout to confirm the email, but it is expected that the Fron End removes the checksum from the local storage after an expiration time defined in the Front End.
|
||||
|
||||
Expects a body with the same data as the POST request, but adding the OTP received in the email, and the checksum generated by the POST request. Here is an example:
|
||||
|
||||
```{.json}
|
||||
{
|
||||
"email":"testing@etaviaporte.com",
|
||||
"password":"New Password Example",
|
||||
"otp":"OTP string",
|
||||
"checksum":"Checksum generated in the POST request"
|
||||
}
|
||||
```
|
||||
|
||||
Returns:
|
||||
```{.json}
|
||||
{
|
||||
"msg" : "Password is reset!"
|
||||
}
|
||||
```
|
||||
|
||||
### POST /contact-email
|
||||
|
||||
Send an email from the Landing Page:
|
||||
|
||||
Body content:
|
||||
|
||||
```{.json}
|
||||
{
|
||||
"email":"josepablo134@gmail.com",
|
||||
"name":"Josepablo C.",
|
||||
"message":"This is a test"
|
||||
}
|
||||
```
|
||||
|
||||
Returns:
|
||||
```{.json}
|
||||
{
|
||||
"msg": "Email sent!"
|
||||
}
|
||||
```
|
||||
|
||||
### GET /public-companies
|
||||
|
||||
Get public fields from registered companies.
|
||||
|
||||
- `GET /shipper`: List registered shippers that are not hidden only.
|
||||
- `GET /carrier`: List registered carriers that are not hidden only.
|
||||
|
||||
### GET /public-loads
|
||||
|
||||
Get public fields from registered loads.
|
||||
|
||||
- `GET /`: List only loads with status Published.
|
||||
|
||||
### GET /public-vehicles
|
||||
|
||||
Get public fields from registered vehicles.
|
||||
|
||||
- `GET /published`: List only latest published vehicles.
|
||||
- `GET /location`: List only location from vehicles in status Free.
|
||||
|
||||
### /news
|
||||
|
||||
- `GET /` : Get a list of elements with pagination.
|
||||
- `GET /find` : Find a list of elements with any of the following fields:
|
||||
- regex
|
||||
- `GET /:id` : Get data from specific element.
|
||||
- `GET /download/:image_name`: Download image from DB.
|
||||
|
||||
## Private Endpoints
|
||||
|
||||
The following list of endpoints requires a JWT.
|
||||
|
||||
- `GET /loads`: List loads related to my company.
|
||||
- `GET /load-attachments`: List load attachments related to my company or load id.
|
||||
|
||||
### /public-load-tracking
|
||||
|
||||
- `GET /:id`: Get tracking data from load id
|
||||
|
||||
### Test Endpoint
|
||||
|
||||
A private endpoint to test the JWT and the api response.
|
||||
|
||||
- `POST /apitest`: Return whatever is sent on the body, queries and parameters.
|
||||
- `GET /version`: Return the API version.
|
||||
|
||||
### /account
|
||||
|
||||
Complete the register process
|
||||
|
||||
- `POST /register` : Creates the company from the body data provided and assigns account to this new company.
|
||||
|
||||
#### POST /account/register
|
||||
|
||||
Send company data to complete the register.
|
||||
|
||||
After this process, the logged user will receive the flag "isVerified" and the company id will be associated, at the same time, the role will be set to "owner" and the permissions will be set according to the company type: `role_shipper` or `role_carrier`.
|
||||
|
||||
This request can only happen once, since this process is the creation of a new company in the DB.
|
||||
After setting up the company, the updates can be handled in the `/companies` endpoint.
|
||||
|
||||
Body content:
|
||||
|
||||
```{.json}
|
||||
{
|
||||
"company_type":"carrier|shipper",
|
||||
"company_name" : "Company Name",
|
||||
"company_description" : "This is a description example"
|
||||
}
|
||||
```
|
||||
|
||||
Returns a company object
|
||||
|
||||
```{.json}
|
||||
{
|
||||
"_id": "company_id",
|
||||
"company_type":"carrier|shipper",
|
||||
"company_name" : "Company Name",
|
||||
"company_description" : "This is a description example"
|
||||
}
|
||||
```
|
||||
|
||||
### /branches
|
||||
|
||||
- `GET /find` : Find a list of elements with any of the following fields:
|
||||
- categories
|
||||
- branch_name
|
||||
- phone
|
||||
- city
|
||||
- state
|
||||
- truck_type
|
||||
- `POST /new` : Creates a new element.
|
||||
- `PATCH /:id` : Updates data from specific element.
|
||||
- `DELETE /:id` : Delete element from company. Returns the element data.
|
||||
- `GET /:id` : Get data from specific element.
|
||||
|
||||
### /budgets
|
||||
|
||||
- `GET /find` : Find a list of elements with any of the following fields:
|
||||
- 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
|
||||
- `POST /new` : Creates a new element.
|
||||
- `PATCH /:id` : Updates data from specific element.
|
||||
- `DELETE /:id` : Delete element from company. Returns the element data.
|
||||
- `GET /:id` : Get data from specific element.
|
||||
|
||||
### /calendars
|
||||
|
||||
This endpoint is part of /loads endpoint
|
||||
|
||||
### /companies
|
||||
|
||||
- `GET /own` : Get own company data.
|
||||
- `PATCH /own` : Update own company data.
|
||||
- `GET /shipper` : Get list of shipper companies with pagination using the following filters: company_type, company_name, truck_type, categories, company_state, company_city.
|
||||
- $sort[ field ] : -1/1 ; Sort result by field name
|
||||
- `GET /carrier` : Get list of carrier companies with pagination using the following filters: company_type, company_name, truck_type, categories, company_state, company_city
|
||||
- $sort[ field ] : -1/1 ; Sort result by field name
|
||||
- `GET /users/:companyId` : Get the list of users within a company.
|
||||
- `GET /:id` : Get data from specific company.
|
||||
|
||||
### /load-attachments
|
||||
|
||||
- `POST /loading/:id` : Upload/Update a loading attachment.
|
||||
- `POST /downloading/:id` : Upload/Update a download attachment
|
||||
- `GET /load/:id` : Get the list of attachment ids from load.
|
||||
- `GET /:id` : Get attachment file.
|
||||
- `GET /` : Get attachment list from company.
|
||||
|
||||
### /loads
|
||||
|
||||
- `GET /find` : Find a list of elements with any of the following fields:
|
||||
- companyId
|
||||
- carrier
|
||||
- vehicle
|
||||
- driver
|
||||
- status
|
||||
- posted_by_name
|
||||
- load_status
|
||||
- published_date
|
||||
- loaded_date
|
||||
- transit_date
|
||||
- categories
|
||||
- product
|
||||
- shipment_code
|
||||
- company_name[$regex] : Regex string to find company_name
|
||||
- company_name[$options] : Regex options from MongoDB filter description
|
||||
- $sort[ field ] : -1/1 ; Sort result by field name
|
||||
- `GET /calendar` : Find a list of elements with any of the following fields:
|
||||
- date[gte] : Date grater than.
|
||||
- date[lte] : Date less than.
|
||||
- load_status : string enumerator ['Published', 'Loading', 'Transit', 'Downloading', 'Delivered'].
|
||||
- global : 1 To return calendar of all company, or 0/undefined for personal calendar only.
|
||||
- $sort[ field ] : -1/1 ; Sort result by field name
|
||||
- `POST /new` : Creates a new element.
|
||||
- `PATCH /:id` : Updates data from specific element.
|
||||
- `DELETE /:id` : Delete element from company. Returns the element data.
|
||||
- `GET /:id` : Get data from specific element.
|
||||
|
||||
##### Example of filter and sort:
|
||||
|
||||
- `GET /calendar?$sort[createdAt]=-1&date[gte]=2022-08-25&date[lte]=2022-05-25&load_status=Loading`: Get loads within date range 2022-08-25 -> 2022-05-25 with load_state "Loading" and sort it by createdAt field.
|
||||
|
||||
- `GET /loads/find?$sort[createdAt]=-1&load_status=Loading`: Get loads with status "Loading" sorted by createdAt.
|
||||
|
||||
### /proposals
|
||||
|
||||
- `GET /find` : Find a list of elements with any of the following fields:
|
||||
- load
|
||||
- categories
|
||||
- branch_name
|
||||
- phone, city
|
||||
- state
|
||||
- truck_type
|
||||
- `POST /new` : Creates a new element.
|
||||
- `PATCH /:id` : Updates data from specific element.
|
||||
- `DELETE /:id` : Delete element from company. Returns the element data.
|
||||
- `GET /:id` : Get data from specific element.
|
||||
|
||||
### /upload
|
||||
|
||||
Work In Progress
|
||||
|
||||
### /users
|
||||
|
||||
- `GET /find` : Look for a user within ETA.
|
||||
- `POST /member` : Create a new user within the company (only for owner or manager users).
|
||||
- `PATCH /member/:id` : Update member data (except permissions, company, job_role and password).
|
||||
- `DELETE /member/:id` : Delete member but keep metadata for future references. The user will be disabled and won't be able to log in again.
|
||||
- `GET /profile` : Read profile data.
|
||||
- `PATCH /profile` : Update profile data (except permissions, company, job_role and password).
|
||||
- `GET /:id` : Get user information with its ID.
|
||||
|
||||
### /vehicles
|
||||
|
||||
__This endpoint is only valid for carriers.__
|
||||
|
||||
- `GET /find` : Find a list of elements with any of the following fields:
|
||||
- categories,
|
||||
- active_load,
|
||||
- load_shipper,
|
||||
- driver,
|
||||
- vehicle_code,
|
||||
- vehicle_name,
|
||||
- vehicle_number,
|
||||
- circulation_serial_number,
|
||||
- truck_type,
|
||||
- tyre_type,
|
||||
- city,
|
||||
- state,
|
||||
- status,
|
||||
- destino
|
||||
- `POST /new` : Creates a new element.
|
||||
- `PATCH /:id` : Updates data from specific element.
|
||||
- `DELETE /:id` : Delete element from company. Returns the element data.
|
||||
- `GET /:id` : Get data from specific element.
|
||||
9
v1/dotenv
Normal file
9
v1/dotenv
Normal file
@@ -0,0 +1,9 @@
|
||||
SERVER_PORT=3000
|
||||
ROOT_PATH=/mnt/d/Projects/WebDevWorkspace/ETAViaporte/etaapi/v1
|
||||
API_CONFIG=src/config/apiConfig_local.json
|
||||
############################
|
||||
# PATHS relative to ROOT
|
||||
############################
|
||||
LIB_PATH=src/lib
|
||||
MODELS_PATH=src/lib/Models
|
||||
HANDLERS_PATH=src/lib/Handlers
|
||||
53
v1/package.json
Normal file
53
v1/package.json
Normal file
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"name": "etaapi",
|
||||
"version": "1.0.0",
|
||||
"description": "ETA API",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"start": "node src/",
|
||||
"dev": "nodemon src/",
|
||||
"test": "mocha test/lib/handlers/proposals"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://gitlab.com/jcruzbaasworkspace/enruta/etaapi.git"
|
||||
},
|
||||
"author": "Josepablo C.",
|
||||
"license": "ISC",
|
||||
"bugs": {
|
||||
"url": "https://gitlab.com/jcruzbaasworkspace/enruta/etaapi/issues"
|
||||
},
|
||||
"homepage": "https://gitlab.com/jcruzbaasworkspace/enruta/etaapi#readme",
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-s3": "^3.427.0",
|
||||
"audit": "^0.0.6",
|
||||
"axios": "^1.5.1",
|
||||
"body-parser": "^1.20.2",
|
||||
"compression": "^1.7.4",
|
||||
"cors": "^2.8.5",
|
||||
"crypto-js": "^4.1.1",
|
||||
"dotenv": "^16.3.1",
|
||||
"express": "^4.18.2",
|
||||
"express-fileupload": "^1.4.1",
|
||||
"express-jwt": "^8.4.1",
|
||||
"form-data": "^4.0.0",
|
||||
"helmet": "^7.0.0",
|
||||
"jsonschema": "^1.4.1",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"knex": "^2.5.1",
|
||||
"mongodb-core": "^3.2.7",
|
||||
"mongoose": "^7.5.4",
|
||||
"morgan": "^1.10.0",
|
||||
"mysql": "^2.18.1",
|
||||
"nodemailer": "^6.9.5",
|
||||
"nodemailer-sendgrid": "^1.0.3",
|
||||
"nodemon": "^3.0.1",
|
||||
"objection": "^3.1.4",
|
||||
"uuid": "^9.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"chai": "^5.1.0",
|
||||
"mocha": "^10.3.0",
|
||||
"sinon": "^17.0.1"
|
||||
}
|
||||
}
|
||||
94
v1/scripts/ci_functions.sh
Normal file
94
v1/scripts/ci_functions.sh
Normal file
@@ -0,0 +1,94 @@
|
||||
#! /bin/bash
|
||||
|
||||
# Requirements
|
||||
# Docker: Node v18-alpine
|
||||
function build_docker(){
|
||||
if [[ $# -lt 1 ]]; then
|
||||
echo $0 "[conatiner name]"
|
||||
return -1
|
||||
fi
|
||||
CONTAINER_NAME=$1
|
||||
cat src/config/apiConfig.json > src/config/apiConfig_local.json
|
||||
|
||||
set -x
|
||||
docker rmi -f "$AWS_ECR_REPO/$CONTAINER_NAME"
|
||||
docker buildx build --no-cache -t $AWS_ECR_REPO/$CONTAINER_NAME ./
|
||||
set +x
|
||||
}
|
||||
|
||||
function upload_image(){
|
||||
#Global ENV VAR: AWS_DEFAULT_REGION
|
||||
#Global ENV VAR: AWS_ECRWRITTER_ID
|
||||
#Global ENV VAR: AWS_ECRWRITTER_SECRET
|
||||
#Global ENV VAR: AWS_ECR_USER
|
||||
#Global ENV VAR: AWS_ECR_REPO
|
||||
#Global ENV VAR: CONTAINER_NAME
|
||||
mkdir .aws
|
||||
echo "[default]" > ./.aws/config
|
||||
echo "region = $AWS_DEFAULT_REGION" >> ./.aws/config
|
||||
echo "output = json" >> ./.aws/config
|
||||
echo "[default]" > ./.aws/credentials
|
||||
echo "aws_access_key_id = $AWS_ECRWRITTER_ID" >> ./.aws/credentials
|
||||
echo "aws_secret_access_key = $AWS_ECRWRITTER_SECRET" >> ./.aws/credentials
|
||||
DOCKER_PWD=$(docker run --rm -v ./.aws/:/root/.aws amazon/aws-cli ecr get-login-password)
|
||||
rm -rf ./.aws
|
||||
docker login -u $AWS_ECR_USER -p $DOCKER_PWD $AWS_ECR_REPO
|
||||
set -x
|
||||
docker push "$AWS_ECR_REPO/$CONTAINER_NAME":latest
|
||||
set +x
|
||||
}
|
||||
|
||||
function prepare_deployment(){
|
||||
# Global Env Var: AWS_DEFAULT_REGION
|
||||
# Global Env Var: AWS_ECRWRITTER_ID
|
||||
# Global Env Var: AWS_ECRWRITTER_SECRET
|
||||
# Global Env Var: SYSTEM_HOSTNAME
|
||||
#Generate Docker Access Token
|
||||
mkdir .aws
|
||||
echo "[default]" > ./.aws/config
|
||||
echo "region = $AWS_DEFAULT_REGION" >> ./.aws/config
|
||||
echo "output = json" >> ./.aws/config
|
||||
echo "[default]" > ./.aws/credentials
|
||||
echo "aws_access_key_id = $AWS_ECRWRITTER_ID" >> ./.aws/credentials
|
||||
echo "aws_secret_access_key = $AWS_ECRWRITTER_SECRET" >> ./.aws/credentials
|
||||
export DOCKER_PWD=$(docker run --rm -v ./.aws/:/root/.aws amazon/aws-cli ecr get-login-password)
|
||||
rm -rf ./.aws
|
||||
}
|
||||
|
||||
function deploy_uservice(){
|
||||
# CONTAINER NAME
|
||||
# PUBLIC PORT
|
||||
# PRIVATE PORT
|
||||
# ECR REPO
|
||||
if [[ $# -lt 4 ]]; then
|
||||
echo "$0 [container_name] [public port] [private port] [ecr_repo]"
|
||||
return -1
|
||||
fi
|
||||
container_name=$1
|
||||
public_port=$2
|
||||
private_port=$3
|
||||
ecr_repo=$4
|
||||
|
||||
docker stop $container_name && docker rm $container_name
|
||||
docker run -p"$public_port:$private_port" -d --restart unless-stopped --name $container_name $ecr_repo/$container_name:latest
|
||||
}
|
||||
|
||||
function deploy_local(){
|
||||
# docker login --username $AWS_ECR_USER --password $DOCKER_PWD $AWS_ECR_REPO
|
||||
deploy_uservice $CONTAINER_NAME $PUBLIC_PORT $PRIVATE_PORT $AWS_ECR_REPO
|
||||
}
|
||||
|
||||
function deploy(){
|
||||
# Global Env Var: AWS_ECR_USER
|
||||
# Global Env Var: AWS_ECR_REPO
|
||||
# Global Env Var: CONTAINER_NAME
|
||||
# Global Env Var: PUBLIC_PORT
|
||||
# Global Env Var: PRIVATE_PORT
|
||||
# Global Env Var: AWS_ECR_REPO
|
||||
# Global Env Var: SYSTEM_HOSTNAME
|
||||
prepare_deployment
|
||||
set -x
|
||||
ssh -i ~/.ssh/gitlab_runner gitlab-runner@$SYSTEM_HOSTNAME "docker login --username $AWS_ECR_USER --password $DOCKER_PWD $AWS_ECR_REPO && ./deploy_uservice.sh $CONTAINER_NAME $PUBLIC_PORT $PRIVATE_PORT $AWS_ECR_REPO && exit"
|
||||
#deploy_local
|
||||
set +x
|
||||
}
|
||||
10
v1/src/apps/index.js
Normal file
10
v1/src/apps/index.js
Normal 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;
|
||||
7
v1/src/apps/private/account/routes.js
Normal file
7
v1/src/apps/private/account/routes.js
Normal 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;
|
||||
15
v1/src/apps/private/account/services.js
Normal file
15
v1/src/apps/private/account/services.js
Normal 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 };
|
||||
12
v1/src/apps/private/branches/routes.js
Normal file
12
v1/src/apps/private/branches/routes.js
Normal 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;
|
||||
147
v1/src/apps/private/branches/services.js
Normal file
147
v1/src/apps/private/branches/services.js
Normal 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 };
|
||||
12
v1/src/apps/private/budgets/routes.js
Normal file
12
v1/src/apps/private/budgets/routes.js
Normal 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;
|
||||
178
v1/src/apps/private/budgets/services.js
Normal file
178
v1/src/apps/private/budgets/services.js
Normal 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 };
|
||||
15
v1/src/apps/private/companies/routes.js
Normal file
15
v1/src/apps/private/companies/routes.js
Normal 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;
|
||||
229
v1/src/apps/private/companies/services.js
Normal file
229
v1/src/apps/private/companies/services.js
Normal 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
|
||||
};
|
||||
45
v1/src/apps/private/index.js
Normal file
45
v1/src/apps/private/index.js
Normal 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;
|
||||
23
v1/src/apps/private/lib/context/index.js
Normal file
23
v1/src/apps/private/lib/context/index.js
Normal 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
|
||||
};
|
||||
11
v1/src/apps/private/load-attachments/routes.js
Normal file
11
v1/src/apps/private/load-attachments/routes.js
Normal 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;
|
||||
164
v1/src/apps/private/load-attachments/services.js
Normal file
164
v1/src/apps/private/load-attachments/services.js
Normal 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 };
|
||||
13
v1/src/apps/private/loads/routes.js
Normal file
13
v1/src/apps/private/loads/routes.js
Normal 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;
|
||||
294
v1/src/apps/private/loads/services.js
Normal file
294
v1/src/apps/private/loads/services.js
Normal 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 };
|
||||
12
v1/src/apps/private/proposals/routes.js
Normal file
12
v1/src/apps/private/proposals/routes.js
Normal 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;
|
||||
142
v1/src/apps/private/proposals/services.js
Normal file
142
v1/src/apps/private/proposals/services.js
Normal 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 };
|
||||
16
v1/src/apps/private/users/routes.js
Normal file
16
v1/src/apps/private/users/routes.js
Normal 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;
|
||||
177
v1/src/apps/private/users/services.js
Normal file
177
v1/src/apps/private/users/services.js
Normal 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 };
|
||||
12
v1/src/apps/private/vehicles/routes.js
Normal file
12
v1/src/apps/private/vehicles/routes.js
Normal 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;
|
||||
168
v1/src/apps/private/vehicles/services.js
Normal file
168
v1/src/apps/private/vehicles/services.js
Normal 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 };
|
||||
16
v1/src/apps/public/account/routes.js
Normal file
16
v1/src/apps/public/account/routes.js
Normal 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;
|
||||
279
v1/src/apps/public/account/services.js
Normal file
279
v1/src/apps/public/account/services.js
Normal 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};
|
||||
9
v1/src/apps/public/cities/routes.js
Normal file
9
v1/src/apps/public/cities/routes.js
Normal 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;
|
||||
33
v1/src/apps/public/cities/services.js
Normal file
33
v1/src/apps/public/cities/services.js
Normal 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 };
|
||||
7
v1/src/apps/public/contact-email/routes.js
Normal file
7
v1/src/apps/public/contact-email/routes.js
Normal file
@@ -0,0 +1,7 @@
|
||||
'use strict';
|
||||
const router = require('express').Router();
|
||||
const services= require('./services.js');
|
||||
|
||||
router.post('/', services.postSendConactEMail);
|
||||
|
||||
module.exports = router;
|
||||
38
v1/src/apps/public/contact-email/services.js
Normal file
38
v1/src/apps/public/contact-email/services.js
Normal 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 };
|
||||
9
v1/src/apps/public/countries/routes.js
Normal file
9
v1/src/apps/public/countries/routes.js
Normal 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;
|
||||
33
v1/src/apps/public/countries/services.js
Normal file
33
v1/src/apps/public/countries/services.js
Normal 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 };
|
||||
42
v1/src/apps/public/index.js
Normal file
42
v1/src/apps/public/index.js
Normal 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;
|
||||
9
v1/src/apps/public/meta-data/routes.js
Normal file
9
v1/src/apps/public/meta-data/routes.js
Normal 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;
|
||||
33
v1/src/apps/public/meta-data/services.js
Normal file
33
v1/src/apps/public/meta-data/services.js
Normal 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 };
|
||||
9
v1/src/apps/public/meta-groups/routes.js
Normal file
9
v1/src/apps/public/meta-groups/routes.js
Normal 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;
|
||||
33
v1/src/apps/public/meta-groups/services.js
Normal file
33
v1/src/apps/public/meta-groups/services.js
Normal 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 };
|
||||
10
v1/src/apps/public/news/routes.js
Normal file
10
v1/src/apps/public/news/routes.js
Normal 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;
|
||||
52
v1/src/apps/public/news/services.js
Normal file
52
v1/src/apps/public/news/services.js
Normal 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 };
|
||||
9
v1/src/apps/public/product-categories/routes.js
Normal file
9
v1/src/apps/public/product-categories/routes.js
Normal 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;
|
||||
33
v1/src/apps/public/product-categories/services.js
Normal file
33
v1/src/apps/public/product-categories/services.js
Normal 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 };
|
||||
9
v1/src/apps/public/products/routes.js
Normal file
9
v1/src/apps/public/products/routes.js
Normal 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;
|
||||
33
v1/src/apps/public/products/services.js
Normal file
33
v1/src/apps/public/products/services.js
Normal 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 };
|
||||
9
v1/src/apps/public/public-companies/routes.js
Normal file
9
v1/src/apps/public/public-companies/routes.js
Normal 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;
|
||||
182
v1/src/apps/public/public-companies/services.js
Normal file
182
v1/src/apps/public/public-companies/services.js
Normal 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 };
|
||||
7
v1/src/apps/public/public-load-attachments/routes.js
Normal file
7
v1/src/apps/public/public-load-attachments/routes.js
Normal 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;
|
||||
22
v1/src/apps/public/public-load-attachments/services.js
Normal file
22
v1/src/apps/public/public-load-attachments/services.js
Normal 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 };
|
||||
7
v1/src/apps/public/public-load-tracking/routes.js
Normal file
7
v1/src/apps/public/public-load-tracking/routes.js
Normal 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;
|
||||
55
v1/src/apps/public/public-load-tracking/services.js
Normal file
55
v1/src/apps/public/public-load-tracking/services.js
Normal 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 };
|
||||
7
v1/src/apps/public/public-loads/routes.js
Normal file
7
v1/src/apps/public/public-loads/routes.js
Normal file
@@ -0,0 +1,7 @@
|
||||
'use strict';
|
||||
const router = require('express').Router();
|
||||
const services= require('./services.js');
|
||||
|
||||
router.get('/', services.getList);
|
||||
|
||||
module.exports = router;
|
||||
32
v1/src/apps/public/public-loads/services.js
Normal file
32
v1/src/apps/public/public-loads/services.js
Normal 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 };
|
||||
8
v1/src/apps/public/public-vehicles/routes.js
Normal file
8
v1/src/apps/public/public-vehicles/routes.js
Normal 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;
|
||||
71
v1/src/apps/public/public-vehicles/services.js
Normal file
71
v1/src/apps/public/public-vehicles/services.js
Normal 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 };
|
||||
9
v1/src/apps/public/states/routes.js
Normal file
9
v1/src/apps/public/states/routes.js
Normal 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;
|
||||
33
v1/src/apps/public/states/services.js
Normal file
33
v1/src/apps/public/states/services.js
Normal 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 };
|
||||
8
v1/src/apps/public/test/routes.js
Normal file
8
v1/src/apps/public/test/routes.js
Normal 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;
|
||||
20
v1/src/apps/public/test/services.js
Normal file
20
v1/src/apps/public/test/services.js
Normal 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 };
|
||||
48
v1/src/config/apiConfig.json
Normal file
48
v1/src/config/apiConfig.json
Normal 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": "QhM8gQ5O3hVDIf41YeO5/A6Wo58D1xQz8pzxBB2W",
|
||||
"bucket": "enruta",
|
||||
"load_attachments_key":"loadattachments",
|
||||
"news_key":"news",
|
||||
"region": "us-west-1"
|
||||
},
|
||||
"sendgrid" : {
|
||||
"HOST": "smtp.sendgrid.net",
|
||||
"PORT": "465",
|
||||
"username": "apikey",
|
||||
"API_KEY": "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",
|
||||
"FROM": "noreply@etaviaporte.com"
|
||||
},
|
||||
"email_standalone" : {
|
||||
"host": "smtp.hostinger.com",
|
||||
"port": "465",
|
||||
"secure": true,
|
||||
"auth": {
|
||||
"user": "noreply@etaviaporte.com",
|
||||
"pass": "-)WJt[oP~P$`76Q4"
|
||||
}
|
||||
},
|
||||
"mongodb": "mongodb+srv://enruta_admin:NeptFx4RUZG8OsfA@enruta.vwofshy.mongodb.net/enrutaviaporte?retryWrites=true&w=majority"
|
||||
}
|
||||
48
v1/src/config/apiConfig_local.json
Normal file
48
v1/src/config/apiConfig_local.json
Normal 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": "QhM8gQ5O3hVDIf41YeO5/A6Wo58D1xQz8pzxBB2W",
|
||||
"bucket": "enruta",
|
||||
"load_attachments_key":"loadattachments",
|
||||
"news_key":"news",
|
||||
"region": "us-west-1"
|
||||
},
|
||||
"sendgrid" : {
|
||||
"HOST": "smtp.sendgrid.net",
|
||||
"PORT": "465",
|
||||
"username": "apikey",
|
||||
"API_KEY": "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",
|
||||
"FROM": "noreply@etaviaporte.com"
|
||||
},
|
||||
"email_standalone" : {
|
||||
"host": "smtp.hostinger.com",
|
||||
"port": "465",
|
||||
"secure": true,
|
||||
"auth": {
|
||||
"user": "noreply@etaviaporte.com",
|
||||
"pass": "-)WJt[oP~P$`76Q4"
|
||||
}
|
||||
},
|
||||
"mongodb": "mongodb://localhost/etaviaporte?retryWrites=true&w=majority"
|
||||
}
|
||||
73
v1/src/index.js
Normal file
73
v1/src/index.js
Normal 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 );
|
||||
}
|
||||
});
|
||||
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
|
||||
};
|
||||
14
v1/test/lib/handlers/proposals/common.test.js
Normal file
14
v1/test/lib/handlers/proposals/common.test.js
Normal file
@@ -0,0 +1,14 @@
|
||||
"use strict";
|
||||
/// System implementation dependences
|
||||
require('dotenv').config();
|
||||
/// Unit testing dependences
|
||||
const assert = require("assert");
|
||||
|
||||
|
||||
describe('Example' , () => {
|
||||
it('finds list', async () => {
|
||||
assert.equal( 0,0 );
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user