- NodeJS >= 18
- Bash tools : curl, awk, grep, sed, xsltproc, bc
- PostgreSQL >= 13
- Python 3 (and
requests
module) - Osmium > 1.10
- osmctools
- Imposm >= 3
- pg_tileserv
- Dependencies of sendfile_osm_oauth_protector
ProjetDuMois requires a recent version of osmium as it takes advantage to newest tags-filter abilities. Not many Linux distros got the appropriate package available in their repositories and you may need to build your own binary of osmium.
See guidelines on the official README.
Following packets on debian can be useful
- build-essential
- cmake
- zlib1g-dev
- libbz2-dev
- liblz4-dev
- libboost-dev
- libboost-program-options-dev
git clone https://github.com/vdct/ProjetDuMois.git
cd ProjetDuMois
git submodule update --init
The general configuration of the tool is to be filled in config.json
. There is a suggested model in the config.example.json
file. The parameters are as follows:
OSM_USER
: OpenStreetMap username for retrieving the modification history with metadataOSM_PASS
: password associated with the OSM user accountOSM_CLIENT_ID
: client ID généré depuis le compte OpenStreetMapOSH_PBF_URL
: URL of the OSH.PBF file (history and metadata, examplehttps://osm-internal.download.geofabrik.de/europe/france/reunion-internal.osh.pbf
)DB_USE_IMPOSM_UPDATE
: enable or disabled Imposm3 integration (to use an existing database which would be maintained by other means, by defaulttrue
)WORK_DIR
: download and temporary storage folder (must have capacity to store the OSH PBF file, example/tmp/pdm
)OSM_URL
: OpenStreetMap instance to use (examplehttps://www.openstreetmap.org
)OSM_API_URL
: API OpenStreetMap instance to use (examplehttps://www.api.openstreetmap.org
)JOSM_REMOTE_URL
: address of the JOSM server to reach (examplehttp://localhost:8111
)OSMOSE_URL
: Osmose instance to use (examplehttps://osmose.openstreetmap.fr
)NOMINATIM_URL
: instance of Nominatim to use (examplehttps://nominatim.openstreetmap.org
)MAPILLARY_URL
: Mapillary instance to use (examplehttps://www.mapillary.com
)MAPILLARY_API_KEY
: Mapillary API key (could be created here)MATOMO_HOST
: URL to the Matomo host you want to report analytics to, with trailing /. Remove to disable. (examplehttps://stats.home.com/
).MATOMO_SITE
: ID of the Matomo website you want to report analytics (example6
)REPOSITORY_URL
: URL of the software repository (examplehttps://github.com/vdct/ProjetDuMois
)VECT_STYLE
: URL to Maplibre GL compatible style (examplehttps://tile-vect.openstreetmap.fr/styles/liberty/style.json
)PDM_TILES_URL
: URL to access the pg_tileserv service, which provides the layers in your databaseGEOJSON_BOUNDS
: object ofGeometry
type (polygon or multipolygon) in GeoJSON delimiting the area to search for OSM notes.MAINTENANCE_MODE
: optional flag to display a notice page on website when doing maintenance (set totrue
to enable)
As to connect to any Postgresql host, DB_URL
environement variable is expected to be set with a conninfo string.
This is necessary for standalone or Docker environments.
export DB_URL="postgres://user:password@host:5432/database"
See also 33.1.1 chapter about Postgresql conninfo strings.
Each project is defined via a subdirectory of `projects'. Each subdirectory must contain the following files :
info.json
: project metadatahowto.md
: description of tasks to be performed in Markdown format (use title levels >= 3)contribs.sql
: SQL script containing UPDATE request onpdm_changes
table, to set contribution classes to certain type of OSM changes and associate points
The properties in info.json
are as follows:
id
: mission identifier (authorized characters: A-Z, 0-9, _ and -)title
: name of the mission (short enough)start_date
: start date of the mission (format YYYYY-MM-DD)end_date
: end date of the mission (format YYYYY-MM-DD)summary
: summary of the missionlinks
: definition of the URLs for links to third party pages (OSM wiki)database.osmium_tag_filter
: Osmium filter on the tags to be applied to keep only the relevant OSM objects (for examplenwr/*:covid19
, syntax described here). It is possible to list many filters using&
character and same syntax. Only latest defined filter will be used for Osmium feature counts.database.imposm
: configuration for importing updated OSM data (types
for geometry types to be taken into account,mapping
for attributes, see the Imposm documentation for the format of these fields)database.compare
: configuration for the search of OpenStreetMap objects to compare, follows the format ofdatabase.imposm
with an additional propertyradius
(reconciliation radius in meters)datasources
: list of data sources that appear on the page (see below)statistics
: configuration of statistics display on the project pagestatistics.count
: enable object counting in OSMstatistics.feature_name
: name to display to the user for these objectsstatistics.osmose_tasks
: name of the tasks performed via Osmosestatistics.points
: configuration of the points obtained according to the type of contribution (in relation withcontribs.sql
)editors
: specific configuration to each OSM editor. ProjetDuMois is described below, for iD, it is possible to use the parameters listed here.
It is possible to define projects occuring during overlapping time periods. The project:update
script will only update currently active projects.
It is possible to not use Imposm3 and connect to an existing database already populated with necessary data. You should make sure that it is correctly hourly-updated for this application needs.
In case Imposm3 is disabled, you have also to make available materialized views named pdm_project_${project_id}
, with following structure:
osm_id BIGINT
name VARCHAR(255)
tags json
geom GEOMETRY
Optionally, if compare mode is enabled in a given project, another view pdm_project_${project_id}_compare
containing data to which features should be compared is necessary. It has the same structure as described above.
In complement of these tables, you need a pdm_boundary
table with administrative boundaries for your area (administrative levels 4, 6 and 8) with following structure:
id INT
osm_id BIGINT
name VARCHAR
admin_level INT
tags HSTORE
geom GEOMETRY(Geometry, 3857)
centre GEOMETRY(Point, 3857)
centre
column is understood as a point included in the boundary shape (you can use ST_PointOnSurface)
Create indexes on osm_id
, tags
, geom
and centre
columns might be useful depending of your database content.
PdM will autonomously derivate a pdm_boundary_subdivide
table with usage of ST_Subdivide function as to improve features intersection with admin boundaries.
Several data sources can be used, and are to be displayed in the datasources
field of the info.json
file.
Osmose is a tool for quality analysis and open data integration. The properties to be filled in are the following:
source
(mandatoryosmose
): source typeitem
: item number (four-digit code)class
(optional): class number (multi-digit code)country
(optional): Osmose country name pattern (examplefrance*
)name
: name to be displayed to the usersubtitles
(optional): key object > value to replace the subtitles of Osmose reports (search by pattern)buttons
: label to be displayed on the edit buttons (example{ "done": "It's done", "false": "Nothing here" }
)minzoom
(default 7): minimum zoom level for making this layer visiblemaxzoom
(default 18): maximum zoom level for making this layer visibletiles
(default): TMS URL list
The OpenStreetMap notes are a simple method for sending text comments on the map, and facilitate contribution by novice audiences. The properties to be filled in are the following:
source
(mandatorynotes
): source typename
: name to be displayed to the userdescription
: descriptive text explaining the resolution method for a noteterms
: list of terms to search for in the notes (singular)buttons
: label to display on the edit buttons (example{ "close": "It's done" }
)data
(default): data in Geojson format
Objects currently present in OpenStreetMap can be displayed to avoid duplicates and allow editing. The properties to be filled in are the following:
source
(mandatoryosm
): source typename
: name to be displayed to the userdescription
: descriptive text of the displayed objectminzoom
(default 7): minimum zoom level for making this layer visiblemaxzoom
(default 14): maximum zoom level for making this layer visibletiles
(default): TMS URL listlayers
(default): Layer names list to use and corresponding totiles
indices
This source can appear only once, and corresponds to the objects searched for in the database
options of info.json
.
Objects indirectly related to the project but relevant to the contribution may also appear. The properties to be filled in are the following:
source
(mandatoryosm-compare
): type of sourcename
: name to be displayed to the userdescription
: descriptive text of the displayed objectminzoom
(default 9): minimum zoom level for making this layer visiblemaxzoom
(default 14): maximum zoom level for making this layer visibletiles
(default): TMS URL listlayers
(default): Layer names list to use and corresponding totiles
indices
This source can only appear once, and corresponds to the objects searched for in the database.compare
options of info.json
.
Objects outside the project's scope, displayed as to inform contributors that something different already exists in place. The properties to be filled in are the following:
source
(mandatoryosm-extra
): type of sourcename
: name to be displayed to the userdescription
: descriptive text of the displayed objectminzoom
(default 9): minimum zoom level for making this layer visiblemaxzoom
(default 14): maximum zoom level for making this layer visibletiles
(default): TMS URL listlayers
(default): Layer names list to use and corresponding totiles
indices
This source can appear as many time as required
Raster tile imagery can be added in background to make contribution easier or give context. You have to define following properties:
source
(mandatorybackground
): type of sourceicon
(defaultother
): symbol to display in legend (betweenaerial
,thematic
,picture
,other
)name
: name shown to userstiles
(default): list of TMS URLattribution
: attribution to display on mapminzoom
(default 2): minimum zoom level for making this layer visiblemaxzoom
(default 19): maximum zoom level for making this layer visibletileSize
(default 256): width and length of a tile in pixels
These sources should be declared in reverse order of display. The lower layer should be declared first.
Another kind of datasource can be added and refers to geographical statistics, over administrative boundaries for instance
source
(mandatorystats
): statistics source typeminzoom
(default 2): minimum zoom level for making this layer visiblemaxzoom
(default 14): maximum zoom level for making this layer visibletiles
(default): list of TMS URLlayers
(default): Layer names list to use and corresponding totiles
indices
Project configuration allows to customize embedded editor with appropriate fields. Let's consider following json to be set in the editors
list:
"pdm": {
"fields": [
... fields list...
],
"title": {
"add": "Add action label",
"edit": "Edit action label"
}
}
Fields are defined with standard JSON objects added to the fields
array in the uspide json.
Every type except hidden
supports those common attributes:
name
: Field name to be displayed to the userhelp
: HREF link to a relevant help page regarding this particular fielddescription
: An extensive text displayed to the user providing details about the fieldoptional
: A boolean false/true field making the field respectively mandatory or not
Define static tags to be added to every created object by the editor, or retrieve existing values from external sources (like identifiers from Osmose such as ref:FR:SIRET
tag, use in that case *
value).
{ "type": "hidden", "tags": { "tag_1": "value_1", "tag_2": "value_2", "external_tag_3": "*" } }
Text fields comes with 3 different types: text, number or email. They're all producing a standard text field, leading to a given OSM key with appropriate validation features.
{ "type": "text", "name": "Field label", "tag": "tag_key", "optional": false },
{ "type": "number", "name": "Field label", "tag": "tag_key", "optional": false },
{ "type": "email", "name": "Field label", "tag": "tag_key", "optional": false }
A wider textarea field similar to text one.
{ "type": "textarea", "name": "Field label", "tag": "tag_key", "optional": false }
A drop down list with custom entries leading to a given OSM tag
{
"type": "select",
"name": "Field label",
"tag": "tag_key",
"optional": false,
"values": [
{ "v": "value_1", "l": "Value 1 label" },
{ "v": "value_2", "l": "Value 2 label" }
]
}
You can also set multiple tags using a single value in the list, for example:
{
"type": "select",
"name": "Type",
"tag": "_select1",
"values": [
{
"l": "National police",
"tags": { "name": "National police", "operator": "National police", "police:FR": "police" }
},
{ "l": "City police", "tags": { "name": "City police", "police:FR": "police_municipale" } }
]
}
In case of multiple tags for a single value, you can force removal of certain tags with empty strings, for example to cover objects that belongs to different categories:
{
"type": "select",
"name": "Type de commerce",
"tag": "_select1",
"values": [
{ "l": "Agence d'assurance", "tags": { "shop": "", "office": "insurance" } },
{ "l": "Agence de voyages", "tags": { "shop": "travel_agency", "office": "" } }
]
}
States input are using radio buttons to provide 2 or 3 options to the user. It leads to a given OSM key.
2states
is yes/unknown and 3states
is yes/no/unknown.
{ "type": "2states", "name": "Field label", "tag": "tag_key"},
{ "type": "3states", "name": "Field label", "tag": "tag_key"}
To make brand or operators input easier, you can use the nsi
field (related to Name Suggestion Index, a collaborative listing of all brands and operators worldwide). It has specific options:
path
: path to brand listing to use (this appears in website title, for examplebrands/shop/coffee
)locationSet
: a two-letter, lowercase country code to only list brands from this specific country (optional)
For example:
{ "type": "nsi", "name": "Brand", "path": "brands/shop/bakery", "locationSet": "fr" }
Icon select fields allow simple selecting of several similar attributes, for example available sockets at a charging station or kind of waste accepted in a recycling container. Icons must be available in the /website/images/form
folder, as PNG image. Tags associated to an icon are applied on feature if icon is selected.
{
"type": "icons",
"name": "Available sockets",
"tag": "_socket",
"values": [
{ "icon": "socket_typee", "label": "TE", "tags": { "socket:typee": "yes" } },
{ "icon": "socket_type2", "label": "T2", "tags": { "socket:type2": "yes" } },
{ "icon": "socket_type2_combo", "label": "T2 Combo", "tags": { "socket:type2_combo": "yes" } },
{ "icon": "socket_chademo", "label": "Chademo", "tags": { "socket:chademo": "yes" } }
]
}
Project statistics are made by ./db/31_projects_update_tmp.sh
script. This script fills pdm_feature_counts
SQL table with missing daily data according to last OSH file timestamp and current day.
It is possible to force full recount for a project by deleting OSH timestamp file, retreive again PBF/PBH files and launch again the script:
rm ${WORK_DIR}/osh_timestamp
./db/11_pbf_update_tmp.sh
./db/31_projects_update_tmp.sh
Certain OSM contributions can give points to users. Each project configuration set how many points are given according to the type of contribution. By default, the platform create the following contribution types:
add
: changes concerning features with version=1 (creation)edit
: changes concerning features version>1 (tag or geometry edits)
It is possible to attribute your own type for each project by creating a contribs.sql
file next to info.json
.
This script contains UPDATE SQL requests to add entries in pdm_changes
table. Each OSM change can only have a single type and have a single amount of points associated.
Configuration of points is in info.json
:
{
"statistics": {
"points": { "add": 3, "project1": 1 }
}
}
Once PDM has been properly configured, you should choose between Docker or standalone to build it. Refers to Database section in run chapter to make ProjetDuMois fully runable.
ProjetDuMois relies on some git submodules. Please mind using the following to retreive them prior to build
git submodule init
git submodule update
You can build a node.js based ProjetDuMois server including necessary features to run. It includes osmium 1.10.0 with Debian Buster. It doesn't includes a PgSQL server. You can use CampToCamp Postgres image.
docker build [--build-arg IMPOSM3_VERSION=0.11.0] -t pdm/server:latest .
Where:
- IMPOSM3_VERSION: Version of imposm3 to use in the docker image
npm install
The database relies on PostgreSQL. To create the database :
psql -c "CREATE DATABASE pdm"
As pg_tileserv is required to display osm data on the map, you'll have to install it or use the image include in docker-compose file.
You will need wget
and unzip
to use it.
# download latest build
wget https://postgisftw.s3.amazonaws.com/pg_tileserv_latest_linux.zip
# unzip / delete it
unzip pg_tileserv_latest_linux.zip -d /opt/pg_tileserv
rm pg_tileserv_latest_linux.zip
# specify database url to connect
export DATABASE_URL=postgres://postgres:password@pdm-db:5432/pdm
# launch it
cd /opt/pg_tileserv
./pg_tileserv
You can use the image in docker-compose.yml or for a lightweight image you should build yourself the alpine Dockerfile It's possible to install pg_tileserv in pdm Dockerfile before building the image. But it's not recommended.
Database is installed and inited simply with:
docker run --rm [--network=your-network] -e DB_URL=postgres://user:password@host:5432/database pdm/server:latest install
docker run --rm [--network=your-network] -v host_work_dir:container_work_dir -e DB_URL=postgres://user:password@host:5432/database pdm/server:latest init
And then run the server with:
docker run -d --rm [--network=your-network] -p 3000:3000 --name=pdm -v host_work_dir:container_work_dir -e DB_URL=postgres://user:password@host:5432/database pdm/server:latest run
Don't forger to add following lines into your crontab for periodic updates, for example daily updates:
docker run --rm [--network=your-network] -v host_work_dir:container_work_dir -e DB_URL=postgres://user:password@host:5432/database pdm/server:latest update_daily
Individual updates are also available for punctual calls:
docker run --rm [--network=your-network] -v host_work_dir:container_work_dir -e DB_URL=postgres://user:password@host:5432/database pdm/server:latest update_pbf
docker run --rm [--network=your-network] -v host_work_dir:container_work_dir -e DB_URL=postgres://user:password@host:5432/database pdm/server:latest update_features
docker run --rm [--network=your-network] -v host_work_dir:container_work_dir -e DB_URL=postgres://user:password@host:5432/database pdm/server:latest update_projects
Database relies on PostgreSQL. To install the schema before first run:
psql -d pdm -f db/00_init.sql
The following script is to run to retreive and update PBF/PBH files:
npm run pbf:update
./db/11_pbf_update_tmp.sh
The following script is to run after first initialization of database to create list of OSM features:
npm run features:update
./db/21_features_update_tmp.sh init
The following script has to be launched daily to retrieve the contribution statistics (notes, objects added, badges obtained):
npm run projects:update
./db/31_projects_update_tmp.sh
The code for the web interface can be found in the website
folder. This is an ExpressJS server, combined with Pug templates.
The Pug templates are in the templates
sub-folder. It is organized according to the following logic:
- In
templates
, the general modellayout.pug
and its CSS file - In
common
, generic elements to all pages (<head>
, header, footer) - In
components
, the main components that populate the pages (map, statistics block...) - In
pages
, each page of the site (home, map, project page...)
The site can be viewed at localhost:3000.
Docker image includes websites and background updating tasks. You can run it with:
docker run -d --rm [--network=your-network] -p 3000:3000 --name=pdm -v host_work_dir:container_work_dir -e DB_URL=postgres://user:password@host:5432/database pdm/server:latest run
A compose file is provided to ease the running processing. It won't prevent you from creating database, adding users and make the appropriate configuration nor building dockers as mentionned upside. Docker compose only allows to run easilly a functionnal instance if and only it has already been properly configured before.
Depending on your Postgresql configuration, you'll surely have to customize the DB_URL
env variable in the compose file to let the pdm server access the database safely.
Don't try to run the instance with docker-compose first, try to run each component separately and check if everything work as expected. Once everything runs normally, you can use the following for further runs:
To start:
docker-compose up
To stop:
docker-compose down
Standalone running requires a node server complient with compatility at the top of this document and planned tasks to update projects regularly.
To launch the web site :
export DB_URL="postgres://user:password@host:5432/database" # Database URL
export PORT=3000 # Nodejs port (defaults to 3000)
npm run start
The site can be viewed at localhost:3000.