Skip to content

Commit

Permalink
Timezone overlay, etc. (#32)
Browse files Browse the repository at this point in the history
* Improve non-English geographic search and other search engine improvements.
* Live search mode.
* Updated asteroid/comet data.
* Update zoneloc API call to use geo-tz.
* Update Angular to version 14.
* Add timezone map overlay option.
* Add visual reminder that found locations can be saved.
  • Loading branch information
kshetline authored Jul 17, 2022
1 parent 1519cc9 commit a470222
Show file tree
Hide file tree
Showing 38 changed files with 2,338 additions and 1,260 deletions.
883 changes: 455 additions & 428 deletions package-lock.json

Large diffs are not rendered by default.

58 changes: 29 additions & 29 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{
"name": "svc-ng",
"version": "1.15.2",
"version": "1.16.0",
"license": "MIT AND GPL-3.0-or-later",
"author": "Kerry Shetline <[email protected]>",
"scripts": {
"ng": "ng",
"start": "ng serve",
"start": "ng serve --proxy-config proxy.conf.json",
"build": "rimraf dist && ng build --configuration production --source-map=true && cd server && npm run build && cd .. && copyfiles -u 2 \"server/dist/**/*\" \"dist\"",
"build-debug": "ng build --source-map=true",
"test": "ng test",
Expand All @@ -14,62 +14,62 @@
},
"private": true,
"dependencies": {
"@angular/animations": "^14.0.2",
"@angular/cdk": "^14.0.2",
"@angular/common": "^14.0.2",
"@angular/compiler": "^14.0.2",
"@angular/core": "^14.0.2",
"@angular/forms": "^14.0.2",
"@angular/platform-browser": "^14.0.2",
"@angular/platform-browser-dynamic": "^14.0.2",
"@angular/router": "^14.0.2",
"@angular/animations": "^14.0.6",
"@angular/cdk": "^14.0.5",
"@angular/common": "^14.0.6",
"@angular/compiler": "^14.0.6",
"@angular/core": "^14.0.6",
"@angular/forms": "^14.0.6",
"@angular/platform-browser": "^14.0.6",
"@angular/platform-browser-dynamic": "^14.0.6",
"@angular/router": "^14.0.6",
"@fortawesome/fontawesome-free": "^6.1.1",
"@tubular/array-buffer-reader": "^3.0.2",
"@tubular/astronomy": "^3.3.0",
"@tubular/math": "^3.1.0",
"@tubular/ng-widgets": "^2.2.0",
"@tubular/time": "^3.8.2",
"@tubular/util": "^4.11.0",
"@tubular/time": "^3.8.3",
"@tubular/util": "^4.12.0",
"core-js": "^2.6.12",
"detect-resize": "^0.1.5",
"lodash-es": "^4.17.21",
"primeicons": "^5.0.0",
"primeng": "^13.4.1",
"primeng": "^14.0.0-rc.1",
"rxjs": "^6.6.7",
"three": "^0.140.2",
"zone.js": "~0.11.5"
"three": "^0.142.0",
"zone.js": "~0.11.6"
},
"devDependencies": {
"@angular-devkit/build-angular": "^14.0.2",
"@angular/cli": "^14.0.2",
"@angular/compiler-cli": "^14.0.2",
"@angular/language-service": "^14.0.2",
"@tubular/browser-check": "^1.3.0",
"@angular-devkit/build-angular": "^14.0.6",
"@angular/cli": "^14.0.6",
"@angular/compiler-cli": "^14.0.6",
"@angular/language-service": "^14.0.6",
"@tubular/browser-check": "^2.0.0",
"@types/googlemaps": "^3.43.3",
"@types/jasmine": "^4.0.3",
"@types/jasminewd2": "^2.0.10",
"@types/lodash-es": "^4.17.6",
"@types/three": "^0.140.0",
"@typescript-eslint/eslint-plugin": "^5.28.0",
"@typescript-eslint/parser": "^5.28.0",
"@types/three": "^0.141.0",
"@typescript-eslint/eslint-plugin": "^5.30.6",
"@typescript-eslint/parser": "^5.30.6",
"codelyzer": "^6.0.2",
"copyfiles": "^2.4.1",
"eslint": "^8.17.0",
"eslint": "^8.20.0",
"eslint-config-standard": "^17.0.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-n": "^15.2.2",
"eslint-plugin-n": "^15.2.4",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^6.0.0",
"jasmine-core": "~4.2.0",
"jasmine-spec-reporter": "~7.0.0",
"karma": "^6.3.19",
"karma": "^6.4.0",
"karma-chrome-launcher": "~3.1.1",
"karma-coverage-istanbul-reporter": "~3.0.3",
"karma-jasmine": "~5.0.0",
"karma-jasmine": "~5.1.0",
"karma-jasmine-html-reporter": "^1.7.0",
"protractor": "~7.0.0",
"rimraf": "^3.0.2",
"ts-node": "^10.7.0",
"ts-node": "^10.9.1",
"typescript": "^4.5.5"
}
}
8 changes: 8 additions & 0 deletions proxy.conf.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"/api/*": {
"target": "http://localhost:4201"
},
"/maps/*": {
"target": "http://localhost:4201"
}
}
8 changes: 8 additions & 0 deletions server/app/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { router as stateRouter } from './states';
import { router as ipToLocationRouter } from './ip-to-location';
import { router as logRouter } from './log-access';
import { router as zoneRouter } from './zone-for-location';
import { router as zoneMapRouter } from './zone-map-url';
import { router as mapsRouter } from './maps-api';
import { router as directoryRouter } from './directory-listing';
import { initTimezoneLargeAlt } from '@tubular/time';
Expand Down Expand Up @@ -41,14 +42,21 @@ app.use(morgan((tokens, req, res) => {
}));

