From c51ea668e1b3e1633d81bc7107bc7d7338c1fb60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Blanc?= Date: Thu, 3 Nov 2022 15:45:05 +0100 Subject: [PATCH 1/5] Create installation section --- content/installation/_index.md | 10 +++++++++ content/installation/authentication/_index.md | 8 +++++++ content/installation/services/_index.md | 10 +++++++++ .../installation/troubleshooting/_index.md | 21 +++++++++++++++++++ 4 files changed, 49 insertions(+) create mode 100644 content/installation/_index.md create mode 100644 content/installation/authentication/_index.md create mode 100644 content/installation/services/_index.md create mode 100644 content/installation/troubleshooting/_index.md diff --git a/content/installation/_index.md b/content/installation/_index.md new file mode 100644 index 00000000..dff1b2ab --- /dev/null +++ b/content/installation/_index.md @@ -0,0 +1,10 @@ +--- +title: "Installation" +date: 2022-11-03T14:15:36+01:00 +chapter: true +weight: 2 +--- + +# Installation/Deployment + +This section aims to explain how to install/deploy all of *QWC services*. \ No newline at end of file diff --git a/content/installation/authentication/_index.md b/content/installation/authentication/_index.md new file mode 100644 index 00000000..59c72490 --- /dev/null +++ b/content/installation/authentication/_index.md @@ -0,0 +1,8 @@ ++++ +title = "Authentication" +date = 2021-09-17T16:40:01+02:00 +weight = 5 +chapter = true ++++ + +# Authentication services diff --git a/content/installation/services/_index.md b/content/installation/services/_index.md new file mode 100644 index 00000000..cff59cad --- /dev/null +++ b/content/installation/services/_index.md @@ -0,0 +1,10 @@ ++++ +title = "Services" +date = 2021-09-17T15:11:57+02:00 +weight = 4 +chapter = true ++++ + +# QWC Services + +The QWC Services are a collection of microservices providing configurations for and authorized access to different QWC Map Viewer components. diff --git a/content/installation/troubleshooting/_index.md b/content/installation/troubleshooting/_index.md new file mode 100644 index 00000000..7928cbf7 --- /dev/null +++ b/content/installation/troubleshooting/_index.md @@ -0,0 +1,21 @@ ++++ +title = "Troubleshooting" +weight = 6 ++++ + +Login redirects to http instead of https +---------------------------------------- + +This happens, when the `X-Forwarded-Proto` header is not set to `https`. In that +case you need to force it in the nginx config: + +``` +location ~ /ldap-auth/ { + proxy_set_header Host REPLACE_THIS.WITH.THE.HOSTNAME.OF.YOUR.SERVI.CE:PORTNUMBER; + proxy_set_header X-Forwarded-Proto https; + rewrite ^/[^/]+(.+) $1 break; + proxy_pass http://qwc-ldap-auth-service:9090; +} +``` + +It might be necessary to do the same to the `/qwc_admin` location configuration. From 59dfdf6d142a49f863043d2fb7b3cececf1a12fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Blanc?= Date: Thu, 3 Nov 2022 15:46:11 +0100 Subject: [PATCH 2/5] Update Makefile with new installation section --- Makefile | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index 54cfd5a5..7495a71d 100644 --- a/Makefile +++ b/Makefile @@ -3,18 +3,18 @@ all: fetch: no=1; \ for repo in qwc-map-viewer qwc-ogc-service qwc-feature-info-service qwc-fulltext-search-service qwc-legend-service qwc-permalink-service qwc-print-service qwc-mapinfo-service qwc-data-service qwc-document-service qwc-elevation-service qwc-admin-gui qwc-registration-gui qwc-config-generator; do \ - echo "+++\ntitle = \"$$repo\"\nmenuTitle = \"$$repo\"\nweight = $$no\n+++" >content/services/$$repo.md; \ - curl -s -L https://github.com/qwc-services/$$repo/raw/master/README.md | sed '/^\[/d' >>content/services/$$repo.md; \ + echo "+++\nmenuTitle = \"$$repo\"\nweight = $$no\nchapter = false\n+++" >content/installation/services/$$repo.md; \ + curl -s -L https://github.com/qwc-services/$$repo/raw/master/README.md | sed '/^\[/d' >>content/installation/services/$$repo.md; \ no=$$((no+1)); \ done no=1; \ for repo in qwc-db-auth qwc-ldap-auth; do \ - echo "+++\ntitle = \"$$repo\"\nmenuTitle = \"$$repo\"\nweight = $$no\n+++" >content/authentication/$$repo.md; \ - curl -s -L https://github.com/qwc-services/$$repo/raw/master/README.md | sed '/^\[/d' >>content/authentication/$$repo.md; \ + echo "+++\nmenuTitle = \"$$repo\"\nweight = $$no\nchapter = false\n+++" >content/installation/authentication/$$repo.md; \ + curl -s -L https://github.com/qwc-services/$$repo/raw/master/README.md | sed '/^\[/d' >>content/installation/authentication/$$repo.md; \ no=$$((no+1)); \ done - echo "+++\ntitle = \"QGIS Web Client 2\"\nmenuTitle = \"Viewer\"\nweight = 3\n+++\n" >content/viewer/_index.md; \ - curl -s -L https://github.com/qgis/qwc2-demo-app/raw/master/doc/QWC2_Documentation.md >>content/viewer/_index.md; + echo "+++\nmenuTitle = \"Viewer\"\nweight = 3\nchapter = false\n+++\n" >content/installation/viewer/_index.md; \ + curl -s -L https://github.com/qgis/qwc2-demo-app/raw/master/doc/QWC2_Documentation.md >>content/installation/viewer/_index.md; schemas: # Convert JSON schemas to Markdown @@ -22,8 +22,8 @@ schemas: no=1; \ for repo in qwc-map-viewer qwc-ogc-service qwc-feature-info-service qwc-fulltext-search-service qwc-legend-service qwc-permalink-service qwc-print-service qwc-mapinfo-service qwc-data-service qwc-document-service qwc-elevation-service qwc-ext-service qwc-admin-gui qwc-registration-gui qwc-config-generator; do \ curl -s -o /tmp/schema.json -L https://github.com/qwc-services/$$repo/raw/master/schemas/$$repo.json; \ - echo "+++\ntitle = \"$$repo\"\nweight = $$no\n+++" >content/configuration/$$repo.md; \ + echo "+++\ntitle = \"$$repo\"\nweight = $$no\n+++" >content/installation/configuration/$$repo.md; \ .venv/bin/generate-schema-doc --config template_name=md /tmp/schema.json /tmp/schema.md; \ - cat /tmp/schema.md >>content/configuration/$$repo.md; \ + cat /tmp/schema.md >>content/installation/configuration/$$repo.md; \ no=$$((no+1)); \ done From 829d66ecf0435e9f25e051543c503a77337425a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Blanc?= Date: Thu, 3 Nov 2022 15:47:26 +0100 Subject: [PATCH 3/5] Execute Makefile to generate up-to-date doc in installation section --- .../authentication/qwc-db-auth.md | 149 ++++ .../authentication/qwc-ldap-auth.md | 68 ++ content/installation/configuration/_index.md | 122 +++ content/installation/quick-start/_index.md | 134 +++ .../installation/services/qwc-admin-gui.md | 233 ++++++ .../services/qwc-config-generator.md | 364 +++++++++ .../installation/services/qwc-data-service.md | 387 +++++++++ .../services/qwc-document-service.md | 136 +++ .../services/qwc-elevation-service.md | 82 ++ .../services/qwc-feature-info-service.md | 581 +++++++++++++ .../services/qwc-fulltext-search-service.md | 211 +++++ .../services/qwc-legend-service.md | 207 +++++ .../installation/services/qwc-map-viewer.md | 327 ++++++++ .../services/qwc-mapinfo-service.md | 149 ++++ .../installation/services/qwc-ogc-service.md | 301 +++++++ .../services/qwc-permalink-service.md | 119 +++ .../services/qwc-print-service.md | 117 +++ .../services/qwc-registration-gui.md | 95 +++ content/installation/viewer/_index.md | 773 ++++++++++++++++++ 19 files changed, 4555 insertions(+) create mode 100644 content/installation/authentication/qwc-db-auth.md create mode 100644 content/installation/authentication/qwc-ldap-auth.md create mode 100644 content/installation/configuration/_index.md create mode 100644 content/installation/quick-start/_index.md create mode 100644 content/installation/services/qwc-admin-gui.md create mode 100644 content/installation/services/qwc-config-generator.md create mode 100644 content/installation/services/qwc-data-service.md create mode 100644 content/installation/services/qwc-document-service.md create mode 100644 content/installation/services/qwc-elevation-service.md create mode 100644 content/installation/services/qwc-feature-info-service.md create mode 100644 content/installation/services/qwc-fulltext-search-service.md create mode 100644 content/installation/services/qwc-legend-service.md create mode 100644 content/installation/services/qwc-map-viewer.md create mode 100644 content/installation/services/qwc-mapinfo-service.md create mode 100644 content/installation/services/qwc-ogc-service.md create mode 100644 content/installation/services/qwc-permalink-service.md create mode 100644 content/installation/services/qwc-print-service.md create mode 100644 content/installation/services/qwc-registration-gui.md create mode 100644 content/installation/viewer/_index.md diff --git a/content/installation/authentication/qwc-db-auth.md b/content/installation/authentication/qwc-db-auth.md new file mode 100644 index 00000000..03d66e10 --- /dev/null +++ b/content/installation/authentication/qwc-db-auth.md @@ -0,0 +1,149 @@ ++++ +menuTitle = "qwc-db-auth" +weight = 1 +chapter = false ++++ + +Authentication with User DB +=========================== + +Authentication service with local user database. + + +Configuration +------------- + +The static config files are stored as JSON files in `$CONFIG_PATH` with subdirectories for each tenant, +e.g. `$CONFIG_PATH/default/*.json`. The default tenant name is `default`. + +### DB Auth Service config + +* [JSON schema](schemas/qwc-db-auth.json) +* File location: `$CONFIG_PATH//dbAuthConfig.json` + +Example: +```json +{ + "$schema": "https://raw.githubusercontent.com/qwc-services/qwc-db-auth/master/schemas/qwc-db-auth.json", + "service": "db-auth", + "config": { + "db_url": "postgresql:///?service=qwc_configdb" + } +} +``` + +Set the `MAX_LOGIN_ATTEMPTS` environment variable to set the maximum number of +failed login attempts before sign in is blocked (default: `20`). + +A minimum password length of `8` with no other constraints is set by default. Optional password complexity constraints can be set using the following `config` options: +```json +"config": { + "password_min_length": 8, + "password_max_length": 128, + "password_constraints": [ + "[A-Z]", + "[a-z]", + "\\d", + "[ !\"#$%&'()*+,\\-./\\\\:;<=>?@\\[\\]^_`{|}~]" + ], + "password_min_constraints": 3, + "password_constraints_message": "Password must contain at least three of these character types: uppercase letters, lowercase letters, numbers, special characters" +} +``` + +`password_min_length` and `password_max_length` can be set independently. `password_constraints` is a list of regular expression of which at least `password_min_constraints` have to match for the password to be valid, otherwise the `password_constraints_message` is shown. Note that the regular expression have to be JSON escaped and allow only patterns supported by Python's `re` module. + +If the `qwc_config.password_histories` table is present, additional optional password constraints may be set: +```json +"config": { + "password_expiry": 365, + "password_expiry_notice": 10, + "password_update_interval": 600, + "password_allow_reuse": false +} +``` + +* `password_expiry` (default: `-1`): Number of days until a password expires, or `-1` to disable. Forces a password change once expired. +* `password_expiry_notice` (default: `-1`): Show an expiry notice within this number of days before a password expires, or `-1` to disable +* `password_update_interval` (default: `-1`): Min number of seconds before a password may be changed again, or `-1` to disable +* `password_allow_reuse` (default: `true`): Set whether a user may reuse previous passwords or not + +Besides the form based DB login, an (insecure) plain POST login is supported. This method can be +activated by setting `POST_PARAM_LOGIN=True`. User and password are passed as POST parameters +`username` and `password`. +Usage example: `curl -d 'username=demo&password=demo' http://localhost:5017/login`. + +Additional user info fields from `qwc_config.user_infos` may be added to the JWT identity by setting `user_info_fields`: +```json +"config": { + "user_info_fields": ["surname", "first_name"] +} +``` + +* `MAIL_SERVER`: default ‘localhost’ +* `MAIL_PORT`: default 25 +* `MAIL_USE_TLS`: default False +* `MAIL_USE_SSL`: default False +* `MAIL_DEBUG`: default app.debug +* `MAIL_USERNAME`: default None +* `MAIL_PASSWORD`: default None +* `MAIL_DEFAULT_SENDER`: default None +* `MAIL_MAX_EMAILS`: default None +* `MAIL_SUPPRESS_SEND`: default app.testing +* `MAIL_ASCII_ATTACHMENTS`: default False + +In addition the standard Flask `TESTING` configuration option is used by Flask-Mail in unit tests. + +### Two factor authentication + +Two factor authentication using TOTP can be enabled by setting the environment variable `TOTP_ENABLED=True`. +This will require an additional verification token after sign in, based on the user's TOTP secret. + +A personal QR code for setting up the two factor authentication is shown to the user on first sign in (or if the TOTP secret is empty). +The TOTP issuer name for your application can be set using the environment variable `TOTP_ISSUER_NAME="QWC Services"`. + +An user's TOTP secret can be reset by clearing it in the Admin GUI user form. + + +Usage +----- + +Run standalone application: + + python server.py + +Endpoints: + + http://localhost:5017/login + + http://localhost:5017/logout + + +Development +----------- + +Create a virtual environment: + + virtualenv --python=/usr/bin/python3 .venv + +Activate virtual environment: + + source .venv/bin/activate + +Install requirements: + + pip install -r requirements.txt + +Set the `CONFIG_PATH` environment variable to the path containing the service config and permission files when starting this service (default: `config`). + + export CONFIG_PATH=../qwc-docker/volumes/config + +Configure environment: + + echo FLASK_ENV=development >.flaskenv + export MAIL_SUPPRESS_SEND=True + export MAIL_DEFAULT_SENDER=from@example.com + +Start local service: + + python server.py diff --git a/content/installation/authentication/qwc-ldap-auth.md b/content/installation/authentication/qwc-ldap-auth.md new file mode 100644 index 00000000..047c560f --- /dev/null +++ b/content/installation/authentication/qwc-ldap-auth.md @@ -0,0 +1,68 @@ ++++ +menuTitle = "qwc-ldap-auth" +weight = 2 +chapter = false ++++ + +Authentication with LDAP/Active Directory +========================================= + +Configuration +------------- + +See also [flask-ldap3-login](https://flask-ldap3-login.readthedocs.io/en/latest/configuration.html) + +ENV | default value | description +--------------------------------|-------------------------|--------- +`JWT_SECRET_KEY` | `********` | secret key for JWT token (same for all services) +`LDAP_HOST` | `localhost` | Hostname of your LDAP Server +`LDAP_PORT` | `389` | The port number of your LDAP server. +`LDAP_USE_SSL` | `False` | Set to True if your server uses SSL +`LDAP_BASE_DN` | `dc=example,dc=org` | Base DN of your directory +`LDAP_USER_DN` | `ou=users` | Users DN to be prepended to the Base DN +`LDAP_GROUP_DN` | `ou=groups` | Groups DN to be prepended to the Base DN +`LDAP_SEARCH_FOR_GROUPS` | `False` | Search for groups +`LDAP_GROUP_SEARCH_SCOPE` | `LEVEL` | Specifies what scope to search in when searching for a specific group +`LDAP_GROUP_OBJECT_FILTER` | `(objectclass=group)` | Specifies what object filter to apply when searching for groups +`LDAP_GROUP_MEMBERS_ATTR` | `uniqueMember` | Specifies the LDAP attribute where group members are declared +`LDAP_GROUP_NAME_ATTRIBUTE` | `cn` | Group name attribute in LDAP group response +`LDAP_GET_GROUP_ATTRIBUTES` | `*` (ALL_ATTRIBUTES) | Specifies which LDAP attributes to get when searching LDAP for a group/groups +`LDAP_USER_SEARCH_SCOPE` | `LEVEL` | Specifies what scope to search in when searching for a specific user +`LDAP_USER_RDN_ATTR` | `cn` | The RDN attribute for your user schema on LDAP +`LDAP_USER_LOGIN_ATTR` | `cn` | The Attribute you want users to authenticate to LDAP with +`LDAP_BIND_USER_DN` | `None` | The Username to bind to LDAP with +`LDAP_BIND_USER_PASSWORD` | `None` | The Password to bind to LDAP with + + +Usage +----- + +Run standalone application: + + python server.py + +Endpoints: + + http://localhost:5017/login + + http://localhost:5017/logout + + +Development +----------- + +Create a virtual environment: + + virtualenv --python=/usr/bin/python3 .venv + +Activate virtual environment: + + source .venv/bin/activate + +Install requirements: + + pip install -r requirements.txt + +Start local service: + + python server.py diff --git a/content/installation/configuration/_index.md b/content/installation/configuration/_index.md new file mode 100644 index 00000000..9c871d62 --- /dev/null +++ b/content/installation/configuration/_index.md @@ -0,0 +1,122 @@ ++++ +title = "Configuration" +date = 2021-09-17T15:11:34+02:00 +weight = 2 +chapter = false ++++ + +## Configuration database + +The [Configuration database](https://github.com/qwc-services/qwc-config-db) (ConfigDB) contains the database schema `qwc_config` for configurations and permissions of QWC services. + +This database uses the PostgreSQL connection service `qwc_configdb` by default, which can be setup for the corresponding database in the PostgreSQL connection service file `pg_service.conf`. This default can be overridden by setting the environment variable `CONFIGDB_URL` to a custom DB connection string (see [below](#service-configurations)). + +Additional user fields are saved in the table `qwc_config.user_infos` with a a one-to-one relation to `qwc_config.users` via the `user_id` foreign key. +To add custom user fields, add new columns to your `qwc_config.user_infos` table and set your `USER_INFO_FIELDS` accordingly (see [below](#service-configurations)). + + +### Database migrations + +An existing ConfigDB can be updated to the latest schema by running the database migrations from the `qwc-config-db` directory: + + cd qwc-config-db/ + git pull + alembic upgrade head + + +## Service configurations + +The QWC Services are generally configured using environment variables. +These can be set when running the services locally or in `docker-compose.yml` when using Docker. + +Common configuration: + +ENV | default value | description +----------------------|--------------------|--------- +`CONFIG_PATH` | . | Base path for service configuration files +`JWT_SECRET_KEY` | `********` | secret key for JWT token +`TENANT_URL_RE` | None | Regex for tenant extraction from base URL. Example: ^https?://.+?/(.+?)/ +`TENANT_HEADER` | None | Tenant Header name. Example: Tenant + + +See READMEs of services for details. + + +## Resources and Permissions + +Permissions and configurations are based on different resources with assigned permissions in the [configuration database](https://github.com/qwc-services/qwc-config-db). +These can be managed in the [QWC configuration backend](https://github.com/qwc-services/qwc-admin-gui). + + +### Resources + +The following resource types are available: + +* `map`: WMS corresponding to a QGIS Project + * `layer`: layer of a map + * `attribute`: attribute of a map layer + * `print_template`: print composer template of a QGIS Project + * `data`: Data layer for editing + * `attribute`: attribute of a data layer + * `data_create`: Data layer for creating features + * `data_read`: Data layer for reading features + * `data_update`: Data layer for updating features + * `data_delete`: Data layer for deleting features +* `viewer`: custom map viewer configuration +* `viewer_task`: permittable viewer tasks + +The resource `name` corresponds to the technical name of its resource (e.g. WMS layer name). + +The resource types can be extended by inserting new types into the `qwc_config.resource_types` table. +These can be queried, e.g. in a custom service, by using `PermissionClient::resource_permissions()` or +`PermissionClient::resource_restrictions()` from [QWC Services Core](https://github.com/qwc-services/qwc-services-core). + +Available `map`, `layer`, `attribute` and `print_template` resources are collected from WMS `GetProjectSettings` and the QGIS projects. + +`data` and their `attribute` resources define a data layer for the [Data service](https://github.com/qwc-services/qwc-data-service). +Database connections and attribute metadata are collected from the QGIS projects. + +For more detailed CRUD permissions `data_create`, `data_read`, `data_update` and `data_delete` can be used instead of `data` +(`data` and `write=False` is equivalent to `data_read`; `data` and `write=True` is equivalent to all CRUD resources combined). + +The `viewer` resource defines a custom viewer configuration for the map viewer (see [Custom viewer configurations](https://github.com/qwc-services/qwc-map-viewer#custom-viewer-configurations)). + +The `viewer_task` resource defines viewer functionalities (e.g. printing or raster export) that can be restricted or permitted. +Their `name` (e.g. `RasterExport`) corresponds to the `key` in `menuItems` and `toolbarItems` in the QWC2 `config.json`. Restricted viewer task items are then removed from the menu and toolbar in the map viewer. Viewer tasks not explicitly added as resources are kept unchanged from the `config.json`. + + +### Permissions + +Permissions are based on roles. Roles can be assigned to groups or users, and users can be members of groups. +A special role is `public`, which is always included, whether a user is signed in or not. + +Each role can be assigned a permission for a resource. +The `write` flag is only used for `data` resources and sets whether a data layer is read-only. + +Based on the user's identity (user name and/or group name), all corresponding roles and their permissions and restrictions are collected. +The service configurations are then modified according to these permissions and restrictions. + +Using the `DEFAULT_ALLOW` environment variable, some resources can be set to be permitted or restricted by default if no permissions are set (default: `False`). Affected resources are `map`, `layer`, `print_template` and `viewer_task`. + +e.g. `DEFAULT_ALLOW=True`: all maps and layers are permitted by default +e.g. `DEFAULT_ALLOW=False`: maps and layers are only available if their resources and permissions are explicitly configured + + +## Group registration + +Using the optional [Registration GUI](https://github.com/qwc-services/qwc-registration-gui) allows users to request membership or unsubscribe from registrable groups. These requests can then be accepted or rejected in the [Admin GUI](https://github.com/qwc-services/qwc-admin-gui). + +Workflow: +* Admin GUI + * admin user creates new groups with assigned roles and permissions on resources + * admin user configures registrable groups +* Registration GUI + * user select desired groups from registrable groups and submits application form + * admin users are notified of new registration requests +* Admin GUI + * admin user selects entry from list of pending registration requests + * admin user accepts or rejects registration requests for a user + * user is added to or removed from accepted groups + * user is notified of registration request updates +* Map Viewer + * user permissions are updated for new groups diff --git a/content/installation/quick-start/_index.md b/content/installation/quick-start/_index.md new file mode 100644 index 00000000..b09cee92 --- /dev/null +++ b/content/installation/quick-start/_index.md @@ -0,0 +1,134 @@ ++++ +title = "Quick Start" +date = 2021-09-17T15:10:55+02:00 +weight = 1 +chapter = false ++++ + +### Docker containers for QWC services + +Create a QWC services dir: + + mkdir qwc-services + cd qwc-services/ + +Clone [Docker containers for QWC services](https://github.com/qwc-services/qwc-docker): + + git clone https://github.com/qwc-services/qwc-docker.git + +Install Docker and setup containers (see [qwc-docker README](https://github.com/qwc-services/qwc-docker#setup)): + + cd qwc-docker/ + cp docker-compose-example.yml docker-compose.yml + +Create a secret key: + + python3 -c 'import secrets; print("JWT_SECRET_KEY=\"%s\"" % secrets.token_hex(48))' >.env + +Set permissions for writable volumes: + + sudo chown -R www-data:www-data volumes/qgs-resources + sudo chown -R www-data:www-data volumes/config + sudo chown -R www-data:www-data volumes/qwc2/assets + + sudo chown 8983:8983 volumes/solr/data + +### Run containers + +Start all containers: + + docker-compose up -d + +Follow log output: + + docker-compose logs -f + +Open map viewer: + + http://localhost:8088/ + +Open Admin GUI (Admin user: `admin:admin`, requires password change on first login): + + http://localhost:8088/qwc_admin + +Sign in (Demo user: `demo:demo`): + + http://localhost:8088/auth/login + +Sign out: + + http://localhost:8088/auth/logout + +Stop all containers: + + docker-compose down + +### Add a QGIS project + +Setup PostgreSQL connection service file `~/.pg_service.conf` +for DB connections from the host machine to PostGIS container: + +``` +cat >>~/.pg_service.conf </adminGuiConfig.json` + +Example: +```json +{ + "$schema": "https://raw.githubusercontent.com/qwc-services/qwc-admin-gui/master/schemas/qwc-admin-gui.json", + "service": "admin-gui", + "config": { + "db_url": "postgresql:///?service=qwc_configdb", + "config_generator_service_url": "http://qwc-config-service:9090", + "totp_enabled": false, + "user_info_fields": [], + "proxy_url_whitelist": [], + "proxy_timeout": 60 + } +} +``` + +To connect with the demo database, the following `~/.pg_service.conf` entry is expected: + +``` +host=localhost +port=5439 +dbname=qwc_demo +user=qwc_admin +password=qwc_admin +sslmode=disable +``` + +Set the `GROUP_REGISTRATION_ENABLED` environment variable to `False` to disable registrable groups and group registration requests, if not using the [Registration GUI](https://github.com/qwc-services/qwc-registration-gui) (default: `True`). + +To automatically logout from the admin gui after a period of inactivity, set the `IDLE_TIMEOUT` environment variable to the desired period, in seconds (default: `0`, i.e. disabled). + +Set `totp_enabled` to `true` to show the TOTP fields in the user form, if two factor authentication is enabled in the [DB-Auth service](https://github.com/qwc-services/qwc-db-auth) (default: `false`). + +### Additional user fields + +Additional user fields are saved in the table `qwc_config.user_infos` with a a one-to-one relation to `qwc_config.users` via the `user_id` foreign key. +To add custom user fields, add new columns to your `qwc_config.user_infos` table and set your `user_info_fields` to a JSON with the following structure: + +```json + { + "title": "", + "name": "", + "type": "", + "required" "" + } +] +``` + +These fields are then added to the user form. + +Example: + +```sql +-- add custom columns +ALTER TABLE qwc_config.user_infos ADD COLUMN surname character varying NOT NULL; +ALTER TABLE qwc_config.user_infos ADD COLUMN first_name character varying NOT NULL; +``` + +```bash +# set user info fields config +"user_info_fields": [{"title": "Surname", "name": "surname", "type": "text", "required": true}, {"title": "First name", "name": "first_name", "type": "text", "required": true}] +``` + +### Mailer + +* `MAIL_SERVER`: default ‘localhost’ +* `MAIL_PORT`: default 25 +* `MAIL_USE_TLS`: default False +* `MAIL_USE_SSL`: default False +* `MAIL_DEBUG`: default app.debug +* `MAIL_USERNAME`: default None +* `MAIL_PASSWORD`: default None +* `MAIL_DEFAULT_SENDER`: default None +* `MAIL_MAX_EMAILS`: default None +* `MAIL_SUPPRESS_SEND`: default app.testing +* `MAIL_ASCII_ATTACHMENTS`: default False + +In addition the standard Flask `TESTING` configuration option is used by Flask-Mail in unit tests. + +### Proxy to internal services + +The route `/proxy?url=http://example.com/path?a=1` serves as a proxy for calling whitelisted internal services. This can be used e.g. to call other internal services from custom pages in the Admin GUI, without having to expose those services externally. + +Set `proxy_url_whitelist` to a list of RegExes for whitelisted URLs (default: `[]`), e.g. +```json + ["", "^http://example.com/path\\?.*$"] +``` + +Set `proxy_timeout` to the timeout in seconds for proxy requests (default: `60`s). + +### Translations + +Translation strings are stored in a JSON file for each locale in `translations/.json` (e.g. `en.json`). Add any new languages as new JSON files. + +Set the `DEFAULT_LOCALE` environment variable to choose the locale for the user notification mails (default: `en`). + +### Solr search index update + +If using a Solr search service, the Solr search index of a tenant may be updated via a button on the main page. This can be activated by adding the following configuration options to the Admin GUI service config: +```json +{ + "config": { + "solr_service_url": "http://qwc-solr:8983/solr/gdi/", + "solr_tenant_dih": "dih_geodata", + "solr_tenant_dih_config_file": "/solr/config-in/dih_geodata_config.xml", + "solr_config_path": "/solr/config-out", + "solr_update_check_wait": 5, + "solr_update_check_max_retries": 10 + } +} +``` + +* `solr_service_url`: Solr Service base URL for collection +* `solr_tenant_dih`: Solr DataImportHandler for the tenant +* `solr_tenant_dih_config_file` (optional): Path to source DataImportHandler config file for the tenant +* `solr_config_path` (optional): Path to Solr configs (**Note:** requires write permissions for DataImportHandler config files) +* `solr_update_check_wait` (optional): Wait time in seconds for checks during Solr index update (default: `5`s) +* `solr_update_check_max_retries` (optional): Max number of retries for checks during Solr index update (default: `10`) + +If both `solr_tenant_dih_config_file` and `solr_config_path` are set, the tenant config file is first copied to the Solr configs dir before updating the Solr search index. + +Example volumes for `qwc-docker` environment and above service config: +```yaml +services: + qwc-admin-gui: + # ... + volumes: + # ... + # Solr configs + - ./volumes/solr/configsets/gdi/conf:/solr/config-in:ro + - ./volumes/solr/data/gdi/conf:/solr/config-out +``` + +### Plugins + +The admin gui is extendable through plugins, which reside in the `plugins` folder. To enable them, list them in `plugins` in the admin gui configuration. See the JSON schema for details, and for configuration parameters which may be required by plugins shipped by default with `qwc-admin-gui`. + +Usage +----- + +Base URL: + + http://localhost:5031/ + +### Default login + +username: admin +password: admin + + +Docker usage +------------ + +To run this docker image you will need a configuration database. For testing purposes you can use the demo DB. + +The following steps explain how to download the demo DB docker image and how to run the `qwc-admin-gui` service with `docker-compose`. + +**Step 1: Clone qwc-docker** + + git clone https://github.com/qwc-services/qwc-docker + cd qwc-docker + +**Step 2: Create docker-compose.yml file** + + cp docker-compose-example.yml docker-compose.yml + +**Step 3: Set flask debug mode to true** + +For the QWC Admin GUI to work without login you will have to add the following `env` variable: + + FLASK_DEBUG=1 + +**Step 4: Start docker containers** + + docker-compose up qwc-admin-gui + +For more information please visit: https://github.com/qwc-services/qwc-docker + +Development +----------- + +Create a virtual environment: + + virtualenv --python=/usr/bin/python3 .venv + +Activate virtual environment: + + source .venv/bin/activate + +Install requirements: + + pip install -r requirements.txt + +Set the `CONFIG_PATH` environment variable to the path containing the service config and permission files when starting this service (default: `config`). + + export CONFIG_PATH=../qwc-docker/volumes/config + +Configure environment: + + echo FLASK_ENV=development >.flaskenv + +Start local service: + + python server.py diff --git a/content/installation/services/qwc-config-generator.md b/content/installation/services/qwc-config-generator.md new file mode 100644 index 00000000..460620e4 --- /dev/null +++ b/content/installation/services/qwc-config-generator.md @@ -0,0 +1,364 @@ ++++ +menuTitle = "qwc-config-generator" +weight = 14 +chapter = false ++++ + +QWC ConfigGenerator +==================== + +Generates JSON files for service configs and permissions from WMS GetCapabilities, QGS projects and QWC ConfigDB. + + +Setup +----- + +Create a ConfigGenerator config file `tenantConfig.json` for each tenant (see below). + + +Configuration +------------- + +Example `tenantConfig.json`: +```json +{ + "$schema": "https://github.com/qwc-services/qwc-config-generator/raw/master/schemas/qwc-config-generator.json", + "service": "config-generator", + "config": { + "tenant": "default", + "config_db_url": "postgresql:///?service=qwc_configdb", + "default_qgis_server_url": "http://localhost:8001/ows/", + "qgis_projects_base_dir": "/data", + "qgis_projects_scan_base_dir": "/data/scan", + "qgis_projects_gen_base_dir": "/data/gen", + "permissions_default_allow": true, + "validate_schema": true, + "autogen_keyvaltable_datasets": false + }, + "themesConfig": { + "defaultScales": [100000000, 50000000, 25000000, 10000000, 4000000, 2000000, 1000000, 400000, 200000, 80000, 40000, 20000, 10000, 8000, 6000, 4000, 2000, 1000, 500, 250, 100], + "defaultPrintGrid": [{"s": 10000000, "x": 1000000, "y": 1000000}, {"s": 1000000, "x": 100000, "y": 100000}, {"s": 100000, "x": 10000, "y": 10000}, {"s": 10000, "x": 1000, "y": 1000}, {"s": 1000, "x": 100, "y": 100}, {"s": 100, "x": 10, "y": 10}], + "defaultWMSVersion":"1.3.0", + "defaultBackgroundLayers": [], + "defaultSearchProviders": ["coordinates"], + "defaultMapCrs": "EPSG:3857", + "themes": { + "items": [ + { + "title": "Demo", + "url": "/ows/qwc_demo", + "default": true, + "attribution": "Demo attribution", + "attributionUrl": "https://127.0.0.1/", + "backgroundLayers": [ + { + "name": "bluemarble", + "printLayer": "bluemarble_bg", + "visibility": true + }, + { + "name": "mapnik", + "printLayer": "osm_bg" + } + ], + "searchProviders": ["coordinates"], + "mapCrs": "EPSG:3857", + "additionalMouseCrs": [], + "extent": [-1000000, 4000000, 3000000, 8000000], + "skipEmptyFeatureAttributes": true, + "printResolutions": [300], + "thumbnail": "default.jpg" + } + ], + "backgroundLayers": [ + { + "name": "mapnik", + "title": "Open Street Map", + "type": "osm", + "source": "osm", + "thumbnail": "mapnik.jpg", + "attribution": "OpenStreetMap contributors", + "attributionUrl": "https://www.openstreetmap.org/copyright" + } + ] + } + }, + "custom_resource_types": [], + "services": [ + { + "name": "ogc", + "generator_config": { + "wms_services": { + "online_resources": { + "service": "http://localhost:8088/ows/", + "feature_info": "http://localhost:8088/ows/", + "legend": "http://localhost:8088/ows/" + } + } + }, + "config": { + "default_qgis_server_url": "http://qwc-qgis-server/ows/" + } + }, + { + "name": "mapViewer", + "generator_config": { + "qwc2_config": { + "qwc2_config_file": "../qwc-docker/volumes/qwc2/config.json", + "qwc2_index_file": "../qwc-docker/volumes/qwc2/index.html" + } + }, + "config": { + "qwc2_path": "/qwc2/", + "auth_service_url": "/auth/", + "data_service_url": "/api/v1/data/", + "#document_service_url": "/api/v1/document/", + "elevation_service_url": "/elevation/", + "#info_service_url": "/api/v1/featureinfo/", + "#legend_service_url": "/api/v1/legend/", + "mapinfo_service_url": "/api/v1/mapinfo/", + "ogc_service_url": "/ows/", + "permalink_service_url": "/api/v1/permalink/", + "#print_service_url": "/api/v1/print/", + "search_data_service_url": "/api/v1/data/", + "search_service_url": "/api/v2/search/" + } + }, + { + "name": "featureInfo", + "config": { + "default_qgis_server_url": "http://qwc-qgis-server/ows/" + } + }, + { + "name": "search", + "config": { + "solr_service_url": "http://qwc-solr:8983/solr/gdi/select", + "search_result_limit": 50, + "db_url": "postgresql:///?service=qwc_geodb" + }, + "resources": { + "facets": [ + { + "name": "background", + "filter_word": "Background" + }, + { + "name": "foreground", + "filter_word": "Map" + }, + { + "name": "ne_10m_admin_0_countries", + "filter_word": "Country", + "table_name": "qwc_geodb.search_v", + "geometry_column": "geom", + "facet_column": "subclass" + } + ] + }, + "permissions": [ + { + "role": "public", + "permissions": { + "dataproducts": [ + "qwc_demo" + ], + "solr_facets": [ + "foreground", + "ne_10m_admin_0_countries" + ] + } + } + ] + } + ] +} +``` + +For a full example see [tenantConfig-example.json](tenantConfig-example.json) ([JSON schema](schemas/qwc-config-generator.json)). + +*NOTE:* QWC2 themes are defined under `themesConfig` in the ConfigGenerator configuration and not in a separate file. + +QGIS projects can be automatically detected when `qgis_projects_scan_base_dir` is defined. +In order to have projects automatically added, the following settings need to be defined in `themesConfig`. + +- `defaultBackgroundLayers` +- `defaultSearchProviders` +- `defaultMapCrs` + +The ConfigGenerator can also autodetect thumbnails when adding projects. The projects have to meet the following criteria: + +- `qwc2_base_dir` is defined in the ConfigGenerator configuration +- the thumbnail of the project has to be located in the QWC2 thumbnail directory (Example: `/qwc/assets/img/mapthumbs`) +- the thumbnail image needs to have the same filename as the QGIS project + +*NOTE:* the Search service configuration takes its resources directly from the ConfigGenerator configuration. Its Permissions are collected from the ConfigDB (`solr_facet` resources), unless they are defined in the ConfigGenerator configuration. + +*NOTE:* the FeatureInfo service configuration may take additional WMS service resources and permissions directly from the ConfigGenerator configuration, e.g. for external info layers. Its Permissions are collected from the ConfigDB (`feature_info_service`, `feature_info_layer` resources), unless they are defined in the ConfigGenerator configuration. Example: + +```json + { + "name": "featureInfo", + "config": { + "default_qgis_server_url": "http://qwc-qgis-server/ows/" + }, + "resources": { + "wms_services": [ + { + "name": "external_info_layers", + "root_layer": { + "name": "external_info_layers", + "layers": [ + { + "name": "example_info_layer", + "title": "External info layer", + "attributes": [ + { + "name": "name" + }, + { + "name": "geometry" + } + ], + "info_template": { + "type": "wms", + "wms_url": "https://example.com/wms/demo" + } + } + ] + } + } + ] + }, + "permissions": [ + { + "role": "public", + "permissions": { + "wms_services": [ + { + "name": "external_info_layers", + "layers": [ + { + "name": "external_info_layers" + }, + { + "name": "example_info_layer", + "attributes": ["name", "geometry"], + "info_template": true + } + ] + } + ] + } + } + ] + } +``` + + +### Split categorized layers + +The ConfigGenerator has also the ability to split a layer, that has been [classified](https://docs.qgis.org/3.16/en/docs/training_manual/vector_classification/classification.html) with QGIS, into multiple layers and move them into a new group (the group name will be the original layer name). The following steps need to be done, to activate this functionality: + +1. Place the projects whose layers you want to split below `//qgis_projects`. + +2. Ensure `qgis_projects_gen_base_dir` is set in the ConfigGenerator configuration, see the [schema definition](https://github.com/qwc-services/qwc-config-generator/blob/master/schemas/qwc-config-generator.json) for more details. + +3. In the ConfigGenerator configuration set: `"split_categorized_layers": true` + +4. If necessary, define the environment variable `QGIS_APPLICATION_PREFIX_PATH` (default: `/usr`). The prefix path is the location where QGIS is installed on your system (the split function needs this, because it uses the `qgis.core` library) + +5. For all layers that you want to split, create the [variable](https://docs.qgis.org/3.22/en/docs/user_manual/working_with_vector/vector_properties.html#variables-properties) 'convert_categorized_layer' and set it to 'true'. + +6. The ConfigGenerator will process the projects and write the modified projects to qgis_projects_gen_base_dir`. Hence, if for instance qgis_projects_base_dir=/data` and `qgis_projects_gen_base_dir=/data/gen`, the resource name for map `mymap` will be `gen/mymap`. + +*NOTE:* If you are using the qwc-config-generator Docker images, make sure you are using `qwc-config-generator:v` and not `qwc-config-generator:v-noqgis`. + +### Schema validation + +By default, the ConfigGenerator will validate the service configurations in `tenantConfig.json` against the schema definition of the service. The JSON Schemas are loaded from local files in `JSON_SCHEMAS_PATH`, or else downloaded from https://github.com/qwc-services/ if no schema files are present. You can disable the schema validation by setting `"validate_schema": false` in the ConfigGenerator's `config` block in `tenantConfig.json`. + +### Permissions + +Using the `permissions_default_allow` setting, some resources can be set to be permitted or restricted by default if no permissions are set (default: `true`). Affected resources are `map`, `layer`, `print_template` and `viewer_task`. + +* i.e. `permissions_default_allow: true`: all maps, layers and attributes are permitted by default +* i.e. `permissions_default_allow: false`: maps and layers are only available if their resources and permissions are explicitly configured; though attributes are still permitted by default + +### Custom resource types + +If you want to define custom resource types for a custom service, you can add a record for the resource type to the configdb + + INSERT INTO qwc_config.resource_types(name, description, list_order) values ('', '', ); + +and then add it to the `custom_resource_types` setting. + + +Usage +----- + +### Script + +Show command options: + + python config_generator_cli.py --help + +Generate both service configs and permissions: + + python config_generator_cli.py ./tenantConfig.json all + +Generate service config files: + + python config_generator_cli.py ./tenantConfig.json service_configs + +Generate permissions file: + + python config_generator_cli.py ./tenantConfig.json permissions + +### Service + +Set the `INPUT_CONFIG_PATH` environment variable to the base directory where for the configuration files are that should be read by the ConfigGenerator (default: `config-in/`). +Set the `OUTPUT_CONFIG_PATH` environment variable to the base directory where the ConfigGenerator should output service configurations and permissions (default: `/tmp/`). + +*NOTE:* the ConfigGenerator's docker user (`www-data`) needs to have write permissions to the directory defined in `OUTPUT_CONFIG_PATH`! + +Base URL: + + http://localhost:5010/ + +Generate both service configs and permissions for `default` tenant: + + curl -X POST "http://localhost:5010/generate_configs?tenant=default" + +### Update JSON schemas + +You can change the directory from where the ConfigGenerator reads its schemas via the `JSON_SCHEMAS_PATH` environment variable (default `/tmp/`). +You can change the versions of the schemas that the ConfigGenerator uses for verification inside [schema-versions.json](schemas/schema-versions.json) (default: current `master`). + +Download JSON schemas: + + python download_json_schemas.py + + +Development +----------- + +Create a virtual environment: + + virtualenv --python=/usr/bin/python3 --system-site-package .venv + +Activate virtual environment: + + source .venv/bin/activate + +Install requirements (*NOTE:* additionally requires modules from `python-qgis`): + + pip install -r requirements.txt + +Run Demo-DB and QGIS Server: + + cd ../qwc-docker && docker-compose up -d qwc-postgis qwc-qgis-server + +Generate service configs and permissions for Docker: + + python config_generator_cli.py ./tenantConfig-example.json all diff --git a/content/installation/services/qwc-data-service.md b/content/installation/services/qwc-data-service.md new file mode 100644 index 00000000..8532a8eb --- /dev/null +++ b/content/installation/services/qwc-data-service.md @@ -0,0 +1,387 @@ ++++ +menuTitle = "qwc-data-service" +weight = 9 +chapter = false ++++ + +QWC Data Service +================ + +Edit spatial and unlocated features of datasets via GeoJSON. + +**Note:** requires a PostGIS database for reading and writing features + +Setup +----- + +Uses PostgreSQL connection service or connection to a PostGIS database. +This connection's user requires read and write access to the configured tables. + +### qwc_demo example + +Uses PostgreSQL connection service `qwc_geodb` (GeoDB). +The user `qwc_service_write` requires read and write access to the configured tables +of the data layers from the QGIS project `qwc_demo.qgs`. + +Setup PostgreSQL connection service file `~/.pg_service.conf`: + +``` +host=localhost +port=5439 +dbname=qwc_demo +user=qwc_service_write +password=qwc_service_write +sslmode=disable +``` + + +Configuration +------------- + +The static config and permission files are stored as JSON files in `$CONFIG_PATH` with subdirectories for each tenant, +e.g. `$CONFIG_PATH/default/*.json`. The default tenant name is `default`. + + +### Data Service config + +* [JSON schema](schemas/qwc-data-service.json) +* File location: `$CONFIG_PATH//dataConfig.json` + +Example: +```json +{ + "$schema": "https://raw.githubusercontent.com/qwc-services/qwc-data-service/v2/schemas/qwc-data-service.json", + "service": "data", + "config": { + "attachments_base_dir": "/tmp/qwc_attachments/", + "allowed_attachment_extensions": ".bmp,.jpg,.pdf", + "max_attachment_file_size": 10485760, + "upload_user_field_suffix": "uploaduser", + "edit_user_field": "edituser", + "edit_timestamp_field": "edittimestamp" + }, + "resources": { + "datasets": [ + { + "name": "qwc_demo.edit_points", + "db_url": "postgresql:///?service=qwc_geodb", + "schema": "qwc_geodb", + "table_name": "edit_points", + "primary_key": "id", + "fields": [ + { + "name": "id", + "data_type": "integer", + "constraints": { + "min": -2147483648, + "max": 2147483647 + } + }, + { + "name": "name", + "data_type": "character varying", + "constraints": { + "maxlength": 32 + } + }, + { + "name": "description", + "data_type": "text" + }, + { + "name": "num", + "data_type": "integer", + "constraints": { + "min": -2147483648, + "max": 2147483647 + } + }, + { + "name": "value", + "data_type": "double precision", + "constraints": { + "pattern": "[0-9]+([\\.,][0-9]+)?" + } + }, + { + "name": "type", + "data_type": "smallint", + "constraints": { + "min": -32768, + "max": 32767 + } + }, + { + "name": "amount", + "data_type": "numeric", + "constraints": { + "numeric_precision": 5, + "numeric_scale": 2, + "min": -999.99, + "max": 999.99, + "step": 0.01 + } + }, + { + "name": "validated", + "data_type": "boolean" + }, + { + "name": "datetime", + "data_type": "timestamp without time zone" + } + ], + "geometry": { + "geometry_column": "geom", + "geometry_type": "POINT", + "srid": 3857 + } + } + ] + } +} +``` + +### Permissions + +* [JSON schema](https://github.com/qwc-services/qwc-services-core/blob/master/schemas/qwc-services-permissions.json) +* File location: `$CONFIG_PATH//permissions.json` + +Example: +```json +{ + "$schema": "https://raw.githubusercontent.com/qwc-services/qwc-services-core/master/schemas/qwc-services-permissions.json", + "users": [ + { + "name": "demo", + "groups": ["demo"], + "roles": [] + } + ], + "groups": [ + { + "name": "demo", + "roles": ["demo"] + } + ], + "roles": [ + { + "role": "public", + "permissions": { + "data_datasets": [ + { + "name": "qwc_demo.edit_points", + "attributes": [ + "id", + "name", + "description", + "num", + "value", + "type", + "amount", + "validated", + "datetime" + ], + "writable": true, + "creatable": true, + "readable": true, + "updatable": true, + "deletable": true + } + ] + } + } + ] +} +``` + +### Overview + + QWC2 build: Public: + +--------------------+ +------------+ + | themesConfig.json | | | + | ^ +-----------> yarn build +----------------------------------> (themes.json) + | | | +---> | + | + +-----+ | +------------+ +---------------+ + | (edit.json) | | | | | + +--------------------+ | +------------------------+ QGIS Server +----------> WMS/WFS + | | Capabilities | | + +--------------------+ | | +------^--------+ + | ui Files +-----------------------------------------------------------> assets/*.ui + +--------------------+ | | | + | | | +------------------+ + +--------------------+ | | + | +--> html/js/css/assets + | qgs Files +--+-------------------------------> *.qgs +---------> qwc-map-viewer | + +--------------------+ | | | | | +--> config.json/themes.json + | | | | +------------------+ + | | | | + | | | | +------------------+ + | | | | | | REST-API + +---------+ | | | +---------> qwc-data-service <---------------> + | | | | | +------------+ | | | + | config- | | | +---> | + +------------------+ + | DB | +-------v--v-----> Config- +------> [service].json+permissions.json + | | | Generator | + | | | | + +---------+ +------------+ + +Edit forms: + +- Edit forms are automatically created from field information extracted from QGS files, according to the attribute form configuration: + * For autogenerated attribute forms, a flat edit form is in QWC2 + * Drag and Drop designer forms are automatically translated to Qt Designer forms in the `assets/forms/autogen` and loaded by QWC2 + * UI file are copied to the `assets/forms/autogen` folder and loaded by QWC2 + +- You can also manually create Qt Designer forms to use exclusively with QWC2 as follows: + * For the desired theme, add a block as follows in the theme block of the `tenantConfig.json`: + + "editConfig":{ + "":{ + "editDataset":".", + "layerName":"", + "geomType":"", + "form":":/forms/form.ui" + } + } + + Note: `:/` in the `form` property is resolved to the assets directory of the viewer. + * Create the designer form in Qt-Designer, using the dataset field names as edit widget names. +- *Note*: In general, for tables with an auto-incrementing primary key field, you'll want to set the attribute form widget type to "Hidden" in the QGIS layer properties. This way, the data-service won't block the commit if the feature is comitted with an empty PK field value. + +- Starting with qwc-map-viewer v2022.05.17, localized translation forms are supported. To this end, place a Qt Translation file called `_.ts` next to the designer form `.ui`, where `lang` is a language or language/country code, i.e. `en` or `en-US`. There is a [`translateui.sh`](https://github.com/qgis/qwc2/tree/master/scripts/translateui.sh) script to help generate the translation files. Example: + + ./translateui.sh <...>/qwc2/assets/forms/form.ui de it fr + + +File uploads: + +- For Autogenerated and Drag and Drop designer forms, set the widget type to Attachment. You can set the file type filter in the widget configuration under `Display button to open file dialog -> Filter`. +- For manually created Qt Designed Ui forms, use a `QLineEdit` widget named `__upload`, and optionally as the text value of the `QLineEdit` set a comma separated list of suggested file extensions. +- *Note*: Make sure the client uses the EditingInterface.js shipped with [QWC2 submodule f053fdc or newer](https://github.com/qgis/qwc2/commit/f053fdceba4a2d8112fb516c793702b9fd118609) to support file uploads. +- You can set the allowed attachment extensions and maximum file sizes globally by setting `allowed_attachment_extensions` and `max_attachment_file_size` in the data service configuration. +- You can also set the allowed attachment extensions and maximum file sizes per dataset by setting `max_attachment_file_size_per_dataset` and `allowed_extensions_per_dataset` in the dataset service configuration. If you set the per dataset values, the global settings will be disregarded (i.e. if a attachment satisfies the per dataset constraint it will be considered valid, even if it violates the global constraint). + +Logging mutations: + +- If you set `upload_user_field_suffix` in the data service config, the username of the last user who performed a mutation to `` will be logged to `__`. +- If you set `edit_user_field` in the data service config, the username of the last user who performed a mutation to a record with be logged to the `` field of the record. +- If you set `edit_timestamp_field` in the data service config, the timestamp of the last mutation to a record will be logged to the `` field of the record. + +Note: for these fields to be written, ensure the qgis project is also up-to-date, i.e. that contain the up-to-date table schemas. You can set the respective field types to hidden in the QGIS layer properties to avoid them showing up in the autogenerated edit forms. + +1:N relations: + +- For autogenerated and Drag and Drop designer forms, configure the 1-N relation in the QGIS project properties. +- In a manually created Qt-Designer Ui form, create a widget of type `QWidget`, `QGroupBox` or `QFrame` named according to the pattern `nrel____`, where `` is the name of the relation table and `` the name of the foreign key field in the relation table. +- In a manually created Qt-Designer Ui form, you can also specify a sort column for the 1:N relation in the form `nrel______`. If a sort-column is specified, QWC2 will display sort arrows for each entry in the relation widget. +- Inside this widget, add the edit widgets for the values of the relation table. Name the widgets `__`. These edit widgets will be replicated for each relation record. +- *Note:* The relation table needs to be added as a (geometryless) table to the QGIS Project. You also need to set appropriate permissions for the relation table dataset in the QWC admin backend. + +Key-value relations: + +- For Drag and Drop designer forms, use widgets of type Value Relation. In the generated designer form, the naming convention indicated below is used. +- In a manually created Qt-Designer Ui form, you can use key-value relations for combo box entries by naming the `QComboBox` widget according to the following pattern: `kvrel________`. `` refers to a table containing a field called `` for the value of the entry and a field `` for the label of the entry. For key-value relations inside a 1:N relation, use `kvrel__________`. `` +- *Note:* In any case, the relation table needs to be added as a (geometryless) table to the QGIS Project. You also need to set appropriate permissions for the relation table dataset in the QWC admin backend. Alternatively, you can set `"autogen_keyvaltable_datasets": true` in the config generator configuration, to automatically generate resources and read-only permissions as required. + +Special form widgets: + +- In manually created Qt-Designer Ui forms, there are a number of special widgets you can define: + + * *Images*: To display attribute values which contain an image URL as an inline image, use a `QLabel` named `img__`. + * *Linked features*: To display a button to choose a linked feature and edit it's attributes in a nested edit form, create a `QPushButton` named `featurelink____` (simple join) or `featurelink______` in a 1:N relation. In a 1:N relation, `linkdataset` can be equal to `reltable` to edit the relation record itself in the nested form. `fieldname` will contain the `id` of the linked feature. + * *External fields*: Some times it is useful to display information from an external source in the edit form. This can be accomplished by creating a `QWidget` with name `ext__` and using a form preprocessor hook (see `registerFormPreprocessor` in [`QtDesignerForm.jsx`](https://github.com/qgis/qwc2/blob/master/components/QtDesignerForm.jsx) to populate the field by assigning a React fragment to `formData.externalFields.`. + * *Buttons*: To add a button with a custom action, add a `QPushButton` with name `btn__`, and use a form preprocessor hook to set the custom function to `formData.buttons.buttonname.onClick`. + +Data service configuration: + +- DB connection information, table and column names and primary key information are extracted from QGS files +- Data contraints are extracted from QGS files +- Column types and additional constraints are read from the the geo-DB + +Data read/write: + +- QWC2 issues data-service API requests for reading und writing + + +Usage +----- + +Set the `CONFIG_PATH` environment variable to the path containing the service config and permission files when starting this service (default: `config`). + +Base URL: + + http://localhost:5012/ + +Service API: + + http://localhost:5012/api/ + +Sample requests: + + curl 'http://localhost:5012/qwc_demo.edit_points/' + + +Docker usage +------------ + +To run this docker image you will need a PostGIS database. For testing purposes you can use the demo DB. + +The following steps explain how to download the demo DB docker image and how to run the `qwc-data-service` with `docker-compose`. + +**Step 1: Clone qwc-docker** + + git clone https://github.com/qwc-services/qwc-docker + cd qwc-docker + +**Step 2: Create docker-compose.yml file** + + cp docker-compose-example.yml docker-compose.yml + +**Step 3: Start docker containers** + + docker-compose up qwc-data-service + +For more information please visit: https://github.com/qwc-services/qwc-docker + +Development +----------- + +Create a virtual environment: + + virtualenv --python=/usr/bin/python3 --system-site-packages .venv + +Without system packages: + + virtualenv --python=/usr/bin/python3 .venv + +Activate virtual environment: + + source .venv/bin/activate + +Install requirements: + + pip install -r requirements.txt + +Start local service: + + CONFIG_PATH=/PATH/TO/CONFIGS/ python server.py + + +Testing +------- + +Run all tests: + + python test.py + +Run single test module: + + python -m unittest tests.feature_validation_tests + +Run single test case: + + python -m unittest tests.feature_validation_tests.FeatureValidationTestCase + +Run single test method: + + python -m unittest tests.feature_validation_tests.FeatureValidationTestCase.test_field_constraints diff --git a/content/installation/services/qwc-document-service.md b/content/installation/services/qwc-document-service.md new file mode 100644 index 00000000..f8f6d09d --- /dev/null +++ b/content/installation/services/qwc-document-service.md @@ -0,0 +1,136 @@ ++++ +menuTitle = "qwc-document-service" +weight = 10 +chapter = false ++++ + +Document service +================ + +The document service delivers reports from the Jasper reporting service with permission control. + + +Dependencies +------------ + +* [Jasper reporting service](https://github.com/qwc-services/jasper-reporting-service/) + + +Configuration +------------- + +The static config files are stored as JSON files in `$CONFIG_PATH` with subdirectories for each tenant, +e.g. `$CONFIG_PATH/default/*.json`. The default tenant name is `default`. + +### JSON config + +* [JSON schema](schemas/qwc-document-service.json) +* File location: `$CONFIG_PATH//documentConfig.json` + +Example: +```json +{ + "$schema": "https://raw.githubusercontent.com/qwc-services/qwc-document-service/master/schemas/qwc-document-service.json", + "service": "document", + "config": { + "jasper_service_url": "http://localhost:8002/reports", + "jasper_timeout": 60 + }, + "resources": { + "document_templates": [ + { + "template": "demo", + "report_filename": "PieChartReport" + } + ] + } +} +``` + +### Environment variables + +Config options in the config file can be overridden by equivalent uppercase environment variables. + +Environment variables: + +| Variable | Description | Default value | +|----------------------|----------------------------|-------------------------------| +| `JASPER_SERVICE_URL` | Jasper Reports service URL | http://localhost:8002/reports | +| `JASPER_TIMEOUT` | Timeout (s) | 60 | + + +Usage +----- + +API documentation: + + http://localhost:5018/api/ + +Request format: + + http://localhost:5018/