From b7e20169e76df30dc6c263eb87b2904c05148b54 Mon Sep 17 00:00:00 2001 From: Sandro Mani Date: Tue, 24 Oct 2023 17:00:12 +0200 Subject: [PATCH] Rework QWC Config DB setup: * Move migrations to qwc-base-db * Introduce qwc-base-db-migrate image to migrate dockerized or external config DB * Demo data will be initialized by an optional setup script in qwc-docker --- .github/workflows/qwc-base-db.yml | 23 +++- Dockerfile | 56 ++------- Dockerfile.migrate | 14 +++ README.md | 109 +++++++++--------- alembic.ini | 75 ++++++++++++ alembic/env.py | 74 ++++++++++++ alembic/script.py.mako | 24 ++++ ...352a94313d6_create_user_bookmarks_table.py | 41 +++++++ .../0f409f15e0b7_create_user_infos.py | 43 +++++++ ...ee212_insert_plugin_data_resource_types.py | 44 +++++++ .../217f272b9c26_add_data_to_resource_type.py | 62 ++++++++++ ...increase_length_of_totp_secret_in_users.py | 36 ++++++ ...84dd72_insert_viewer_task_resource_type.py | 38 ++++++ .../56846d9f2753_insert_admin_user.py | 45 ++++++++ .../5c9dccb16fc2_create_permalinks_table.py | 39 +++++++ ...cb_refactor_resource_type_enum_to_table.py | 82 +++++++++++++ ...75aa9290232_insert_viewer_resource_type.py | 38 ++++++ ...65_insert_theme_info_link_resource_type.py | 38 ++++++ .../90b3b4fbc8f6_add_totp_secret_to_users.py | 36 ++++++ ...93625bd_insert_solr_facet_resource_type.py | 38 ++++++ ...sign_in_timestamp_and_attempts_to_users.py | 40 +++++++ ...create_users_groups_roles_and_relations.py | 94 +++++++++++++++ ...nsert_more_detailed_data_resource_types.py | 56 +++++++++ .../ad5e7b02469a_create_password_histories.py | 51 ++++++++ ...b3dfe_add_reset_password_token_to_users.py | 36 ++++++ ...053154_create_resources_and_permissions.py | 63 ++++++++++ ...ert_feature_info_service_resource_types.py | 46 ++++++++ .../db5a31995054_create_last_update.py | 39 +++++++ ...e9c31b610e0a_create_registration_tables.py | 63 ++++++++++ ...266_insert_print_template_resource_type.py | 38 ++++++ .../f805e8e4a791_insert_public_role.py | 35 ++++++ er-diagram.png | Bin 0 -> 109783 bytes install-alembic-and-clone-qwc-config-db.sh | 25 ---- install-postgis.sh | 20 ---- pg_service.conf | 6 + run-migrations.sh | 6 - setup-roles-and-db.sh | 17 +-- 37 files changed, 1417 insertions(+), 173 deletions(-) create mode 100644 Dockerfile.migrate create mode 100644 alembic.ini create mode 100644 alembic/env.py create mode 100644 alembic/script.py.mako create mode 100644 alembic/versions/0352a94313d6_create_user_bookmarks_table.py create mode 100644 alembic/versions/0f409f15e0b7_create_user_infos.py create mode 100644 alembic/versions/0fa6610ee212_insert_plugin_data_resource_types.py create mode 100644 alembic/versions/217f272b9c26_add_data_to_resource_type.py create mode 100644 alembic/versions/46eeef9d6787_increase_length_of_totp_secret_in_users.py create mode 100644 alembic/versions/4ff55a84dd72_insert_viewer_task_resource_type.py create mode 100644 alembic/versions/56846d9f2753_insert_admin_user.py create mode 100644 alembic/versions/5c9dccb16fc2_create_permalinks_table.py create mode 100644 alembic/versions/60c460c23acb_refactor_resource_type_enum_to_table.py create mode 100644 alembic/versions/875aa9290232_insert_viewer_resource_type.py create mode 100644 alembic/versions/8c5ebe688265_insert_theme_info_link_resource_type.py create mode 100644 alembic/versions/90b3b4fbc8f6_add_totp_secret_to_users.py create mode 100644 alembic/versions/9168093625bd_insert_solr_facet_resource_type.py create mode 100644 alembic/versions/916ed45fa0ba_add_sign_in_timestamp_and_attempts_to_users.py create mode 100644 alembic/versions/9c671585cfb1_create_users_groups_roles_and_relations.py create mode 100644 alembic/versions/a793057bbf20_insert_more_detailed_data_resource_types.py create mode 100644 alembic/versions/ad5e7b02469a_create_password_histories.py create mode 100644 alembic/versions/b0cb86db3dfe_add_reset_password_token_to_users.py create mode 100644 alembic/versions/b21139053154_create_resources_and_permissions.py create mode 100644 alembic/versions/c77774920e5b_insert_feature_info_service_resource_types.py create mode 100644 alembic/versions/db5a31995054_create_last_update.py create mode 100644 alembic/versions/e9c31b610e0a_create_registration_tables.py create mode 100644 alembic/versions/f2681d70c266_insert_print_template_resource_type.py create mode 100644 alembic/versions/f805e8e4a791_insert_public_role.py create mode 100644 er-diagram.png delete mode 100755 install-alembic-and-clone-qwc-config-db.sh delete mode 100755 install-postgis.sh create mode 100644 pg_service.conf delete mode 100755 run-migrations.sh diff --git a/.github/workflows/qwc-base-db.yml b/.github/workflows/qwc-base-db.yml index 9acd77a..ff642e1 100644 --- a/.github/workflows/qwc-base-db.yml +++ b/.github/workflows/qwc-base-db.yml @@ -1,4 +1,4 @@ -name: Publish qwc-base-db docker image +name: Publish qwc-base-db docker images on: [push] @@ -6,6 +6,7 @@ jobs: build: runs-on: ubuntu-latest + if: github.event_name == 'push' && contains(github.ref, 'refs/tags/') steps: - uses: actions/checkout@master @@ -13,17 +14,27 @@ jobs: - name: Get version tag id: get_tag run: | - if [ ${{ startsWith(github.ref, 'refs/tags/') }} = true ]; then - echo ::set-output name=tag::${GITHUB_REF:10} + if [ ${{ endsWith(github.ref, '-lts') }} = true ]; then + echo "tag=latest-lts,${GITHUB_REF:10}" >>$GITHUB_OUTPUT else - echo ::set-output name=tag:: + echo "tag=latest,${GITHUB_REF:10}" >>$GITHUB_OUTPUT fi - - name: Build and publish docker image + - name: Build and publish qwc-base-db docker image uses: elgohr/Publish-Docker-Github-Action@v5 with: name: sourcepole/qwc-base-db username: ${{ secrets.DOCKER_HUB_USER }} password: ${{ secrets.DOCKER_HUB_PASSWORD }} - tags: "latest,${{ steps.get_tag.outputs.tag }}" + tags: "${{ steps.get_tag.outputs.tag }}" workdir: . + + - name: Build and publish qwc-base-db-migrate docker image + uses: elgohr/Publish-Docker-Github-Action@v5 + with: + name: sourcepole/qwc-base-db-migrate + username: ${{ secrets.DOCKER_HUB_USER }} + password: ${{ secrets.DOCKER_HUB_PASSWORD }} + tags: "${{ steps.get_tag.outputs.tag }}" + workdir: . + dockerfile: Dockerfile.migrate diff --git a/Dockerfile b/Dockerfile index 1a6bb51..f9940b4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,59 +1,21 @@ -# QWC Services base DB -# -# This is mostly the same as setup-external-db.sh -# -# PLEASE KEEP IN SYNC -# -# container ready to serve data from /data volume: -# -# - includes postgres server with postgis -# - *on start* will check whether migration is needed. -# If migration is needed: -# - will set up config-db -# -# Please set ALEMBIC_VERSION to a specific commit hash -# in the docker image runtime environment, if you want -# to check out and run a different version of -# qwc-config-db migrations than those from `head`. -# See the `run-migrations.sh`. +# A postgres DB with the minimal QWC config DB setup -FROM postgres:13 +FROM postgres:15 -ENV DEBIAN_FRONTEND=noninteractive +ENV PGDATA=/var/lib/postgresql/docker +ENV POSTGRES_PASSWORD= -ARG PG_MAJOR=13 +ARG PG_MAJOR=15 ARG POSTGIS_VERSION=3 -ARG GIT_REPO=https://github.com/qwc-services/qwc-config-db.git - -ENV PGSERVICEFILE=/tmp/.pg_service.conf - -COPY install-postgis.sh install-alembic-and-clone-qwc-config-db.sh /usr/local/bin/ -RUN cd /usr/local/bin && \ - chmod +x install-postgis.sh install-alembic-and-clone-qwc-config-db.sh - +# Install postgis RUN \ - export PATH=/usr/local/bin:/usr/bin:/bin && \ apt-get update && \ - apt-get upgrade -y && \ - /usr/local/bin/install-postgis.sh $PG_MAJOR $POSTGIS_VERSION && \ - /usr/local/bin/install-alembic-and-clone-qwc-config-db.sh $GIT_REPO && \ + apt-get install -y curl postgresql-$PG_MAJOR-postgis-$POSTGIS_VERSION postgresql-$PG_MAJOR-postgis-$POSTGIS_VERSION-scripts && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* -#RUN localedef -i de_CH -c -f UTF-8 -A /usr/share/locale/locale.alias de_CH.UTF-8 -#ENV LANG de_CH.utf8 - - -# setup database +# Setup database # script to create DB, roles, grants etc COPY setup-roles-and-db.sh /docker-entrypoint-initdb.d/0_setup-db.sh - -# script to create tables -COPY run-migrations.sh /docker-entrypoint-initdb.d/1_run-migrations.sh - -RUN chmod +x /docker-entrypoint-initdb.d/*.sh -RUN cp -a /usr/local/bin/docker-entrypoint.sh /tmp/docker-entrypoint.sh - -ENV PGDATA /var/lib/postgresql/docker -ENV POSTGRES_PASSWORD U6ZqsEdBmrER +RUN chmod +x /docker-entrypoint-initdb.d/0_setup-db.sh diff --git a/Dockerfile.migrate b/Dockerfile.migrate new file mode 100644 index 0000000..9f4ff05 --- /dev/null +++ b/Dockerfile.migrate @@ -0,0 +1,14 @@ +# Helper image to run qwc-config-db migrations +FROM alpine:3.18 + +ENV PGSERVICEFILE=/tmp/pg_service.conf +ENV ALEMBIC_VERSION=head + +RUN apk add --no-cache --update py3-alembic py3-psycopg2 + +COPY pg_service.conf /tmp/pg_service.conf +COPY alembic.ini /tmp/alembic.ini +COPY alembic /tmp/alembic + +WORKDIR /tmp +ENTRYPOINT ["/bin/sh", "-c", "PGSERVICE=qwc_configdb alembic upgrade ${ALEMBIC_VERSION}"] diff --git a/README.md b/README.md index 8c17ec8..69ec9ed 100644 --- a/README.md +++ b/README.md @@ -1,76 +1,71 @@ [![CI](https://github.com/qwc-services/qwc-base-db/actions/workflows/qwc-base-db.yml/badge.svg)](https://github.com/qwc-services/qwc-base-db/actions) [![docker](https://img.shields.io/docker/v/sourcepole/qwc-base-db?label=qwc-base-db%20image&sort=semver)](https://hub.docker.com/r/sourcepole/qwc-base-db) -QWC base DB -============ - -This repository creates a Docker image with a postgres server -that can be used by QWC. - -The image contains the postgres server, the postgis extension, -and scripts to set up the `qwc_configdb` configuration database -and scripts to insert the demo data. +QWC Base DB +=========== + +This repository creates two Docker images: + +* `qwc-base-db`: Image with a postgis server and the minimal schemas and roles for the QWC Config DB +* `qwc-base-db-migrate`: Image containing `alembic` and the migrations to update the QWC Config DB to the latest schema + +These images are designed to be configured in a `docker-compose.yml` as follows (minimal configuration): + +```yml + qwc-postgis: + image: sourcepole/qwc-base-db: + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 10s + environment: + POSTGRES_PASSWORD: '' # TODO: Set your postgres password here! + volumes: + - ./volumes/db:/var/lib/postgresql/docker + + qwc-config-db-migrate: + image: sourcepole/qwc-base-db-migrate: + depends_on: + qwc-postgis: + condition: service_healthy +``` -When the image is run, then it checks whether the directory -referenced by the `$PGDATA` ENV variable is empty. If that's -the case then it will proceed with setting up the -`qwc_configdb` DB and adding demo data to the `qwc_demo` DB. +Note: -The default value for `$PGDATA` ENV is `/var/lib/postgresql/docker`. +* **You need to set a non-empty `POSTGRES_PASSWORD` ENV variable**. +* For persistent storage, mount folder volume to `/var/lib/postgresql/docker`. -The https://github.com/qwc-services/qwc-demo-db repository -uses this image to create another container image with a -ready to use database filled with demo data for easy trying -out QWC2. +When the `qwc-postgis` image is run, then it checks whether `/var/lib/postgresql/docker` is empty. +If that's the case then it will proceed with setting up the +`qwc_configdb` DB. -Usage ------ +The `qwc-config-db-migrate` image will run `qwc-postgis` is up, and will apply all available migrations to the Config DB. -### The Docker container image +# Keeping the Config DB up-to-date -The qwc-base-db Docker image is based on the -[official Postgres Docker container image](https://hub.docker.com/_/postgres/). -The mechanisms discussed below are based on those -provided by the Postgres Docker image. Please -see at the mentioned link. +To keep the Config DB up to date, it is sufficient to update the `qwc-base-db-migrate` image version to the latest available version. -The qwc-base-db Docker container image meant to be used like this: +Migrations will be applied automatically, if necessary, whenever the Docker application is started. - $ cat docker-compose.yml - version: '2.1' - services: - qwc-postgis: - image: sourcepole/qwc-base-db - environment: - - ALEMBIC_VERSION=head - - PGDATA=/var/lib/postgresql/data/pgdata - healthcheck: - test: ["CMD-SHELL", "pg_isready -U postgres"] - interval: 10s - ports: - - "0.0.0.0:5432:5432" - volumes: - - ./volumes/postgres-data:/var/lib/postgresql/data - [...] +To upgrade to a migration different than `head`, set the `ALEMBIC_VERSION` ENV variable. -Upon start, the container will check whether `/var/lib/postgresql/data` -is empty. +# Managing an external Config DB -#### starting with an empty `/var/lib/postgresql/data` volume +You can use an external DB instead of the `qwc-base-db` dockerized DB. -If `/var/lib/postgresql/data` is empty, then postgres will initialize it -and execute scripts under `/docker-entrypoint-initdb.d` that will set up -a `qwc_demo` DB and fill it with demo data. +To set up the external DB, run the SQL commands in `setup-roles-and-db.sh` on your external DB. -#### starting with an non-empty `/var/lib/postgresql/data` volume +To apply the migrations, both as part as the initial setup and subsequently to keep the Config DB up-to-date: -If `/var/lib/postgresql/data` is *NOT* empty, such as when: +* Modify the `qwc_configdb` connection in `pg_service.conf` with the connection information to your external DB +* Configure the `qwc-config-db-migrate` image mounting the modified `pg_service.conf`: -* the container had already been started in the past and had already - initialized the the DB inside the provided volume or +```yml + qwc-config-db-migrate: + image: sourcepole/qwc-base-db-migrate: + volumes: + ./pg_service.conf:/tmp/pg_service.conf:ro +``` -* the admin has attached a volume to the container that had some - other postgres database in it +# DB Schema overview -then postgres will just start and try to use the data that is already -under `/var/lib/postgresql/data`. +![er-diagram](er-diagram.png) diff --git a/alembic.ini b/alembic.ini new file mode 100644 index 0000000..0e04b0b --- /dev/null +++ b/alembic.ini @@ -0,0 +1,75 @@ +# A generic, single database configuration. + +[alembic] +# path to migration scripts +script_location = alembic + +# template used to generate migration files +# file_template = %%(rev)s_%%(slug)s + +# timezone to use when rendering the date +# within the migration file as well as the filename. +# string value is passed to dateutil.tz.gettz() +# leave blank for localtime +# timezone = + +# max length of characters to apply to the +# "slug" field +#truncate_slug_length = 40 + +# set to 'true' to run the environment during +# the 'revision' command, regardless of autogenerate +# revision_environment = false + +# set to 'true' to allow .pyc and .pyo files without +# a source .py file to be detected as revisions in the +# versions/ directory +# sourceless = false + +# version location specification; this defaults +# to alembic/versions. When using multiple version +# directories, initial revisions must be specified with --version-path +# version_locations = %(here)s/bar %(here)s/bat alembic/versions + +# the output encoding used when revision files +# are written from script.py.mako +# output_encoding = utf-8 + +sqlalchemy.url = postgresql:///?service=qwc_configdb +version_table_schema = qwc_config + + +# Logging configuration +[loggers] +keys = root,sqlalchemy,alembic + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = WARN +handlers = console +qualname = + +[logger_sqlalchemy] +level = WARN +handlers = +qualname = sqlalchemy.engine + +[logger_alembic] +level = INFO +handlers = +qualname = alembic + +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = NOTSET +formatter = generic + +[formatter_generic] +format = %(levelname)-5.5s [%(name)s] %(message)s +datefmt = %H:%M:%S diff --git a/alembic/env.py b/alembic/env.py new file mode 100644 index 0000000..02c2959 --- /dev/null +++ b/alembic/env.py @@ -0,0 +1,74 @@ +from __future__ import with_statement +from alembic import context +from sqlalchemy import engine_from_config, pool +from logging.config import fileConfig + +# this is the Alembic Config object, which provides +# access to the values within the .ini file in use. +config = context.config + +# Interpret the config file for Python logging. +# This line sets up loggers basically. +fileConfig(config.config_file_name) + +# add your model's MetaData object here +# for 'autogenerate' support +# from myapp import mymodel +# target_metadata = mymodel.Base.metadata +target_metadata = None + +# other values from the config, defined by the needs of env.py, +# can be acquired: +# my_important_option = config.get_main_option("my_important_option") +# ... etc. + + +def run_migrations_offline(): + """Run migrations in 'offline' mode. + + This configures the context with just a URL + and not an Engine, though an Engine is acceptable + here as well. By skipping the Engine creation + we don't even need a DBAPI to be available. + + Calls to context.execute() here emit the given string to the + script output. + + """ + url = config.get_main_option("sqlalchemy.url") + version_table_schema = config.get_main_option("version_table_schema") + context.configure( + url=url, version_table_schema=version_table_schema, + target_metadata=target_metadata, literal_binds=True) + + with context.begin_transaction(): + context.run_migrations() + + +def run_migrations_online(): + """Run migrations in 'online' mode. + + In this scenario we need to create an Engine + and associate a connection with the context. + + """ + connectable = engine_from_config( + config.get_section(config.config_ini_section), + prefix='sqlalchemy.', + poolclass=pool.NullPool) + + with connectable.connect() as connection: + version_table_schema = config.get_main_option("version_table_schema") + context.configure( + connection=connection, + version_table_schema=version_table_schema, + target_metadata=target_metadata + ) + + with context.begin_transaction(): + context.run_migrations() + +if context.is_offline_mode(): + run_migrations_offline() +else: + run_migrations_online() diff --git a/alembic/script.py.mako b/alembic/script.py.mako new file mode 100644 index 0000000..2c01563 --- /dev/null +++ b/alembic/script.py.mako @@ -0,0 +1,24 @@ +"""${message} + +Revision ID: ${up_revision} +Revises: ${down_revision | comma,n} +Create Date: ${create_date} + +""" +from alembic import op +import sqlalchemy as sa +${imports if imports else ""} + +# revision identifiers, used by Alembic. +revision = ${repr(up_revision)} +down_revision = ${repr(down_revision)} +branch_labels = ${repr(branch_labels)} +depends_on = ${repr(depends_on)} + + +def upgrade(): + ${upgrades if upgrades else "pass"} + + +def downgrade(): + ${downgrades if downgrades else "pass"} diff --git a/alembic/versions/0352a94313d6_create_user_bookmarks_table.py b/alembic/versions/0352a94313d6_create_user_bookmarks_table.py new file mode 100644 index 0000000..a176c85 --- /dev/null +++ b/alembic/versions/0352a94313d6_create_user_bookmarks_table.py @@ -0,0 +1,41 @@ +"""create user bookmarks table + +Revision ID: 0352a94313d6 +Revises: c77774920e5b +Create Date: 2021-04-15 14:58:38.844986 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '0352a94313d6' +down_revision = 'c77774920e5b' +branch_labels = None +depends_on = None + + +def upgrade(): + sql = sa.sql.text(""" + CREATE TABLE qwc_config.user_bookmarks ( + username character varying NOT NULL, + data text, + key varchar(10), + date date, + description text, + PRIMARY KEY(username, key) + ); + """) + + conn = op.get_bind() + conn.execute(sql) + + +def downgrade(): + sql = sa.sql.text(""" + DROP TABLE qwc_config.user_bookmarks; + """) + + conn = op.get_bind() + conn.execute(sql) diff --git a/alembic/versions/0f409f15e0b7_create_user_infos.py b/alembic/versions/0f409f15e0b7_create_user_infos.py new file mode 100644 index 0000000..77e4ffa --- /dev/null +++ b/alembic/versions/0f409f15e0b7_create_user_infos.py @@ -0,0 +1,43 @@ +"""Create user_infos + +Add additional user fields in a separate qwc_config.table user_infos +with a one-to-one relation to qwc_config.users. + +Revision ID: 0f409f15e0b7 +Revises: b0cb86db3dfe +Create Date: 2018-12-17 10:59:38.886407 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '0f409f15e0b7' +down_revision = 'b0cb86db3dfe' +branch_labels = None +depends_on = None + + +def upgrade(): + sql = sa.sql.text(""" + CREATE TABLE qwc_config.user_infos ( + user_id integer NOT NULL, + CONSTRAINT user_infos_pk PRIMARY KEY (user_id), + CONSTRAINT user_fk FOREIGN KEY (user_id) + REFERENCES qwc_config.users (id) MATCH FULL + ON UPDATE CASCADE ON DELETE RESTRICT + ); + """) + + conn = op.get_bind() + conn.execute(sql) + + +def downgrade(): + sql = sa.sql.text(""" + DROP TABLE qwc_config.user_infos CASCADE; + """) + + conn = op.get_bind() + conn.execute(sql) diff --git a/alembic/versions/0fa6610ee212_insert_plugin_data_resource_types.py b/alembic/versions/0fa6610ee212_insert_plugin_data_resource_types.py new file mode 100644 index 0000000..c71d473 --- /dev/null +++ b/alembic/versions/0fa6610ee212_insert_plugin_data_resource_types.py @@ -0,0 +1,44 @@ +"""Insert plugin data resource types + +Revision ID: 0fa6610ee212 +Revises: 8c5ebe688265 +Create Date: 2020-08-13 11:06:10.456910 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '0fa6610ee212' +down_revision = '8c5ebe688265' +branch_labels = None +depends_on = None + + +def upgrade(): + sql = sa.sql.text(""" + INSERT INTO qwc_config.resource_types (name, description, list_order) + VALUES ( + 'plugin', 'Plugin', + (SELECT MAX(list_order) + 1 FROM qwc_config.resource_types) + ); + INSERT INTO qwc_config.resource_types (name, description, list_order) + VALUES ( + 'plugin_data', 'Plugin data', + (SELECT MAX(list_order) + 1 FROM qwc_config.resource_types) + ); + """) + + conn = op.get_bind() + conn.execute(sql) + + +def downgrade(): + sql = sa.sql.text(""" + DELETE FROM qwc_config.resource_types WHERE name = 'plugin'; + DELETE FROM qwc_config.resource_types WHERE name = 'plugin_data'; + """) + + conn = op.get_bind() + conn.execute(sql) diff --git a/alembic/versions/217f272b9c26_add_data_to_resource_type.py b/alembic/versions/217f272b9c26_add_data_to_resource_type.py new file mode 100644 index 0000000..3e19ae3 --- /dev/null +++ b/alembic/versions/217f272b9c26_add_data_to_resource_type.py @@ -0,0 +1,62 @@ +"""add data to resource_type + +Revision ID: 217f272b9c26 +Revises: db5a31995054 +Create Date: 2018-07-24 11:10:35.963663 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '217f272b9c26' +down_revision = 'db5a31995054' +branch_labels = None +depends_on = None + + +def upgrade(): + # NOTE: recreate resource_type, as the following does not work inside + # a transaction: + # + # ALTER TYPE qwc_config.resource_type + # ADD VALUE 'data' AFTER 'attribute'; + sql = sa.sql.text(""" + ALTER TYPE qwc_config.resource_type + RENAME TO resource_type_old; + + CREATE TYPE qwc_config.resource_type AS + ENUM ('map', 'layer', 'attribute', 'data'); + + ALTER TABLE qwc_config.resources + ALTER COLUMN type TYPE qwc_config.resource_type + USING type::text::qwc_config.resource_type; + + DROP TYPE qwc_config.resource_type_old; + """) + + conn = op.get_bind() + conn.execute(sql) + + +def downgrade(): + # NOTE: removes resources of type 'data' + sql = sa.sql.text(""" + DELETE FROM qwc_config.resources WHERE type = 'data'; + + ALTER TYPE qwc_config.resource_type + RENAME TO resource_type_old; + + CREATE TYPE qwc_config.resource_type AS + ENUM ('map', 'layer', 'attribute'); + + ALTER TABLE qwc_config.resources + ALTER COLUMN type TYPE qwc_config.resource_type + USING type::text::qwc_config.resource_type; + + DROP TYPE qwc_config.resource_type_old; + """) + + conn = op.get_bind() + conn.execute(sql) diff --git a/alembic/versions/46eeef9d6787_increase_length_of_totp_secret_in_users.py b/alembic/versions/46eeef9d6787_increase_length_of_totp_secret_in_users.py new file mode 100644 index 0000000..6181e5a --- /dev/null +++ b/alembic/versions/46eeef9d6787_increase_length_of_totp_secret_in_users.py @@ -0,0 +1,36 @@ +"""Increase length of TOTP secret in users + +Revision ID: 46eeef9d6787 +Revises: ad5e7b02469a +Create Date: 2022-04-20 13:30:44.304793 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '46eeef9d6787' +down_revision = 'ad5e7b02469a' +branch_labels = None +depends_on = None + + +def upgrade(): + sql = sa.sql.text(""" + ALTER TABLE qwc_config.users + ALTER COLUMN totp_secret TYPE character varying(128); + """) + + conn = op.get_bind() + conn.execute(sql) + + +def downgrade(): + sql = sa.sql.text(""" + ALTER TABLE qwc_config.users + ALTER COLUMN totp_secret TYPE character varying(16); + """) + + conn = op.get_bind() + conn.execute(sql) diff --git a/alembic/versions/4ff55a84dd72_insert_viewer_task_resource_type.py b/alembic/versions/4ff55a84dd72_insert_viewer_task_resource_type.py new file mode 100644 index 0000000..ed95355 --- /dev/null +++ b/alembic/versions/4ff55a84dd72_insert_viewer_task_resource_type.py @@ -0,0 +1,38 @@ +"""Insert viewer_task resource type + +Revision ID: 4ff55a84dd72 +Revises: a793057bbf20 +Create Date: 2019-01-09 16:40:45.622573 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '4ff55a84dd72' +down_revision = 'a793057bbf20' +branch_labels = None +depends_on = None + + +def upgrade(): + sql = sa.sql.text(""" + INSERT INTO qwc_config.resource_types (name, description, list_order) + VALUES ( + 'viewer_task', 'Viewer task', + (SELECT MAX(list_order) + 1 FROM qwc_config.resource_types) + ); + """) + + conn = op.get_bind() + conn.execute(sql) + + +def downgrade(): + sql = sa.sql.text(""" + DELETE FROM qwc_config.resource_types WHERE name = 'viewer_task'; + """) + + conn = op.get_bind() + conn.execute(sql) diff --git a/alembic/versions/56846d9f2753_insert_admin_user.py b/alembic/versions/56846d9f2753_insert_admin_user.py new file mode 100644 index 0000000..34f7756 --- /dev/null +++ b/alembic/versions/56846d9f2753_insert_admin_user.py @@ -0,0 +1,45 @@ +"""Insert admin user + +Revision ID: 56846d9f2753 +Revises: f805e8e4a791 +Create Date: 2018-07-03 13:13:36.555067 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '56846d9f2753' +down_revision = 'f805e8e4a791' +branch_labels = None +depends_on = None + + +def upgrade(): + # >>> from werkzeug.security import generate_password_hash + # >>> print(generate_password_hash('admin')) + sql = sa.sql.text(""" + INSERT INTO qwc_config.roles (name, description) + VALUES ('admin', 'Administrator role'); + INSERT INTO qwc_config.users (name, description, password_hash) + VALUES ('admin', 'Default admin user', 'pbkdf2:sha256:50000$HnkznZ75$43a7c397b974757380b126f6e2cea51b533027b1d0eda3de2d248645c8f9d6cb'); + INSERT INTO qwc_config.users_roles (user_id, role_id) + VALUES ((SELECT id FROM qwc_config.users WHERE name = 'admin'), (SELECT id FROM qwc_config.roles WHERE name = 'admin')); + """) + + conn = op.get_bind() + conn.execute(sql) + + +def downgrade(): + sql = sa.sql.text(""" + DELETE FROM qwc_config.users_roles + WHERE user_id = (SELECT id FROM qwc_config.users WHERE name = 'admin') + OR role_id = (SELECT id FROM qwc_config.roles WHERE name = 'admin'); + DELETE FROM qwc_config.users WHERE name = 'admin'; + DELETE FROM qwc_config.roles WHERE name = 'admin'; + """) + + conn = op.get_bind() + conn.execute(sql) diff --git a/alembic/versions/5c9dccb16fc2_create_permalinks_table.py b/alembic/versions/5c9dccb16fc2_create_permalinks_table.py new file mode 100644 index 0000000..0b215b9 --- /dev/null +++ b/alembic/versions/5c9dccb16fc2_create_permalinks_table.py @@ -0,0 +1,39 @@ +"""Create permalinks table + +Revision ID: 5c9dccb16fc2 +Revises: 217f272b9c26 +Create Date: 2018-09-06 10:48:08.151209 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '5c9dccb16fc2' +down_revision = '217f272b9c26' +branch_labels = None +depends_on = None + + +def upgrade(): + sql = sa.sql.text(""" + CREATE TABLE qwc_config.permalinks ( + data text, + key char(10), + date date, + PRIMARY KEY(key) + ); + """) + + conn = op.get_bind() + conn.execute(sql) + + +def downgrade(): + sql = sa.sql.text(""" + DROP TABLE qwc_config.permalinks; + """) + + conn = op.get_bind() + conn.execute(sql) diff --git a/alembic/versions/60c460c23acb_refactor_resource_type_enum_to_table.py b/alembic/versions/60c460c23acb_refactor_resource_type_enum_to_table.py new file mode 100644 index 0000000..4da0d98 --- /dev/null +++ b/alembic/versions/60c460c23acb_refactor_resource_type_enum_to_table.py @@ -0,0 +1,82 @@ +"""Refactor resource_type enum to table + +Revision ID: 60c460c23acb +Revises: 5c9dccb16fc2 +Create Date: 2018-09-25 15:03:14.447255 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '60c460c23acb' +down_revision = '5c9dccb16fc2' +branch_labels = None +depends_on = None + + +def upgrade(): + sql = sa.sql.text(""" + -- create resource_types + + CREATE TABLE qwc_config.resource_types ( + name character varying NOT NULL, + description character varying, + list_order integer NOT NULL DEFAULT 0, + CONSTRAINT resource_types_pk PRIMARY KEY (name) + ); + + WITH types AS ( + SELECT name::text, list_order::integer + FROM unnest( + enum_range(NULL::qwc_config.resource_type) + ) WITH ORDINALITY AS t(name, list_order) + ) + INSERT INTO qwc_config.resource_types + (name, description, list_order) + SELECT name, initcap(name), list_order FROM types; + + -- refactor resources.type from enum to FK on resource_types + + ALTER TABLE qwc_config.resources + ALTER COLUMN type TYPE character varying + USING type::text; + + ALTER TABLE qwc_config.resources + ADD CONSTRAINT type_fk FOREIGN KEY (type) + REFERENCES qwc_config.resource_types (name) MATCH FULL + ON UPDATE CASCADE ON DELETE RESTRICT; + + -- cleanup + + DROP TYPE qwc_config.resource_type; + """) + + conn = op.get_bind() + conn.execute(sql) + + +def downgrade(): + sql = sa.sql.text(""" + -- recreate enum + + CREATE TYPE qwc_config.resource_type AS + ENUM ('map', 'layer', 'attribute', 'data'); + + -- revert resources.type from FK on resource_types to enum + + ALTER TABLE qwc_config.resources + DROP CONSTRAINT type_fk; + + ALTER TABLE qwc_config.resources + ALTER COLUMN type TYPE qwc_config.resource_type + USING type::qwc_config.resource_type; + + -- cleanup + + DROP TABLE qwc_config.resource_types CASCADE; + """) + + conn = op.get_bind() + conn.execute(sql) diff --git a/alembic/versions/875aa9290232_insert_viewer_resource_type.py b/alembic/versions/875aa9290232_insert_viewer_resource_type.py new file mode 100644 index 0000000..eeb65c1 --- /dev/null +++ b/alembic/versions/875aa9290232_insert_viewer_resource_type.py @@ -0,0 +1,38 @@ +"""Insert viewer resource type + +Revision ID: 875aa9290232 +Revises: f2681d70c266 +Create Date: 2018-12-13 16:01:28.360306 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '875aa9290232' +down_revision = 'f2681d70c266' +branch_labels = None +depends_on = None + + +def upgrade(): + sql = sa.sql.text(""" + INSERT INTO qwc_config.resource_types (name, description, list_order) + VALUES ( + 'viewer', 'Viewer', + (SELECT MAX(list_order) + 1 FROM qwc_config.resource_types) + ); + """) + + conn = op.get_bind() + conn.execute(sql) + + +def downgrade(): + sql = sa.sql.text(""" + DELETE FROM qwc_config.resource_types WHERE name = 'viewer'; + """) + + conn = op.get_bind() + conn.execute(sql) diff --git a/alembic/versions/8c5ebe688265_insert_theme_info_link_resource_type.py b/alembic/versions/8c5ebe688265_insert_theme_info_link_resource_type.py new file mode 100644 index 0000000..0648094 --- /dev/null +++ b/alembic/versions/8c5ebe688265_insert_theme_info_link_resource_type.py @@ -0,0 +1,38 @@ +"""Insert theme_info_link resource type + +Revision ID: 8c5ebe688265 +Revises: e9c31b610e0a +Create Date: 2020-08-13 11:00:54.732613 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '8c5ebe688265' +down_revision = 'e9c31b610e0a' +branch_labels = None +depends_on = None + + +def upgrade(): + sql = sa.sql.text(""" + INSERT INTO qwc_config.resource_types (name, description, list_order) + VALUES ( + 'theme_info_link', 'Theme info link', + (SELECT MAX(list_order) + 1 FROM qwc_config.resource_types) + ); + """) + + conn = op.get_bind() + conn.execute(sql) + + +def downgrade(): + sql = sa.sql.text(""" + DELETE FROM qwc_config.resource_types WHERE name = 'theme_info_link'; + """) + + conn = op.get_bind() + conn.execute(sql) diff --git a/alembic/versions/90b3b4fbc8f6_add_totp_secret_to_users.py b/alembic/versions/90b3b4fbc8f6_add_totp_secret_to_users.py new file mode 100644 index 0000000..9856722 --- /dev/null +++ b/alembic/versions/90b3b4fbc8f6_add_totp_secret_to_users.py @@ -0,0 +1,36 @@ +"""Add TOTP secret to users + +Revision ID: 90b3b4fbc8f6 +Revises: 4ff55a84dd72 +Create Date: 2019-02-01 13:46:48.426617 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '90b3b4fbc8f6' +down_revision = '4ff55a84dd72' +branch_labels = None +depends_on = None + + +def upgrade(): + sql = sa.sql.text(""" + ALTER TABLE qwc_config.users + ADD COLUMN totp_secret character varying(16); + """) + + conn = op.get_bind() + conn.execute(sql) + + +def downgrade(): + sql = sa.sql.text(""" + ALTER TABLE qwc_config.users + DROP COLUMN totp_secret; + """) + + conn = op.get_bind() + conn.execute(sql) diff --git a/alembic/versions/9168093625bd_insert_solr_facet_resource_type.py b/alembic/versions/9168093625bd_insert_solr_facet_resource_type.py new file mode 100644 index 0000000..fada2de --- /dev/null +++ b/alembic/versions/9168093625bd_insert_solr_facet_resource_type.py @@ -0,0 +1,38 @@ +"""Insert solr_facet resource type + +Revision ID: 9168093625bd +Revises: 0fa6610ee212 +Create Date: 2020-08-13 11:08:43.109973 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '9168093625bd' +down_revision = '0fa6610ee212' +branch_labels = None +depends_on = None + + +def upgrade(): + sql = sa.sql.text(""" + INSERT INTO qwc_config.resource_types (name, description, list_order) + VALUES ( + 'solr_facet', 'Solr search facet', + (SELECT MAX(list_order) + 1 FROM qwc_config.resource_types) + ); + """) + + conn = op.get_bind() + conn.execute(sql) + + +def downgrade(): + sql = sa.sql.text(""" + DELETE FROM qwc_config.resource_types WHERE name = 'solr_facet'; + """) + + conn = op.get_bind() + conn.execute(sql) diff --git a/alembic/versions/916ed45fa0ba_add_sign_in_timestamp_and_attempts_to_users.py b/alembic/versions/916ed45fa0ba_add_sign_in_timestamp_and_attempts_to_users.py new file mode 100644 index 0000000..aaa752d --- /dev/null +++ b/alembic/versions/916ed45fa0ba_add_sign_in_timestamp_and_attempts_to_users.py @@ -0,0 +1,40 @@ +"""Add last_sign_in_at and failed_sign_in_count to users + +Revision ID: 916ed45fa0ba +Revises: 60c460c23acb +Create Date: 2018-12-12 10:41:04.687232 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '916ed45fa0ba' +down_revision = '60c460c23acb' +branch_labels = None +depends_on = None + + +def upgrade(): + sql = sa.sql.text(""" + ALTER TABLE qwc_config.users + ADD COLUMN last_sign_in_at timestamp without time zone; + ALTER TABLE qwc_config.users + ADD COLUMN failed_sign_in_count integer DEFAULT 0; + """) + + conn = op.get_bind() + conn.execute(sql) + + +def downgrade(): + sql = sa.sql.text(""" + ALTER TABLE qwc_config.users + DROP COLUMN last_sign_in_at; + ALTER TABLE qwc_config.users + DROP COLUMN failed_sign_in_count; + """) + + conn = op.get_bind() + conn.execute(sql) diff --git a/alembic/versions/9c671585cfb1_create_users_groups_roles_and_relations.py b/alembic/versions/9c671585cfb1_create_users_groups_roles_and_relations.py new file mode 100644 index 0000000..87c8f62 --- /dev/null +++ b/alembic/versions/9c671585cfb1_create_users_groups_roles_and_relations.py @@ -0,0 +1,94 @@ +"""Create users, groups, roles and relations + +Revision ID: 9c671585cfb1 +Revises: +Create Date: 2018-07-03 13:04:20.054758 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '9c671585cfb1' +down_revision = None +branch_labels = None +depends_on = None + + +def upgrade(): + sql = sa.sql.text(""" + CREATE TABLE qwc_config.users ( + id serial NOT NULL, + name character varying NOT NULL, + description character varying, + email character varying(120), + password_hash character varying(128), + CONSTRAINT users_pk PRIMARY KEY (id), + CONSTRAINT name_unique UNIQUE (name) + ); + + CREATE TABLE qwc_config.groups ( + id serial NOT NULL, + name character varying NOT NULL, + description character varying, + CONSTRAINT groups_pk PRIMARY KEY (id) + ); + + CREATE TABLE qwc_config.roles ( + id serial NOT NULL, + name character varying NOT NULL, + description character varying, + CONSTRAINT roles_pk PRIMARY KEY (id) + ); + + CREATE TABLE qwc_config.users_roles ( + user_id integer NOT NULL, + role_id integer NOT NULL, + CONSTRAINT role_fk FOREIGN KEY (role_id) + REFERENCES qwc_config.roles (id) MATCH FULL + ON UPDATE CASCADE ON DELETE RESTRICT, + CONSTRAINT user_fk FOREIGN KEY (user_id) + REFERENCES qwc_config.users (id) MATCH FULL + ON UPDATE CASCADE ON DELETE RESTRICT + ); + + CREATE TABLE qwc_config.groups_users ( + group_id integer NOT NULL, + user_id integer NOT NULL, + CONSTRAINT group_fk FOREIGN KEY (group_id) + REFERENCES qwc_config.groups (id) MATCH FULL + ON UPDATE CASCADE ON DELETE RESTRICT, + CONSTRAINT user_fk FOREIGN KEY (user_id) + REFERENCES qwc_config.users (id) MATCH FULL + ON UPDATE CASCADE ON DELETE RESTRICT + ); + + CREATE TABLE qwc_config.groups_roles ( + group_id integer NOT NULL, + role_id integer NOT NULL, + CONSTRAINT group_fk FOREIGN KEY (group_id) + REFERENCES qwc_config.groups (id) MATCH FULL + ON UPDATE CASCADE ON DELETE RESTRICT, + CONSTRAINT role_fk FOREIGN KEY (role_id) + REFERENCES qwc_config.roles (id) MATCH FULL + ON UPDATE CASCADE ON DELETE RESTRICT + ); + """) + + conn = op.get_bind() + conn.execute(sql) + + +def downgrade(): + sql = sa.sql.text(""" + DROP TABLE qwc_config.users CASCADE; + DROP TABLE qwc_config.groups CASCADE; + DROP TABLE qwc_config.roles CASCADE; + DROP TABLE qwc_config.users_roles CASCADE; + DROP TABLE qwc_config.groups_users CASCADE; + DROP TABLE qwc_config.groups_roles CASCADE; + """) + + conn = op.get_bind() + conn.execute(sql) diff --git a/alembic/versions/a793057bbf20_insert_more_detailed_data_resource_types.py b/alembic/versions/a793057bbf20_insert_more_detailed_data_resource_types.py new file mode 100644 index 0000000..41f24f9 --- /dev/null +++ b/alembic/versions/a793057bbf20_insert_more_detailed_data_resource_types.py @@ -0,0 +1,56 @@ +"""Insert more detailed data resource types for CRUD + +Revision ID: a793057bbf20 +Revises: 0f409f15e0b7 +Create Date: 2018-12-18 16:12:42.010630 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'a793057bbf20' +down_revision = '0f409f15e0b7' +branch_labels = None +depends_on = None + + +def upgrade(): + sql = sa.sql.text(""" + INSERT INTO qwc_config.resource_types (name, description, list_order) + VALUES ( + 'data_create', 'Data (create)', + (SELECT MAX(list_order) + 1 FROM qwc_config.resource_types) + ); + INSERT INTO qwc_config.resource_types (name, description, list_order) + VALUES ( + 'data_read', 'Data (read)', + (SELECT MAX(list_order) + 1 FROM qwc_config.resource_types) + ); + INSERT INTO qwc_config.resource_types (name, description, list_order) + VALUES ( + 'data_update', 'Data (update)', + (SELECT MAX(list_order) + 1 FROM qwc_config.resource_types) + ); + INSERT INTO qwc_config.resource_types (name, description, list_order) + VALUES ( + 'data_delete', 'Data (delete)', + (SELECT MAX(list_order) + 1 FROM qwc_config.resource_types) + ); + """) + + conn = op.get_bind() + conn.execute(sql) + + +def downgrade(): + sql = sa.sql.text(""" + DELETE FROM qwc_config.resource_types WHERE name = 'data_create'; + DELETE FROM qwc_config.resource_types WHERE name = 'data_read'; + DELETE FROM qwc_config.resource_types WHERE name = 'data_update'; + DELETE FROM qwc_config.resource_types WHERE name = 'data_delete'; + """) + + conn = op.get_bind() + conn.execute(sql) diff --git a/alembic/versions/ad5e7b02469a_create_password_histories.py b/alembic/versions/ad5e7b02469a_create_password_histories.py new file mode 100644 index 0000000..147045a --- /dev/null +++ b/alembic/versions/ad5e7b02469a_create_password_histories.py @@ -0,0 +1,51 @@ +"""Create password_histories + +Add password histories for tracking some optional password constraints +in QWC DB Auth Service. + +NOTE: Foreign key constraint is set to automatically remove +related history entries on user delete + +Revision ID: ad5e7b02469a +Revises: 0352a94313d6 +Create Date: 2022-04-13 11:06:38.665469 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'ad5e7b02469a' +down_revision = '0352a94313d6' +branch_labels = None +depends_on = None + + +def upgrade(): + sql = sa.sql.text(""" + CREATE TABLE qwc_config.password_histories ( + id serial NOT NULL, + user_id integer NOT NULL, + password_hash character varying(128), + created_at timestamp without time zone NOT NULL, + CONSTRAINT password_histories_pk PRIMARY KEY (id), + CONSTRAINT user_fk FOREIGN KEY (user_id) + REFERENCES qwc_config.users (id) MATCH FULL + ON UPDATE CASCADE ON DELETE CASCADE + ); + COMMENT ON TABLE qwc_config.password_histories IS + 'Password histories for tracking some optional password constraints in QWC DB Auth Service'; + """) + + conn = op.get_bind() + conn.execute(sql) + + +def downgrade(): + sql = sa.sql.text(""" + DROP TABLE qwc_config.password_histories CASCADE; + """) + + conn = op.get_bind() + conn.execute(sql) diff --git a/alembic/versions/b0cb86db3dfe_add_reset_password_token_to_users.py b/alembic/versions/b0cb86db3dfe_add_reset_password_token_to_users.py new file mode 100644 index 0000000..12e7dd8 --- /dev/null +++ b/alembic/versions/b0cb86db3dfe_add_reset_password_token_to_users.py @@ -0,0 +1,36 @@ +"""Add reset_password_token to users + +Revision ID: b0cb86db3dfe +Revises: 875aa9290232 +Create Date: 2018-12-14 09:29:05.469465 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'b0cb86db3dfe' +down_revision = '875aa9290232' +branch_labels = None +depends_on = None + + +def upgrade(): + sql = sa.sql.text(""" + ALTER TABLE qwc_config.users + ADD COLUMN reset_password_token character varying(128); + """) + + conn = op.get_bind() + conn.execute(sql) + + +def downgrade(): + sql = sa.sql.text(""" + ALTER TABLE qwc_config.users + DROP COLUMN reset_password_token; + """) + + conn = op.get_bind() + conn.execute(sql) diff --git a/alembic/versions/b21139053154_create_resources_and_permissions.py b/alembic/versions/b21139053154_create_resources_and_permissions.py new file mode 100644 index 0000000..960fddd --- /dev/null +++ b/alembic/versions/b21139053154_create_resources_and_permissions.py @@ -0,0 +1,63 @@ +"""Create resources and permissions + +Revision ID: b21139053154 +Revises: 9c671585cfb1 +Create Date: 2018-07-03 13:09:23.087429 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'b21139053154' +down_revision = '9c671585cfb1' +branch_labels = None +depends_on = None + + +def upgrade(): + sql = sa.sql.text(""" + CREATE TYPE qwc_config.resource_type AS + ENUM ('map', 'layer', 'attribute'); + + CREATE TABLE qwc_config.resources ( + id serial NOT NULL, + parent_id integer, + type qwc_config.resource_type NOT NULL, + name character varying NOT NULL, + CONSTRAINT resources_pk PRIMARY KEY (id), + CONSTRAINT parent_fk FOREIGN KEY (parent_id) + REFERENCES qwc_config.resources (id) MATCH FULL + ON UPDATE CASCADE ON DELETE RESTRICT + ); + + CREATE TABLE qwc_config.permissions ( + id serial NOT NULL, + role_id integer NOT NULL, + resource_id integer NOT NULL, + priority integer NOT NULL DEFAULT 0, + write boolean NOT NULL DEFAULT FALSE, + CONSTRAINT permissions_pk PRIMARY KEY (id), + CONSTRAINT role_fk FOREIGN KEY (role_id) + REFERENCES qwc_config.roles (id) MATCH FULL + ON UPDATE CASCADE ON DELETE RESTRICT, + CONSTRAINT resource_fk FOREIGN KEY (resource_id) + REFERENCES qwc_config.resources (id) MATCH FULL + ON UPDATE CASCADE ON DELETE RESTRICT + ); + """) + + conn = op.get_bind() + conn.execute(sql) + + +def downgrade(): + sql = sa.sql.text(""" + DROP TABLE qwc_config.resources CASCADE; + DROP TABLE qwc_config.permissions CASCADE; + DROP TYPE qwc_config.resource_type; + """) + + conn = op.get_bind() + conn.execute(sql) diff --git a/alembic/versions/c77774920e5b_insert_feature_info_service_resource_types.py b/alembic/versions/c77774920e5b_insert_feature_info_service_resource_types.py new file mode 100644 index 0000000..88a2285 --- /dev/null +++ b/alembic/versions/c77774920e5b_insert_feature_info_service_resource_types.py @@ -0,0 +1,46 @@ +"""Insert feature info service resource types + +Revision ID: c77774920e5b +Revises: 9168093625bd +Create Date: 2020-08-13 11:11:03.020251 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'c77774920e5b' +down_revision = '9168093625bd' +branch_labels = None +depends_on = None + + +def upgrade(): + sql = sa.sql.text(""" + INSERT INTO qwc_config.resource_types (name, description, list_order) + VALUES ( + 'feature_info_service', 'FeatureInfo service', + (SELECT MAX(list_order) + 1 FROM qwc_config.resource_types) + ); + INSERT INTO qwc_config.resource_types (name, description, list_order) + VALUES ( + 'feature_info_layer', 'FeatureInfo layer', + (SELECT MAX(list_order) + 1 FROM qwc_config.resource_types) + ); + """) + + conn = op.get_bind() + conn.execute(sql) + + +def downgrade(): + sql = sa.sql.text(""" + DELETE FROM qwc_config.resource_types + WHERE name = 'feature_info_service'; + DELETE FROM qwc_config.resource_types + WHERE name = 'feature_info_layer'; + """) + + conn = op.get_bind() + conn.execute(sql) diff --git a/alembic/versions/db5a31995054_create_last_update.py b/alembic/versions/db5a31995054_create_last_update.py new file mode 100644 index 0000000..e923908 --- /dev/null +++ b/alembic/versions/db5a31995054_create_last_update.py @@ -0,0 +1,39 @@ +"""Create last_update + +Revision ID: db5a31995054 +Revises: 56846d9f2753 +Create Date: 2018-07-06 15:54:58.460134 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'db5a31995054' +down_revision = '56846d9f2753' +branch_labels = None +depends_on = None + + +def upgrade(): + sql = sa.sql.text(""" + CREATE TABLE qwc_config.last_update ( + updated_at timestamp without time zone NOT NULL, + CONSTRAINT last_update_pk PRIMARY KEY (updated_at) + ); + INSERT INTO qwc_config.last_update (updated_at) + VALUES(current_timestamp); + """) + + conn = op.get_bind() + conn.execute(sql) + + +def downgrade(): + sql = sa.sql.text(""" + DROP TABLE qwc_config.last_update; + """) + + conn = op.get_bind() + conn.execute(sql) diff --git a/alembic/versions/e9c31b610e0a_create_registration_tables.py b/alembic/versions/e9c31b610e0a_create_registration_tables.py new file mode 100644 index 0000000..4ac1475 --- /dev/null +++ b/alembic/versions/e9c31b610e0a_create_registration_tables.py @@ -0,0 +1,63 @@ +"""Create registration tables + +Add tables for registrable groups and registration requests. + +Revision ID: e9c31b610e0a +Revises: 90b3b4fbc8f6 +Create Date: 2019-02-18 13:00:54.485628 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'e9c31b610e0a' +down_revision = '90b3b4fbc8f6' +branch_labels = None +depends_on = None + + +def upgrade(): + sql = sa.sql.text(""" + CREATE TABLE qwc_config.registrable_groups ( + id serial NOT NULL, + group_id integer NOT NULL, + title character varying NOT NULL, + description character varying, + CONSTRAINT registrable_groups_pk PRIMARY KEY (id), + CONSTRAINT group_fk FOREIGN KEY (group_id) + REFERENCES qwc_config.groups (id) MATCH FULL + ON UPDATE CASCADE ON DELETE RESTRICT + ); + + CREATE TABLE qwc_config.registration_requests ( + id serial NOT NULL, + user_id integer NOT NULL, + registrable_group_id integer NOT NULL, + unsubscribe boolean NOT NULL DEFAULT false, + pending boolean NOT NULL DEFAULT true, + accepted boolean, + created_at timestamp without time zone NOT NULL, + CONSTRAINT registration_requests_pk PRIMARY KEY (id), + CONSTRAINT user_fk FOREIGN KEY (user_id) + REFERENCES qwc_config.users (id) MATCH FULL + ON UPDATE CASCADE ON DELETE RESTRICT, + CONSTRAINT registrable_group_fk FOREIGN KEY (registrable_group_id) + REFERENCES qwc_config.registrable_groups (id) MATCH FULL + ON UPDATE CASCADE ON DELETE RESTRICT + ); + """) + + conn = op.get_bind() + conn.execute(sql) + + +def downgrade(): + sql = sa.sql.text(""" + DROP TABLE qwc_config.registration_requests CASCADE; + DROP TABLE qwc_config.registrable_groups CASCADE; + """) + + conn = op.get_bind() + conn.execute(sql) diff --git a/alembic/versions/f2681d70c266_insert_print_template_resource_type.py b/alembic/versions/f2681d70c266_insert_print_template_resource_type.py new file mode 100644 index 0000000..28690e6 --- /dev/null +++ b/alembic/versions/f2681d70c266_insert_print_template_resource_type.py @@ -0,0 +1,38 @@ +"""Insert print template resource type + +Revision ID: f2681d70c266 +Revises: 916ed45fa0ba +Create Date: 2018-12-12 15:45:01.694680 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'f2681d70c266' +down_revision = '916ed45fa0ba' +branch_labels = None +depends_on = None + + +def upgrade(): + sql = sa.sql.text(""" + INSERT INTO qwc_config.resource_types (name, description, list_order) + VALUES ( + 'print_template', 'Print template', + (SELECT MAX(list_order) + 1 FROM qwc_config.resource_types) + ); + """) + + conn = op.get_bind() + conn.execute(sql) + + +def downgrade(): + sql = sa.sql.text(""" + DELETE FROM qwc_config.resource_types WHERE name = 'print_template'; + """) + + conn = op.get_bind() + conn.execute(sql) diff --git a/alembic/versions/f805e8e4a791_insert_public_role.py b/alembic/versions/f805e8e4a791_insert_public_role.py new file mode 100644 index 0000000..d9b7331 --- /dev/null +++ b/alembic/versions/f805e8e4a791_insert_public_role.py @@ -0,0 +1,35 @@ +"""Insert public role + +Revision ID: f805e8e4a791 +Revises: b21139053154 +Create Date: 2018-07-03 13:11:00.253559 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'f805e8e4a791' +down_revision = 'b21139053154' +branch_labels = None +depends_on = None + + +def upgrade(): + sql = sa.sql.text(""" + INSERT INTO qwc_config.roles (name, description) + VALUES ('public', 'Public role'); + """) + + conn = op.get_bind() + conn.execute(sql) + + +def downgrade(): + sql = sa.sql.text(""" + DELETE FROM qwc_config.roles WHERE name = 'public'; + """) + + conn = op.get_bind() + conn.execute(sql) diff --git a/er-diagram.png b/er-diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..37ded8c6fdadc98a32b53031349ff3f97b393316 GIT binary patch literal 109783 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 z oY=hm>`tNNTx?kiix4D930aEz<0SU@~%R^HjI^Qkl|IN-IxDmn*1T6&rtKkTU+lz>M3xh!cYM&CNG za8tvh!hKhUf5@@ZQ^w;S@FnYVlz+tNFajHp4(}(y&YKRV*T=AIhqtbunRa!Tql z;&+C$kq>z(d`={Zqp4#n*Yt5DMm|RDk*Mpv+eN}u{!Q1jO)WAKvdtW4545I8(+><% z6HkwGp-iP0nXm8}R3iohcR@bBpZ<>0LgXnGbJPR1GSP z#2S&Rq4(ZZXIN#vx7s+w;$A5F*`J&yZO5og4h#Kl=FvF2F6C zaJ?SrG)pG%-?_(OMogjk_!*LBPx#=pu@ zzhXi}s-VoU{$=t(!iCv3!|M=1c3s&h(X4T@h(zyacf9LdIQe+)oLr7 zM?!R9I|DsDozIhR0-cm$1je(-x2qZi_i~86fF?FQhkxoTXW59QFF9vTXDEwoZ=dX$ znK3ZBRilBsPBet@|GZjwPq-(eO*muWvOVNTDeIxHBt{;np$V;a1S$GrO8TInj9B3}PmF?DczgHrP(s~Nq2hEXnlWQk7vY}1aP?>*DI;*kK(WQML*3#07-Q9gd z7OO`nFY0*oqv#c^5hz!UW7DID$}36~Kh*K4O8a6zXgv}YrSS!R(G?V|KCyWI=E;+Y zxl9w}Gqu*4dRAy35VSt=Z2vt92HqJV671mHi2?HkdfsHAj0OXiPIDiAh5xcOZclnR z_G+Mu$5C1p1T#K^^qq%Vn8<{(2RM5u*n7aImRA}(>q|FhSj}{zxg?|gaC5I$f4*d) zYMc9FTj`eF6ziA`pqX#C-m(9A|C;;3yKSYJHD20r^vlvhF6SVFcS-{{28d^xD-Sxt zF?kl(-Q3)6-s=0gKgROPtd)qW+3$3*KBra0!8;52Kz3iq)&S`~{*6Lo%usj4Xaxu= zW2DHgU$N9{gV&)UO?H?>;a=*2f`AhB z7-ui^g88GLU&m1!ZGa6%(`wv#;%Q~p`gEq1E&zLs@l|`K!VsqCbhw=eWAn2Fff9k8 zQfSXlqvIq*|0D_LkVe%Y`wcfT#&Vt@JB-l&Vz0Lpg0Y>`NhQd6|0ReUU4#xsNi>|6 zf+Ul3N!oVjQ^nMR|HH{BxxNXzNf)ndx((o4Eh)m}b2O$1?q?pWeom=GQGi-n0F-|I z7fCkoUxJr!pzr^AbZyuiv)c$vGJ8*I{qU>~pu!Tc{HzloaBXm18vGEgMFV*07|z$f zbC<6_@BGil77M_uG!9Jf6!5}@Q~dpardEf}~}u7+q+lXd)108`3^G8pI}z6E^iDEKv!_)z{c^THHz&!a;g+@744R@?{N zq1Uy3;KKxtB$TmPl{Sulj*r?1xugvLShe-4fqszd+JM}NT|*$?=nc)Ln8@H@kBe-o z4UcqBA#IXKcI|mw>K{A~rR-tZ?1L7qaxI>n(dq9VLEd{3MFzN|l^TA@nwW;lDq#JtV&Elqx~Blb9%)$NxhJ`~0|Gs)Qw3SevDkD}#;SA;%{(f5wLlYl zOlBSEqDqt_f*K_Ft8Q*DHLf6t_LMCmOt2?@4C>YM*C%^=XeSHRf6w~)+$ z*uQrv&#Yk14)z`2#@lqaz*j6I7Jud73QFd7%zk-Z68V@c=LW7lzZ@Qm{z0xpEo`SJ zvLIE|cOoOg&`NtZWjN;Q!Ht0pd$%mb>31d}%*r0?B`Q83P^ZppE$`{#+Q@-z9bnz= zi{YOh|HM^|ZHvEKHxuj==RBK^n-Y-J%f}XZMisU{a`veq>yLa;{jnZfOKB7PG~9&} zrvI=`ubiGWKYXb9BIy070|3@NaRo;7Bl)zQx;n0j00a-NNv&cZL@xCuwP&s&{^XTc zwgfbl+Fshp_P~Ywba@nRgi@p5JbMn_^DU7u+{8T3%m@mK)jo0U%l|eQx*=cJ@t4a! z5$&5QkB{8Reu^XM3~T!I;on=MF(c(vaOOjv&9o?SFOZ#KALm}U{1}4s)A8@#Bn1pX z;x4Y%A3mnjTwkhDXCuw}bIuOKkow6?h=&U_n80ZeymNUl73g3>lx#puD z`SCUylldW4oU&qW4Z$O$cG3+7b0gGDg-#Bb*dR`K=&7~*`fcGU8~$?Kb}t@#6-Qum z8{;o78pGEo9JG=0CfDA2%^H2rtwm8(geK7d zfg_h+%I_@gE`9cWV004vZ;o#vTiHfd9Zo-`e+RHBzs*K9yMCQ!2grNE3b?u@=>IHE z&Cl(pN#hIn%!?m(S^`{vbEyH`?fdW9wGY&lb4J>&o{_=;GXo;0W+*{EJ%2r^`N`%0 zzT18a-1^%r7-KOXJaxkLjr6Az-<mHJ5qXm=3jF)$$w7;Yjy!~UGa6b!qvCR3vFg%X3O8njnCt+ zcH{T(r8_trd)Z^9M}DN3SmYnNe>@vf1<~_Ju9W_=@*X~K$5#F50m!-DTUq9E*cfbl zgU{qmzNK5eZP(eQ?v(yKP>3a{hy?tn1vw9vk}MX1<0{->!^z6ED{9zD7;c2Qn0iM# zi@r(1CHYQ~a3nZ13EED#RC%9&^o~Ojt59b=c2V09-#o(Gx3mZUW`?$EYP$vMz@h|q zg!R2#Rb>%io|{`++eav(NCtX`mEj;l(BMru;4WG|TT)wJdBRz6xMw15YHL{8Lsg#cdP)FG{9Fj`S#%)q+c>vG* zD;>TO{zR;KkJ@71KTj)5ifm2mqBGv;B6qSkgv2arE6n<(pjwYAXXP z)+Y;e+rlFtY~vm=*Qt4((8LY`CCu~M&5`SDZAO^7`M77}3(*UlPIxu!UsJ&A*#uw6 zl2QUvQ#L^OGsOQ7oGozvZ>QYiOEb^O<#`PQEP-|T&f7__4$Ha&{PS&nIN*Bc|1pQ; z!0ne`Tb=`!g5d3oPQCtX|IZz;0H6$?_S?JVfgffmA^%fyXZYZDhb%Qvff>=N6dsUp?^U{Pes$hv2UWc{KmU0c}d^I1Kxw0x&9XZ<_=vA zjWAPaE{6Z|f!rBLl7Yw0!2@MJf4VZ6@$rb)>vhkfAV!aSj&b5m_uKsqAPXeuzC#TK z!mW9~m(7|YP2o3=B<^x;DAAX64s514nbp3zB&|&~ETTI~NlR1K*VkXnHW=fR=7awn zs=&@N3E0=?tNm&(!(WFTm>;FTgx;V&sZSqko_1epMbC|BGCY7LVrC@5nWYGJC?vhvoZGn1dS?^e{(2pb zvH$<)|G(%z3Xfj{0LHLE?s`4aUf2WB1Q0xlI!esBA9MY#OZUgS00obr+u#u!QB-kx z`Tf;YH&qj03=zcquu`S`;|l>Z$;=-?Kv+v4b_cK`PCv*O`+q3CBp`4l-T~M}!0QIy z{x(u7Ly^3?SFaJoH2-a=-07hT`3Dz(;0BxW>+9BDp+${Ng^!Ax9s{Wo;f49u z3E$gW5_L?USaD#%!X5yhf24y_cpCeTS5D{h6ZHfZs^5aN9-Nh>K}&kyJN|x&n#o}F z=Q1k6u1#y>90u#$Ah2MCkJslV_u;WjVr!|!ug`3Ee1$5+9A@^6hQ2=wa;8t7`1~Pu z+K>NyD5vdP#WO~eIf0d>XB$)BKJO$87wkxqk_HBJ**BJioA|YULC6hMvkoi*ik;(> z)(!+8yAWt==0}ObWB_7Vq>Y0kEi*9Ku3W{(436Trbhg~;sR*~1$lcRApKUzFY^t3~ z5r;R4;bh4KIA%}61_Y%xcIODs)O+!Zc(>5SQbpq zKiuNqcx;WFeJ6K_sO6SKhoN z?z*wi9J&YRnwnD?Qu{RwxtOzK3s_S>XvNI-H*;%VAmAd=yb!Cw-6)l`y7eV-dq`G- z$)}!Y&4~xmTj}FJJI<=+XWeO!L!9&YrWg^^dNMu|hZ!;jqu(mh^tcW3HqQ%S{RrtC zgJ-(^>!!|kpP6mQlK15A$se2#sraeUf21D=!1>5d=htN)q{hWdiKe`w-Bj5rU8Rag z9Jb2m-=wS;G+r8E>a^-`n4fZ=-rXdt{$lcayN&z~^~J_sp2?U*;<(vvMsG@i`^Tc& z^2;{_TPz0~g)Ty&vX3rjs@ZT)nI_nEIBRk&csCva8QJ5Mz_OP_`^k4pltZPk*pQ)% zDCFaoOZ0(mTS3SXZ}ZCyVw@>x@$t_jw7v92Yrqm;^v6)>76J#`3%pcG9u9DdRxzLD z6+tyi1W4{bNrpPeq|{&JAQe1e$jZ6yz#nqU=;~A2g|xApjDatC5B5U(?cL4~dYLC> zC}MF~QbLIZgC&vjoiBXRtV$JfHwM!6dES^WiOZ7O!cboakIuHA2X7lUax@qXEigq& zcu4Akb1jFYJuFCW8)EO9$OL!v)yn$xpNc-(v7s*8&=#DzoZ0nGdnN~7-j$(SGCYi@ zKRfuk*d}OSM;j<24?aG3109|miOED4HNP6KYT%{5(kG3EuNg-`CDVm{0xr37d_@?W zoC_A7x~A!k2-vpa+!sHxOsX_9(OYRX?YwmfSJSR5o_6>q726~iRN12*R*}XUBzFda8Oq-s(%lX6DRCZTJM z_n&~d>4p~IPKsM~J=ct*rTE6%kESA}RKTj8+ey7CzO0asDB(7VHu zogaO?kaW9r>LWGIH&HzJ{v-W9t|Zv)yIkLMmtdgU-d$JBve*|2 zw5d=%Tk%~>e%Rf#=l#Cu(8BC2tGGns0jB}O&noI5kN{2Hb_332$Oqk*-=Nm<8C%a3 z;T+(%t{J0^sK+698@}WElFSr?7CYp4J9SuIqdyJ|EsAD38pEx13dB9adIaDnsZf1k zC)25AR78i17{3V!QejLpT;YqB&xvM&Qga}hheF7jr4e_N+hCwYq`$(VTNd;KOv+#2 z_4jDHe3VJk($`;Fde@F-7gvgqSsz^|{Euc%?vymP+8tGi!G&$qHKXPy6HVzQ{8W=% z{Qdnqn!H>j$mWM&*jyPxC14^^*J>&*VHl;OKTXqI1Ox=^HMdD0ByGyyJ~^=b0QKUb z<*z|)OSxR5==gXp)UdWvgod20zbb{&Px}fE4dj$J;WWh#c7NttuRZ1-_y(otkrLx~ zyO)wirvL^Q^*Q(a_6xH3-2@cn61nd%=$PR6Y&Ce);%2ZA)r+4C`=PMfV!aZdT05S= z#``EBKn{3iR+&{5Pw&rSJTx-G+VSmyxeH?K=gUYZW)SGv`=B5X1o^#t9Mqvv=R)_N zpsyK?FLkNqDUwYTSNV~U$nXDr+UX=p?*Aruwe_lruc#D^bSM*&3Y2qDJ;Yi$KxTwM6%Jqf(Dsj637yGNd# zMobkN7Dhf19-G6n*Hm$qR8zR1&`}Bw7YO%+HTsC|%ISM~O^*l+?k@l%MbVhnd2i`s zk(qnBo-{nguB)E)Y&SEAY>$qN@R&Y|SF=D>fNaUoLz=&}a`51lgR#-Lz>o@NQ9`NM zIy2sr|5cC=|Mw=-RxnLH%Ce%~@Nt=NQ&Cy5ichGsJfDfGRYFDB#nq7r<7*D4E_~b*8b;A-DgJoX)RiLmgBO1E1hd>jvuTrN*aa zva50dp&M00M>15_FQgR|v|>+$Y*1^-e70-8w0G}vQH4=cjgT7Jj(C+B`&%s2_!|-< zPYcy5T!%!XPqBI3_7{{InBy08mDZ`rRE6VNKlm{zjF-tso=N+I@DGeY1|y`|^u|24 zYcKC=@U1kKsPB!2qZ%J`xd>|YpsakqpZ{@Sqr-W-t*PiWQ*is^V-v_5KR?|z$vmAB z=yT+ui;>h0WGo5ND$>s=;kgr9e?BXHizJHF7er1$d1y>a#Q`EmEn9MuGHvilPau_W z{c*#@@)0izIXYjH=ZW5prOUIgeba02K4z-3iFZplEd`IekkhoufKN9 zwG~yCR`1_gt0{{qLO~p5&YU)pGV#*~-t$AcbI|yGia4WPpjhf!0>oOWU_pbMntks; z^4|OUJ=FzjOZ6(oP40>puSqIMw#3PW3tSk+T$*`Vs=@oUcSSd6#gJ#Uv(`gXdA_%D zuzhNU(tg2=b8bS#D(D9)Y`*9zUeXsZK`uQLM$vLeNaBT*vee9O2k*A{gyV@H`W$0dv4?Hv0MppC~<1FZ#?x<2#2z>`W~Gt?p*k=J9!kED_H>klvbA9 zwqUR3Lr6$?Xz0SFEKq1_|8a{%RTTx=J9v*$RXv`47y31XG$%JVD5%@bM30bgzRfnh zan_z#e)+2H>XYYIkxn1^_B>)EOq$YrIgvuS-o%v}zeM0WhDbAN$Vs=yDsyD+m!ClS zdRaAv>AJ#{V!))Fj<(8pd**cQ>gksUaZNjS8@Ej}?WFQ6*0!_iqco5|SaasjF0f-4 z%yO@BRb#6cw+_zb0GBZ$?qeIb=R58{w%&0-YQ2?a_SOHuBhPR3<_<%ICvke>Nu~g3 z|4q*{$2F46hSS`Ynwhl0x#%xkCe11Ak>GLV=( zSoWcw(WM?1UfVpl&~T}(Rq0a^T9$wa+|u)Zc4%}mpKX2_ap9YU3PF;dtd`9nw|$eW z12LKYAeVaMjiZkb4)Y+2&oVjzGu1x&NDA_*)fZFl&TBFYcCtefMICJ>Q8boM$=Xf= z>wd2m-zOuhLNDYrx(3dK`ho-sqG1ts$QJL<_iinYnysUllE@obK(?^Pv)f1;evq}I zr@)&pa<#ek?u1iCS}&rc22WVqK7CV88uRXP*DNx-=AenHuI(ZeX2^3y#2&S$z!ecx!DJw@HwII2F3R^+l=R4h^BLE1-mIKsEQ>mz5B(%T`F22=F8V2U4&=WLnAd~;mj z+5W9)wOgsdQhUvBPKI#n$)ruKJ}Ux{Xdh|_s#N?_44>e+)*mn|rnAeWEnT`r|4K<= zRx=H$3VL@werY33N*XDceZhvYenHFcKhP~1dnJh!H+z(Z7G*gYTb8d7z5SW*=s{@w zSOYRo`LnKy%;iShs;L_2$2p%_18lT^FTo>IS|&hr#(!zs!1QzQCUMGvqvHhOF3nTn z{2i0zAza0#W?LT^BSJ32?-Dpd8s52eX*=-;@+q9jcV~JzZN;p$ppT^p=Iv^o{0nen zZ0mgD870A5hB#jHSPB)Zsv@hwBc*__v8BV;9Z0F;@SdRQQy#6+D zy)DP*Cr-S}v~Ghv>24dyLy3eL=W4Lo2x|Jxq7S-R?ZkHaX}Sb)bz1oVtA+{k3yF(FqNykaxaPelGnGl7eK$Qd zn-wmx4{{zya;=RN53UIppruKp|7`Si4Ytql^T8%=iu(>te655If29kdA+ZzLiIK0) zgUpHLx}rXv-$NBmd-OJ0h+Z|72e;jBfgGKnyv;u>m+e+X@i1V zbU*DImH_6eywTBvzzmiYKq!@JPVe!Z^G=|1-*3~4NLrx;N5S|X|-YV%@(Jh zh2jqYjN=bt~8()`J*tyjPN zuuqVmPeO9WF8&@GTx8dgbwJ%U9a5589@ZU*)H#2H;_;w*Lj7C>m8Z~cCfmHQjoVB= z(xFcvfWZ%W83%V++wR4^Q_eRV8e>KZ+uy5Rh2@1z-4muwEbog3YWL-zZ8Qx0(_tuUX4esX6|a->9&jj zs1^kGu|4VR$y?j^2<{i`(QcMT=-_L~uJ2xizBhjHDXrbaGl5uO5jc^cr5t$g3H8hN z2Wj1Hzkv_Ml-MTxe+as_lK})&x#|N@g1T=7K(&n&|3p3dDxdr&_x=Zrb_+}~Gd-W% z*K{{F6+U;&xLN8XcT7V|)jW#bgV$%y`%*sub!_$1#edn<>Ko~e*TCQM{VN)G8bdIx zG;zms-jw8@ON?***-Cw<3FkT-J)k_!`MPXM^q|Ffbkt|qiL3~V$jM3YNDs@G$?Eq8HKcbq@wZ)*up&ajMNy7a16vmQB{?!6*@f=S@lPERH}#qIjd*& zOGYgUX73Y_5|}Xi3z5wQBjAmN7K!*Sn^+~-)iTse&?hfmF4esKVO{Byf^PRDH) zKvbTZkDNhZWB*be_kfBCWfx|%hiST|*E+ZtSvUGxrvchMt5%y< z`#ODEv`A~>nK!p%Sl}?GUh4t*qEz6^c}-8<$zU#_(^p3m!zZi#1J80^v28cz0Fjle zAh?eB#a-iJ8zJCX-;4~K02Zz!AdpRL)KE{mrc>`e)u5|fm#rt{^f=4emW&Kuo5{8) zJ#U6Nl;i>}PPYbfDSLmhc;lE9ASg-?XQZ@WwV}Z-Z~W46+O`YWa^c{-xNlgGa(BXx znXNK@0NV+HXwhgxcXuQ2lit=laaV)4goeH_)vo;9jHs)lrht|dI z9<0sHIv$*Meg4I_lVN(QvpJZ75Wy`DE!D$9S`XnqZvxPsGCm3=m>z#!ADKxrn$%K- z2V`8WOQ3+38s>W5nr8I;p$gVc4xraLDEm!glPqpJze~EriIr*?5Gsea$Q47}5#D_A zQ^2wl0d(@U&f2XtS^-ANT3QD!r^>pQmc#wmNNeF#aNFAWt3QtIeRmk+)qp2fMc2gV zgdFdZ81>tTZ|UK|jVG9T6iK%w^)`sUc#_r%m?unESVc>s&yrqrjL@w>wnsnG5W z5BsRDFsQNNlJ`?^t{3czib{5L1F`8A9jj)`>J8-mOKda~EbS~dxch*4sjFNueKhk% zvIwkpb8$WdGRV7ada?i~^tS-#uA?FEcaZ)k+}vAx!6wRGB9&@2YUyjTPCpWnq0|DL z5-;aFe$qT$)jRT}1_p7k?7Z5;R8u11;`IQLlZn3O%#2%5sN}J6tBm=3PAc0S8_W34 z3idVcU*>6prqTk{!L?AupKb6#?UUElLwP@tjmhEAIsI0Y_M(()&X2aC@x0}8U#>hS zCBsuTC~xHyEMRU1yBC{&%TsG^s4>Y}jptw})^*^|iaWM@aVY@-9i6SJVqgVa z?KaL_sp&$@kmLb2F28F#3%45D8X{YvA2L$Tel!)3`@igkG{eH7@oQCE{XgDH5C-xx zrFv~tDQn<8Ue|FW z+AITmQSOo+N~Q<#u8#n25)~=z{1%^`XlDr zjeTi^sRcL$UV16ek;PWxu+e=T*9dFS9Zluc*a>#yEUz3FEo_ovjdj&W9_6_iA^)x6 zfYv6+x`6w|3_mkjEVM)q2L=m>2#AEG#cD@HsJwXbq9#}fumyYL9Nq(3y;Y`|>=nzF z!%W>FRSn9H!Z#(SN#9v(!&IRUC3Uz=mkh=q|? z9Y+zf<=R-s`cERZG9K%UEQ`Z=fz5mnXTN)uwgW@dARxefO%Ct9k3c4@4{cv)S}8z2?HboU zI!H@N0X7YDD7`Wd%1h2Tt$nNRX0h@-HxyHdk;|RyKL~i}Qt|d!rO-cm{o@187|rFu z3Tz}D75hs*a?t)GetrD^bXtesaqkz!9~hv zhg}kk51mG%Ai1YNk8T4!>Q2MM*89!}O@ve8eCGeU-d6fz+D(9SG@$3*5w0&qYDS7 z?x8iTgaioZVmcl{bk#8<#U>nd^KwD90SjSC1wY=FAA`tSX8qe>Q2koQVG}F^=>(#V z2hgrI&G?^ZVq-y|)Zq|oks;dA!_ADnW;V9(_A`gVUAO~nr_m}j4e~|izPHLPve+1f z=ueG(%8`?0x5A;_-wbl5(gXLozgnM8o2dcJj?l?6&UJ|YW@$K0Jp~yV%tV5*-Nw}9 zWME#<-~RHpR*=~Sj~WKHPyADR-~ zd23$pWIMHs8h{}s124{jd%alh>1)W`BU9NNe-DGmj6n4pB4qq9a`Ey&A|764+RSqA z22`su%X8)nFqUFz6Ix-2uzz%Yk9%OCd%~e{O)1~`qVu*iquWVQa{OA;J~9&M_`FtV z{rBMt>AE|y3MDibI3@7%;jBj+2&8kv@8aFXHy~R3Vv3UgHf}4E!6w5BkVa5EHx9Wu z_b7zxG6>!4Mnsaw-Haq_N>dcu8x44rrl)Bm?A=c>28x&{djhsyoXjXWr94oent$1YWqcY!0Ujy$i*{1M z(**nJoRBzxqMpAnIO)CLiuU2=965YQzOL0LAfzPt>LAk4ZE%icGQa6iF>pDcZ70O} zvh8g5*UEs|Ws9&exc!Skb#$(4+{4*+&zC(d%H|+)zuhSvm#G|J9@rFmuDG^s3~W&M z*=O&W)gQmL6Z=xu+A0!yYI1lp3K|s^HK8cp`L`h9m}A9q_7?$8MtHs1#$dH~+{tX4 zlydBm|0ILKm{xPS#DH9jW>&QQ&^d_wi}z>ix83WtoBnd`4HsVn(Chdm-gliWU9+Am zD?Q+k(wM*Eza%3d=E*eNt2y=QGVZiMt&A3#^Yl8K{feBrVyR;&hR*ZUu6HqZ7Tc8j zwZ*5N&$srx@|lLw&6|JT7VR@D*4^a0e0(?s{j`w@0-`_j6ik&|IfFE}$^D9yDuacq zR>tCyratH6=W6uhCP?wDW z&!DnR%#Z+V*8xI@T{Bm+06C-pg<1{l#WkTQ;vP~2IGJ;SVojGyB*c<A{mA{72*zR4I6K?UQh$~8xe19Q$he` z%3Fv+>*3Zwce>l7)%2#+4|Qqf1$GoON+RbIx$a5@=#Mo9uAfm3&f7BcSS5s5aJ@ly zV?%dFz0FY+g(y>ssUB7)=ct!IQa)#9SOwb%M@48U>(Io_xo26SaDzrcV6TKf$5(WEW)%i{Rb3B#Dz@350K zVXovXsz~)Y#;XMFHj(x;P;fme^@He>o*R)FkznwP-b3U*yDsp(LIrIcyr3SwMU~y3 z(GT-MpgdY3c23YMgnu8G2aNu~dN@Gaaut%x@lNA{*HG~Fn8YV2_5k~=F0}rb>D)Sg z8&(WjXmr0&t=8l$p!{3PX^ynUz!d01Ve=!$;{!wwn=OP@XF_+`087`#7m4G z6kUifB)DgODmNM>Y?8j|{B|?b8(u8oFhxOjz{w1uKekEbJ6rp6^$ad^N1#IbHKLAV zAUrkn;o+~D`OI+CX+82%xuik1Wp=V!-*>3M#VGjWPO~W7wx#?f3jx8cZGh~hosX>K zqG0iN!LtyKoup&#$}cy!EI9f4i1T^b$nF}#_YpPS&N`-(XcKk)S&t^uCI^| zxZMTf?E5iX0_3qG)^yeVrq9kD<_VI}$5L%>=oF|%k+~DD!Gj&ZDtPg5k2W>;gQx%> z%L)t-AEIO6g?|60|H+E^%b4ZZ5k zQ+6w%Xr$Mpql3mpB}AUGcqc&RJ++7~C4dyHRxK1A17xZ0S9pr~3c&UKD?gVip)x2Z z&C|$cd?zH2(Zdl(>g9K|o@x_Ix@7nRJ@+T?ysdG)i`=$~tY0)whDhOH$8aC^BQ?c; zB^9!er@96L{m3m3XzZ}I7MTIG+>KjG*^E8S^}AR(3|ExQF*GSzghZ5fKrQbL9GO{YCy`@5gwL63HiaZyP}0VnTsA<0>}KZT6q2 zg-f$c{x(e>LyVWsA3O78kW#+Rq1xnRvD11L&pLR`+D;ZmOzG+*p~yRAzokI8#vBVK z0CmKDu01Pqf|yU)L2RVFUO%x5TE`0kjI@6K*oFnTX*fJaJz}HA!O7R>SM+9u^@FPhH=r_e!tECz2v79+LCV+{J9A(2Jh$r@lg2jitxcc= zd}H~QC#w0atS|QMrT3b=fUP#Vt$=9(%tC@7S^Qp^|1XXf*}Mc#cBuY)q|*hUHNVt9 zIlT5&-3#eE;@Gj$VMs!E>7W%UB;c>V1N=`!)wU2+N z6BpriH#1i??!0}v+lF~Holh723{;bL{UBM~AkB_RhA8xI-MW0!*h`<&|1b}~N3js6 z=V+z`ARf?byaz(uXsbW~Jeq;*RPW;h&Q*#5@ldADteOpJ-SoGk<7E#-k9ow@*2V0(#};?QEU7ip}&-aM@U@F4*NJwpSiBy1ewLqIdjYSQznJ6nQTHBi|88%46btQA{V> zl|*$5`%1Mg|COal_son~dDqgZ*`<4@%Smhye4?6?%yu%{?!`p0R=xwn`pnFu3;Z$> z20_=e32ui6hiWKBtOqi4714bP+mm+TELN&#Ojx?qOr6{wX-qZ^>6U1=CU(-O_S-w3 zOr)kxJbHcFQ)@qUD86><-w76_d`#g$rQ=B=URSxJ*FSh}_@uD0YM*7a-FF-d(sV+d zJ`(A1SFU0Bhn-0{tT$!2J6|*Lr3F{e6z#^LH9R|avKQtQS@1Dr(_@N;{>~lddh4nB zKdQWdZBKhPO{zp;+s)N*IeaQn%0~CKKl0Y4A=fH*3Z+k|DL|gcv|h+ zB~!5%yDMHlc{Tl5UC51dFPjfW%iJ}u3wN!*|8253uijhZoyE-4Z*9F@6(hD0=N|d6 z3%5bTzug*;jYM;NK7J4cPdhbxWQ4r&dVjpVc7EpmxJ5JORs#F;z}Qfm$=?#CwO$KY z3U}@Z6KG%rb)|xqZ+KPx1lV}t5nz4@3|G|cj9B?Qnl&2kc>aD0EY2A`#5OlUbp7b6 p1ThROfK3G;-Ea`NU1UhpKkXg;{y1H}x$P6kU!JahF6*2UngHE=eBl59 literal 0 HcmV?d00001 diff --git a/install-alembic-and-clone-qwc-config-db.sh b/install-alembic-and-clone-qwc-config-db.sh deleted file mode 100755 index 9550f8a..0000000 --- a/install-alembic-and-clone-qwc-config-db.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash - -help() { - echo 'usage: install-alembic-and-clone-qwc-config-db QWC_CONFIG_DB_GIT_REPO' - echo ' install-alembic-and-clone-qwc-config-db -alembic --help' - echo - exit 1 -} - -[ "$1" == "--help" ] || [ "$1" == "" ] && help - -set -e # stop on error - -QWC_CONFIG_DB_GIT_REPO="$1" -QWC_CONFIG_DB_DEST="$2" - -apt-get install -y ca-certificates tmux screen curl less \ - git python3-pip python3-psycopg2 gdal-bin - -# get qwc-config-db for migrations -cd /tmp/ && git clone $QWC_CONFIG_DB_GIT_REPO qwc-config-db -cd /tmp/qwc-config-db/ && git pull -pip3 install --upgrade pip -pip3 install --no-cache-dir -r /tmp/qwc-config-db/requirements.txt - diff --git a/install-postgis.sh b/install-postgis.sh deleted file mode 100755 index 110b81d..0000000 --- a/install-postgis.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -help() { - echo 'usage: install-postgis POSTGRES_MAJOR_VERSION POSTGIS_VERSION' - echo ' install-postgis --help' - echo - exit 1 -} - -[ "$1" == "--help" ] || [ "$1" == "" ] || [ "$2" == "" ] && help - - -POSTGRES_MAJOR_VERSION="$1" -POSTGIS_VERSION="$2" - -set -e # stop on error - -apt-get install --no-install-recommends -y \ - postgresql-$POSTGRES_MAJOR_VERSION-postgis-$POSTGIS_VERSION \ - postgresql-$POSTGRES_MAJOR_VERSION-postgis-$POSTGIS_VERSION-scripts; diff --git a/pg_service.conf b/pg_service.conf new file mode 100644 index 0000000..f6c2f4b --- /dev/null +++ b/pg_service.conf @@ -0,0 +1,6 @@ +[qwc_configdb] +host=qwc-postgis +port=5432 +dbname=qwc_services +user=qwc_admin +password=qwc_admin diff --git a/run-migrations.sh b/run-migrations.sh deleted file mode 100755 index 7300b43..0000000 --- a/run-migrations.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash -set -e - -# run migrations from qwc-config-db -cd /tmp/qwc-config-db/ -PGSERVICE=qwc_configdb alembic upgrade ${ALEMBIC_VERSION:-head} diff --git a/setup-roles-and-db.sh b/setup-roles-and-db.sh index 83e358f..50102c9 100755 --- a/setup-roles-and-db.sh +++ b/setup-roles-and-db.sh @@ -7,25 +7,18 @@ psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<-EOSQL CREATE ROLE qwc_service LOGIN PASSWORD 'qwc_service'; CREATE ROLE qwc_service_write LOGIN PASSWORD 'qwc_service_write'; - CREATE DATABASE qwc_demo; - COMMENT ON DATABASE qwc_demo IS 'Demo DB for qwc-services'; + CREATE DATABASE qwc_services; + COMMENT ON DATABASE qwc_services IS 'DB for qwc-services'; EOSQL -psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" -d qwc_demo <<-EOSQL +psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" -d qwc_services <<-EOSQL CREATE SCHEMA qwc_config AUTHORIZATION qwc_admin; - COMMENT ON SCHEMA qwc_config IS 'Configurations for qwc-services'; + COMMENT ON SCHEMA qwc_config IS 'ConfigDB for qwc-services'; EOSQL -psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" -d qwc_demo <<-EOSQL +psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" -d qwc_services <<-EOSQL CREATE EXTENSION postgis; GRANT SELECT ON TABLE geometry_columns TO PUBLIC; GRANT SELECT ON TABLE geography_columns TO PUBLIC; GRANT SELECT ON TABLE spatial_ref_sys TO PUBLIC; - - CREATE SCHEMA qwc_geodb; - COMMENT ON SCHEMA qwc_geodb IS 'Demo GeoDB for qwc-services'; - GRANT USAGE ON SCHEMA qwc_geodb TO qgis_server; - GRANT ALL ON SCHEMA qwc_geodb TO qwc_admin; - GRANT USAGE ON SCHEMA qwc_geodb TO qwc_service; - GRANT ALL ON SCHEMA qwc_geodb TO qwc_service_write; EOSQL