app.use('/atlas/', atlasRouter);
app.use('/api/atlas/', atlasRouter);
app.use('/atlasdb/atlas/', atlasRouter); // Legacy Tomcat path
app.use('/states/', stateRouter);
app.use('/api/states/', stateRouter);
app.use('/atlasdb/states/', stateRouter); // Legacy Tomcat path
app.use('/ip/', ipToLocationRouter);
app.use('/api/ip/', ipToLocationRouter);
app.use('/log/', logRouter);
app.use('/api/log/', logRouter);
app.use('/zoneloc/', zoneRouter);
app.use('/api/zoneloc/', zoneRouter);
app.use('/timeservices/zoneloc/', zoneRouter); // Legacy Tomcat path
app.use('/api/zonemap/', zoneMapRouter);
app.use('/maps/', mapsRouter);
app.use('/api/maps/', mapsRouter);
// Make the flags folder browsable.
app.use('/assets/resources/flags/', directoryRouter);
app.use(express.static(pathJoin(__dirname, 'public')));
Expand Down
68 changes: 55 additions & 13 deletions server/app/atlas_database.ts → server/app/atlas-database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { doubleMetaphone } from './double-metaphone';
import { Pool, PoolConnection } from './mysql-await-async';
import {
closeMatchForState, code3ToName, countyStateCleanUp, getFlagCode, LocationMap, makeLocationKey,
ParsedSearchString, simplify, closeMatchForCity, code3ToNameByLang, admin1ToNameByLang, admin1s, code2ToCode3, admin2s
ParsedSearchString, simplify, closeMatchForCity, code3ToNameByLang, admin1ToNameByLang, admin1s, code2ToCode3, admin2s, admin1Abbreviations
} from './gazetteer';
import { AtlasLocation } from './atlas-location';
import { MIN_EXTERNAL_SOURCE } from './common';
Expand All @@ -24,11 +24,25 @@ const MAX_MONTHS_BEFORE_REDOING_EXTENDED_SEARCH = 12;
const ZIP_RANK = 9;
const ZIP_SUPPLEMENT_RANK = 1;

const logTimersByIp = new Map<string, NodeJS.Timeout>();

export function logMessage(message: string, lang?: string, ip?: string, noTrace = false): void {
svcApiConsole.info(message);

if (!noTrace)
logMessageAux(message, lang, ip, false);
if (!noTrace) {
if (!ip)
logMessageAux(message, lang, '', false);
else {
let timer = logTimersByIp.get(ip);

if (timer)
clearTimeout(timer);

timer = setTimeout(() => { logTimersByIp.delete(ip); logMessageAux(message, lang, ip, false); }, 3000);
timer.unref();
logTimersByIp.set(ip, timer);
}
}
}

