diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a785c9be..f5c9514d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -55,9 +55,7 @@ jobs: - name: "Retag / push the docker images (not stable)" if: github.repository == 'mviewer/mviewerstudio' run: | - docker tag mviewer/mviewerstudio:python-latest mviewer/mviewerstudio:python-${{ steps.version.outputs.VERSION }} - docker tag mviewer/mviewerstudio:php-latest mviewer/mviewerstudio:php-${{ steps.version.outputs.VERSION }} - docker push mviewer/mviewerstudio:python-${{ steps.version.outputs.VERSION }} - docker push mviewer/mviewerstudio:php-${{ steps.version.outputs.VERSION }} + docker tag mviewer/mviewerstudio:latest mviewer/mviewerstudio:${{ steps.version.outputs.VERSION }} + docker push mviewer/mviewerstudio:${{ steps.version.outputs.VERSION }} diff --git a/.gitignore b/.gitignore index 198c532b..1a375000 100644 --- a/.gitignore +++ b/.gitignore @@ -9,7 +9,7 @@ __pycache__/ *.egg-info/ *.egg - +srv/python/build # IDE stuff @@ -31,3 +31,7 @@ pydocs* # store store/ public/ + +# npm +node* +package-* diff --git a/README.md b/README.md index 8059b4a3..388ce34e 100644 --- a/README.md +++ b/README.md @@ -8,5 +8,5 @@ Application écrite en Javascript pour le front. Référez-vous à la documentation pour plus d'information : * [Documentation utilisateur](https://mviewerstudio.readthedocs.io/fr/stable/doc_user/accueil.html) - * [Documentation d'installation](https://mviewerstudio.readthedocs.io/fr/stable/doc_tech/install.html) - * [Documentation administrateur](https://mviewerstudio.readthedocs.io/fr/stable/doc_tech/config.html) + * [Documentation d'installation](https://mviewerstudio.readthedocs.io/fr/stable/doc_tech/install_python.html) + * [Documentation administrateur](https://mviewerstudio.readthedocs.io/fr/stable/doc_tech/config_front.html) diff --git a/config-php-sample.json b/config-php-sample.json index d5107613..cd571d42 100644 --- a/config-php-sample.json +++ b/config-php-sample.json @@ -2,7 +2,7 @@ "app_conf": { "studio_title": "GéoBretagne mviewer studio", "mviewer_version": "3.9", - "mviewerstudio_version": "4", + "mviewerstudio_version": "4.0.1", "is_php": "true", "php": { "upload_service": "srv/php/store.php", diff --git a/config-python-sample.json b/config-python-sample.json index ce45dd86..2f5a15e4 100644 --- a/config-python-sample.json +++ b/config-python-sample.json @@ -2,11 +2,11 @@ "app_conf": { "studio_title": "Mviewer Studio", "mviewer_version": "3.9", - "mviewerstudio_version": "4", + "mviewerstudio_version": "4.0.1", "api": "api/app", "store_style_service": "api/style", - "mviewer_instance": "http://127.0.0.1:5051/", - "publish_url": "http://127.0.0.1:5051/?config=apps/public/{{config}}.xml", + "mviewer_instance": "/mviewer/", + "publish_url": "/mviewer/?config=apps/public/{{config}}.xml", "conf_path_from_mviewer": "apps/store/", "mviewer_short_url": { "used": true, diff --git a/docker-compose.yml b/docker-compose.yml index 2c61eae3..97b5d5cb 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,61 +1,53 @@ version: '3' volumes: apps: - mviewerstudio_config: services: - - # Select between the next 2 services the backend you want to use by - # commenting / uncommenting the 'volume' section & modify the links alias - # on the mviewer-studio service. - # - # You cannot use both backends at the same time, and you have to be wary if - # you switch from one to another, as each comes with a custom config.json - # file. - # - # If you want to switch, make sure either you modify the config.json, or - # reinitialize the docker volume. - - # PHP version - mviewerstudio-php: - build: - context: . - dockerfile: docker/Dockerfile-php-backend - image: mviewer/mviewerstudio:php-latest -# volumes: -# - "apps:/var/www/html/apps" + # Reverse-proxy using nginx. Groups mviewer and mviewerstudio under respective paths + # Config can be found under ./docker/nginx/default.conf.template + www: + image: nginx + ports: + - 80:80 + environment: + - NGINX_HOST=localhost + - MVIEWERSTUDIO_URL_PATH_PREFIX=mviewerstudio + volumes: + - ./docker/nginx:/etc/nginx/templates + depends_on: + - mviewerstudio + - mviewer # Python version - mviewerstudio-python: + # Served under /${MVIEWERSTUDIO_URL_PATH_PREFIX}/ see docker/nginx/default.conf.template + mviewerstudio: build: context: . dockerfile: docker/Dockerfile-python-backend - image: mviewer/mviewerstudio:python-latest + image: mviewer/mviewerstudio:latest +# ports: +# - "8000:8000" + environment: + - CONF_PATH_FROM_MVIEWER=apps/store + - CONF_PUBLISH_PATH_FROM_MVIEWER=apps/public + - DEFAULT_ORG=my_org + - EXPORT_CONF_FOLDER=/home/apprunner/apps/store + - MVIEWERSTUDIO_PUBLISH_PATH=/home/apprunner/apps/public + - MVIEWERSTUDIO_URL_PATH_PREFIX=mviewerstudio volumes: - "apps:/home/apprunner/apps" - - "mviewerstudio_config:/home/apprunner/mviewerstudio_backend/static/apps" - - "./docker/config-docker-python.json:/home/apprunner/mviewerstudio_backend/static/apps/config.json" + - "./config-python-sample.json:/home/apprunner/mviewerstudio_backend/static/apps/config.json" + # Served under /mviewer/ see docker/nginx/default.conf.template mviewer: + depends_on: + - mviewerstudio # this image is automatically built in # the mviewer/mviewer github repository # See https://github.com/mviewer/mviewer/pull/236 image: mviewer/mviewer +# ports: +# - "5051:80" volumes: - "apps:/usr/share/nginx/html/apps" - links: - - mviewerstudio-php - - mviewerstudio-python - - mviewer-studio: - image: nginx:1.17.9 - volumes: - - "./docker/nginx-default.conf:/etc/nginx/conf.d/default.conf" - ports: - - "8080:8080" - links: - - mviewer - # use the correct link entry below, depending on the selected - # backend - #- mviewerstudio-php:mviewerstudio - - mviewerstudio-python:mviewerstudio +# \ No newline at end of file diff --git a/docker/Dockerfile-python-backend b/docker/Dockerfile-python-backend index e3249183..4340adba 100644 --- a/docker/Dockerfile-python-backend +++ b/docker/Dockerfile-python-backend @@ -1,4 +1,12 @@ -FROM python:3.8-slim +FROM python:3.11-slim + +#install git & studio dependencies +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + libxml2-dev \ + libxslt1-dev \ + git \ + && rm -rf /var/lib/apt/lists/* RUN useradd -r -m apprunner @@ -6,30 +14,34 @@ USER apprunner ENV HOME=/home/apprunner ENV PATH=$HOME/.local/bin:$PATH -ENV EXPORT_CONF_FOLDER=/home/apprunner/apps/store RUN mkdir -p /home/apprunner/apps/store RUN chown -R apprunner:apprunner /home/apprunner/apps WORKDIR /home/apprunner -COPY srv/python/requirements.txt . -RUN pip install --user -r requirements.txt - COPY --chown=apprunner:apprunner srv/python . -RUN pip install --user . && pip install --user gunicorn - -RUN rm -rf mviewerstudio_backend/static/* +# We need to install the app so that the config is properly read (there might be something to fix on +# app-factory.py, calling app.config.from_object requires the package to be installed +RUN pip install --user -r requirements.txt && pip install --user . VOLUME [ "/home/apprunner/apps" ] COPY css/ mviewerstudio_backend/static/css COPY img/ mviewerstudio_backend/static/img COPY index.html mviewerstudio_backend/static/index.html -COPY mviewerstudio.i18n.json mviewerstudio_backend/static/mviewerstudio.i18n.json COPY js/ mviewerstudio_backend/static/js COPY lib/ mviewerstudio_backend/static/lib -COPY *.json mviewerstudio_backend/static/ -COPY docker/config-docker-python.json mviewerstudio_backend/static/apps/config.json +COPY mviewerstudio.i18n.json mviewerstudio_backend/static/mviewerstudio.i18n.json + +ENV EXPORT_CONF_FOLDER=/home/apprunner/apps/store \ + CONF_PATH_FROM_MVIEWER=apps/store \ + MVIEWERSTUDIO_PUBLISH_PATH=/home/apprunner/apps/public \ + CONF_PUBLISH_PATH_FROM_MVIEWER=apps/public \ + DEFAULT_ORG=public \ + MVIEWERSTUDIO_URL_PATH_PREFIX=mviewerstudio/ + +# You will probably have to override this one on runtime with your custom config +COPY config-python-sample.json mviewerstudio_backend/static/apps/config.json CMD ["gunicorn", "-w 4", "-b 0.0.0.0:8000", "mviewerstudio_backend.app:app"] diff --git a/docker/config-docker-python.json b/docker/config-docker-python.json deleted file mode 100644 index 2fae4e88..00000000 --- a/docker/config-docker-python.json +++ /dev/null @@ -1,189 +0,0 @@ -{ - "app_conf": { - "studio_title": "GéoBretagne mviewer studio", - "upload_service": "srv/store", - "delete_service": "srv/delete", - "list_service": "srv/list", - "store_style_service": "srv/store/style", - "mviewer_instance": "/mviewer/", - "conf_path_from_mviewer" :"apps/store", - "mviewer_short_url": { - "used": true, - "apps_folder": "store" - }, - "external_themes": { - "used": false, - "url": "https://geobretagne.fr/minicatalog/csv" - }, - "user_info": "srv/user_info", - "proxy" : "../proxy/?url=", - "user_info_visible": false, - "app_form_placeholders": { - "app_title": "Kartenn", - "logo_url": "https://geobretagne.fr/pub/logo/region-bretagne.jpg", - "help_file": "mviewer_help.html" - }, - "map": { - "center": [-307903.74898791354, 6141345.088741366], - "zoom": 7 - }, - "baselayers": { - "positron": { - "id": "positron", - "thumbgallery": "img/basemap/positron.png", - "title": "CartoDb", - "label": "Positron", - "type": "OSM", - "url": "https://{a-c}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png", - "attribution": "Map tiles by CartoDb, under CC BY 3.0 " - }, - "esriworldimagery": { - "id": "esriworldimagery", - "thumbgallery": "img/basemap/esriworldwide.jpg", - "title": "Esri", - "label": "Esri world imagery", - "type": "OSM", - "url": "http://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}", - "attribution": "Esri world imagery" - }, - "stamen1": { - "id": "stamen1", - "thumbgallery": "img/basemap/toner-lite.png", - "title": "Stamen Design", - "label": "Toner-lite", - "type": "OSM", - "url": "http://{a-d}.tile.stamen.com/toner-lite/{z}/{x}/{y}.png", - "maxzoom": "20", - "attribution": "Map tiles by Stamen Design , under CC BY 3.0 " - }, - "stamen2": { - "id": "stamen2", - "thumbgallery": "img/basemap/watercolor.jpg", - "title": "Stamen Design", - "label": "Watercolor", - "type": "OSM", - "url": "http://{a-c}.tile.stamen.com/watercolor/{z}/{x}/{y}.jpg", - "maxzoom": "20", - "attribution": "Map tiles by Stamen Design , under CC BY 3.0 " - }, - "darkmatter": { - "id": "darkmatter", - "thumbgallery": "img/basemap/darkmatter.png", - "title": "CartoDb", - "label": "Dark Matter", - "type": "OSM", - "url": "https://{a-c}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png", - "maxzoom": "20", - "attribution": "Map tiles by CartoDb, under CC BY 3.0 " - }, - "ortho1": { - "id": "ortho1", - "thumbgallery": "img/basemap/ortho.jpg", - "title": "GéoBretagne", - "label": "Photo aérienne actuelle", - "type": "WMTS", - "url": "https://tile.geobretagne.fr/gwc02/service/wmts", - "layers": "satellite", - "format": "image/png", - "style": "_null", - "matrixset": "EPSG:3857", - "fromcapacity": "false", - "attribution": "partenaires GéoBretagne - IGN RGE BD ORTHO - PlanetObserver" - }, - "ortho_ir": { - "id": "ortho_ir", - "thumbgallery": "img/basemap/ir.jpg", - "title": "GéoBretagne", - "label": "Photo aérienne infra rouge", - "type": "WMTS", - "url": "https://geobretagne.fr/geoserver/gwc/service/wmts", - "layers": "photo:ir-composite", - "format": "image/jpeg", - "style": "_null", - "matrixset": "EPSG:3857", - "fromcapacity": "false", - "attribution": "partenaires GéoBretagne - IGN RGE BD ORTHO - PlanetObserver" - }, - "osm_google": { - "id": "osm_google", - "thumbgallery": "img/basemap/osm_google.png", - "title": "GéoBretagne", - "label": "OpenStreetMap", - "type": "WMS", - "url": "https://osm.geobretagne.fr/gwc01/service/wms", - "layers": "osm:google", - "format": "image/png", - "attribution": "GéoBretagne. Données : les contributeurs d'OpenStreetMap , ODbL " - }, - "osm": { - "id": "osm", - "thumbgallery": "img/basemap/osm.png", - "title": "OSM", - "label": "OpenStreetMap", - "type": "OSM", - "url": "https://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.png", - "attribution": "Données : les contributeurs d'OpenStreetMap ODbL " - }, - "osm_bzh": { - "id": "osm_bzh", - "thumbgallery": "img/basemap/osm.png", - "title": "OSM BZH", - "label": "OpenStreetMap en breton", - "type": "OSM", - "maxzoom": "20", - "url": "https://tile.openstreetmap.bzh/br/{z}/{x}/{y}.png", - "attribution": "Kendaolerien OpenStreetMap" - }, - "scan_ign": { - "id":"scan_ign", - "thumbgallery":"img/basemap/scan.jpg", - "title":"GéoPortail", - "label":"Cartes IGN", - "type":"WMTS", - "url":"https://geobretagne.fr/geoportail/wmts", - "layers":"GEOGRAPHICALGRIDSYSTEMS.MAPS", - "format":"image/jpeg", - "fromcapacity":"false", - "attribution":"", - "style":"normal", - "matrixset":"PM", - "maxzoom":"22" - } - }, - "data_providers" : { - "csw" : [ - { - "title" : "Catalogue GéoBretagne", - "url": "https://geobretagne.fr/geonetwork/srv/fre/csw", - "baseref": "https://geobretagne.fr/geonetwork/srv/eng/catalog.search?node=srv#/metadata/" - }, - { - "title" : "Catalogue Région Bretagne", - "url": "https://applications.region-bretagne.fr/geonetwork/srv/fre/csw", - "baseref": "https://applications.region-bretagne.fr/geonetwork/srv/fre/catalog.search#/metadata/" - }, - { - "title" : "Catalogue de la Région Grand Est", - "url": "https://geobretagne.fr/geonetwork/srv/fre/csw", - "baseref": "https://www.cigalsace.org/geonetwork/" - }, - { - "title" : "Catalogue de la Région Pays de la Loire", - "url": "../proxy/?url=https://www.geopal.org/geonetwork/srv/fre/csw", - "baseref": "https://www.geopal.org/geonetwork/" - } - ], - "wms" : [ - { - "title" : "Serveur WMS de la Région", - "url": "https://ows.region-bretagne.fr/geoserver/rb/wms" - } - ] - }, - "default_params" : { - "layer": { - "info_format": "text/html" - } - } - } -} diff --git a/docker/nginx-default.conf b/docker/nginx/default.conf.template similarity index 60% rename from docker/nginx-default.conf rename to docker/nginx/default.conf.template index 363af7b9..d12b3f75 100644 --- a/docker/nginx-default.conf +++ b/docker/nginx/default.conf.template @@ -1,20 +1,13 @@ -upstream mviewerstudio { - server mviewerstudio:8000; -} - -upstream mviewer { - server mviewer:80; -} - server { - listen 8080; - server_name localhost; + listen 80; + server_name ${NGINX_HOST}; location /mviewer/ { - proxy_pass http://mviewer/; + proxy_pass http://mviewer:80/; } - location / { - proxy_pass http://mviewerstudio; + + location /${MVIEWERSTUDIO_URL_PATH_PREFIX}/ { + proxy_pass http://mviewerstudio:8000/${MVIEWERSTUDIO_URL_PATH_PREFIX}/; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; @@ -24,5 +17,10 @@ server { #proxy_set_header sec-roles "ROLE_ADMINISTRATOR;ROLE_MVIEWER_ADMIN"; #proxy_set_header sec-org "geobretagne"; } + + location / { + server_name_in_redirect off; + return 302 /${MVIEWERSTUDIO_URL_PATH_PREFIX}; + } } diff --git a/docker/readme.md b/docker/readme.md new file mode 100644 index 00000000..36c85dd8 --- /dev/null +++ b/docker/readme.md @@ -0,0 +1,22 @@ +# mviewerstudio Dockerfile + +## Which one ? +The maintained dockerfile is the python one. The php one is there for historical reasons and will probably soon be dropped. + +## Environment variables + +- EXPORT_CONF_FOLDER is the "staging" folder where studio will store draft configs and work in progress +- CONF_PATH_FROM_MVIEWER is the url path given to mviewer to access the same map files +- MVIEWERSTUDIO_PUBLISH_PATH is the "production" folder where studio will copy the map files when you ask to *Publish* +- CONF_PUBLISH_PATH_FROM_MVIEWER is the url path given to mviewer to access the same map files +- MVIEWERSTUDIO_URL_PATH_PREFIX allows to serve studio on a non-root path, see [#271](https://github.com/mviewer/mviewerstudio/pull/271) + +## Default configuration + +The default configuration (env vars defined in the dockerfile and json config file copied) assume that: +- the mviewer _apps_ folder is mounted at EXPORT_CONF_FOLDER=/home/apprunner/apps +- /home/apprunner/apps/store and /home/apprunner/apps/prod are existing folders (you might need to create them manually beforehand) +- it is using config-python-sample.json, which at some point you will probably want to override with your own config. + + +It is also configured to serve the frontend (static files) with gunicorn, which is usually not recommended. Later versions might use an nginx container to serve the frontend. diff --git a/index.html b/index.html index 65a7f19b..e883fdc6 100755 --- a/index.html +++ b/index.html @@ -213,7 +213,7 @@

Besoin d'aide ?

Options Dépublier @@ -259,25 +259,25 @@

- +
- + @@ -468,37 +468,37 @@

- +
- +
- +
- +
- +
- +
@@ -506,12 +506,12 @@

- +
- +
- +
- +
@@ -581,7 +581,7 @@

- +
@@ -675,8 +675,8 @@

Thématiques & do
- @@ -903,7 +903,7 @@
Données de la thématique<
- @@ -1065,7 +1065,7 @@
- +
@@ -1089,7 +1089,7 @@
- +
- +
@@ -1177,7 +1177,7 @@
- +
@@ -1186,7 +1186,7 @@
Style(s) de la donnée disponible(s)
- +
@@ -1196,11 +1196,11 @@
Style de la donnée
- +
- +
@@ -1227,7 +1227,7 @@
Style de la donnée