8000 Unit tests, documentation, jsDoc added, CI flow by tomashq · Pull Request #68 · windingtree/glider-ota · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Unit tests, documentation, jsDoc added, CI flow #68

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 19 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions

name: unit tests

on:
push:
branches: [ develop ]
pull_request:
branches: [ develop ]

jobs:
build:

runs-on: ubuntu-latest

strategy:
matrix:
node-version: [12.x]

steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm run test:unit
159 changes: 141 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,33 +1,156 @@
# ota
OTA monorepo
# Glider OTA
**Open source Online Travel Agency backed up by Winding Tree ecosystem**


## Start
* npm install
* npm start
* now dev
## Setting up local development environment
#### Prerequisites
Before you start, make sure you have the following prerequisites completed:

* create an account in [Winding Tree marketplace](https://marketplace.windingtree.com/join) for your travel agency - this step is needed to get ORGiD of your organization
* you need an account on [vercel.com](https://vercel.com/)
* download and install [vercel CLI](https://vercel.com/download)
* have an instance of [Redis](https://redis.io/) - either local or cloud. It will be used as a temporary storage/cache.
* have an instance of [Mongo](https://www.mongodb.com/) - either local or cloud. It will be used as a permanent storage.
* have an instance of [Elasticsearch](https://www.elastic.co/) - either local or cloud. It will be used to store logs and analyze app usage/troubleshoot.
* create an account in [Stripe](https://stripe.com/). Stripe is used as a payment gateway to allow acceptance of card payments.

#### List of airports
List of airports that is used in origin/destination lookup fields is taken from IATA list
* https://github.com/opentraveldata/opentraveldata/tree/master/data/IATA
#### Initial setup
In order to start your local environment, you will need to:
* clone this repository to a local folder
* initiate project and install all required packages

It's curated with a script that transforms data to JSON format and filters out unwanted types
To achieve this, execute below commands
```bash
git clone https://github.com/windingtree/glider-ota.git
cd glider-ota
npm install
```
Now you have to connect your local project with Vercel project.
This will be needed only once and vercel CLI will walk you through the process. Just execute the following:
```bash
vercel
```
Congratulations.
Now the last step is to provide some configuration details for your own setup (things like database access details, Redis, Elastisearch ...)
Skip now for details to the next [chapter](#configuration) which explains in details what you need and how configuration is done.
To provide all configuration details, you will need to add few 'secrets' and you can do this using the following Vercel CLI command:
```bash
vercel secrets add secret_name "secret_value"
```

After configuration is completed, you are ready to start your project in local environment with this Vercel CLI command:
```bash
/tools/locations/airports.js
vercel dev
```
Original list contains not only airports but also heliports, railstations, ferry ports.
Unwanted locations can be filtered out

Above command starts backend services as well as React frontend.
Just open your browser and point to: http://localhost:3000



#### Configuration
Most important configuration entries are provided as environment variables and are initiated by as stored in Vercel secrets.
Read more about:
* [environment variables](https://vercel.com/docs/v2/build-step?query=secrets#environment-variables)
* [secrets](https://vercel.com/docs/cli#commands/secrets)


You will need to define the below secrets in Vercel:
* {staging||production}.glider-ota.mongo.uri2 - Mongo instance URL
* {staging||production}.glider-ota.mongo.dbname - Mongo database name
* {staging||production}.glider-ota.redis.host - Redis hostname
* {staging||production}.glider-ota.redis.password - Redis password
* {staging||production}.glider-ota.stripe.publishable_key - Stripe publishable key
* {staging||production}.glider-ota.stripe.secret_key - Stripe secret key
* {staging||production}.glider-ota.stripe.webhook_secret - Stripe webhook secret key
* {staging||production}.glider-ota.elastic.url - Elasticsearch URL
* {staging||production}.glider-ota.glider_jwt - Glider JWT
* {staging||production}.glider-ota.simard_jwt - Simard JWT
* {staging||production}.glider-ota.glider-b2b_orgid - Your travel agency ORGiD [Winding Tree marketplace](https://marketplace.windingtree.com)

Depending on an environment, either 'staging' or 'production' variables will be used.
More details [here](./api/_lib/config.js)

#### List of locations
List of locations that is used in hotels lookup fields is taken from geonames.org list of cities
* https://download.geonames.org/export/dump/

It's also curated with a script that transforms data to JSON format and filters out unwanted cities (currently cities with population over 300000 are taken into account)
## Documentation

Code is documented using JSDoc comments which allows automatic API docs creation.
Backend and frontend code is separated, thus API documentation can be generated separately for backend and frontend

Use jsdoc to generate documentation.


#### Backend end API documentation
Execute the following command from the main project folder
```bash
/tools/locations/process_dictionary_data.js
jsdoc -c jsdoc_frontend_conf.json
```
Documentation will be generated into `./docs/frontend` folder
#### Front end API documentation
Execute the following command from the main project folder
```bash
jsdoc -c jsdoc_backend_conf.json
```

Documentation will be generated into `./docs/backend` folder


## Static/dictionary data
There are multiple types of external data sources needed by Glider OTA, for example:
* list of airports (e.g. to let users search the right departure&arrival airport using airport, city name)
* list of airlines (e.g. to display full airline name, not only 2-letter carrier code)
* list of cities

This data needs to be sourced and maintained.
Please refer to documentation [here](./docs/data.md) for more information on this topic


## Development
### System architecture

##### Frontend
Frontend is a React web app.


##### Backend
Backend is developed as serverless nodejs functions and running on Vercel cloud hosting platform.
More info:
* [Vercel](https://vercel.com/)
* [serverless functions](https://vercel.com/docs/v2/serverless-functions/introduction)


##### Integration
Glider OTA integrates with:
* Glider B2B to
* search for flight offers from airlines connected to Glider B2B
* retrieve flight seatmaps
* search for hotel offers from hotels connected to Glider B2B
* creating flight & hotel reservations
* Simard
* which handles settlement between customers & suppliers (hotels, airlines)
* Stripe
* for online payments processing


#### Running application locally
In order to develop application locally, you need to run backend and frontend.
This is done with one command.
```bash
vercel dev
```

Changes in the code will be automatically hot deployed.

#### React components & testing
We use [storybook](https://storybook.js.org/) to document and test UI components.
To start storybook dashboard, simply run:
```bash
npm run storybook
```
and open http://localhost:9009/ to see all components used by Glider OTA


#### Unit Tests
Apart from storybook, there are multiple unit tests that can be executed by:


25 changes: 25 additions & 0 deletions api/_data/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Introduction
Files in this folder are considered a static data.
This data is required at multiple stages and are crucial for Glider OTA.

##List of files

* airlines.json
* list of all available airlines
* It is used to resolve airline name based on IATA code (and display airline name in search results))
* airports.json
* list of all airports and metropolitan areas
* It's used in airports name lookup field(flights search), when user enters airport name in the UI
* It's also used to resolve full airport name based on IATA code (and display full airport name in search results)

* cities.json
* list of cities and locations
* It's used in city name lookup (hotel search), when user enters city name in the UI)

* countries.json
* list of countries ('country code' to 'country name' map)

* currencies.json
* list of currency codes, names and it's precision digits (aka 'minor units')
* it's used in payment (stripe) to calculate amount that needs to be charged in minor units (e.g. 10,65EUR = 1065 in minor units)

76 changes: 61 additions & 15 deletions api/_lib/config.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
// Define the current enviroment
/**
* Main configuration is maintained here
* @module _lib/config
*/

/**
* Detect what is the current environment
* @returns {string} 'production' || 'staging' || 'develop'
*/

const determineEnviroment = () => {
// If defined, use the Glider environment variable
if(process.env.GLIDER_ENV) {
return process.env.GLIDER_ENV;
}

// Otherwise use the Github branch provided by Vercel
switch(process.env.VERCEL_GITHUB_COMMIT_REF || process.env.NOW_GITHUB_COMMIT_REF) {
case 'master':
Expand All @@ -14,30 +23,40 @@ const determineEnviroment = () => {
return 'staging';
}
}
const enviroment = determineEnviroment();
const environment = determineEnviroment();

// Get an an environment variable
/**
* Get the value of an environment variable
* @param key
* @returns {string|undefined}
*/
const getConfigKey = (key) => {
// Return environment specific variable if any
const envKey = `${enviroment.toUpperCase()}_${key}`;
const envKey = `${environment.toUpperCase()}_${key}`;
if(process.env.hasOwnProperty(envKey)) {
return process.env[envKey];
}

// Return variable key
if(process.env.hasOwnProperty(key)) {
return process.env[key];
}

// Config key does not exist
return undefined;
};

const GLIDER_BASEURL = getConfigKey('GLIDER_BASEURL') || `https://${enviroment}.b2b.glider.travel/api/v1`;


const GLIDER_BASEURL = getConfigKey('GLIDER_BASEURL') || `https://${environment}.b2b.glider.travel/api/v1`;

/**
* Glider related configuration
*
* @type {{ORGID: (string|undefined), SEARCH_OFFERS_URL: string, FULFILL_URL: string, SEATMAP_URL: string, CREATE_WITH_OFFER_URL: string, REPRICE_OFFER_URL: string, GLIDER_TOKEN: (string|undefined)}}
*/
const GLIDER_CONFIG =
{
GLIDER_TOKEN: getConfigKey('GLIDER_JWT'),
GLIDER_TOKEN: getConfigKey('GLIDER_JWT'), //JWT Token needed for Glider API (offers search, creating offers, fulfilment)
SEARCH_OFFERS_URL: GLIDER_BASEURL + "/offers/search",
CREATE_WITH_OFFER_URL: GLIDER_BASEURL + "/orders/createWithOffer",
SEATMAP_URL: GLIDER_BASEURL + "/offers/{offerId}/seatmap",
Expand All @@ -46,49 +65,76 @@ const GLIDER_CONFIG =
ORGID: getConfigKey('GLIDER_ORGID'),
};


//Glider OTA OrgID
const ORGID = {
OTA_ORGID: getConfigKey('OTA_ORGID'),
}

const SIMARD_BASEURL = getConfigKey('SIMARD_BASEURL') || `https://${enviroment}.api.simard.io/api/v1`;
const SIMARD_BASEURL = getConfigKey('SIMARD_BASEURL') || `https://${environment}.api.simard.io/api/v1`;

/**
* Simard related configuration
* @type {{ORGID: (string|string), SIMARD_TOKEN: (string|undefined), GUARANTEES_URL: string, SIMULATE_DEPOSIT_URL: string, CREATE_WITH_OFFER_URL: string, DEPOSIT_EXPIRY_DAYS: number}}
*/
const SIMARD_CONFIG =
{
SIMARD_TOKEN: getConfigKey('SIMARD_JWT'),
SIMARD_TOKEN: getConfigKey('SIMARD_JWT'), //JWT Token needed for Simard API
GUARANTEES_URL: SIMARD_BASEURL + "/balances/guarantees",
CREATE_WITH_OFFER_URL: SIMARD_BASEURL + "/orders/createWithOffer",
SIMULATE_DEPOSIT_URL: SIMARD_BASEURL + "/balances/simulateDeposit",
ORGID: getConfigKey('SIMARD_ORGID') || "0x5e6994f76764ceb42c476a2505065a6170178a24c03d81c9f372563830001171",
DEPOSIT_EXPIRY_DAYS:14,
};


/**
* Redis related configuration
* @type {{REDIS_HOST: (string|undefined), REDIS_PORT: number, REDIS_PASSWORD: (string|undefined), SESSION_TTL_IN_SECS: number}}
*/
const REDIS_CONFIG =
{
REDIS_PORT: (getConfigKey('REDIS_PORT') && parseInt(getConfigKey('REDIS_PORT'))) || 14563,
REDIS_HOST: getConfigKey('REDIS_HOST'),
REDIS_PASSWORD: getConfigKey('REDIS_PASSWORD'),
SESSION_TTL_IN_SECS: 60 * 60,
SESSION_TTL_IN_SECS: 60 * 60, //how long session data is stored in redis
};

/**
* Mongo configuration
* @type {{DBNAME: (string|undefined), URL: (string|undefined)}}
*/
const MONGO_CONFIG =
{
URL: getConfigKey('MONGO_URL'),
DBNAME: getConfigKey('MONGO_DBNAME'),
};

/**
* Stripe related config
* @type {{BYPASS_WEBHOOK_SIGNATURE_CHECK: boolean, WEBHOOK_SECRET: (string|undefined), PUBLISHABLE_KEY: (string|undefined), SECRET_KEY: (string|undefined)}}
*/
const STRIPE_CONFIG =
{
PUBLISHABLE_KEY: getConfigKey('STRIPE_PUBLISHABLE_KEY'),
SECRET_KEY: getConfigKey('STRIPE_SECRET_KEY'),
WEBHOOK_SECRET: getConfigKey('STRIPE_WEBHOOK_SECRET'),
BYPASS_WEBHOOK_SIGNATURE_CHECK: (getConfigKey('STRIPE_BYPASS_WEBHOOK_SIGNATURE_CHECK') === "yes"),
};

/**
* Elastic access details
* @type {{URL: (string|undefined)}}
*/
const ELASTIC_CONFIG =
{
URL: getConfigKey('ELASTIC_URL'),
};


/**
* Generic configuration is here
* @type {{ENABLE_HEALHCHECK: boolean, ENVIRONMENT: string}}
*/
const GENERIC_CONFIG =
{
ENVIRONMENT: determineEnviroment(),
Expand All @@ -106,4 +152,4 @@ module.exports = {
ELASTIC_CONFIG,
ORGID,
GENERIC_CONFIG
};
};
Loading
0