Commit ee5b5bc3 authored by Valeriy Panov's avatar Valeriy Panov Committed by Matija Obreza
Browse files

#199 Resolve "Resolve place name"

parent ffb57e4b
......@@ -18,6 +18,9 @@ const PORT = process.env.PORT || 3000;
// other...
const GOOGLE_CLIENT_ID = process.env.GOOGLE_CLIENT_ID;
const SSR = process.env.SSR;
const GEONAMES_USERNAME = process.env.GEONAMES_USERNAME || 'geonames_test';
const GEONAMES_API_URL = 'https://secure.geonames.org';
const sortedChunks = function(list) {
return function(chunk1, chunk2) {
......@@ -88,7 +91,19 @@ module.exports = {
// view disconnected websocket connections
console.log('Client disconnected');
}
},
'/api/geonames': {
target: GEONAMES_API_URL,
logLevel: 'debug',
pathRewrite(path, req) {
const p = `${path.replace('/api/geonames', '')}&username=${GEONAMES_USERNAME}`;
// remove all headers from request
req.headers = {};
console.log(`HTTP proxy to ${GEONAMES_API_URL}${p}`);
return p;
}
}
},
},
......
......@@ -2,7 +2,7 @@ import * as minimist from 'minimist';
// console.log(process.argv);
const argv = minimist(process.argv.slice(2), {
string: ['--api-url', '--api-timeout', '--client-id', '--client-secret' ],
string: ['--api-url', '--api-timeout', '--client-id', '--client-secret', '--geonames-username' ],
});
console.dir(argv);
......@@ -17,6 +17,8 @@ const config = {
// OAuth Client
clientId: argv['client-id'] || 'my-trusted-client',
clientSecret: argv['client-secret'] || 'my-secret-client',
// Username for Geonames http://www.geonames.org/login
geonamesUsername: argv['geonames-username'] || 'geonames_test',
};
console.log('Catalog config', config);
......
import * as proxy from 'express-http-proxy';
import config from '../config';
const geonamesApiUrl = 'https://secure.geonames.org';
const geonamesHttpProxy = proxy(geonamesApiUrl, {
parseReqBody: false,
proxyReqPathResolver: (req) => {
const path = `${req.url}&username=${config.geonamesUsername}`;
// remove all headers from request
req.headers = {};
console.log(`HTTP proxy to ${geonamesApiUrl}${path}`);
return path;
},
});
export default geonamesHttpProxy;
......@@ -9,6 +9,7 @@ import {readFileSync} from 'fs';
import prerenderer from './middleware/prerenderer';
import httpProxy from './middleware/httpProxy';
import geonamesHttpProxy from './middleware/geonamesHttpProxy';
import robots from './robots';
const app = express();
......@@ -26,6 +27,8 @@ app.use((req, res, next) => {
app.use(compression());
// Proxy all requests starting with /proxy
app.use('/proxy', httpProxy);
// Proxy geonames requests
app.use('/api/geonames', geonamesHttpProxy);
// robots.txt
app.get('/robots.txt', robots);
// Serve static resources (this should be the only thing publicly accessible)
......
const clientUrl = typeof window !== 'undefined' ? `${window.location.origin}/proxy` : 'http://localhost:3000/proxy';
const origin = typeof window !== 'undefined' ? window.location.origin : 'http://localhost:3000';
const clientUrl = `${origin}/proxy`;
export const LOGIN_URL = `${clientUrl}/oauth/token`;
export const LOGOUT_URL = `${clientUrl}/token`;
......@@ -71,6 +72,10 @@ export const LIST_LOCATION_URL = '/location/list';
export const CREATE_LOCATION_URL = '/location/create';
export const UPDATE_LOCATION_URL = '/location/update';
export const REMOVE_LOCATION_URL = '/location/delete';
// Geonames API.
export const API_GEONAMES = `${origin}/api/geonames`;
export const GET_GEONAMES_COUNTRY_URL = `${API_GEONAMES}/countryCodeJSON`;
export const GET_GEONAMES_DETAIL_INFO_URL = `${API_GEONAMES}/findNearbyPlaceNameJSON`;
// Dataset CREATOR API
// FIXME base on DATASET_API
......
import axios from 'axios';
import {Location} from 'model/location.model';
import {Page} from 'model/common.model';
import authenticatedRequest from 'utilities/requestUtils';
......@@ -8,6 +10,8 @@ import {
UPDATE_LOCATION_URL,
REMOVE_LOCATION_URL,
GET_DATASET_URL,
GET_GEONAMES_COUNTRY_URL,
GET_GEONAMES_DETAIL_INFO_URL,
} from 'constants/apiURLS';
export class LocationService {
......@@ -56,4 +60,28 @@ export class LocationService {
})
.then(({data}) => new Location(data));
}
// Call geonames api
public static geonames(lat: number, lng: number): Promise<[any]> {
const params = {
formatted: true,
style: 'full',
lat,
lng,
};
return Promise.all([
axios({
url: GET_GEONAMES_COUNTRY_URL,
method: 'GET',
params,
}),
axios({
url: GET_GEONAMES_DETAIL_INFO_URL,
method: 'GET',
params,
}),
]);
}
}
import * as React from 'react';
import {withStyles} from 'material-ui/styles';
import {error} from 'utilities/debug';
import {isNumeric} from 'utilities';
let Map;
......@@ -13,8 +14,12 @@ interface IFormMapProps extends React.ClassAttributes<any> {
decimalLatitude: any,
decimalLongitude: any,
mapCountry: any,
userCountry: any,
stateProvince: any,
verbatimLocality: any,
}];
onMouseOut: () => any;
checkGeonames: (lat, lng) => Promise<{userCountry: string, stateProvince: string, verbatimLocality?: string}>;
}
const styleSheet = {
......@@ -52,15 +57,35 @@ class FormMap extends React.Component<IFormMapProps, any> {
}
}
protected getCurrentLocation = () => {
return this.props.locations.find((e) => !!e);
}
protected onMapClick = (e) => {
const {decimalLatitude, decimalLongitude} = this.props.locations.find((e) => !!e);
const {checkGeonames} = this.props;
const {decimalLatitude, decimalLongitude, userCountry, stateProvince, verbatimLocality} = this.getCurrentLocation();
const {lat, lng} = e.latlng;
decimalLatitude.input.onChange(e.latlng.lat);
decimalLongitude.input.onChange(e.latlng.lng);
decimalLatitude.input.onChange(lat);
decimalLongitude.input.onChange(lng);
checkGeonames(lat, lng)
.then((value) => {
userCountry.input.onChange(value.userCountry);
stateProvince.input.onChange(value.stateProvince);
if (!verbatimLocality.input.value) {
verbatimLocality.input.onChange(value.verbatimLocality);
}
})
.catch((e) => {
error(e);
});
}
protected onMarkerRightClick = () => {
const {decimalLatitude, decimalLongitude} = this.props.locations.find((e) => !!e);
const {decimalLatitude, decimalLongitude} = this.getCurrentLocation();
decimalLatitude.input.onChange(null);
decimalLongitude.input.onChange(null);
......@@ -71,15 +96,15 @@ class FormMap extends React.Component<IFormMapProps, any> {
return null;
}
const {classes, locations} = this.props;
const {classes} = this.props;
const {decimalLatitude, decimalLongitude} = locations.find((e) => !!e);
const {decimalLatitude, decimalLongitude} = this.getCurrentLocation();
let position = null;
if (isNumeric(decimalLatitude.input.value) && isNumeric(decimalLongitude.input.value)) {
position = {
lat: decimalLatitude.input.value,
lng: decimalLongitude.input.value,
lat: parseFloat(decimalLatitude.input.value),
lng: parseFloat(decimalLongitude.input.value),
};
}
......
......@@ -12,6 +12,9 @@ import countries from 'data/countries';
import FormMap from './FormMap';
import {Dataset} from 'model/dataset.model';
import {Location} from 'model/location.model';
import {error, log} from 'utilities/debug';
import {LocationService} from 'service/LocationService';
import {isNumeric} from 'utilities';
interface ILocationFormProps extends React.ClassAttributes<any> {
initialValues: any;
......@@ -49,6 +52,29 @@ class TimingAndLocationForm extends React.Component<ILocationFormProps, any> {
}
}
protected saveLatLng = (fields, index) => (property: string) => () => {
const {updateLocation, dataset: {locations, uuid}} = this.props;
const value = fields.get(index);
const location = locations.find((e) => e.uuid === value.uuid);
if (value[property] !== location[property]) {
this.checkGeonames(value.decimalLatitude, value.decimalLongitude)
.then(({userCountry, stateProvince, verbatimLocality}) => {
if (!location.verbatimLocality) {
updateLocation(uuid, {...value, userCountry, stateProvince, verbatimLocality});
} else {
updateLocation(uuid, {...value, userCountry, stateProvince});
}
})
.catch((e) => {
error(e);
});
}
}
protected deleteLocation = (fields, index) => () => {
this.props.deleteLocation(this.props.dataset.uuid, fields.get(index));
}
......@@ -57,6 +83,33 @@ class TimingAndLocationForm extends React.Component<ILocationFormProps, any> {
this.props.createLocation(this.props.dataset.uuid);
}
protected checkGeonames = (lat, lng): Promise<{userCountry: string, stateProvince: string, verbatimLocality?: string}> => {
if (!isNumeric(lat) || !isNumeric(lng)) {
return Promise.resolve({
userCountry: null,
stateProvince: null,
});
}
return LocationService.geonames(lat, lng)
.then((values) => {
if (values[0].data.status) {
log(values[0].data.status.message);
return Promise.reject(values[0].data.status.message);
}
const {adminName1, name, adminName5, adminName4, adminName3} = values[1].data.geonames[0];
const description = [name, adminName5, adminName4, adminName3].filter(Boolean).join(', ');
return Promise.resolve({
userCountry: values[0].data.countryName,
stateProvince: adminName1,
verbatimLocality: description,
});
});
}
protected renderLocations = ({ fields, meta: { touched, error, submitFailed } }) => (
<div>
{ fields.map((location, index) => (
......@@ -101,21 +154,25 @@ class TimingAndLocationForm extends React.Component<ILocationFormProps, any> {
name={ `${location}.decimalLatitude` }
component={ TextField }
label="Latitude"
onBlur={ this.save(fields, index) }
onBlur={ this.saveLatLng(fields, index)('decimalLatitude') }
/>
<Field
name={ `${location}.decimalLongitude` }
component={ TextField }
label="Longitude"
onBlur={ this.save(fields, index) }
onBlur={ this.saveLatLng(fields, index)('decimalLongitude') }
/>
<Fields
names={ [
`${location}.userCountry`,
`${location}.stateProvince`,
`${location}.verbatimLocality`,
`${location}.mapCountry`,
`${location}.decimalLatitude`,
`${location}.decimalLongitude`,
] }
checkGeonames={ this.checkGeonames }
component={ FormMap }
onMouseOut={ this.save(fields, index) }
/>
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment