-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.js
139 lines (120 loc) · 3.68 KB
/
index.js
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
'use strict'
const request = require('request');
const toGeojson = (id, callback) => {
if (!id) throw new Error('No spreadsheet id provided');
const url = `https://spreadsheets.google.com/feeds/cells/${id}/od6/public/basic?alt=json`;
request.get(url, (err, res, body) => {
if (err) return callback(err);
if (res.statusCode !== 200) {
const error = new Error(`unable to find spreadsheet with id: ${id}`);
error.code = 'ENOENT';
return callback(error);
}
body = JSON.parse(body);
let headers = {};
let entries = {};
body.feed.entry.forEach((e) => {
// get the row number
const row = parseInt(e.title['$t'].match(/\d+/g)[0]);
const column = e.title['$t'].match(/[a-zA-Z]+/g)[0];
const content = e.content['$t'];
if (row === 1) { // it's a header
headers[column] = content;
} else {
if (!entries[row]) entries[row] = {};
entries[row][headers[column]] = content;
}
});
// check headers for lng/lat values
let hasLng = false;
let hasLat = false;
for (let h in headers) {
const val = headers[h];
if (val === 'longitude' ||
val === 'LONGITUDE' ||
val === 'long' ||
val === 'LONG' ||
val === 'lng' ||
val === 'LNG' ||
val === 'lon' ||
val === 'LON' ||
val === 'x' ||
val === 'X') hasLng = true;
if (val === 'latitude' ||
val === 'LATITUDE' ||
val === 'lat' ||
val === 'LAT' ||
val === 'y' ||
val === 'Y') hasLat = true;
}
if (!hasLng || !hasLat) {
const error = new Error('longitude and/or latitude columns are missing or not properly named');
error.code = 'EINVALID';
return callback(error);
}
const gj = { type: 'FeatureCollection', features: [] };
for (let e in entries) {
const feature = {
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [0, 0]
},
properties: entries[e]
};
for (let p in entries[e]) {
switch(p) {
case 'longitude':
case 'LONGITUDE':
case 'long':
case 'LONG':
case 'lng':
case 'LNG':
case 'lon':
case 'LON':
case 'x':
case 'X':
feature.geometry.coordinates[0] = parseFloat(entries[e][p] || 0);
case 'latitude':
case 'LATITUDE':
case 'lat':
case 'LAT':
case 'y':
case 'Y':
feature.geometry.coordinates[1] = parseFloat(entries[e][p] || 0);
}
}
gj.features.push(feature);
}
return callback(null, gj);
});
};
const handler = (event, context, callback) => {
if (!event.pathParameters.id) return callback(null, ErrorHTTP(400, 'no spreadsheet ID provided'));
const id = event.pathParameters.id;
toGeojson(id, (err, gj) => {
if (err && err.code === 'ENOENT') return callback(null, ErrorHTTP(404, err.message));
if (err && err.code === 'EINVALID') return callback(null, ErrorHTTP(400, err.message));
if (err) return callback(null, ErrorHTTP(502, err.message));
const response = {
statusCode: 200,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials': true,
},
body: JSON.stringify(gj)
};
return callback(null, response);
});
};
const ErrorHTTP = (code, message) => {
return {
statusCode: code,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials': true,
},
body: JSON.stringify({ message: message })
};
};
module.exports = { toGeojson, handler };