- NodeJS >= 18
- Outils Bash : curl, awk, grep, sed, xsltproc, bc
- PostgreSQL >= 13
- Python 3 (et le module
requests
) - Osmium > 1.10
- osmctools
- Imposm >= 3
- pg_tileserv
- Dépendances de sendfile_osm_oauth_protector
ProjetDuMois a besoin d'une version récente de osmium puisqu'il tire parti des nouvelles fonctions tags-filter. Peu de distributions linux ont les dernières versions disponibles et vous aurez surement besoin de compiler osmium vous-même.
Voir les consignes sur le README officiel.
Les paquets suivants pourront être utiles pour cela
- 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
La configuration générale de l'outil est à renseigner dans config.json
. Un modèle est proposé dans le fichier config.example.json
. Les paramètres sont les suivants :
OSM_USER
: nom d'utilisateur OpenStreetMap pour la récupération de l'historique des modifications avec métadonnéesOSM_PASS
: mot de passe associé au compte utilisateur OSMOSM_CLIENT_ID
: client ID généré depuis le compte OpenStreetMapOSH_PBF_URL
: URL du fichier OSH.PBF (historique et métadonnées, exemplehttps://osm-internal.download.geofabrik.de/europe/france/reunion-internal.osh.pbf
)DB_USE_IMPOSM_UPDATE
: Active ou désactive l'intégration d'imposm3 (permet d'utiliser une base existante et tenue à jour par d'autres moyens, par défauttrue
)WORK_DIR
: dossier de téléchargement et stockage temporaire (doit pouvoir contenir le fichier OSH PBF, exemple/tmp/pdm
)OSM_URL
: instance OpenStreetMap à utiliser (exemplehttps://www.openstreetmap.org
)OSM_API_URL
: instance API OpenStreetMap à utiliser (exemplehttps://api.openstreetmap.org
)JOSM_REMOTE_URL
: adresse du serveur JOSM à contacter (exemplehttp://localhost:8111
)OSMOSE_URL
: instance Osmose à utiliser (exemplehttps://osmose.openstreetmap.fr
)NOMINATIM_URL
: instance de Nominatim à utiliser (exemplehttps://nominatim.openstreetmap.org
)MAPILLARY_URL
: instance Mapillary à utiliser (exemplehttps://www.mapillary.com
)MAPILLARY_API_KEY
: clé d'API Mapillary (peut être créée ici)MATOMO_HOST
: URL vers l'hôte Matomo auquel nous souhaitons envoyer les statistiques terminant par un /. Supprimez pour désactiver. (exemplehttps://stats.maison.fr/
)MATOMO_SITE
: Identifiant du site web Matomo auquel se rapportent les statistiques (exemple6
)REPOSITORY_URL
: URL du dépôt du logiciel (exemplehttps://github.com/vdct/ProjetDuMois
)VECT_STYLE
: URL d'un style compatible avec Maplibre GL (exemplehttps://tile-vect.openstreetmap.fr/styles/liberty/style.json
)PDM_TILES_URL
: URL d'accès au service pg_tileserv, qui met à disposition les couches dans votre base de donnéesGEOJSON_BOUNDS
: objet de typeGeometry
(polygone ou multipolygone) en GeoJSON délimitant la zone où rechercher des notes OSMMAINTENANCE_MODE
: option pour afficher une page spéciale sur le site indiquant qu'il est en cours de maintenance (valeurtrue
pour activer)
Pour se connecter à Postgresql, une variable d'environement DB_URL
est attendue avec une chaine conninfo pour disposer des informations nécessaires.
Ceci est valable quelle que soit la solution retenue, docker ou locale.
export DB_URL="postgres://user:password@host:5432/database"
Reportez-vous au chapitre 33.1.1 du guide postgresql.
Chaque projet est défini via un sous-répertoire de projects
. Chaque sous-répertoire doit contenir les fichiers suivants :
info.json
: métadonnées du projethowto.md
: descriptif des tâches à réaliser au format Markdown (utiliser les niveaux de titres >= 3)contribs.sql
: Script SQL contenant des requêtes UPDATE sur la table pdm_changes, attribuant des classes de contribution à certains changements donnant droit à des points
Les propriétés dans info.json
sont les suivantes :
id
: identifiant de la mission (caractères autorisés : A-Z, 0-9, _ et -)title
: nom de la mission (assez court)start_date
: date de début de la mission (format AAAA-MM-JJ)end_date
: date de fin de la mission (format AAAA-MM-JJ)summary
: résumé de la missionlinks
: définition des URL pour les liens vers des pages tierces (wiki OSM)database.osmium_tag_filter
: filtre Osmium sur les tags à appliquer pour ne conserver que les objets OSM pertinents (par exemplenwr/*:covid19
, syntaxe décrite ici). Il est possible d'enchaîner plusieurs filtres par & et en répétant l'indication de primitive à chaque niveau. Seul le dernier filtre est utilisé pour catégoriser les décomptes par osmium.database.imposm
: configuration pour l'import des données actualisées d'OSM (types
pour les types de géométrie à prendre en compte,mapping
pour les attributs, voir la documentation Imposm pour le format de ces champs)database.compare
: configuration pour la recherche d'objets OpenStreetMap à comparer, suit le format dedatabase.imposm
avec une propriété supplémentaireradius
(rayon de rapprochement en mètres)datasources
: liste des sources de données qui apparaissent sur la page (voir ci-dessous)statistics
: configuration de l'affichage des statistiques sur la page du projetstatistics.count
: activer le comptage des objets dans OSMstatistics.feature_name
: nom à afficher à l'utilisateur pour ces objetsstatistics.osmose_tasks
: nom des tâches accomplies via Osmosestatistics.points
: configuration des points obtenus selon le type de contribution (en lien aveccontribs.sql
)editors
: configuration spécifique à chaque éditeur OSM. Pour ProjetDuMois, les informations sont disponibles ci-dessous. Pour iD, il est possible d'utiliser les paramètres listés ici.
Il est possible de définir des projets se déroulant aux mêmes dates. Le script project:update
ne rafraichira que les projets en cours.
Il est possible de ne pas utiliser imposm3 et de se connecter à une base de données pourvue des données nécessaires. Il faudra s'assurer qu'elle est tenue à jour toutes les heures minimum pour les besoins de PdM.
Dans le cas où imposm3 serait désactivé, il faudra produire des vues matérialisées pour chaque projet configurés appelées pdm_project_${project_id}
, avec la structure suivante :
osm_id BIGINT,
name VARCHAR(255)
tags json
geom GEOMETRY
Optionellement, si le mode compare est activé dans un projet donné, une vue supplémentaire appelée pdm_project_${project_id}_compare
conforme à ce qui doit être comparé est nécessaire. Elle a la même structure que ci-dessus.
Au-delà de ces tables, il est nécessaire d'avoir une table pdm_boundary
contenant le découpage administratif de la zone (niveaux administratifs 4, 6 et 8) et ayant cette structure :
id INT
osm_id BIGINT
name VARCHAR
admin_level INT
tags HSTORE
geom GEOMETRY(Geometry, 3857)
centre GEOMETRY(Point, 3857)
La colonne centre
est comprise comme étant un point compris dans le périmètre de la limite (vous pouvez utiliser ST_PointOnSurface).
Créer des indexes sur les colonnes osm_id
, tags
, geom
et centre
peut être utile suivant la population d'objets touchée par un projet donné.
PdM va automatiquement créer une table pdm_boundary_subdivide
en utilisant ST_Subdivide pour faciliter le calcul d'intersection entre les objets du projet et le zonage administratif.
Plusieurs sources de tuiles sont mobilisables, et sont à faire apparaître dans le champ datasources
du fichier info.json
.
Osmose est un outil d'analyse qualité et d'aide à l'intégration de données ouvertes. Les propriétés à renseigner sont les suivantes :
source
(obligatoireosmose
): type de sourceitem
: numéro d'item (code à quatre chiffres)class
(optionnel) : numéro de classe (code à plusieurs chiffres)country
(optionnel) : motif de nom de pays Osmose (exemplefrance*
)name
: nom à faire apparaître à l'utilisateursubtitles
(optionnel) : objet clé > valeur pour remplacer les sous-titres des signalements Osmose (recherche par motif)buttons
: libellé à faire apparaître sur les boutons d'édition (exemple{ "done": "C'est fait", "false": "Rien ici" }
)minzoom
(défaut 7): Niveau de zoom minimum au delà duquel la couche est visiblemaxzoom
(défaut 18): Niveau de zoom maximal au delà duquel la couche n'est plus visibletiles
(défaut) : Liste d'URL TMS
Les notes OpenStreetMap sont une méthode simple pour envoyer des commentaires textuels par dessus la carte, et faciliter la contribution par des publics novices. Les propriétés à renseigner sont les suivantes :
source
(obligatoirenotes
): type de sourcename
: nom à faire apparaître à l'utilisateurdescription
: texte descriptif indiquant la méthode de résolution d'une noteterms
: liste des termes à rechercher dans les notes (au singulier)buttons
: libellé à faire apparaître sur les boutons d'édition (exemple{ "close": "C'est fait" }
)data
(défaut) : GeoJson de données de la couche
Les objets actuellement présents dans OpenStreetMap peuvent être affichés pour éviter les doublons et permettre leur édition. Les propriétés à renseigner sont les suivantes :
source
(obligatoireosm
): type de sourcename
: nom à faire apparaître à l'utilisateurdescription
: texte descriptif de l'objet affichéminzoom
(défaut 7) : Niveau de zoom minimum au delà duquel la couche est visiblemaxzoom
(défaut 14) : Niveau de zoom maximal au delà duquel la couche n'est plus visibletiles
(défaut) : Liste d'URL TMSlayers
(défaut) : Liste des layers correspondant àtiles
à utiliser
Cette source ne peut apparaître qu'une seule fois, et correspond aux objets recherchés dans les options database
de info.json
.
Des objets indirectement liés au projet mais pertinents pour la contribution peuvent également apparaître. Les propriétés à renseigner sont les suivantes :
source
(obligatoireosm-compare
) : type de sourcename
: nom à faire apparaître à l'utilisateurdescription
: texte descriptif de l'objet affichéminzoom
(défaut 9) : Niveau de zoom minimum au delà duquel la couche est visiblemaxzoom
(défaut 14) : Niveau de zoom maximal au delà duquel la couche n'est plus visibletiles
(défaut) : Liste d'URL TMSlayers
(défaut) : Liste des layers correspondant àtiles
à utiliser
Cette source ne peut apparaître qu'une seule fois, et correspond aux objets recherchés dans les options database.compare
de info.json
.
Ces couches affichent des objets non pris en compte dans le périmètre du projet. Ils sont affichés pour informer les contributeurs que quelque chose de différent existe déjà à cet endroit. Les propriétés à fournir sont les suivantes :
source
(obligatoireosm-extra
) : type de sourcename
: nom à faire apparaître à l'utilisateurdescription
: texte descriptif de l'objet affichéminzoom
(défaut 9) : Niveau de zoom minimum au delà duquel la couche est visiblemaxzoom
(défaut 14) : Niveau de zoom maximal au delà duquel la couche n'est plus visibletiles
(défaut) : Liste d'URL TMSlayers
(défaut) : Liste des layers correspondant àtiles
à utiliser
Ces sources peuvent apparaitre autant de fois que nécessaire
Des couches raster peuvent être ajoutées en fond de carte pour faciliter la contribution ou donner plus de contexte. Les propriétés suivantes doivent être définies :
source
(obligatoirebackground
): type de sourceicon
(défautother
): le symbole à afficher dans la légende (au choixaerial
,thematic
,picture
,other
)name
: nom à faire apparaître à l'utilisateurtiles
: Tableau d'URL TMSattribution
: Attribution à faire apparaitre sur la carteminzoom
(défaut 2) : Niveau de zoom minimum au delà duquel la couche est visiblemaxzoom
(défaut 19) : Niveau de zoom maximal au delà duquel la couche n'est plus visibletileSize
(défaut 256) : Taille d'une arrête de tuile en pixels
Ces sources doivent être déclarées dans l'ordre inverse d'apparition. La couche inférieure doit être donnée en premier.
Pour activer l'affichage de statistiques selon le découpage administratif, vous pouvez ajouter la couche ayant la définition suivante :
source
(obligatoirestats
): type de sourceminzoom
(défaut 2) : Niveau de zoom minimum au delà duquel la couche est visiblemaxzoom
(défaut 14) : Niveau de zoom maximal au delà duquel la couche n'est plus visibletiles
(défaut) : Tableau d'URL TMSlayers
(défaut) : Liste des layers correspondant àtiles
à utiliser
La configuration des projets permets de personnaliser les champs disponibles dans l'éditeur intégré. La configuration s'exprime en JSON comme l'exemple suivant (ajouté dans l'objet editors
du fichier config.json
) :
"pdm": {
"fields": [
... liste de champs...
],
"title": {
"add": "Libellé de l'action ajouter",
"edit": "Libellé de l'action éditer"
}
}
Les champs sont définis comme des objets JSON standards, ajouté au tableau fields
ci-dessus.
Chaque type, à l'exception de hidden
supporte les champ communs suivants :
name
: Libellé du champ tel qu'affiché à l'utilisateurhelp
: Lien hypertexte pointant vers toute ressource appropriée d'aide pour ce champdescription
: Un text plus long que le libellé qui apporte les détails nécessaire à propos de champoptional
: Un champ booléen false/true rendant respectivement le champ obligatoire ou non.
Il permet de définir des tags statiques ajoutés à tout objet créé avec l'éditeur. Il est possible dans la liste de tags d'ajouter une valeur *
pour accepter toute valeur arrivant d'une source externe (par exemple les identifiants ref:FR:SIRET
renseignés dans Osmose).
{ "type": "hidden", "tags": { "tag_1": "value_1", "tag_2": "value_2", "tag_3_externe": "*" } }
Les champs textuels simples sont couverts par 3 types différents : text
, number
ou email
.
Ils produisent tous trois un champ texte standard muni des fonctions de validation appropriées.
{ "type": "text", "name": "Libellé", "tag": "tag_key", "optional": false },
{ "type": "number", "name": "Libellé", "tag": "tag_key", "optional": false },
{ "type": "email", "name": "Libellé", "tag": "tag_key", "optional": false }
Une zone de texte plus ample pour saisir des valeurs plus conséquentes.
{ "type": "textarea", "name": "Libellé", "tag": "tag_key", "optional": false }
Une liste de valeurs avec des entrées personnalisées pointant sur une clé OSM définie.
{
"type": "select",
"name": "Libellé",
"tag": "tag_key",
"optional": false,
"values": [
{ "v": "value_1", "l": "Value 1 label" },
{ "v": "value_2", "l": "Value 2 label" }
]
}
On peut également faire en sorte que une valeur dans la liste renseigne plusieurs attributs OSM, par exemple :
{
"type": "select",
"name": "Type",
"tag": "_select1",
"values": [
{
"l": "Gendarmerie",
"tags": { "name": "Gendarmerie nationale", "operator": "Gendarmerie nationale", "police:FR": "gendarmerie" }
},
{
"l": "Police nationale",
"tags": { "name": "Police nationale", "operator": "Police nationale", "police:FR": "police" }
},
{ "l": "Police municipale", "tags": { "name": "Police municipale", "police:FR": "police_municipale" } }
]
}
Dans le cas où plusieurs attributs sont renseignés, il est possible de forcer la suppression de certains tags avec un texte vide, par exemple pour gérer le cas où les objets sont dans plusieurs catégories :
{
"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": "" } }
]
}
Les champs booléens à 2 ou 3 états utilisent les boutons radio pour proposer des options à l'utilisateur vers une clé OSM définie.
2states
pour oui/inconnu et 3states
pour oui/non/inconnu.
{ "type": "2states", "name": "Libellé", "tag": "tag_key"},
{ "type": "3states", "name": "Libellé", "tag": "tag_key"}
Pour faciliter la sélection d'une enseigne ou d'un réseau de commerces/équipements, le champ de type nsi
(pour Name Suggestion Index, un recensement collaboratif des marques et enseignes) peut être utilisé. Celui-ci dispose d'options spécifiques :
path
: chemin vers la liste à utiliser (elle apparaît en titre du site web, par exemplebrands/shop/coffee
)locationSet
: un code pays sur deux lettres, en minuscules, pour ne lister que les enseignes du pays concerné (optionel)
Exemple d'utilisation :
{ "type": "nsi", "name": "Marque", "path": "brands/shop/bakery", "locationSet": "fr" }
Les statistiques projet sont établies par le script ./db/31_projects_update_tmp.sh
. Le script complète la table SQL pdm_feature_counts avec les jours manquant entre le timestamp OSH et le jour courant.
Il est possible de forcer le recomptage de l'intégralité d'un projet en supprimant le fichier de timestamp OSH, récupération des fichiers PBF/PBH et en relançant le script
rm ${WORK_DIR}/osh_timestamp
./db/11_pbf_update_tmp.sh
./db/31_projects_update_tmp.sh
Certaines contribution peuvent donner lieu à l'attribution de points aux contributeurs responsables. La configuration des projets établit le lien entre des classes de contribution et les points associés. Il faut donc qualifier certains changement avec les bonnes classes. La plateforme attribue les classes communes suivantes :
add
: Les changements concernant des objets version=1edit
: Les changements concernant des objets version>1
Il est possible d'attribuer des classes propres à chaque projet en créant un fichier contribs.sql
à côté de info.json
.
Ce script contient des requêtes UPDATE modifiant les entrées nécessaires de la table pdm_changes
. Chaque changement ne peut avoir qu'une classe et ne correspondre qu'à une valeur de point unique.
Les montant de points attribués sont configurés dans info.json
:
{
"statistics": {
"points": { "add": 3, "project1": 1 }
}
}
Choisissez ensuite entre une instance Docker ou locale pour poursuivre. Confère à la section Déploiement ci-dessous pour obtenir un ProjetDuMois exploitable.
ProjetDuMois dépend de quelques sous-modules git. Pensez à executer les commandes suivantes avant le build :
git submodule init
git submodule update
Il est possible de construire un serveur node.js unique pourvu des fonctionnalités nécessaires à toute l'exploitation. Il inclus osmium 1.10.0 avec Debian Buster. L'image Docker n'inclue cependant pas de serveur postgresql et vous pourrez utiliser l'image de CampToCamp.
docker build [--build-arg IMPOSM3_VERSION=0.11.0] -t pdm/server:latest .
Avec :
- IMPOSM3_VERSION : Version d'imposm3 à intégrer à l'image Docker
npm install
La base de données utilise PostgreSQL. Pour créer la base, lancez la commande :
psql -c "CREATE DATABASE pdm"
pg_tileserv étant requit pour afficher la données osm sur la carte, vous pouvez soit l'installer soit utiliser une image Docker.
Pour l'installation wget
et unzip
sont nécessaires.
# télécharge la dernière version
wget https://postgisftw.s3.amazonaws.com/pg_tileserv_latest_linux.zip
# décompression / suprresion
unzip pg_tileserv_latest_linux.zip -d /opt/pg_tileserv
rm pg_tileserv_latest_linux.zip
# url de la base de données à laquelle se connecter
export DATABASE_URL=postgres://postgres:password@pdm-db:5432/pdm
# lanchement de pg_tileserver
cd /opt/pg_tileserv
./pg_tileserv
Vous pouvez aussi utiliser l'image incluse dans le docker-compose.yml ou, pour une image plus lègere utiliser le Dockerfile alpine suivant afin de build vous même l'image. Vous pouvez aussi très bien installer pg_tileserv dans pdm via le Dockerfile pour builder l'image Docker pdm en l'incluant. Mais ceci n'est pas recommandé.
Le service s'installe avec les deux commandes suivantes :
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
Ensuite, lancez le serveur avec la commande :
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
N'oubliez pas d'ajouter les lignes suivantes dans vos crontab pour mettre à jour les projets périodiquement, idéalement quotidiennement.
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
Des commandes dédiées sont néamoins disponibles pour relancer une update particuliere:
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_projects
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
La base de données s'appuie sur PostgreSQL. Pour installer la base :
psql -d pdm -f db/00_init.sql
Le script suivant est à lancer pour récupérer et mettre à jour les fichiers PBF/PBH :
npm run pbf:update
./db/11_pbf_update_tmp.sh
Le script suivant est à lancer à la première initialisation de la base de données pour créer la liste des objets venant d'OpenStreetMap :
npm run features:update
./db/21_features_update_tmp.sh init
Le script suivant est à lancer quotidiennement pour récupérer les statistiques de contribution (notes, objets ajoutés, badges obtenus) :
npm run projects:update
./db/31_projects_update_tmp.sh
Le code de l'interface web se trouve dans le dossier website
. Il s'agit d'un serveur ExpressJS, combiné à des modèles Pug.
Les modèles Pug sont dans le sous-dossier templates
. Celui-ci est organisé selon la logique suivante :
- Dans
templates
, le modèle générallayout.pug
et son fichier CSS - Dans
common
, les éléments génériques à toutes les pages (<head>
, en-tête, pied de page) - Dans
components
, les composants principaux qui peuplent les pages (carte, bloc statistiques...) - Dans
pages
, chacune des pages du site (accueil, carte, page projet...)
Le site est visible à l'adresse localhost:3000.
L'image Docker inclue le nécessaire pour servir le site web et executer les tâches de mise à jour automatiques. Vous pouvez la lancer avec:
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
Un fichier docker-compose est fourni ici pour faciliter l'execution de la plateforme. Cela ne vous dispensera pas de créer la base de données, y ajouter les bons rôles et configurer pdm de manière appropriée selon la méthode expliquée ci-dessus. Docker-compose permet seulement de faciliter l'execution d'une instance déjà fonctionnelle si et seulement si elle a été configurée correctement préalablement.
En fonction de la configuration de votre serveur Postgresql, vous devrez certainement adapter la valeur de la variable DB_URL
dans le fichier compose pour permettre au serveur pdm d'accéder à la base de données correctement.
N'essayez pas de débuter la configuration d'une instance avec docker-compose, essayez plutôt d'obtenir une configuration fonctionnelle de chaque composant et de vous assurer que tout fonctionne séparément d'abord. Une fois que vous avez constaté que tout fonctionnait, lancez-vous avec docker-compose pour faciliter les executions futures.
Pour démarrer :
docker-compose up
Pour arrêter :
docker-compose down
L'execution locale nécessite un serveur node conforme à la compatilité ci-dessus et des tâches planifiées pour tenir la base de données à jour.
Pour lancer le site web :
export DB_URL="postgres://user:password@host:5432/database" # Database URL
export PORT=3000 # Nodejs port (defaults to 3000)
npm run start
Le site est accessible à cette url localhost:3000.