Commit eb43cd31 authored by Anne Blankert's avatar Anne Blankert

initial commit

parents
node_modules
config/dbconfig.json
public/files
\ No newline at end of file
{
"host": "host.example.com",
"user": "dbuser",
"password": "dbpassword",
"database": "dbname",
"ssl": true,
"port": 5432,
"max": 20,
"idleTimeoutMillis": 30000,
"connectionTimeoutMillis": 2000
}
\ No newline at end of file
{
"port": 8090
}
\ No newline at end of file
function login(app) {
/**
* @swagger
*
* /login:
* post:
* description: Login to the application
* produces:
* - application/json
* parameters:
* - name: username
* description: Username to use for login.
* in: formData
* required: true
* type: string
* - name: password
* description: User's password.
* in: formData
* required: true
* type: string
* responses:
* 200:
* description: login
*/
app.post('/login', (req, res) => {
// Your implementation comes here ...
});
app.get('/login', (req, res) => {
res.json({result:"ok"})
});
}
module.exports = login
\ No newline at end of file
const sm = require('@mapbox/sphericalmercator');
const fs = require('fs');
const {Pool} = require('pg');
const fsPromises = fs.promises;
const path = require('path');
const merc = new sm({
size: 256
})
const dbconfig = require('./config/dbconfig.json');
const pool = new Pool(dbconfig);
pool.connect();
// route query
const sql = (params, query) => {
let bounds = merc.bbox(params.x, params.y, params.z, false, '900913')
return `
SELECT
ST_AsMVT(q, '${params.table}', 4096, 'geom')
FROM (
SELECT
${query.columns ? `${query.columns},` : ''}
ST_AsMVTGeom(
ST_Transform(${query.geom_column}, 3857),
ST_MakeBox2D(ST_Point(${bounds[0]}, ${bounds[1]}), ST_Point(${
bounds[2]
}, ${bounds[3]}))
) geom
FROM (
SELECT
${query.columns ? `${query.columns},` : ''}
${query.geom_column},
srid
FROM
${params.table},
(SELECT ST_SRID(${query.geom_column}) AS srid FROM ${
params.table
} LIMIT 1) a
WHERE
ST_transform(
ST_MakeEnvelope(${bounds.join()}, 3857),
srid
) &&
${query.geom_column}
-- Optional Filter
${query.filter ? `AND ${query.filter}` : ''}
) r
) q
`
}
// TODO add flat-cache
module.exports = function(app) {
/**
* @swagger
*
* /data/{datasource}/mvt/{z}/{x}/{y}?columns={columns}:
* get:
* description: get mapbox vector tile (mvt)
* produces:
* - application/x-protobuf
* parameters:
* - name: datasource
* description: name of postgis datasource
* in: path
* required: true
* type: string
* - name: z
* description: zoom level of tile
* in: path
* required: true
* type: number
* - name: x
* description: x value (column number) of tile
* in: path
* required: true
* type: number
* - name: y
* description: y value (row number) of tile
* in: path
* required: true
* type: number
* - name: geom_column
* description: name of geometry column (default 'geom')
* in: query
* default: geom
* required: false
* - name: columns
* description: optional comma seperated list of attribute columns to be added to the mvt geometries
* in: query
* required: false
* type: string
* default: null
* allowEmptyValue: true
* responses:
* 200:
* description: vector tile
* 204:
* description: no data (empty tile)
* 422:
* description: invalid datasource or columnname
*/
app.get('/data/:datasource/mvt/:z/:x/:y', async (req, res)=>{
if (!req.query.geom_column) {
req.query.geom_column = 'geom';
}
req.params.table = req.params.datasource;
const sqlString = sql(req.params, req.query);
console.log(sqlString);
try {
const result = await pool.query(sqlString);
const mvt = result.rows[0].st_asmvt
if (mvt.length === 0) {
res.status(204)
}
res.header('Content-Type', 'application/x-protobuf').send(mvt);
} catch(err) {
console.log(err);
switch (err.code) {
case '42P01':
err.name = `table ${req.params.table} does not exist`;
break;
case '42703':
err.name = `column does not exist`;
break;
}
res.status(422).json({error:err})
}
})
}
\ No newline at end of file
This diff is collapsed.
{
"name": "pgserver",
"version": "0.0.0",
"description": "PGserver receives, converts and serves geo-data between postgis and http-clients.",
"main": "pgserver.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Anne Blankert, Geodan",
"license": "ISC",
"dependencies": {
"@mapbox/sphericalmercator": "^1.1.0",
"cors": "^2.8.5",
"express": "^4.17.1",
"express-fileupload": "^1.1.5",
"morgan": "^1.9.1",
"pg": "^7.12.1",
"swagger-jsdoc": "^3.4.0",
"swagger-ui-express": "^4.0.7"
}
}
const pgserverconfig = require('./config/pgserver.json')
const express = require('express');
const logger = require('morgan');
const cors = require('cors');
const app = express();
const swagger = require('./swagger.js')(app);
app.use(logger('dev'));
app.use(cors());
app.use('/', express.static(__dirname + '/public'));
const login = require('./login.js')(app);
const upload = require('./upload.js')(app);
const mvt = require('./mvt.js')(app);
app.listen(pgserverconfig.port);
console.log(`pgserver listening on port ${pgserverconfig.port}`);
module.exports = app;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="pgserver.css">
<title>Welcome</title>
</head>
<style>
</style>
<body>
<h1>PGServer</h1>
Welcome to pgserver<br>
<a href="/api-docs">Swagger api docs</a><br>
<a href="/upload.html">Upload files</a>
</body>
</html>
\ No newline at end of file
body,html {
font-family: Verdana, Geneva, Tahoma, sans-serif
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Upload</title>
<!-- Filepond stylesheet -->
<link href="pgserver.css" rel="stylesheet">
</head>
<body>
<form action="upload" method="post" encType="multipart/form-data">
<input name="uploadfile" type="file"><br>
<input type="submit" value="upload">
</form>
</body>
</html>
\ No newline at end of file
const swaggerUi = require('swagger-ui-express');
const swaggerJSDoc = require('swagger-jsdoc');
const swaggerDefinition = {
info: {
// API informations (required)
title: 'PGServer', // Title (required)
version: '1.0.0', // Version (required)
description: 'PostGIS http api', // Description (optional)
},
basePath: '/', // Base path (optional)
}
const swaggerJSDocOptions = {
swaggerDefinition,
apis: ['./login.js', './mvt.js']
}
const swaggerSpec = swaggerJSDoc(swaggerJSDocOptions);
module.exports = function(app) {
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec));
}
const express = require('express');
const fs = require('fs');
const fileUpload = require('express-fileupload');
module.exports = function(app) {
app.use(fileUpload({
useTempFiles: true,
tempFileDir : `${__dirname}/public/files/`
}));
app.post('/upload', (req, res) => {
let uploadFile = req.files.uploadfile;
const fileName = uploadFile.name;
res.json({
file: `${fileName}`
})
uploadFile.mv(
`${__dirname}/public/files/${fileName}`,
function (err) {
if (err) {
return res.status(500).send(err);
}
}
)
});
app.get('/upload', (req, res) =>{
url = req.query.fetch;
console.log(url);
res.json({
file: 'index.html'
});
})
app.delete('/upload', express.json({type: '*/*'}), (req, res) => {
fs.unlinkSync(`${__dirname}/public/files/${req.body.file}`);
res.json({
file: 'done'
});
});
}
Markdown is supported
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