export function logWarning(message: string, noTrace = false): void {
Expand Down Expand Up @@ -132,22 +146,27 @@ export async function doDataBaseSearch(connection: PoolConnection, parsed: Parse
const matches = new LocationMap();
const postal = !!parsed.postalCode;
let altParseMatches = 0;
let passRankAdj = 0;

for (let pass = 0; pass < 2; ++pass) {
const altParse = (pass > 0 && !!parsed.altCity);
const city = (altParse ? parsed.altCity : parsed.targetCity);
const targetState = (altParse ? parsed.altState : parsed.targetState);
const simplifiedCity = simplify(city);
const condition = (pass === 0 ? ' AND rank > 0' : '');

examined.clear();

for (let matchType: number = MatchType.EXACT_MATCH; matchType <= MatchType.SOUNDS_LIKE; ++matchType) {
let rankAdjust = 0;
if (lang && lang !== 'en' && matchType === MatchType.SOUNDS_LIKE)
continue;

let rankAdjust = -passRankAdj;
let query: string;
let values: any[];
let fromAlt = false;

passRankAdj = 0;

switch (matchType) {
case MatchType.EXACT_MATCH:
if (postal) {
Expand All @@ -165,7 +184,7 @@ export async function doDataBaseSearch(connection: PoolConnection, parsed: Parse
query = `SELECT * FROM gazetteer_alt_names WHERE key_name = ? AND lang = ? AND type = 'P' AND colloquial = 0 AND historic = 0`;
}
else
query = 'SELECT * FROM gazetteer WHERE key_name = ?' + condition;
query = 'SELECT * FROM gazetteer WHERE key_name = ?';
}
break;

Expand All @@ -184,7 +203,7 @@ export async function doDataBaseSearch(connection: PoolConnection, parsed: Parse
fromAlt = true;
}
else
query = 'SELECT * FROM gazetteer WHERE key_name >= ? AND key_name < ? ' + condition;
query = 'SELECT * FROM gazetteer WHERE key_name >= ? AND key_name < ? ';

break;

Expand All @@ -193,7 +212,7 @@ export async function doDataBaseSearch(connection: PoolConnection, parsed: Parse
continue;

rankAdjust = -1;
query = 'SELECT * FROM gazetteer WHERE mphone1 = ? OR mphone2 = ?' + condition;
query = 'SELECT * FROM gazetteer WHERE mphone1 = ? OR mphone2 = ?';
values = doubleMetaphone(parsed.targetCity);
break;
}
Expand All @@ -211,7 +230,7 @@ export async function doDataBaseSearch(connection: PoolConnection, parsed: Parse
values = [results.map((row: any) => row.gazetteer_id).filter((id: number) => id !== 0).join(', ')];

if (values[0]) {
query = `SELECT * FROM gazetteer WHERE id IN (${values[0]})` + condition;
query = `SELECT * FROM gazetteer WHERE id IN (${values[0]})`;
results = (await connection.queryResults(query)) || [];
}
else
Expand Down Expand Up @@ -338,11 +357,17 @@ export async function doDataBaseSearch(connection: PoolConnection, parsed: Parse
location.source = source;
location.geonamesID = geonamesID;

if (/^\d+$/.test(location.state) || (country !== 'USA' && country !== 'CAN' && /^[A-Z]{3,}$/.test(location.state))) {
const numericState = /^\d+$/.test(location.state);

if (numericState || (country !== 'USA' && country !== 'CAN' && /^[A-Z]{3,}$/.test(location.state))) {
const key = country + '.' + location.state;
const abbr = admin1Abbreviations[key];

location.state = (admin1ToNameByLang[key] || {})[lang || 'en'] || (admin1ToNameByLang[key] || {})[''] ||
admin1s[key] || location.state;
if (numericState && abbr)
location.state = abbr;
else
location.state = (admin1ToNameByLang[key] || {})[lang || 'en'] || (admin1ToNameByLang[key] || {})[''] ||
admin1s[key] || location.state;
}

if (matchType === MatchType.EXACT_MATCH_ALT)
Expand All @@ -364,8 +389,25 @@ export async function doDataBaseSearch(connection: PoolConnection, parsed: Parse
break;
}

if (postal)
let postalOnce = postal;

if (postal && parsed.postalCode.includes(' ')) {
parsed.postalCode = parsed.postalCode.replace(/\s+\S.*$/, '');
postalOnce = false;
}

if (postalOnce)
break;
else if (lang && lang !== 'en') {
--pass;
lang = '';
passRankAdj = (matches.size > 0 ? 2 : 0);
}
else if (pass === 0 && matches.size === 0 &&
parsed.targetState && simplifiedCity === simplify(parsed.targetState)) {
--pass;
parsed.targetState = '';
}
}

if (altParseMatches === 0) {
Expand Down
6 changes: 3 additions & 3 deletions server/app/atlas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { max } from '@tubular/math';
import { Request, Response, Router } from 'express';

import { asyncHandler, notFoundForEverythingElse, formatVariablePrecision } from './common';
import { doDataBaseSearch, hasSearchBeenDoneRecently, logMessage, logSearchResults, pool } from './atlas_database';
import { doDataBaseSearch, hasSearchBeenDoneRecently, logMessage, logSearchResults, pool } from './atlas-database';
import {
celestialNames, initGazetteer, LocationMap, ParsedSearchString, parseSearchString,
roughDistanceBetweenLocationsInKm
Expand Down Expand Up @@ -68,7 +68,7 @@ router.get('/', asyncHandler(async (req: Request, res: Response) => {
const withoutDB = /only|geonames|getty/i.test(remoteMode);
const extend = (remoteMode === 'extend' || remoteMode === 'only' || remoteMode === 'forced');
const client = (req.query.client ? req.query.client.toString().toLowerCase() : '');
const svc = (!client || client === 'sa' || client === 'web');
const svc = (!client || /^(sa|svc|web)$/.test(client));
const limit = Math.min(toInt(req.query.limit, DEFAULT_MATCH_LIMIT), MAX_MATCH_LIMIT);
const noTrace = toBoolean(req.query.notrace, false, true) || remoteMode === 'only';
const dbUpdate = DB_UPDATE && !noTrace;
Expand Down Expand Up @@ -180,7 +180,7 @@ router.get('/', asyncHandler(async (req: Request, res: Response) => {
else if (callback)
res.jsonp(result);
else
res.send(result);
res.json(result);
}));

function copyAndMergeLocations(destination: LocationArrayMap, source: LocationMap): void {
Expand Down
Loading

0 comments on commit a470222

Please sign in to comment.