diff --git a/dist/config/config.js b/dist/config/config.js new file mode 100644 index 0000000..f65f9f9 --- /dev/null +++ b/dist/config/config.js @@ -0,0 +1,4 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.config = void 0; +exports.config = Object.assign({ THRESHOLD_DISTANCE_KM: parseFloat(process.env.THRESHOLD_DISTANCE_KM || '') || 0.50, THRESHOLD_TIME_MIN: parseInt(process.env.THRESHOLD_TIME_MIN || '') || 3, USE_TIME_THRESHOLD: false, USE_MAPS_API: true, MAX_STATIONS: parseInt(process.env.MAX_STATIONS || '') || 2, DISTANCE_LIMIT_KM: parseFloat(process.env.DISTANCE_LIMIT_KM || '') || 15, bpp_id: process.env.bpp_id || 'gtfs_bpp', bpp_uri: process.env.bpp_uri || 'https://b587-49-207-220-210.ngrok.io/', registry_url: process.env.registry_url || 'https://pilot-gateway-1.beckn.nsdl.co.in', unique_key_id: process.env.unique_key_id || '25', country: process.env.country || "IND", domain: process.env.domain || "nic2004:60212", city: process.env.city || "Kochi", core_version: process.env.core_version || "0.9.3", auth: false }, (process.env.ENABLE_LOCATION_SERVICES === 'true' ? { ENABLE_LOCATION_SERVICES: true } : { ENABLE_LOCATION_SERVICES: false })); diff --git a/dist/config/db.js b/dist/config/db.js new file mode 100644 index 0000000..161af44 --- /dev/null +++ b/dist/config/db.js @@ -0,0 +1,3 @@ +"use strict"; +const db_config = 'sqlite::memory:'; +module.exports = db_config; diff --git a/dist/config/key.js b/dist/config/key.js new file mode 100644 index 0000000..c1eb45f --- /dev/null +++ b/dist/config/key.js @@ -0,0 +1,8 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const nconf_1 = __importDefault(require("nconf")); +const key = nconf_1.default.file(`${__dirname}/key_store.json`); +exports.default = key; diff --git a/dist/src/db/index.js b/dist/src/db/index.js new file mode 100644 index 0000000..643f4af --- /dev/null +++ b/dist/src/db/index.js @@ -0,0 +1,9 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.sequelize = void 0; +const { Sequelize } = require('sequelize-typescript'); +const { db_config } = require('../../config/db'); +exports.sequelize = new Sequelize({ + dialect: 'sqlite', + logging: false +}); diff --git a/dist/src/db/models/Agency.model.js b/dist/src/db/models/Agency.model.js new file mode 100644 index 0000000..615376a --- /dev/null +++ b/dist/src/db/models/Agency.model.js @@ -0,0 +1,36 @@ +"use strict"; +var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +var __metadata = (this && this.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Agency = void 0; +const sequelize_typescript_1 = require("sequelize-typescript"); +let Agency = class Agency extends sequelize_typescript_1.Model { +}; +exports.Agency = Agency; +__decorate([ + sequelize_typescript_1.PrimaryKey, + sequelize_typescript_1.Column, + __metadata("design:type", String) +], Agency.prototype, "agency_id", void 0); +__decorate([ + sequelize_typescript_1.Column, + __metadata("design:type", String) +], Agency.prototype, "agency_name", void 0); +__decorate([ + sequelize_typescript_1.Column, + __metadata("design:type", String) +], Agency.prototype, "agency_url", void 0); +__decorate([ + sequelize_typescript_1.Column, + __metadata("design:type", String) +], Agency.prototype, "agency_timezone", void 0); +exports.Agency = Agency = __decorate([ + sequelize_typescript_1.Table +], Agency); diff --git a/dist/src/db/models/Calendar.model.js b/dist/src/db/models/Calendar.model.js new file mode 100644 index 0000000..8a9fa68 --- /dev/null +++ b/dist/src/db/models/Calendar.model.js @@ -0,0 +1,67 @@ +"use strict"; +var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +var __metadata = (this && this.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Calendar = void 0; +const sequelize_typescript_1 = require("sequelize-typescript"); +let Calendar = class Calendar extends sequelize_typescript_1.Model { +}; +exports.Calendar = Calendar; +__decorate([ + sequelize_typescript_1.PrimaryKey, + sequelize_typescript_1.Column, + __metadata("design:type", String) +], Calendar.prototype, "service_id", void 0); +__decorate([ + (0, sequelize_typescript_1.IsIn)([["0", "1"]]), + sequelize_typescript_1.Column, + __metadata("design:type", Number) +], Calendar.prototype, "monday", void 0); +__decorate([ + (0, sequelize_typescript_1.IsIn)([["0", "1"]]), + sequelize_typescript_1.Column, + __metadata("design:type", Number) +], Calendar.prototype, "tuesday", void 0); +__decorate([ + (0, sequelize_typescript_1.IsIn)([["0", "1"]]), + sequelize_typescript_1.Column, + __metadata("design:type", Number) +], Calendar.prototype, "wednesday", void 0); +__decorate([ + (0, sequelize_typescript_1.IsIn)([["0", "1"]]), + sequelize_typescript_1.Column, + __metadata("design:type", Number) +], Calendar.prototype, "thursday", void 0); +__decorate([ + (0, sequelize_typescript_1.IsIn)([["0", "1"]]), + sequelize_typescript_1.Column, + __metadata("design:type", Number) +], Calendar.prototype, "friday", void 0); +__decorate([ + (0, sequelize_typescript_1.IsIn)([["0", "1"]]), + sequelize_typescript_1.Column, + __metadata("design:type", Number) +], Calendar.prototype, "saturday", void 0); +__decorate([ + (0, sequelize_typescript_1.IsIn)([["0", "1"]]), + sequelize_typescript_1.Column, + __metadata("design:type", Number) +], Calendar.prototype, "sunday", void 0); +__decorate([ + sequelize_typescript_1.Column, + __metadata("design:type", Date) +], Calendar.prototype, "start_date", void 0); +__decorate([ + sequelize_typescript_1.Column, + __metadata("design:type", Date) +], Calendar.prototype, "end_date", void 0); +exports.Calendar = Calendar = __decorate([ + sequelize_typescript_1.Table +], Calendar); diff --git a/dist/src/db/models/FareAttributes.model.js b/dist/src/db/models/FareAttributes.model.js new file mode 100644 index 0000000..816cc91 --- /dev/null +++ b/dist/src/db/models/FareAttributes.model.js @@ -0,0 +1,40 @@ +"use strict"; +var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +var __metadata = (this && this.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.FareAttributes = void 0; +const sequelize_typescript_1 = require("sequelize-typescript"); +let FareAttributes = class FareAttributes extends sequelize_typescript_1.Model { +}; +exports.FareAttributes = FareAttributes; +__decorate([ + sequelize_typescript_1.PrimaryKey, + sequelize_typescript_1.Column, + __metadata("design:type", String) +], FareAttributes.prototype, "fare_id", void 0); +__decorate([ + sequelize_typescript_1.Column, + __metadata("design:type", String) +], FareAttributes.prototype, "price", void 0); +__decorate([ + sequelize_typescript_1.Column, + __metadata("design:type", String) +], FareAttributes.prototype, "currency_type", void 0); +__decorate([ + sequelize_typescript_1.Column, + __metadata("design:type", String) +], FareAttributes.prototype, "payment_method", void 0); +__decorate([ + sequelize_typescript_1.Column, + __metadata("design:type", String) +], FareAttributes.prototype, "transfers", void 0); +exports.FareAttributes = FareAttributes = __decorate([ + sequelize_typescript_1.Table +], FareAttributes); diff --git a/dist/src/db/models/FareRules.model.js b/dist/src/db/models/FareRules.model.js new file mode 100644 index 0000000..237255c --- /dev/null +++ b/dist/src/db/models/FareRules.model.js @@ -0,0 +1,36 @@ +"use strict"; +var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +var __metadata = (this && this.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.FareRules = void 0; +const sequelize_typescript_1 = require("sequelize-typescript"); +const FareAttributes_model_1 = require("./FareAttributes.model"); +const Stops_model_1 = require("./Stops.model"); +let FareRules = class FareRules extends sequelize_typescript_1.Model { +}; +exports.FareRules = FareRules; +__decorate([ + (0, sequelize_typescript_1.ForeignKey)(() => FareAttributes_model_1.FareAttributes), + sequelize_typescript_1.Column, + __metadata("design:type", String) +], FareRules.prototype, "fare_id", void 0); +__decorate([ + (0, sequelize_typescript_1.ForeignKey)(() => Stops_model_1.Stops), + sequelize_typescript_1.Column, + __metadata("design:type", String) +], FareRules.prototype, "origin_id", void 0); +__decorate([ + (0, sequelize_typescript_1.ForeignKey)(() => Stops_model_1.Stops), + sequelize_typescript_1.Column, + __metadata("design:type", String) +], FareRules.prototype, "destination_id", void 0); +exports.FareRules = FareRules = __decorate([ + sequelize_typescript_1.Table +], FareRules); diff --git a/dist/src/db/models/StopTimes.model.js b/dist/src/db/models/StopTimes.model.js new file mode 100644 index 0000000..ca8985d --- /dev/null +++ b/dist/src/db/models/StopTimes.model.js @@ -0,0 +1,51 @@ +"use strict"; +var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +var __metadata = (this && this.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.StopTimes = void 0; +const sequelize_typescript_1 = require("sequelize-typescript"); +const Stops_model_1 = require("./Stops.model"); +const Trips_model_1 = require("./Trips.model"); +let StopTimes = class StopTimes extends sequelize_typescript_1.Model { +}; +exports.StopTimes = StopTimes; +__decorate([ + sequelize_typescript_1.Column, + (0, sequelize_typescript_1.ForeignKey)(() => Trips_model_1.Trips), + __metadata("design:type", String) +], StopTimes.prototype, "trip_id", void 0); +__decorate([ + sequelize_typescript_1.Column, + __metadata("design:type", String) +], StopTimes.prototype, "arrival_time", void 0); +__decorate([ + sequelize_typescript_1.Column, + __metadata("design:type", String) +], StopTimes.prototype, "departure_time", void 0); +__decorate([ + sequelize_typescript_1.Column, + (0, sequelize_typescript_1.ForeignKey)(() => Stops_model_1.Stops), + __metadata("design:type", String) +], StopTimes.prototype, "stop_id", void 0); +__decorate([ + sequelize_typescript_1.Column, + __metadata("design:type", Number) +], StopTimes.prototype, "stop_sequence", void 0); +__decorate([ + sequelize_typescript_1.Column, + __metadata("design:type", String) +], StopTimes.prototype, "timepoint", void 0); +__decorate([ + sequelize_typescript_1.Column, + __metadata("design:type", String) +], StopTimes.prototype, "shape_dist_traveled", void 0); +exports.StopTimes = StopTimes = __decorate([ + sequelize_typescript_1.Table +], StopTimes); diff --git a/dist/src/db/models/Stops.model.js b/dist/src/db/models/Stops.model.js new file mode 100644 index 0000000..0848670 --- /dev/null +++ b/dist/src/db/models/Stops.model.js @@ -0,0 +1,44 @@ +"use strict"; +var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +var __metadata = (this && this.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Stops = void 0; +const sequelize_typescript_1 = require("sequelize-typescript"); +let Stops = class Stops extends sequelize_typescript_1.Model { +}; +exports.Stops = Stops; +__decorate([ + sequelize_typescript_1.PrimaryKey, + sequelize_typescript_1.Column, + __metadata("design:type", String) +], Stops.prototype, "stop_id", void 0); +__decorate([ + sequelize_typescript_1.Column, + __metadata("design:type", String) +], Stops.prototype, "stop_name", void 0); +__decorate([ + sequelize_typescript_1.Column, + __metadata("design:type", String) +], Stops.prototype, "stop_lat", void 0); +__decorate([ + sequelize_typescript_1.Column, + __metadata("design:type", String) +], Stops.prototype, "stop_lon", void 0); +__decorate([ + sequelize_typescript_1.Column, + __metadata("design:type", String) +], Stops.prototype, "zone_id", void 0); +__decorate([ + sequelize_typescript_1.Column, + __metadata("design:type", String) +], Stops.prototype, "wheelchair_boarding", void 0); +exports.Stops = Stops = __decorate([ + sequelize_typescript_1.Table +], Stops); diff --git a/dist/src/db/models/Subscribers.model.js b/dist/src/db/models/Subscribers.model.js new file mode 100644 index 0000000..9e5c552 --- /dev/null +++ b/dist/src/db/models/Subscribers.model.js @@ -0,0 +1,40 @@ +"use strict"; +var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +var __metadata = (this && this.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Subscribers = void 0; +const sequelize_typescript_1 = require("sequelize-typescript"); +let Subscribers = class Subscribers extends sequelize_typescript_1.Model { +}; +exports.Subscribers = Subscribers; +__decorate([ + sequelize_typescript_1.PrimaryKey, + sequelize_typescript_1.Column, + __metadata("design:type", String) +], Subscribers.prototype, "subscriber_id", void 0); +__decorate([ + sequelize_typescript_1.Column, + __metadata("design:type", String) +], Subscribers.prototype, "subscriber_url", void 0); +__decorate([ + sequelize_typescript_1.Column, + __metadata("design:type", String) +], Subscribers.prototype, "signing_public_key", void 0); +__decorate([ + sequelize_typescript_1.Column, + __metadata("design:type", String) +], Subscribers.prototype, "type", void 0); +__decorate([ + sequelize_typescript_1.Column, + __metadata("design:type", Date) +], Subscribers.prototype, "valid_until", void 0); +exports.Subscribers = Subscribers = __decorate([ + sequelize_typescript_1.Table +], Subscribers); diff --git a/dist/src/db/models/Trips.model.js b/dist/src/db/models/Trips.model.js new file mode 100644 index 0000000..a722fb5 --- /dev/null +++ b/dist/src/db/models/Trips.model.js @@ -0,0 +1,54 @@ +"use strict"; +var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +var __metadata = (this && this.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Trips = void 0; +const sequelize_typescript_1 = require("sequelize-typescript"); +const Calendar_model_1 = require("./Calendar.model"); +let Trips = class Trips extends sequelize_typescript_1.Model { +}; +exports.Trips = Trips; +__decorate([ + sequelize_typescript_1.Column, + __metadata("design:type", String) +], Trips.prototype, "route_id", void 0); +__decorate([ + sequelize_typescript_1.Column, + (0, sequelize_typescript_1.ForeignKey)(() => Calendar_model_1.Calendar), + __metadata("design:type", String) +], Trips.prototype, "service_id", void 0); +__decorate([ + sequelize_typescript_1.PrimaryKey, + sequelize_typescript_1.Column, + __metadata("design:type", String) +], Trips.prototype, "trip_id", void 0); +__decorate([ + sequelize_typescript_1.Column, + __metadata("design:type", String) +], Trips.prototype, "trip_headsign", void 0); +__decorate([ + sequelize_typescript_1.Column, + __metadata("design:type", String) +], Trips.prototype, "direction_id", void 0); +__decorate([ + sequelize_typescript_1.Column, + __metadata("design:type", String) +], Trips.prototype, "shape_id", void 0); +__decorate([ + sequelize_typescript_1.Column, + __metadata("design:type", String) +], Trips.prototype, "zone_id", void 0); +__decorate([ + sequelize_typescript_1.Column, + __metadata("design:type", String) +], Trips.prototype, "wheelchair_accessible", void 0); +exports.Trips = Trips = __decorate([ + sequelize_typescript_1.Table +], Trips); diff --git a/dist/src/db/models/index.js b/dist/src/db/models/index.js new file mode 100644 index 0000000..1b1176c --- /dev/null +++ b/dist/src/db/models/index.js @@ -0,0 +1,12 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.MODELS = void 0; +const Calendar_model_1 = require("./Calendar.model"); +const FareAttributes_model_1 = require("./FareAttributes.model"); +const FareRules_model_1 = require("./FareRules.model"); +const Stops_model_1 = require("./Stops.model"); +const StopTimes_model_1 = require("./StopTimes.model"); +const Trips_model_1 = require("./Trips.model"); +const Agency_model_1 = require("./Agency.model"); +const Subscribers_model_1 = require("./Subscribers.model"); +exports.MODELS = [Calendar_model_1.Calendar, FareAttributes_model_1.FareAttributes, FareRules_model_1.FareRules, Stops_model_1.Stops, StopTimes_model_1.StopTimes, Trips_model_1.Trips, Subscribers_model_1.Subscribers, Agency_model_1.Agency]; diff --git a/dist/src/db/models/setupData.js b/dist/src/db/models/setupData.js new file mode 100644 index 0000000..49862e3 --- /dev/null +++ b/dist/src/db/models/setupData.js @@ -0,0 +1,49 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.setupData = void 0; +const csvtojson_1 = __importDefault(require("csvtojson")); +const path_1 = __importDefault(require("path")); +const Calendar_model_1 = require("./Calendar.model"); +const FareAttributes_model_1 = require("./FareAttributes.model"); +const FareRules_model_1 = require("./FareRules.model"); +const Stops_model_1 = require("./Stops.model"); +const StopTimes_model_1 = require("./StopTimes.model"); +const Trips_model_1 = require("./Trips.model"); +const Agency_model_1 = require("./Agency.model"); +const setupData = (data_path) => __awaiter(void 0, void 0, void 0, function* () { + //Clear database + Calendar_model_1.Calendar.destroy({ where: {} }); + FareAttributes_model_1.FareAttributes.destroy({ where: {} }); + FareRules_model_1.FareRules.destroy({ where: {} }); + Stops_model_1.Stops.destroy({ where: {} }); + StopTimes_model_1.StopTimes.destroy({ where: {} }); + Trips_model_1.Trips.destroy({ where: {} }); + Agency_model_1.Agency.destroy({ where: {} }); + const files = ['calendar', 'fare_attributes', 'fare_rules', 'stops', 'stop_times', 'trips', 'agency']; + const MODELS = [Calendar_model_1.Calendar, FareAttributes_model_1.FareAttributes, FareRules_model_1.FareRules, Stops_model_1.Stops, StopTimes_model_1.StopTimes, Trips_model_1.Trips, Agency_model_1.Agency]; + for (let index = 0; index < files.length; index++) { + const file_name = files[index] + '.txt'; + const model = MODELS[index]; + const data = yield (0, csvtojson_1.default)().fromFile(path_1.default.join(data_path, file_name)); + if (file_name === 'calendar.txt') { + for (var row of data) { + row.start_date = `${row.start_date.slice(0, 4)}-${row.start_date.slice(4, 6)}-${row.start_date.slice(6, 8)}`; + row.end_date = `${row.end_date.slice(0, 4)}-${row.end_date.slice(4, 6)}-${row.end_date.slice(6, 8)}`; + } + } + model.bulkCreate(data); + } +}); +exports.setupData = setupData; diff --git a/dist/src/index.js b/dist/src/index.js new file mode 100644 index 0000000..490ddc2 --- /dev/null +++ b/dist/src/index.js @@ -0,0 +1,49 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const express = require('express'); +const cors_1 = __importDefault(require("cors")); +const auth_1 = require("./utils/auth"); +const app = express(); +//app.use(express.json()); +app.use((0, cors_1.default)()); +app.use(express.json({ + verify: (req, res, buf) => { + req.rawBody = buf.toString(); + } +})); +const index_1 = require("./db/index"); +const models_1 = require("./db/models"); +const setupData_1 = require("./db/models/setupData"); +(() => __awaiter(void 0, void 0, void 0, function* () { + try { + yield index_1.sequelize.addModels(models_1.MODELS); + yield index_1.sequelize.sync(); + yield (0, setupData_1.setupData)('./gtfs-data/'); + console.log('Connection has been established successfully.'); + } + catch (error) { + console.error('Unable to connect to the database:', error); + } + if (process.env.sign_public_key === '' || process.env.sign_public_key === undefined || process.env.sign_private_key === '' || process.env.sign_private_key === undefined) { + throw ("Keys not found"); + } + const PORT = process.env.PORT || 8000; + app.use('/search', auth_1.auth, require("./routes/search")); + app.use('/auth', require("./routes/auth")); + app.use('/health', require("./routes/health")); + app.listen(PORT, () => { + console.log(`Transit BPP listening on port ${PORT}`); + }); +}))(); diff --git a/dist/src/routes/auth.js b/dist/src/routes/auth.js new file mode 100644 index 0000000..ab5dd28 --- /dev/null +++ b/dist/src/routes/auth.js @@ -0,0 +1,26 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const express_1 = __importDefault(require("express")); +const router = express_1.default.Router(); +router.get("/pubkey", (req, res) => __awaiter(void 0, void 0, void 0, function* () { + try { + console.log('Received request for public key'); + res.status(200).send(process.env.sign_public_key); + } + catch (error) { + res.status(500).send(error.message); + } +})); +module.exports = router; diff --git a/dist/src/routes/health.js b/dist/src/routes/health.js new file mode 100644 index 0000000..7eed40f --- /dev/null +++ b/dist/src/routes/health.js @@ -0,0 +1,23 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const express_1 = __importDefault(require("express")); +const router = express_1.default.Router(); +router.get("/", (req, res) => __awaiter(void 0, void 0, void 0, function* () { + res.status(200).send("OK"); +})); +router.post("/", (req, res) => __awaiter(void 0, void 0, void 0, function* () { + res.status(200).send("OK"); +})); +module.exports = router; diff --git a/dist/src/routes/search.js b/dist/src/routes/search.js new file mode 100644 index 0000000..b39aa95 --- /dev/null +++ b/dist/src/routes/search.js @@ -0,0 +1,52 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const express_1 = __importDefault(require("express")); +const utils = require('../utils/util'); +const router = express_1.default.Router(); +router.post("/", (req, res) => __awaiter(void 0, void 0, void 0, function* () { + var _a, _b; + try { + console.log('Received search'); + console.log((_b = (_a = req.body) === null || _a === void 0 ? void 0 : _a.context) === null || _b === void 0 ? void 0 : _b.transaction_id, req.rawBody); + var errorMessage = utils.validateInputs(req); + if (!errorMessage) { + utils.createOnSearch(req); + res.status(200).send({ + "message": { + "ack": { + "status": "ACK" + } + } + }); + } + else { + res.status(400).send({ + "message": { + "ack": { + "status": "NACK" + } + }, + "error": { + "type": "JSON-SCHEMA-ERROR", + "message": errorMessage + } + }); + } + } + catch (error) { + res.status(500).send(error.message); + } +})); +module.exports = router; diff --git a/dist/src/utils/auth.js b/dist/src/utils/auth.js new file mode 100644 index 0000000..acd31ea --- /dev/null +++ b/dist/src/utils/auth.js @@ -0,0 +1,242 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.auth = exports.verifyMessage = exports.createAuthorizationHeader = exports.signMessage = exports.createSigningString = exports.combineURLs = exports.createKeyPair = void 0; +const libsodium_wrappers_1 = __importStar(require("libsodium-wrappers")); +const axios = require('axios').default; +const { config } = require('../../config/config'); +const Subscribers_model_1 = require("../db/models/Subscribers.model"); +const key_1 = __importDefault(require("../../config/key")); +const createKeyPair = () => __awaiter(void 0, void 0, void 0, function* () { + yield libsodium_wrappers_1.default.ready; + const sodium = libsodium_wrappers_1.default; + let { publicKey, privateKey } = sodium.crypto_sign_keypair(); + const publicKey_base64 = sodium.to_base64(publicKey, libsodium_wrappers_1.base64_variants.ORIGINAL); + const privateKey_base64 = sodium.to_base64(privateKey, libsodium_wrappers_1.base64_variants.ORIGINAL); + key_1.default.set('public_key', publicKey_base64); + key_1.default.set('private_key', privateKey_base64); + key_1.default.save(0); + console.log("Key pair created"); +}); +exports.createKeyPair = createKeyPair; +function combineURLs(baseURL, relativeURL) { + return relativeURL + ? baseURL.replace(/\/+$/, '') + '/' + relativeURL.replace(/^\/+/, '') + : baseURL; +} +exports.combineURLs = combineURLs; +const createSigningString = (message, created, expires) => __awaiter(void 0, void 0, void 0, function* () { + if (!created) + created = Math.floor(new Date().getTime() / 1000).toString(); + if (!expires) + expires = (parseInt(created) + (1 * 60 * 60)).toString(); //Add required time to create expired + //const digest = createBlakeHash('blake512').update(JSON.stringify(message)).digest("base64"); + //const digest = blake2.createHash('blake2b', { digestLength: 64 }).update(Buffer.from(message)).digest("base64"); + yield libsodium_wrappers_1.default.ready; + const sodium = libsodium_wrappers_1.default; + const digest = sodium.crypto_generichash(64, sodium.from_string(message)); + const digest_base64 = sodium.to_base64(digest, libsodium_wrappers_1.base64_variants.ORIGINAL); + const signing_string = `(created): ${created} +(expires): ${expires} +digest: BLAKE-512=${digest_base64}`; + return { signing_string, expires, created }; +}); +exports.createSigningString = createSigningString; +const signMessage = (signing_string, privateKey) => __awaiter(void 0, void 0, void 0, function* () { + yield libsodium_wrappers_1.default.ready; + const sodium = libsodium_wrappers_1.default; + const signedMessage = sodium.crypto_sign_detached(signing_string, sodium.from_base64(privateKey, libsodium_wrappers_1.base64_variants.ORIGINAL)); + return sodium.to_base64(signedMessage, libsodium_wrappers_1.base64_variants.ORIGINAL); +}); +exports.signMessage = signMessage; +const createAuthorizationHeader = (message) => __awaiter(void 0, void 0, void 0, function* () { + var _a; + const { signing_string, expires, created } = yield (0, exports.createSigningString)(JSON.stringify(message)); + console.log((_a = message === null || message === void 0 ? void 0 : message.context) === null || _a === void 0 ? void 0 : _a.transaction_id, "Signing string: ", signing_string); + const signature = yield (0, exports.signMessage)(signing_string, process.env.sign_private_key || ""); + const subscriber_id = config.bpp_id; + const header = `Signature keyId="${subscriber_id}|${config.unique_key_id}|ed25519",algorithm="ed25519",created="${created}",expires="${expires}",headers="(created) (expires) digest",signature="${signature}"`; + return header; +}); +exports.createAuthorizationHeader = createAuthorizationHeader; +const verifyMessage = (signedString, signingString, publicKey) => __awaiter(void 0, void 0, void 0, function* () { + try { + yield libsodium_wrappers_1.default.ready; + const sodium = libsodium_wrappers_1.default; + return sodium.crypto_sign_verify_detached(sodium.from_base64(signedString, libsodium_wrappers_1.base64_variants.ORIGINAL), signingString, sodium.from_base64(publicKey, libsodium_wrappers_1.base64_variants.ORIGINAL)); + } + catch (error) { + console.log(error); + return false; + } +}); +exports.verifyMessage = verifyMessage; +const remove_quotes = (value) => { + if (value.length >= 2 && value.charAt(0) == '"' && value.charAt(value.length - 1) == '"') { + value = value.substring(1, value.length - 1); + } + return value; +}; +const split_auth_header_space = (auth_header) => { + const header = auth_header.replace('Signature ', ''); + let re = /\s*([^=]+)=\"([^"]+)"/g; + let m; + let parts = {}; + while ((m = re.exec(header)) !== null) { + if (m) { + parts[m[1]] = m[2]; + } + } + return parts; +}; +const split_auth_header = (auth_header) => { + const header = auth_header.replace('Signature ', ''); + let re = /\s*([^=]+)=([^,]+)[,]?/g; + let m; + let parts = {}; + while ((m = re.exec(header)) !== null) { + if (m) { + parts[m[1]] = remove_quotes(m[2]); + } + } + return parts; +}; +const verifyHeader = (header, req) => __awaiter(void 0, void 0, void 0, function* () { + var _b, _c, _d, _e; + try { + const parts = split_auth_header(header); + if (!parts || Object.keys(parts).length === 0) { + throw (new Error("Header parsing failed")); + } + var [subscriber_id, unique_key_id] = parts['keyId'].split('|'); + const subscriber_details = yield lookupRegistry(subscriber_id, unique_key_id); + const public_key = subscriber_details.signing_public_key; + const subscriber_url = subscriber_details.subscriber_url; + const subscriber_type = subscriber_details.type.toLowerCase(); + req.subscriber_type = subscriber_type; + req.subscriber_url = subscriber_url; + console.log((_c = (_b = req.body) === null || _b === void 0 ? void 0 : _b.context) === null || _c === void 0 ? void 0 : _c.transaction_id, "Received key:", public_key); + const { signing_string } = yield (0, exports.createSigningString)(req.rawBody, parts['created'], parts['expires']); + const verified = yield (0, exports.verifyMessage)(parts['signature'], signing_string, public_key); + if (!verified) { + const sub = yield Subscribers_model_1.Subscribers.findByPk(parts['keyId'].split('|')[0]); + if (sub) { + sub.destroy(); + } + } + return verified; + } + catch (error) { + console.log((_e = (_d = req.body) === null || _d === void 0 ? void 0 : _d.context) === null || _e === void 0 ? void 0 : _e.transaction_id, error.message); + return false; + } +}); +const auth = (req, res, next) => __awaiter(void 0, void 0, void 0, function* () { + var _f, _g, _h, _j, _k, _l, _m, _o, _p, _q; + try { + console.log("\nNew Request txn_id", (_g = (_f = req.body) === null || _f === void 0 ? void 0 : _f.context) === null || _g === void 0 ? void 0 : _g.transaction_id); + if ((_j = (_h = req.body) === null || _h === void 0 ? void 0 : _h.context) === null || _j === void 0 ? void 0 : _j.bap_id) { + console.log((_l = (_k = req.body) === null || _k === void 0 ? void 0 : _k.context) === null || _l === void 0 ? void 0 : _l.transaction_id, "Request from", req.body.context.bap_id); + } + const auth_header = req.headers['authorization'] || ""; + const proxy_header = req.headers['proxy-authorization'] || ""; + if (config.auth) { + var verified = yield verifyHeader(auth_header, req); + var verified_proxy = proxy_header ? yield verifyHeader(proxy_header, req) : true; + console.log((_o = (_m = req.body) === null || _m === void 0 ? void 0 : _m.context) === null || _o === void 0 ? void 0 : _o.transaction_id, "Verification status:", verified, "Proxy verification:", verified_proxy); + if (!verified || !verified_proxy) { + throw Error("Header verification failed"); + } + } + next(); + } + catch (e) { + console.log((_q = (_p = req.body) === null || _p === void 0 ? void 0 : _p.context) === null || _q === void 0 ? void 0 : _q.transaction_id, e.message); + res.status(401).send('Authentication failed'); + } +}); +exports.auth = auth; +const lookupRegistry = (subscriber_id, unique_key_id) => __awaiter(void 0, void 0, void 0, function* () { + const subscriber_details = yield Subscribers_model_1.Subscribers.findByPk(subscriber_id); + if (subscriber_details) { + if (subscriber_details.valid_until > new Date()) { + console.log("Found subscriber details in cache"); + return subscriber_details; + } + else { + subscriber_details.destroy(); + } + } + try { + const header = yield (0, exports.createAuthorizationHeader)({ subscriber_id }); + const axios_config = { + headers: { + Authorization: header + } + }; + console.log("Calling", combineURLs(config.registry_url, '/lookup'), { subscriber_id, unique_key_id }); + const response = yield axios.post(combineURLs(config.registry_url, '/lookup'), { subscriber_id, unique_key_id }); + if (response.data) { + if (response.data.length === 0) { + throw (new Error("Subscriber not found")); + } + const { subscriber_id, subscriber_url, signing_public_key, type, valid_until } = response.data[0]; + Subscribers_model_1.Subscribers.create({ subscriber_id, subscriber_url, signing_public_key, type, valid_until }); + } + return response.data[0]; + } + catch (error) { + console.log(error); + console.log(error.message); + throw (new Error("Registry lookup error")); + } +}); +const getPublicKey = (subscriber_id) => __awaiter(void 0, void 0, void 0, function* () { + try { + const header = yield (0, exports.createAuthorizationHeader)({ subscriber_id }); + const axios_config = { + headers: { + Authorization: header + } + }; + const response = yield axios.post(combineURLs(config.registry_url, '/lookup'), { subscriber_id }, axios_config); + return response.data.signing_public_key; + } + catch (error) { + console.log(error); + } +}); diff --git a/dist/src/utils/util.js b/dist/src/utils/util.js new file mode 100644 index 0000000..7a1fad0 --- /dev/null +++ b/dist/src/utils/util.js @@ -0,0 +1,455 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.combineURLs = void 0; +const lodash_1 = __importDefault(require("lodash")); +const sequelize_1 = require("sequelize"); +const axios = require('axios').default; +const Stops_model_1 = require("../db/models/Stops.model"); +const { config } = require('../../config/config'); +const index_1 = require("../db/index"); +const auth_1 = require("./auth"); +function combineURLs(baseURL, relativeURL) { + return relativeURL + ? baseURL.replace(/\/+$/, '') + '/' + relativeURL.replace(/^\/+/, '') + : baseURL; +} +exports.combineURLs = combineURLs; +function getDistanceFromLatLonInKm(lat1, lon1, lat2, lon2) { + var R = 6371; // Radius of the earth in km + var dLat = deg2rad(lat2 - lat1); // deg2rad below + var dLon = deg2rad(lon2 - lon1); + var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + + Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * + Math.sin(dLon / 2) * Math.sin(dLon / 2); + var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); + var d = R * c; // Distance in km + return d; +} +function deg2rad(deg) { + return deg * (Math.PI / 180); +} +const findClosestStops = (gps) => __awaiter(void 0, void 0, void 0, function* () { + const lat1 = parseFloat(gps.split(',')[0]); + const lon1 = parseFloat(gps.split(',')[1]); + const stops = yield getAllStations(); + var stops_obj = []; + for (var stop of stops) { + var stop_obj = stop.toJSON(); + const lat2 = parseFloat(stop.stop_lat); + const lon2 = parseFloat(stop.stop_lon); + const distance = getDistanceFromLatLonInKm(lat1, lon1, lat2, lon2); + stop_obj.distance = distance; + stops_obj.push(stop_obj); + } + const sortedStops = lodash_1.default.sortBy(stops_obj, ['distance']); + const closestStop = sortedStops[0]; + var closestStops = []; + closestStops.push(closestStop.stop_id); + console.log(closestStop.stop_id, closestStop.distance, "kms away"); + if (closestStop.distance > config.DISTANCE_LIMIT_KM) { + return []; + } + for (var this_stop of sortedStops.slice(1)) { + if ((this_stop.distance - closestStop.distance) < config.THRESHOLD_DISTANCE_KM && sortedStops.indexOf(this_stop) < config.MAX_STATIONS) { + closestStops.push(this_stop.stop_id); + console.log(this_stop.stop_id, this_stop.distance, "kms away"); + } + else { + break; + } + } + return closestStops; +}); +const findClosestFromGMapsResponse = (sortedResponses) => { + const closestStop = sortedResponses[0]; + var closestStops = []; + closestStops.push(closestStop.stop_id); + console.log("Closest is ", closestStop.stop_id, closestStop.distance.text, " and ", closestStop.duration.text, " away"); + if (closestStop.distance.value / 1000 > config.DISTANCE_LIMIT_KM) { + return []; + } + for (var stop of sortedResponses.slice(1)) { + const threshold_passed = config.USE_TIME_THRESHOLD ? + (stop.duration.value / 60 - closestStop.duration.value / 60) < config.THRESHOLD_TIME_MIN : + (stop.distance.value / 1000 - closestStop.distance.value / 1000) < config.THRESHOLD_DISTANCE_KM; + //console.log("Delta distance:", (stop.distance.value / 1000 - closestStop.distance.value / 1000),"Delta time:" ,(stop.duration.value / 60 - closestStop.duration.value / 60)); + if (threshold_passed && sortedResponses.indexOf(stop) < config.MAX_STATIONS) { + closestStops.push(stop.stop_id); + console.log(stop.stop_id, stop.distance.text, " and ", stop.duration.text, " away selected"); + } + else { + break; + } + } + return closestStops; +}; +const findClosestStopsMaps = (gpsStart, gpsEnd) => __awaiter(void 0, void 0, void 0, function* () { + try { + const stops = yield getAllStations(); + const origins = [gpsStart, gpsEnd].join('|'); + const destinations_array = []; + for (var stop of stops) { + destinations_array.push(`${stop.stop_lat},${stop.stop_lon}`); + } + const destinations = destinations_array.join('|'); + const response = yield axios.get('https://maps.googleapis.com/maps/api/distancematrix/json', { + params: { + destinations: destinations, + origins: origins, + key: process.env.MAPS_KEY, + mode: 'DRIVING' + } + }); + if (response.data.status !== 'OK') { + console.log("Response from google maps:", response); + throw ("Maps API error"); + } + const origin_distances = response.data.rows[0].elements; + const destination_distances = response.data.rows[1].elements; + for (var index in origin_distances) { + origin_distances[index].stop_id = stops[index].stop_id; + } + for (var index in destination_distances) { + destination_distances[index].stop_id = stops[index].stop_id; + } + const sorted_origin_distances = lodash_1.default.sortBy(origin_distances, ['distance.value']); + const origin_stations = findClosestFromGMapsResponse(sorted_origin_distances); + const sorted_destination_distances = lodash_1.default.sortBy(destination_distances, ['distance.value']); + const destination_stations = findClosestFromGMapsResponse(sorted_destination_distances); + return [origin_stations, destination_stations]; + } + catch (error) { + console.log(error); + throw (error); + } +}); +const validateGps = (gps) => { + if (gps.split(',').length !== 2) { + return false; + } + var [lat, lon] = gps.split(','); + var lat_val = parseFloat(lat); + var lon_val = parseFloat(lon); + if (!(!isNaN(lat_val) && !isNaN(lat) && lat_val <= 90 && lat_val >= -90)) { + return false; + } + if (!(!isNaN(lon_val) && !isNaN(lon) && lon_val <= 180 && lon_val >= -180)) { + return false; + } + return true; +}; +const validateInputs = (req) => { + var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5; + const body = req.body; + const context = req.body.context; + if (!context) { + return "Context not found"; + } + if (context.city != config.city || context.domain != config.domain || context.country != config.country || context.core_version != config.core_version) { + return "Wrong value in context"; + } + var start_received = false; + var end_received = false; + var start_gps_valid = true; + var end_gps_valid = true; + if ((_e = (_d = (_c = (_b = (_a = body.message) === null || _a === void 0 ? void 0 : _a.intent) === null || _b === void 0 ? void 0 : _b.fulfillment) === null || _c === void 0 ? void 0 : _c.start) === null || _d === void 0 ? void 0 : _d.location) === null || _e === void 0 ? void 0 : _e.station_code) { + start_received = true; + } + if ((_k = (_j = (_h = (_g = (_f = body.message) === null || _f === void 0 ? void 0 : _f.intent) === null || _g === void 0 ? void 0 : _g.fulfillment) === null || _h === void 0 ? void 0 : _h.end) === null || _j === void 0 ? void 0 : _j.location) === null || _k === void 0 ? void 0 : _k.station_code) { + end_received = true; + } + if ((_q = (_p = (_o = (_m = (_l = body.message) === null || _l === void 0 ? void 0 : _l.intent) === null || _m === void 0 ? void 0 : _m.fulfillment) === null || _o === void 0 ? void 0 : _o.start) === null || _p === void 0 ? void 0 : _p.location) === null || _q === void 0 ? void 0 : _q.gps) { + start_received = true; + start_gps_valid = validateGps((_v = (_u = (_t = (_s = (_r = body.message) === null || _r === void 0 ? void 0 : _r.intent) === null || _s === void 0 ? void 0 : _s.fulfillment) === null || _t === void 0 ? void 0 : _t.start) === null || _u === void 0 ? void 0 : _u.location) === null || _v === void 0 ? void 0 : _v.gps); + } + if ((_0 = (_z = (_y = (_x = (_w = body.message) === null || _w === void 0 ? void 0 : _w.intent) === null || _x === void 0 ? void 0 : _x.fulfillment) === null || _y === void 0 ? void 0 : _y.end) === null || _z === void 0 ? void 0 : _z.location) === null || _0 === void 0 ? void 0 : _0.gps) { + end_received = true; + end_gps_valid = validateGps((_5 = (_4 = (_3 = (_2 = (_1 = body.message) === null || _1 === void 0 ? void 0 : _1.intent) === null || _2 === void 0 ? void 0 : _2.fulfillment) === null || _3 === void 0 ? void 0 : _3.end) === null || _4 === void 0 ? void 0 : _4.location) === null || _5 === void 0 ? void 0 : _5.gps); + } + if (start_received && end_received && start_gps_valid && end_gps_valid) { + return null; + } + else { + return "Start and end locations not passed in expected format"; + } +}; +const createOnSearch = (req) => __awaiter(void 0, void 0, void 0, function* () { + var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29; + const body = req.body; + var start_codes = []; + var end_codes = []; + if ((_e = (_d = (_c = (_b = (_a = body.message) === null || _a === void 0 ? void 0 : _a.intent) === null || _b === void 0 ? void 0 : _b.fulfillment) === null || _c === void 0 ? void 0 : _c.start) === null || _d === void 0 ? void 0 : _d.location) === null || _e === void 0 ? void 0 : _e.station_code) { + start_codes.push(body.message.intent.fulfillment.start.location.station_code); + } + if ((_k = (_j = (_h = (_g = (_f = body.message) === null || _f === void 0 ? void 0 : _f.intent) === null || _g === void 0 ? void 0 : _g.fulfillment) === null || _h === void 0 ? void 0 : _h.end) === null || _j === void 0 ? void 0 : _j.location) === null || _k === void 0 ? void 0 : _k.station_code) { + end_codes.push(body.message.intent.fulfillment.end.location.station_code); + } + const date = ((_q = (_p = (_o = (_m = (_l = body.message) === null || _l === void 0 ? void 0 : _l.intent) === null || _m === void 0 ? void 0 : _m.fulfillment) === null || _o === void 0 ? void 0 : _o.start) === null || _p === void 0 ? void 0 : _p.time) === null || _q === void 0 ? void 0 : _q.timestamp) ? + (_v = (_u = (_t = (_s = (_r = body.message) === null || _r === void 0 ? void 0 : _r.intent) === null || _s === void 0 ? void 0 : _s.fulfillment) === null || _t === void 0 ? void 0 : _t.start) === null || _u === void 0 ? void 0 : _u.time) === null || _v === void 0 ? void 0 : _v.timestamp : + new Date().toISOString(); + const callback_url = req.subscriber_type === 'bg' ? req.subscriber_url : body.context.bap_uri; + if ((start_codes.length === 0 || end_codes.length === 0) && config.ENABLE_LOCATION_SERVICES) { + var start_location = (_0 = (_z = (_y = (_x = (_w = body.message) === null || _w === void 0 ? void 0 : _w.intent) === null || _x === void 0 ? void 0 : _x.fulfillment) === null || _y === void 0 ? void 0 : _y.start) === null || _z === void 0 ? void 0 : _z.location) === null || _0 === void 0 ? void 0 : _0.gps; + var end_location = (_5 = (_4 = (_3 = (_2 = (_1 = body.message) === null || _1 === void 0 ? void 0 : _1.intent) === null || _2 === void 0 ? void 0 : _2.fulfillment) === null || _3 === void 0 ? void 0 : _3.end) === null || _4 === void 0 ? void 0 : _4.location) === null || _5 === void 0 ? void 0 : _5.gps; + if (config.USE_MAPS_API) { + try { + console.log((_7 = (_6 = req.body) === null || _6 === void 0 ? void 0 : _6.context) === null || _7 === void 0 ? void 0 : _7.transaction_id, "Received search parameter start location :", start_location); + console.log((_9 = (_8 = req.body) === null || _8 === void 0 ? void 0 : _8.context) === null || _9 === void 0 ? void 0 : _9.transaction_id, "Received search parameter end location :", end_location); + [start_codes, end_codes] = yield findClosestStopsMaps(start_location, end_location); + } + catch (e) { + console.log((_11 = (_10 = req.body) === null || _10 === void 0 ? void 0 : _10.context) === null || _11 === void 0 ? void 0 : _11.transaction_id, "MAPS API call failed. Using fallback algorithm"); + start_codes = yield findClosestStops(start_location); + end_codes = yield findClosestStops(end_location); + } + } + else { + if (start_codes.length === 0) { + var start_location = body.message.intent.fulfillment.start.location.gps; + console.log((_13 = (_12 = req.body) === null || _12 === void 0 ? void 0 : _12.context) === null || _13 === void 0 ? void 0 : _13.transaction_id, "Received search parameter start location :", start_location); + start_codes = yield findClosestStops(start_location); + } + if (end_codes.length === 0) { + var end_location = body.message.intent.fulfillment.end.location.gps; + console.log((_15 = (_14 = req.body) === null || _14 === void 0 ? void 0 : _14.context) === null || _15 === void 0 ? void 0 : _15.transaction_id, "Received search parameter end location :", end_location); + end_codes = yield findClosestStops(end_location); + } + } + } + console.log((_17 = (_16 = req.body) === null || _16 === void 0 ? void 0 : _16.context) === null || _17 === void 0 ? void 0 : _17.transaction_id, 'start stations'); + console.log(start_codes); + console.log((_19 = (_18 = req.body) === null || _18 === void 0 ? void 0 : _18.context) === null || _19 === void 0 ? void 0 : _19.transaction_id, 'end stations'); + console.log(end_codes); + if ((start_codes.length === 0 || end_codes.length === 0) && config.ENABLE_LOCATION_SERVICES) { + console.log((_21 = (_20 = req.body) === null || _20 === void 0 ? void 0 : _20.context) === null || _21 === void 0 ? void 0 : _21.transaction_id, "No routes found"); + return; + } + var locations = []; + var items = []; + var fulfillments = []; + if ((!config.ENABLE_LOCATION_SERVICES) && (start_codes.length === 0 || end_codes.length === 0)) { + var all_stops = yield getAllStations(); + for (var stop of all_stops) { + var location = yield createLocationObject(stop.stop_id); + locations.push(location); + } + const item = { + "id": "sjt", + "descriptor": { + "name": "Single Journey Ticket", + "code": "SJT" + }, + "matched": true + }; + items.push(item); + } + for (var start_code of start_codes) { + for (var end_code of end_codes) { + if (start_code == end_code) { + continue; + } + console.log((_23 = (_22 = req.body) === null || _22 === void 0 ? void 0 : _22.context) === null || _23 === void 0 ? void 0 : _23.transaction_id, "ROUTE:", start_code, "TO", end_code); + const stop_times = yield get_stop_times(start_code, end_code, date); + if (stop_times.length !== 0) { + const fare = yield get_fares(start_code, end_code); + if (!lodash_1.default.find(locations, ['id', start_code])) { + const this_locations = yield createLocationObject(start_code); + locations.push(this_locations); + } + if (!lodash_1.default.find(locations, ['id', end_code])) { + const this_locations = yield createLocationObject(end_code); + locations.push(this_locations); + } + const { item, fulfillment_array } = yield createItemsArray(start_code, end_code, fare, stop_times); + //console.log(fulfillment_array); + items.push(item); + fulfillments = fulfillments.concat(fulfillment_array); + } + } + } + if (items.length !== 0) { + let response = {}; + response.context = body.context; + response.context.action = 'on_search'; + response.context.bpp_id = config.bpp_id; + response.context.bpp_uri = config.bpp_uri; + const agency = yield getAgencyDetails(); + response.message = { + "catalog": { + "bpp/descriptor": { + "name": "BPP" + }, + "bpp/providers": [ + { + "id": agency.agency_id, + "descriptor": { + "name": agency.agency_name + }, + "locations": locations, + "items": items, + "fulfillments": fulfillments + } + ] + } + }; + /* if (fulfillments.length !== 0) { + response.message.catalog['bpp/providers']['fulfillments'] = fulfillments + }*/ + const url = combineURLs(callback_url, '/on_search'); + const axios_config = yield createHeaderConfig(response); + console.log(JSON.stringify(response.message.catalog['bpp/providers'])); + console.log(JSON.stringify(response.message.catalog['bpp/providers']['fulfillments'])); + console.log(JSON.stringify(response)); + console.log((_25 = (_24 = req.body) === null || _24 === void 0 ? void 0 : _24.context) === null || _25 === void 0 ? void 0 : _25.transaction_id, "Response body", JSON.stringify(response)); + console.log((_27 = (_26 = req.body) === null || _26 === void 0 ? void 0 : _26.context) === null || _27 === void 0 ? void 0 : _27.transaction_id, "Header", axios_config.headers); + console.log((_29 = (_28 = req.body) === null || _28 === void 0 ? void 0 : _28.context) === null || _29 === void 0 ? void 0 : _29.transaction_id, "Sending response to ", url); + try { + axios.post(url, response, axios_config); + } + catch (e) { + console.log(e); + } + } +}); +const createHeaderConfig = (request) => __awaiter(void 0, void 0, void 0, function* () { + const header = yield (0, auth_1.createAuthorizationHeader)(request); + const axios_config = { + headers: { + Authorization: header + } + }; + return axios_config; +}); +const createItemsArray = (from, to, fare, stop_times) => __awaiter(void 0, void 0, void 0, function* () { + const item_code = `${from}_TO_${to}`; + const from_details = yield getStationDetails(from); + const to_details = yield getStationDetails(to); + const item_name = `${from_details.stop_name} to ${to_details.stop_name}`; + const price = fare.price; + const currency_type = fare.currency_type; + var from_schedule = []; + var to_schedule = []; + const fulfillment_array = []; + for (var time of stop_times) { + from_schedule.push(time.arrival_time); + to_schedule.push(time.destination_time); + const fulfillment = { + "id": item_code, + "start": { + "location": { + "id": from + }, + "time": { + "timestamp": time.arrival_time + } + }, + "end": { + "location": { + "id": to + }, + "time": { + "timestamp": time.destination_time + } + } + }; + fulfillment_array.push(fulfillment); + } + const item = { + "id": "sjt", + "descriptor": { + "name": "Single Journey Ticket", + "code": "SJT" + }, + "price": { + "currency": currency_type, + "value": price + }, + "location_id": from, + "fulfillment_id": item_code, + "matched": true + }; + return ({ item, fulfillment_array }); +}); +const createLocationObject = (code) => __awaiter(void 0, void 0, void 0, function* () { + const station_details = yield getStationDetails(code); + const gps = `${station_details.stop_lat},${station_details.stop_lon}`; + const name = station_details.stop_name; + const location = { + "id": code, + "descriptor": { + "name": name + }, + "station_code": code, + "gps": gps + }; + return location; +}); +const getStationDetails = (code) => __awaiter(void 0, void 0, void 0, function* () { + const stop = yield Stops_model_1.Stops.findOne({ where: { stop_id: code } }); + if (stop) { + return stop; + } + else { + throw ("Stop not found"); + } +}); +const getAllStations = () => __awaiter(void 0, void 0, void 0, function* () { + const stops = yield Stops_model_1.Stops.findAll(); + return stops; +}); +const getAgencyDetails = () => __awaiter(void 0, void 0, void 0, function* () { + var agency = yield index_1.sequelize.query(`SELECT * FROM 'Agencies'`, { type: sequelize_1.QueryTypes.SELECT }); + return agency[0]; +}); +const get_stop_times = (start_stop, end_stop, date) => __awaiter(void 0, void 0, void 0, function* () { + const date_obj = new Date(date); + const date_ist = new Date(date_obj.getTime() - ((-330) * 60 * 1000)); + var weekday = new Array(7); + weekday[0] = "sunday"; + weekday[1] = "monday"; + weekday[2] = "tuesday"; + weekday[3] = "wednesday"; + weekday[4] = "thursday"; + weekday[5] = "friday"; + weekday[6] = "saturday"; + const day = date_obj.getDay(); + var times = yield index_1.sequelize.query(`SELECT DISTINCT ori.*, end.arrival_time as destination_time + FROM 'StopTimes' ori, 'StopTimes' end, 'Trips' trip, 'Calendars' cal + WHERE ori.trip_id = end.trip_id AND + ori.stop_sequence < end.stop_sequence AND + ori.trip_id = trip.trip_id AND + trip.service_id = cal.service_id AND + ('${date_ist.toISOString().substring(0, 10)}' BETWEEN cal.start_date AND cal.end_date) AND + ori.stop_id = '${start_stop}' AND end.stop_id = '${end_stop}' AND + cal.${weekday[day]} = 1 order by ori.arrival_time`, { type: sequelize_1.QueryTypes.SELECT }); + for (var time of times) { + time.arrival_time = new Date(date_ist.toISOString().substring(0, 10) + 'T' + time.arrival_time + '.000+05:30').toISOString(); + time.departure_time = new Date(date_ist.toISOString().substring(0, 10) + 'T' + time.departure_time + '.000+05:30').toISOString(); + time.destination_time = new Date(date_ist.toISOString().substring(0, 10) + 'T' + time.destination_time + '.000+05:30').toISOString(); + } + return times; +}); +const get_fares = (start, end) => __awaiter(void 0, void 0, void 0, function* () { + var fare = yield index_1.sequelize.query(`SELECT attr.* + FROM 'FareRules' fare, 'FareAttributes' attr + WHERE fare.fare_id = attr.fare_id AND + fare.origin_id = '${start}' AND + fare.destination_id = '${end}'`, { type: sequelize_1.QueryTypes.SELECT }); + if (fare.length === 0) { + throw ('Fare rule not found'); + } + return fare[0]; +}); +module.exports = { createOnSearch, validateInputs };