From 530a44ed41ec249d8843878300eb45485d313584 Mon Sep 17 00:00:00 2001 From: Emanuele Tajariol Date: Fri, 22 Sep 2023 15:52:03 +0200 Subject: [PATCH 01/70] Honor DB username as set in env file (#11522) --- tasks.py | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/tasks.py b/tasks.py index 967c08af386..a37fe622bad 100755 --- a/tasks.py +++ b/tasks.py @@ -504,22 +504,26 @@ def _container_exposed_port(component, instname): def _update_db_connstring(): - user = os.getenv("GEONODE_DATABASE", "geonode") - pwd = os.getenv("GEONODE_DATABASE_PASSWORD", "geonode") - dbname = os.getenv("GEONODE_DATABASE", "geonode") - dbhost = os.getenv("DATABASE_HOST", "db") - dbport = os.getenv("DATABASE_PORT", 5432) - connstr = f"postgis://{user}:{pwd}@{dbhost}:{dbport}/{dbname}" + connstr = os.getenv("DATABASE_URL", None) + if not connstr: + user = os.getenv("GEONODE_DATABASE_USER", "geonode") + pwd = os.getenv("GEONODE_DATABASE_PASSWORD", "geonode") + dbname = os.getenv("GEONODE_DATABASE", "geonode") + dbhost = os.getenv("DATABASE_HOST", "db") + dbport = os.getenv("DATABASE_PORT", 5432) + connstr = f"postgis://{user}:{pwd}@{dbhost}:{dbport}/{dbname}" return connstr def _update_geodb_connstring(): - geouser = os.getenv("GEONODE_GEODATABASE", "geonode_data") - geopwd = os.getenv("GEONODE_GEODATABASE_PASSWORD", "geonode_data") - geodbname = os.getenv("GEONODE_GEODATABASE", "geonode_data") - dbhost = os.getenv("DATABASE_HOST", "db") - dbport = os.getenv("DATABASE_PORT", 5432) - geoconnstr = f"postgis://{geouser}:{geopwd}@{dbhost}:{dbport}/{geodbname}" + geoconnstr = os.getenv("GEODATABASE_URL", None) + if not geoconnstr: + geouser = os.getenv("GEONODE_GEODATABASE_USER", "geonode_data") + geopwd = os.getenv("GEONODE_GEODATABASE_PASSWORD", "geonode_data") + geodbname = os.getenv("GEONODE_GEODATABASE", "geonode_data") + dbhost = os.getenv("DATABASE_HOST", "db") + dbport = os.getenv("DATABASE_PORT", 5432) + geoconnstr = f"postgis://{geouser}:{geopwd}@{dbhost}:{dbport}/{geodbname}" return geoconnstr From 20f8ec58b8334a9a01672ab1ddaa9dcf7767b9a7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Sep 2023 09:44:09 +0200 Subject: [PATCH 02/70] Bump django-filter from 23.2 to 23.3 (#11503) * Bump django-filter from 23.2 to 23.3 Bumps [django-filter](https://github.com/carltongibson/django-filter) from 23.2 to 23.3. - [Release notes](https://github.com/carltongibson/django-filter/releases) - [Changelog](https://github.com/carltongibson/django-filter/blob/main/CHANGES.rst) - [Commits](https://github.com/carltongibson/django-filter/compare/23.2...23.3) --- updated-dependencies: - dependency-name: django-filter dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * - Align setup.cfg to requirements.txt --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: afabiani --- requirements.txt | 2 +- setup.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 0ec3426887d..7c714faa1ab 100644 --- a/requirements.txt +++ b/requirements.txt @@ -32,7 +32,7 @@ pathvalidate==3.1.0 django-allauth==0.54.0 django-appconf==1.0.5 django-celery-results==2.5.1 -django-filter==23.2 +django-filter==23.3 django-imagekit==4.1.0 django-taggit==1.5.1 django-markdownify==0.9.3 diff --git a/setup.cfg b/setup.cfg index 08de7a9da04..88775b742b1 100644 --- a/setup.cfg +++ b/setup.cfg @@ -58,7 +58,7 @@ install_requires = django-allauth==0.54.0 django-appconf==1.0.5 django-celery-results==2.5.1 - django-filter==23.2 + django-filter==23.3 django-imagekit==4.1.0 django-taggit==1.5.1 django-markdownify==0.9.3 From 101b89b22ea9342affe5c7549519ecfff21dbd9d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Sep 2023 09:45:10 +0200 Subject: [PATCH 03/70] Bump django-grappelli from 3.0.7 to 3.0.8 (#11529) * Bump django-grappelli from 3.0.7 to 3.0.8 Bumps [django-grappelli](https://github.com/sehmaschine/django-grappelli) from 3.0.7 to 3.0.8. - [Changelog](https://github.com/sehmaschine/django-grappelli/blob/master/docs/changelog.rst) - [Commits](https://github.com/sehmaschine/django-grappelli/compare/3.0.7...3.0.8) --- updated-dependencies: - dependency-name: django-grappelli dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * - Align setup.cfg to requirements.txt --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: afabiani --- requirements.txt | 2 +- setup.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 7c714faa1ab..b7ebf8f29e7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -44,7 +44,7 @@ django-downloadview==2.3.0 django-polymorphic==3.1.0 django-tastypie<0.15.0 django-tinymce==3.6.1 -django-grappelli==3.0.7 +django-grappelli==3.0.8 django-uuid-upload-path==1.0.0 django-widget-tweaks==1.5.0 django-sequences==2.8 diff --git a/setup.cfg b/setup.cfg index 88775b742b1..48f7f529a54 100644 --- a/setup.cfg +++ b/setup.cfg @@ -70,7 +70,7 @@ install_requires = django-polymorphic==3.1.0 django-tastypie<0.15.0 django-tinymce==3.6.1 - django-grappelli==3.0.7 + django-grappelli==3.0.8 django-uuid-upload-path==1.0.0 django-widget-tweaks==1.5.0 django-sequences==2.8 From 10b936a33b8bfb29a3f53fa52304cbacdbaaeca2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Sep 2023 09:46:57 +0200 Subject: [PATCH 04/70] Bump drf-spectacular from 0.26.4 to 0.26.5 (#11525) * Bump drf-spectacular from 0.26.4 to 0.26.5 Bumps [drf-spectacular](https://github.com/tfranzel/drf-spectacular) from 0.26.4 to 0.26.5. - [Release notes](https://github.com/tfranzel/drf-spectacular/releases) - [Changelog](https://github.com/tfranzel/drf-spectacular/blob/master/CHANGELOG.rst) - [Commits](https://github.com/tfranzel/drf-spectacular/compare/0.26.4...0.26.5) --- updated-dependencies: - dependency-name: drf-spectacular dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Bump drf-spectacular from 0.26.4 to 0.26.5 Bumps [drf-spectacular](https://github.com/tfranzel/drf-spectacular) from 0.26.4 to 0.26.5. - [Release notes](https://github.com/tfranzel/drf-spectacular/releases) - [Changelog](https://github.com/tfranzel/drf-spectacular/blob/master/CHANGELOG.rst) - [Commits](https://github.com/tfranzel/drf-spectacular/compare/0.26.4...0.26.5) --- updated-dependencies: - dependency-name: drf-spectacular dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Bump drf-spectacular from 0.26.4 to 0.26.5 Bumps [drf-spectacular](https://github.com/tfranzel/drf-spectacular) from 0.26.4 to 0.26.5. - [Release notes](https://github.com/tfranzel/drf-spectacular/releases) - [Changelog](https://github.com/tfranzel/drf-spectacular/blob/master/CHANGELOG.rst) - [Commits](https://github.com/tfranzel/drf-spectacular/compare/0.26.4...0.26.5) --- updated-dependencies: - dependency-name: drf-spectacular dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * - Align setup.cfg to requirements.txt --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: afabiani --- requirements.txt | 2 +- setup.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index b7ebf8f29e7..d367a018cdc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -80,7 +80,7 @@ djangorestframework-gis==1.0 djangorestframework-guardian==0.3.0 drf-extensions==0.7.1 drf-writable-nested==0.7.0 -drf-spectacular==0.26.4 +drf-spectacular==0.26.5 dynamic-rest==2.1.2 Markdown==3.4.4 diff --git a/setup.cfg b/setup.cfg index 48f7f529a54..200a6b55b6e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -106,7 +106,7 @@ install_requires = djangorestframework-guardian==0.3.0 drf-extensions==0.7.1 drf-writable-nested==0.7.0 - drf-spectacular==0.26.4 + drf-spectacular==0.26.5 dynamic-rest==2.1.2 Markdown==3.4.4 From 7775303342e0943c537160c8eca2b7852c2ce33a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Sep 2023 09:48:27 +0200 Subject: [PATCH 05/70] Bump google-cloud-storage from 2.10.0 to 2.11.0 (#11524) * Bump google-cloud-storage from 2.10.0 to 2.11.0 Bumps [google-cloud-storage](https://github.com/googleapis/python-storage) from 2.10.0 to 2.11.0. - [Release notes](https://github.com/googleapis/python-storage/releases) - [Changelog](https://github.com/googleapis/python-storage/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/python-storage/compare/v2.10.0...v2.11.0) --- updated-dependencies: - dependency-name: google-cloud-storage dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Bump google-cloud-storage from 2.10.0 to 2.11.0 Bumps [google-cloud-storage](https://github.com/googleapis/python-storage) from 2.10.0 to 2.11.0. - [Release notes](https://github.com/googleapis/python-storage/releases) - [Changelog](https://github.com/googleapis/python-storage/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/python-storage/compare/v2.10.0...v2.11.0) --- updated-dependencies: - dependency-name: google-cloud-storage dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Bump google-cloud-storage from 2.10.0 to 2.11.0 Bumps [google-cloud-storage](https://github.com/googleapis/python-storage) from 2.10.0 to 2.11.0. - [Release notes](https://github.com/googleapis/python-storage/releases) - [Changelog](https://github.com/googleapis/python-storage/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/python-storage/compare/v2.10.0...v2.11.0) --- updated-dependencies: - dependency-name: google-cloud-storage dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * - Align setup.cfg to requirements.txt --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: afabiani --- requirements.txt | 2 +- setup.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index d367a018cdc..4eff0ee1c6b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -111,7 +111,7 @@ django-bootstrap3-datetimepicker-2==2.8.3 # storage manager dependencies django-storages==1.14 dropbox==11.36.2 -google-cloud-storage==2.10.0 +google-cloud-storage==2.11.0 google-cloud-core==2.3.3 boto3==1.28.46 diff --git a/setup.cfg b/setup.cfg index 200a6b55b6e..66488c28a26 100644 --- a/setup.cfg +++ b/setup.cfg @@ -136,7 +136,7 @@ install_requires = # storage manager dependencies django-storages==1.14 dropbox==11.36.2 - google-cloud-storage==2.10.0 + google-cloud-storage==2.11.0 google-cloud-core==2.3.3 boto3==1.28.46 From 64555c51b78801d8349ee3be1c4bbe050423fa8e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Sep 2023 09:50:53 +0200 Subject: [PATCH 06/70] Bump jsonschema from 4.19.0 to 4.19.1 (#11527) * Bump jsonschema from 4.19.0 to 4.19.1 Bumps [jsonschema](https://github.com/python-jsonschema/jsonschema) from 4.19.0 to 4.19.1. - [Release notes](https://github.com/python-jsonschema/jsonschema/releases) - [Changelog](https://github.com/python-jsonschema/jsonschema/blob/main/CHANGELOG.rst) - [Commits](https://github.com/python-jsonschema/jsonschema/compare/v4.19.0...v4.19.1) --- updated-dependencies: - dependency-name: jsonschema dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * - Align setup.cfg to requirements.txt --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: afabiani --- requirements.txt | 2 +- setup.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 4eff0ee1c6b..13fb08302a7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -20,7 +20,7 @@ vine==5.0.0 tqdm==4.66.1 Deprecated==1.2.14 wrapt==1.15.0 -jsonschema==4.19.0 +jsonschema==4.19.1 zipstream-new==1.1.8 schema==0.7.5 rdflib==6.3.2 diff --git a/setup.cfg b/setup.cfg index 66488c28a26..4909847c20c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -46,7 +46,7 @@ install_requires = tqdm==4.66.1 Deprecated==1.2.14 wrapt==1.15.0 - jsonschema==4.19.0 + jsonschema==4.19.1 zipstream-new==1.1.8 schema==0.7.5 rdflib==6.3.2 From da1939d7da8a4e468400f511f790767af18ff6d9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Sep 2023 09:52:28 +0200 Subject: [PATCH 07/70] Update numpy requirement from ==1.25.* to ==1.26.* (#11501) * Update numpy requirement from ==1.25.* to ==1.26.* Updates the requirements on [numpy](https://github.com/numpy/numpy) to permit the latest version. - [Release notes](https://github.com/numpy/numpy/releases) - [Changelog](https://github.com/numpy/numpy/blob/main/doc/RELEASE_WALKTHROUGH.rst) - [Commits](https://github.com/numpy/numpy/compare/v1.25.0.dev0...v1.26.0) --- updated-dependencies: - dependency-name: numpy dependency-type: direct:production ... Signed-off-by: dependabot[bot] * - Align setup.cfg to requirements.txt --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: afabiani --- requirements.txt | 2 +- setup.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 13fb08302a7..65eec1530db 100644 --- a/requirements.txt +++ b/requirements.txt @@ -60,7 +60,7 @@ SQLAlchemy==2.0.20 # required by PyCSW Shapely==1.8.5.post1 mercantile==1.2.1 geoip2==4.7.0 -numpy==1.25.* +numpy==1.26.* # # Apps with packages provided in GeoNode's PPA on Launchpad. diff --git a/setup.cfg b/setup.cfg index 4909847c20c..1aa436f6740 100644 --- a/setup.cfg +++ b/setup.cfg @@ -86,7 +86,7 @@ install_requires = Shapely==1.8.5.post1 mercantile==1.2.1 geoip2==4.7.0 - numpy==1.25.* + numpy==1.26.* # # Apps with packages provided in GeoNode's PPA on Launchpad. From b74e96e3c0eb60b194f3adb7e0adb25f23a24fa4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Sep 2023 09:54:08 +0200 Subject: [PATCH 08/70] Bump pathvalidate from 3.1.0 to 3.2.0 (#11504) * Bump pathvalidate from 3.1.0 to 3.2.0 Bumps [pathvalidate](https://github.com/thombashi/pathvalidate) from 3.1.0 to 3.2.0. - [Release notes](https://github.com/thombashi/pathvalidate/releases) - [Commits](https://github.com/thombashi/pathvalidate/compare/v3.1.0...v3.2.0) --- updated-dependencies: - dependency-name: pathvalidate dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Bump pathvalidate from 3.1.0 to 3.2.0 Bumps [pathvalidate](https://github.com/thombashi/pathvalidate) from 3.1.0 to 3.2.0. - [Release notes](https://github.com/thombashi/pathvalidate/releases) - [Commits](https://github.com/thombashi/pathvalidate/compare/v3.1.0...v3.2.0) --- updated-dependencies: - dependency-name: pathvalidate dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * - Align setup.cfg to requirements.txt --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: afabiani --- requirements.txt | 2 +- setup.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 65eec1530db..e6bab075ae5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -26,7 +26,7 @@ schema==0.7.5 rdflib==6.3.2 smart_open==6.4.0 PyMuPDF==1.22.5 -pathvalidate==3.1.0 +pathvalidate==3.2.0 # Django Apps django-allauth==0.54.0 diff --git a/setup.cfg b/setup.cfg index 1aa436f6740..5f02decc6ca 100644 --- a/setup.cfg +++ b/setup.cfg @@ -52,7 +52,7 @@ install_requires = rdflib==6.3.2 smart_open==6.4.0 PyMuPDF==1.22.5 - pathvalidate==3.1.0 + pathvalidate==3.2.0 # Django Apps django-allauth==0.54.0 From c36e976792f96868898a119e51ee46ff3c4f4caf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Sep 2023 09:56:08 +0200 Subject: [PATCH 09/70] Bump webdriver-manager from 4.0.0 to 4.0.1 (#11530) * Bump webdriver-manager from 4.0.0 to 4.0.1 Bumps [webdriver-manager](https://github.com/SergeyPirogov/webdriver_manager) from 4.0.0 to 4.0.1. - [Release notes](https://github.com/SergeyPirogov/webdriver_manager/releases) - [Changelog](https://github.com/SergeyPirogov/webdriver_manager/blob/master/CHANGELOG.md) - [Commits](https://github.com/SergeyPirogov/webdriver_manager/compare/v4.0.0...v4.0.1) --- updated-dependencies: - dependency-name: webdriver-manager dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Bump webdriver-manager from 4.0.0 to 4.0.1 Bumps [webdriver-manager](https://github.com/SergeyPirogov/webdriver_manager) from 4.0.0 to 4.0.1. - [Release notes](https://github.com/SergeyPirogov/webdriver_manager/releases) - [Changelog](https://github.com/SergeyPirogov/webdriver_manager/blob/master/CHANGELOG.md) - [Commits](https://github.com/SergeyPirogov/webdriver_manager/compare/v4.0.0...v4.0.1) --- updated-dependencies: - dependency-name: webdriver-manager dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * - Align setup.cfg to requirements.txt --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: afabiani --- requirements.txt | 2 +- setup.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index e6bab075ae5..aa5e7a570a9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -167,7 +167,7 @@ factory-boy==3.3.0 flaky==3.7.0 selenium>=4.1.0,<5.0.0 selenium-requests==2.0.3 -webdriver_manager==4.0.0 +webdriver_manager==4.0.1 # Security and audit mistune==3.0.1 diff --git a/setup.cfg b/setup.cfg index 5f02decc6ca..b2b810ab90c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -192,7 +192,7 @@ install_requires = flaky==3.7.0 selenium>=4.1.0,<5.0.0 selenium-requests==2.0.3 - webdriver_manager==4.0.0 + webdriver_manager==4.0.1 # Security and audit mistune==3.0.1 From 401d4a5ba4c5527b9a04872ccd38cc2edd0dcf8f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Sep 2023 09:57:31 +0200 Subject: [PATCH 10/70] Bump sqlalchemy from 2.0.20 to 2.0.21 (#11526) * Bump sqlalchemy from 2.0.20 to 2.0.21 Bumps [sqlalchemy](https://github.com/sqlalchemy/sqlalchemy) from 2.0.20 to 2.0.21. - [Release notes](https://github.com/sqlalchemy/sqlalchemy/releases) - [Changelog](https://github.com/sqlalchemy/sqlalchemy/blob/main/CHANGES.rst) - [Commits](https://github.com/sqlalchemy/sqlalchemy/commits) --- updated-dependencies: - dependency-name: sqlalchemy dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * - Align setup.cfg to requirements.txt --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: afabiani --- requirements.txt | 2 +- setup.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index aa5e7a570a9..95e9ab0f4d8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -56,7 +56,7 @@ pyjwt==2.8.0 pyproj<3.7.0 OWSLib==0.29.2 pycsw==2.6.1 -SQLAlchemy==2.0.20 # required by PyCSW +SQLAlchemy==2.0.21 # required by PyCSW Shapely==1.8.5.post1 mercantile==1.2.1 geoip2==4.7.0 diff --git a/setup.cfg b/setup.cfg index b2b810ab90c..2d23b57b60f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -82,7 +82,7 @@ install_requires = pyproj<3.7.0 OWSLib==0.29.2 pycsw==2.6.1 - SQLAlchemy==2.0.20 # required by PyCSW + SQLAlchemy==2.0.21 # required by PyCSW Shapely==1.8.5.post1 mercantile==1.2.1 geoip2==4.7.0 From 5422fd3d0e9b581f7bcdae9739d27cbc351d6407 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Sep 2023 10:06:47 +0200 Subject: [PATCH 11/70] Bump pillow from 10.0.0 to 10.0.1 (#11505) * Bump pillow from 10.0.0 to 10.0.1 Bumps [pillow](https://github.com/python-pillow/Pillow) from 10.0.0 to 10.0.1. - [Release notes](https://github.com/python-pillow/Pillow/releases) - [Changelog](https://github.com/python-pillow/Pillow/blob/main/CHANGES.rst) - [Commits](https://github.com/python-pillow/Pillow/compare/10.0.0...10.0.1) --- updated-dependencies: - dependency-name: pillow dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * - Align setup.cfg to requirements.txt --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: afabiani --- requirements.txt | 2 +- setup.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 95e9ab0f4d8..5c16fc20020 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ # native dependencies -Pillow==10.0.0 +Pillow==10.0.1 lxml==4.9.3 psycopg2==2.9.7 Django==3.2.21 diff --git a/setup.cfg b/setup.cfg index 2d23b57b60f..b0b687d637d 100644 --- a/setup.cfg +++ b/setup.cfg @@ -25,7 +25,7 @@ setup_requires = setuptools install_requires = # native dependencies - Pillow==10.0.0 + Pillow==10.0.1 lxml==4.9.3 psycopg2==2.9.7 Django==3.2.21 From ae6a48a87610c2b7ef8846291ff60659c4f1ba79 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Sep 2023 10:08:28 +0200 Subject: [PATCH 12/70] Bump boto3 from 1.28.46 to 1.28.53 (#11528) * Bump boto3 from 1.28.46 to 1.28.53 Bumps [boto3](https://github.com/boto/boto3) from 1.28.46 to 1.28.53. - [Release notes](https://github.com/boto/boto3/releases) - [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst) - [Commits](https://github.com/boto/boto3/compare/1.28.46...1.28.53) --- updated-dependencies: - dependency-name: boto3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Bump boto3 from 1.28.46 to 1.28.53 Bumps [boto3](https://github.com/boto/boto3) from 1.28.46 to 1.28.53. - [Release notes](https://github.com/boto/boto3/releases) - [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst) - [Commits](https://github.com/boto/boto3/compare/1.28.46...1.28.53) --- updated-dependencies: - dependency-name: boto3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * - Align setup.cfg to requirements.txt --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: afabiani --- requirements.txt | 2 +- setup.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 5c16fc20020..62ebeda6b1e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -113,7 +113,7 @@ django-storages==1.14 dropbox==11.36.2 google-cloud-storage==2.11.0 google-cloud-core==2.3.3 -boto3==1.28.46 +boto3==1.28.53 # Django Caches python-memcached<=1.59 diff --git a/setup.cfg b/setup.cfg index b0b687d637d..f2b7b1f19a2 100644 --- a/setup.cfg +++ b/setup.cfg @@ -138,7 +138,7 @@ install_requires = dropbox==11.36.2 google-cloud-storage==2.11.0 google-cloud-core==2.3.3 - boto3==1.28.46 + boto3==1.28.53 # Django Caches python-memcached<=1.59 From a9afe17e6c116c5eb38e244e80374f39697824aa Mon Sep 17 00:00:00 2001 From: Francisco Vicent Date: Mon, 25 Sep 2023 05:54:19 -0300 Subject: [PATCH 13/70] Dehydrate organization field (#11498) Co-authored-by: Alessio Fabiani --- geonode/api/api.py | 1 + 1 file changed, 1 insertion(+) diff --git a/geonode/api/api.py b/geonode/api/api.py index 4303c0caa4b..c80c699ed48 100644 --- a/geonode/api/api.py +++ b/geonode/api/api.py @@ -543,6 +543,7 @@ def dehydrate(self, bundle): documents_count=bundle.data.get("documents_count", 0), maps_count=bundle.data.get("maps_count", 0), layers_count=bundle.data.get("layers_count", 0), + organization=bundle.data.get("organization", 0), ) return bundle From 0248da514eb18a5a5f27002912b76c095ecef0e6 Mon Sep 17 00:00:00 2001 From: Giovanni Allegri Date: Tue, 26 Sep 2023 09:46:56 +0200 Subject: [PATCH 14/70] Revert to Ubuntu 22.04 LTS (#11531) --- Dockerfile | 2 +- docker-compose-test.yml | 2 +- docker-compose.yml | 2 +- scripts/docker/base/ubuntu/Dockerfile | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 3fb3fe1df84..1db25a2636e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM geonode/geonode-base:latest-ubuntu-22.10 +FROM geonode/geonode-base:latest-ubuntu-22.04 LABEL GeoNode development team # add bower and grunt command diff --git a/docker-compose-test.yml b/docker-compose-test.yml index 14a4b999fab..9bd764f8da3 100644 --- a/docker-compose-test.yml +++ b/docker-compose-test.yml @@ -3,7 +3,7 @@ version: '3.9' # Common Django template for GeoNode and Celery services below x-common-django: &default-common-django - image: geonode/geonode:latest-ubuntu-22.10 + image: geonode/geonode:latest-ubuntu-22.04 restart: unless-stopped env_file: - .env_test diff --git a/docker-compose.yml b/docker-compose.yml index 36d6d196fe2..7cc150f129c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,7 +3,7 @@ version: '3.9' # Common Django template for GeoNode and Celery services below x-common-django: &default-common-django - image: geonode/geonode:latest-ubuntu-22.10 + image: geonode/geonode:latest-ubuntu-22.04 restart: unless-stopped env_file: - .env diff --git a/scripts/docker/base/ubuntu/Dockerfile b/scripts/docker/base/ubuntu/Dockerfile index 8e406212798..0330c518ed2 100644 --- a/scripts/docker/base/ubuntu/Dockerfile +++ b/scripts/docker/base/ubuntu/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.10 +FROM ubuntu:22.04 RUN mkdir -p /usr/src/geonode From 6cd67df5975214b247722388c73319d62146e9a5 Mon Sep 17 00:00:00 2001 From: Giovanni Allegri Date: Wed, 27 Sep 2023 16:43:55 +0200 Subject: [PATCH 15/70] [Fixes #11535] Return category description in API response (#11536) * Return category description in API response * fix formatting --- geonode/base/api/serializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geonode/base/api/serializers.py b/geonode/base/api/serializers.py index 3e18a25138b..74d74e9a236 100644 --- a/geonode/base/api/serializers.py +++ b/geonode/base/api/serializers.py @@ -197,7 +197,7 @@ class SimpleTopicCategorySerializer(DynamicModelSerializer): class Meta: model = TopicCategory name = "TopicCategory" - fields = ("identifier",) + fields = ("identifier", "gn_description") class RestrictionCodeTypeSerializer(DynamicModelSerializer): From bba8cebca1e566f3e9f9c8615fd7d0c8e4bb88a0 Mon Sep 17 00:00:00 2001 From: Giovanni Allegri Date: Thu, 28 Sep 2023 10:02:12 +0200 Subject: [PATCH 16/70] [Fixes #11533] Remote resources created by harvesters do not have remote subtype (#11537) * Set subtype remote for any remote resurce --- geonode/harvesting/harvesters/base.py | 1 + .../harvesting/harvesters/geonodeharvester.py | 1 + geonode/harvesting/tests/test_integrations.py | 100 ++++++++++++++++++ geonode/resource/utils.py | 7 -- 4 files changed, 102 insertions(+), 7 deletions(-) create mode 100644 geonode/harvesting/tests/test_integrations.py diff --git a/geonode/harvesting/harvesters/base.py b/geonode/harvesting/harvesters/base.py index 5a2c484e9d0..c10b4c035d5 100644 --- a/geonode/harvesting/harvesters/base.py +++ b/geonode/harvesting/harvesters/base.py @@ -247,6 +247,7 @@ def get_geonode_resource_defaults( if self.should_copy_resource(harvestable_resource): defaults["sourcetype"] = enumerations.SOURCE_TYPE_COPYREMOTE else: + defaults["subtype"] = "remote" defaults["sourcetype"] = enumerations.SOURCE_TYPE_REMOTE return {key: value for key, value in defaults.items() if value is not None} diff --git a/geonode/harvesting/harvesters/geonodeharvester.py b/geonode/harvesting/harvesters/geonodeharvester.py index e7103e9bf1c..ec31b84b1d4 100644 --- a/geonode/harvesting/harvesters/geonodeharvester.py +++ b/geonode/harvesting/harvesters/geonodeharvester.py @@ -261,6 +261,7 @@ def get_geonode_resource_defaults( "thumbnail_url": harvested_info.resource_descriptor.distribution.thumbnail_url, "srid": srid, "ptype": GXP_PTYPES["GN_WMS"], + "subtype": "remote", } ) return defaults diff --git a/geonode/harvesting/tests/test_integrations.py b/geonode/harvesting/tests/test_integrations.py new file mode 100644 index 00000000000..37d3cb7aaf6 --- /dev/null +++ b/geonode/harvesting/tests/test_integrations.py @@ -0,0 +1,100 @@ +############################################## +# +# Copyright (C) 2021 OSGeo +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +######################################################################### +import uuid +import datetime as dt +from unittest import mock + +from django.test.utils import override_settings +from django.contrib.auth import get_user_model +from geonode.tests.base import GeoNodeBaseTestSupport +from geonode.layers.models import Dataset + +from geonode.harvesting.resourcedescriptor import ( + RecordDescriptionContact, + RecordDistribution, + RecordIdentification, + RecordDescription, +) +from geonode.harvesting.models import Harvester, HarvestableResource, AsynchronousHarvestingSession +from geonode.harvesting.harvesters.base import HarvestedResourceInfo +from geonode.harvesting.harvesters.geonodeharvester import GeonodeUnifiedHarvesterWorker + + +class HarvesterIntegrationsTestCase(GeoNodeBaseTestSupport): + unique_identifier = "id" + title = "Test" + remote_url = "test.com" + name = "This is a geonode harvester" + user = get_user_model().objects.get(username="AnonymousUser") + harvester_type = "geonode.harvesting.harvesters.geonodeharvester.GeonodeLegacyHarvester" + + @override_settings(ASYNC_SIGNALS=False) + def setUp(self): + super().setUp() + + self.record_description_contact = mock.MagicMock(RecordDescriptionContact) + self.record_distribution = mock.MagicMock(RecordDistribution) + self.record_distribution.thumbnail_url.return_value = "thumb.png" + self.record_distribution.wms_url.return_value = "http://test.com/geoserver" + self.record_identification = RecordIdentification(name=self.name, title=self.title, other_keywords=[]) + + self.harvester = Harvester.objects.create( + remote_url=self.remote_url, name=self.name, default_owner=self.user, harvester_type=self.harvester_type + ) + self.harvestable_resource = HarvestableResource.objects.create( + unique_identifier=self.unique_identifier, + title=self.title, + harvester=self.harvester, + last_refreshed=dt.datetime.now(), + remote_resource_type="dataset", + ) + + self.session = AsynchronousHarvestingSession.objects.create( + harvester=self.harvester, session_type=AsynchronousHarvestingSession.TYPE_HARVESTING + ) + + self.record_description = RecordDescription( + uuid=uuid.uuid4(), + author=self.record_description_contact, + date_stamp=dt.datetime.now(), + distribution=self.record_distribution, + identification=self.record_identification, + point_of_contact=self.record_description_contact, + reference_systems=["EPSG:3857"], + additional_parameters={ + "alternate": "geonode:test", + "workspace": "geonode", + "subtype": "vector", + "resource_type": "", + }, + ) + + self.harvested_info = HarvestedResourceInfo( + resource_descriptor=self.record_description, copied_resources=[], additional_information=None + ) + + @mock.patch( + "geonode.harvesting.harvesters.geonodeharvester.GeonodeCurrentHarvester.check_availability", + mock.Mock(return_value=True), + ) + def test_remote_subtype_is_set_for_harvested_dataset(self): + worker = GeonodeUnifiedHarvesterWorker(remote_url=self.remote_url, harvester_id=self.harvester.id) + worker.update_geonode_resource(self.harvested_info, self.harvestable_resource) + dataset = Dataset.objects.get(alternate="geonode:test") + self.assertEqual(dataset.subtype, "remote") diff --git a/geonode/resource/utils.py b/geonode/resource/utils.py index 5490d85cca6..5a557f8ceb9 100644 --- a/geonode/resource/utils.py +++ b/geonode/resource/utils.py @@ -233,11 +233,6 @@ def update_resource( to_update["ows_url"] = defaults.pop("ows_url", getattr(instance, "ows_url", None)) or _default_ows_url to_update.update(defaults) - try: - ResourceBase.objects.filter(id=instance.resourcebase_ptr.id).update(**defaults) - except Exception as e: - logger.error(f"{e} - {defaults}") - raise try: instance.get_real_concrete_instance_class().objects.filter(id=instance.id).update(**to_update) except Exception as e: @@ -254,8 +249,6 @@ def update_resource( _s = Service.objects.filter(harvester=_h).get() _to_update = { "remote_typename": _s.name, - # "ows_url": _s.service_url, - "subtype": "remote", } if hasattr(instance, "remote_service"): _to_update["remote_service"] = _s From 8bc6132cf5478ee4a78911ca44916fd67f01fe01 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 28 Sep 2023 10:38:59 +0200 Subject: [PATCH 17/70] Bump pymupdf from 1.22.5 to 1.23.1 (#11412) * - Align setup.cfg to requirements.txt * Bump to PyMuPDF 1.23.1 --------- Co-authored-by: afabiani --- requirements.txt | 2 +- setup.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 62ebeda6b1e..0ad9aa5ed4e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -25,7 +25,7 @@ zipstream-new==1.1.8 schema==0.7.5 rdflib==6.3.2 smart_open==6.4.0 -PyMuPDF==1.22.5 +PyMuPDF==1.23.1 pathvalidate==3.2.0 # Django Apps diff --git a/setup.cfg b/setup.cfg index f2b7b1f19a2..cde879727ad 100644 --- a/setup.cfg +++ b/setup.cfg @@ -51,7 +51,7 @@ install_requires = schema==0.7.5 rdflib==6.3.2 smart_open==6.4.0 - PyMuPDF==1.22.5 + PyMuPDF==1.23.1 pathvalidate==3.2.0 # Django Apps From 93aa6100e8dc440fc150111d6603ac91caacf4b6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 28 Sep 2023 13:13:51 +0200 Subject: [PATCH 18/70] Bump pymupdf from 1.23.1 to 1.23.4 (#11540) * Bump pymupdf from 1.23.1 to 1.23.4 Bumps [pymupdf](https://github.com/pymupdf/pymupdf) from 1.23.1 to 1.23.4. - [Release notes](https://github.com/pymupdf/pymupdf/releases) - [Changelog](https://github.com/pymupdf/PyMuPDF/blob/main/changes.txt) - [Commits](https://github.com/pymupdf/pymupdf/compare/1.23.1...1.23.4) --- updated-dependencies: - dependency-name: pymupdf dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * - Align setup.cfg to requirements.txt --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: afabiani --- requirements.txt | 2 +- setup.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 0ad9aa5ed4e..cca54c41c83 100644 --- a/requirements.txt +++ b/requirements.txt @@ -25,7 +25,7 @@ zipstream-new==1.1.8 schema==0.7.5 rdflib==6.3.2 smart_open==6.4.0 -PyMuPDF==1.23.1 +PyMuPDF==1.23.4 pathvalidate==3.2.0 # Django Apps diff --git a/setup.cfg b/setup.cfg index cde879727ad..c80c1ab9c53 100644 --- a/setup.cfg +++ b/setup.cfg @@ -51,7 +51,7 @@ install_requires = schema==0.7.5 rdflib==6.3.2 smart_open==6.4.0 - PyMuPDF==1.23.1 + PyMuPDF==1.23.4 pathvalidate==3.2.0 # Django Apps From 616645c34113221530bba9017cc7bcea2c993652 Mon Sep 17 00:00:00 2001 From: mattiagiupponi <51856725+mattiagiupponi@users.noreply.github.com> Date: Thu, 5 Oct 2023 13:12:49 +0200 Subject: [PATCH 19/70] Test fix CircleCi test (#11560) * Test fix CircleCi test * Test fix CircleCi test * Test fix CircleCi test --- geonode/upload/api/tests.py | 80 ++++++++++++++++++++++++++----------- 1 file changed, 57 insertions(+), 23 deletions(-) diff --git a/geonode/upload/api/tests.py b/geonode/upload/api/tests.py index 8f84fec6a92..81cd4a3ea3f 100644 --- a/geonode/upload/api/tests.py +++ b/geonode/upload/api/tests.py @@ -17,7 +17,9 @@ # ######################################################################### +from geonode.base.models import ResourceBase from geonode.resource.models import ExecutionRequest +from geonode.geoserver.helpers import gs_catalog import os import shutil import logging @@ -233,35 +235,67 @@ def test_rest_uploads(self): """ Ensure we can access the Local Server Uploads list. """ - # Try to upload a good raster file and check the session IDs - fname = os.path.join(GOOD_DATA, "raster", "relief_san_andres.tif") - resp, data = rest_upload_by_path(fname, self.client) - self.assertEqual(resp.status_code, 201) - - url = reverse("uploads-list") - # Anonymous - self.client.logout() - response = self.client.get(url, format="json") - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.data), 5) - self.assertEqual(response.data["total"], 0) - # Pagination - self.assertEqual(len(response.data["uploads"]), 0) - logger.debug(response.data) + resp = None + layer_name = "relief_san_andres" + try: + self._cleanup_layer(layer_name=layer_name) + # Try to upload a good raster file and check the session IDs + fname = os.path.join(GOOD_DATA, "raster", "relief_san_andres.tif") + resp, data = rest_upload_by_path(fname, self.client) + self.assertEqual(resp.status_code, 201) + + url = reverse("uploads-list") + # Anonymous + self.client.logout() + response = self.client.get(url, format="json") + self.assertEqual(response.status_code, 200) + self.assertEqual(len(response.data), 5) + self.assertEqual(response.data["total"], 0) + # Pagination + self.assertEqual(len(response.data["uploads"]), 0) + logger.debug(response.data) + except Exception: + if resp.json().get("errors"): + layer_name = resp.json().get("errors")[0].split("for : ")[1].split(",")[0] + finally: + self._cleanup_layer(layer_name) @override_settings(CELERY_TASK_ALWAYS_EAGER=True) def test_rest_uploads_non_interactive(self): """ Ensure we can access the Local Server Uploads list. """ - # Try to upload a good raster file and check the session IDs - fname = os.path.join(GOOD_DATA, "raster", "relief_san_andres.tif") - resp, data = rest_upload_by_path(fname, self.client, non_interactive=True) - self.assertEqual(resp.status_code, 201) - - exec_id = data.get("execution_id", None) - _exec = ExecutionRequest.objects.get(exec_id=exec_id) - self.assertEqual(_exec.status, "finished") + resp = None + layer_name = "relief_san_andres" + try: + self._cleanup_layer(layer_name=layer_name) + # Try to upload a good raster file and check the session IDs + fname = os.path.join(GOOD_DATA, "raster", "relief_san_andres.tif") + resp, data = rest_upload_by_path(fname, self.client, non_interactive=True) + self.assertEqual(resp.status_code, 201) + exec_id = data.get("execution_id", None) + _exec = ExecutionRequest.objects.get(exec_id=exec_id) + self.assertEqual(_exec.status, "finished") + except Exception: + if resp.json().get("errors"): + layer_name = resp.json().get("errors")[0].split("for : ")[1].split(",")[0] + finally: + self._cleanup_layer(layer_name) + + def _cleanup_layer(self, layer_name): + # removing the layer from geonode + x = ResourceBase.objects.filter(alternate__icontains=layer_name) + if x.exists(): + for el in x.iterator(): + el.delete() + # removing the layer from geoserver + dataset = gs_catalog.get_layer(layer_name) + if dataset: + gs_catalog.delete(dataset, purge="all", recurse=True) + # removing the layer from geoserver + store = gs_catalog.get_store(layer_name, workspace="geonode") + if store: + gs_catalog.delete(store, purge="all", recurse=True) @mock.patch("geonode.upload.uploadhandler.SimpleUploadedFile") def test_rest_uploads_with_size_limit(self, mocked_uploaded_file): From 2ef2a5094f502dad0e76136f98f7217e9f29b34a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 5 Oct 2023 13:14:26 +0200 Subject: [PATCH 20/70] Bump boto3 from 1.28.53 to 1.28.56 (#11539) * Bump boto3 from 1.28.53 to 1.28.56 Bumps [boto3](https://github.com/boto/boto3) from 1.28.53 to 1.28.56. - [Release notes](https://github.com/boto/boto3/releases) - [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst) - [Commits](https://github.com/boto/boto3/compare/1.28.53...1.28.56) --- updated-dependencies: - dependency-name: boto3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * - Align setup.cfg to requirements.txt --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: afabiani Co-authored-by: Giovanni Allegri --- requirements.txt | 2 +- setup.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index cca54c41c83..5e9989c8705 100644 --- a/requirements.txt +++ b/requirements.txt @@ -113,7 +113,7 @@ django-storages==1.14 dropbox==11.36.2 google-cloud-storage==2.11.0 google-cloud-core==2.3.3 -boto3==1.28.53 +boto3==1.28.56 # Django Caches python-memcached<=1.59 diff --git a/setup.cfg b/setup.cfg index c80c1ab9c53..f69ad657dcb 100644 --- a/setup.cfg +++ b/setup.cfg @@ -138,7 +138,7 @@ install_requires = dropbox==11.36.2 google-cloud-storage==2.11.0 google-cloud-core==2.3.3 - boto3==1.28.53 + boto3==1.28.56 # Django Caches python-memcached<=1.59 From 980189c0c8e9d6fb6408447c4ee0cb3730d2c080 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 5 Oct 2023 13:14:46 +0200 Subject: [PATCH 21/70] Bump django-mptt from 0.14.0 to 0.15.0 (#11541) * Bump django-mptt from 0.14.0 to 0.15.0 Bumps [django-mptt](https://github.com/django-mptt/django-mptt) from 0.14.0 to 0.15.0. - [Release notes](https://github.com/django-mptt/django-mptt/releases) - [Changelog](https://github.com/django-mptt/django-mptt/blob/main/CHANGELOG.rst) - [Commits](https://github.com/django-mptt/django-mptt/compare/0.14...0.15) --- updated-dependencies: - dependency-name: django-mptt dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * - Align setup.cfg to requirements.txt --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: afabiani --- requirements.txt | 2 +- setup.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 5e9989c8705..7d1b4a9b914 100644 --- a/requirements.txt +++ b/requirements.txt @@ -36,7 +36,7 @@ django-filter==23.3 django-imagekit==4.1.0 django-taggit==1.5.1 django-markdownify==0.9.3 -django-mptt==0.14.0 +django-mptt==0.15.0 django-modeltranslation>=0.11,<0.19.0 django-treebeard==4.7 django-guardian<2.4.1 diff --git a/setup.cfg b/setup.cfg index f69ad657dcb..2b22c939e0f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -62,7 +62,7 @@ install_requires = django-imagekit==4.1.0 django-taggit==1.5.1 django-markdownify==0.9.3 - django-mptt==0.14.0 + django-mptt==0.15.0 django-modeltranslation>=0.11,<0.19.0 django-treebeard==4.7 django-guardian<2.4.1 From 0438ff3b76a4978d2be1af4e72221d440865ba4c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 5 Oct 2023 13:15:12 +0200 Subject: [PATCH 22/70] Bump django-storages from 1.14 to 1.14.1 (#11547) Bumps [django-storages](https://github.com/jschneier/django-storages) from 1.14 to 1.14.1. - [Changelog](https://github.com/jschneier/django-storages/blob/master/CHANGELOG.rst) - [Commits](https://github.com/jschneier/django-storages/compare/1.14...1.14.1) --- updated-dependencies: - dependency-name: django-storages dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 7d1b4a9b914..1e46920c20d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -109,7 +109,7 @@ elasticsearch>=2.0.0,<9.0.0 django-bootstrap3-datetimepicker-2==2.8.3 # storage manager dependencies -django-storages==1.14 +django-storages==1.14.1 dropbox==11.36.2 google-cloud-storage==2.11.0 google-cloud-core==2.3.3 From ec0429af74cf4805ef4f21e8839bbe5948406ff4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 5 Oct 2023 13:15:45 +0200 Subject: [PATCH 23/70] Bump psycopg2 from 2.9.7 to 2.9.8 (#11550) Bumps [psycopg2](https://github.com/psycopg/psycopg2) from 2.9.7 to 2.9.8. - [Changelog](https://github.com/psycopg/psycopg2/blob/master/NEWS) - [Commits](https://github.com/psycopg/psycopg2/compare/2.9.7...2.9.8) --- updated-dependencies: - dependency-name: psycopg2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 1e46920c20d..b39fc3d8091 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ # native dependencies Pillow==10.0.1 lxml==4.9.3 -psycopg2==2.9.7 +psycopg2==2.9.8 Django==3.2.21 # Other From 9f88645458c86a690f8c01572c7a7a88cee0f624 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 5 Oct 2023 13:16:22 +0200 Subject: [PATCH 24/70] Bump mistune from 3.0.1 to 3.0.2 (#11549) Bumps [mistune](https://github.com/lepture/mistune) from 3.0.1 to 3.0.2. - [Release notes](https://github.com/lepture/mistune/releases) - [Changelog](https://github.com/lepture/mistune/blob/v3.0.2/docs/changes.rst) - [Commits](https://github.com/lepture/mistune/compare/v3.0.1...v3.0.2) --- updated-dependencies: - dependency-name: mistune dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index b39fc3d8091..10f3976e521 100644 --- a/requirements.txt +++ b/requirements.txt @@ -170,7 +170,7 @@ selenium-requests==2.0.3 webdriver_manager==4.0.1 # Security and audit -mistune==3.0.1 +mistune==3.0.2 protobuf==3.20.3 mako==1.2.4 paramiko==3.3.1 # not directly required, fixes Blowfish deprecation warning From e65f4a4f9770127aba82c4b25d28f91c206ee8e1 Mon Sep 17 00:00:00 2001 From: Giovanni Allegri Date: Thu, 5 Oct 2023 14:13:55 +0200 Subject: [PATCH 25/70] [Fixes #11554] Implement WMTS backgrounds for thumbnails (only 3857 tilematricsets) (#11555) * Implement WMTS backgrounds for thumbnails (only 3857 tilematricsets) * use fictious WMTS service url * fix E501 --- geonode/thumbs/background.py | 200 ++++++++++ .../expected_results/tiles/background.png | Bin 0 -> 118362 bytes .../expected_results/tiles/wmts_7_5_4.png | Bin 0 -> 27883 bytes .../expected_results/tiles/wmts_7_6_4.png | Bin 0 -> 34620 bytes .../expected_results/tiles/wmts_8_5_4.png | Bin 0 -> 35010 bytes .../expected_results/tiles/wmts_8_6_4.png | Bin 0 -> 35907 bytes .../expected_results/tiles/wmts_9_5_4.png | Bin 0 -> 31143 bytes .../expected_results/tiles/wmts_9_6_4.png | Bin 0 -> 60528 bytes geonode/thumbs/tests/test_backgrounds.py | 371 ++++++++++++++++++ 9 files changed, 571 insertions(+) create mode 100644 geonode/thumbs/tests/expected_results/tiles/background.png create mode 100644 geonode/thumbs/tests/expected_results/tiles/wmts_7_5_4.png create mode 100644 geonode/thumbs/tests/expected_results/tiles/wmts_7_6_4.png create mode 100644 geonode/thumbs/tests/expected_results/tiles/wmts_8_5_4.png create mode 100644 geonode/thumbs/tests/expected_results/tiles/wmts_8_6_4.png create mode 100644 geonode/thumbs/tests/expected_results/tiles/wmts_9_5_4.png create mode 100644 geonode/thumbs/tests/expected_results/tiles/wmts_9_6_4.png create mode 100644 geonode/thumbs/tests/test_backgrounds.py diff --git a/geonode/thumbs/background.py b/geonode/thumbs/background.py index 8896a5353c3..85bceb64159 100644 --- a/geonode/thumbs/background.py +++ b/geonode/thumbs/background.py @@ -21,13 +21,16 @@ import ast import typing import logging +import math import mercantile +import requests from io import BytesIO from pyproj import Transformer from abc import ABC, abstractmethod from math import ceil, floor, copysign from PIL import Image, UnidentifiedImageError +from owslib.wmts import WebMapTileService from django.conf import settings from django.utils.html import strip_tags @@ -464,3 +467,200 @@ def __init__( self.url = "https://tile.openstreetmap.org/{z}/{x}/{y}.png" self.tile_size = 256 + + +WMTS_TILEMATRIXSET_LEVELS = None + + +class GenericWMTSBackground(BaseThumbBackground): + def __init__(self, thumbnail_width: int, thumbnail_height: int, max_retries: int = 3, retry_delay: int = 1): + super().__init__(thumbnail_width, thumbnail_height, max_retries, retry_delay) + self.options = settings.THUMBNAIL_BACKGROUND.get("options", {}) + self.levels = self.get_levels_for_tilematrix() + + self.thumbnail_width = thumbnail_width + self.thumbnail_height = thumbnail_height + + def fetch(self, bbox: typing.List, *args, **kwargs): + bbox = [bbox[0], bbox[2], bbox[1], bbox[3]] + target_pixelspan = self.get_target_pixelspan(bbox) + level = self.get_level_for_targetpixelspan(target_pixelspan) + + tilewidth = level["tilewidth"] + tileheight = level["tileheight"] + zoom = level["zoom"] + pixelspan = level["pixelspan"] + tilespanx = level["tilespanx"] + tilespany = level["tilespany"] + + pixelspan_ratio = level["pixelspan"] / target_pixelspan + + tile_rowcols = self.get_tiles_coords(level, bbox) + tiles_cols_list = set([tile_rowcol[0] for tile_rowcol in tile_rowcols]) + tiles_mincol = min(tiles_cols_list) + tiles_maxcol = max(tiles_cols_list) + tiles_minx = level["bounds"][0] + (tiles_mincol * tilespanx) + tiles_rows_list = set([tile_rowcol[1] for tile_rowcol in tile_rowcols]) + tiles_minrow = min(tiles_rows_list) + tiles_maxrow = max(tiles_rows_list) + tiles_maxy = level["bounds"][3] - (tiles_minrow * tilespany) + + tiles_width = (tiles_maxcol - tiles_mincol + 1) * tilewidth + tiles_height = (tiles_maxrow - tiles_minrow + 1) * tileheight + + background = Image.new("RGB", (tiles_width, tiles_height), (250, 250, 250)) + + for tile_coord in tile_rowcols: + try: + im = None + imgurl = self.build_request([tile_coord[0], tile_coord[1], zoom]) + resp = requests.get(imgurl) + if resp.status_code > 400: + raise Exception(f"{strip_tags(resp.content)}") + im = BytesIO(resp.content) + Image.open(im).verify() + if im: + offsetx = (tile_coord[0] - tiles_mincol) * tilewidth + offsety = (tile_coord[1] - tiles_minrow) * tileheight + image = Image.open(im) + background.paste(image, (offsetx, offsety)) + except Exception as e: + logger.error(f"Error fetching {imgurl} for thumbnail: {e}") + + left = abs(tiles_minx - bbox[0]) / pixelspan + right = left + self.thumbnail_width + top = abs(tiles_maxy - bbox[3]) / pixelspan + bottom = top + self.thumbnail_height + background = background.crop((left, top, right, bottom)) + + width = round(self.thumbnail_width * pixelspan_ratio) + height = round(self.thumbnail_height * pixelspan_ratio) + + background = background.resize((width, height)) + background.crop((left, top, right, bottom)) + + return background + + def build_kvp_request(self, baseurl, layer, style, xyz): + return f"{baseurl}?&Service=WMTS&Request=GetTile&Version=1.0.0&Format=image/png&layer={layer}&style={style} \ + &tilematrixset={self.options['tilematrixset']}&TileMatrix={xyz[2]}&TileRow={xyz[1]}&TileCol={xyz[0]}" + + def build_request(self, xyz): + request_encoding = self.options.get("requestencoding", "KVP") + baseurl = self.options["url"] + layer = self.options["layer"] + style = self.options["style"] + + imgurl = None + if request_encoding == "KVP": + imgurl = self.build_kvp_request(baseurl, layer, style, xyz) + + return imgurl + + def get_image_bbox_for_level(self, level, bbox): + image_width = self.thumbnail_width + image_height = self.thumbnail_height + + half_imagespanx = image_width * level["pixelspan"] / 2 + half_imagespany = image_height * level["pixelspan"] / 2 + + ( + boundsminx, + boundsminy, + boundsmaxx, + boundsmaxy, + ) = bbox + + bboxcentrex = boundsminx + ((boundsmaxx - boundsminx) / 2) + bboxcentrey = boundsminy + ((boundsmaxy - boundsminy) / 2) + + image_minx = bboxcentrex - half_imagespanx + image_maxx = bboxcentrex + half_imagespanx + image_miny = bboxcentrey - half_imagespany + image_maxy = bboxcentrey + half_imagespany + + return [image_minx, image_miny, image_maxx, image_maxy] + + def get_tiles_coords(self, level, bbox): + tile_coords = [] + + tilematrixminx = level["bounds"][0] + tilematrixmaxy = level["bounds"][3] + tilespanx = level["tilespanx"] + tilespany = level["tilespany"] + + boundsminx, boundsminy, boundsmaxx, boundsmaxy = bbox + + tile_coord_minx = int(math.floor(boundsminx - tilematrixminx) / tilespanx) + # min tile coord corresponds to the maxy coordinate + tile_coord_miny = int(math.floor(tilematrixmaxy - boundsmaxy) / tilespany) + tile_coord_maxx = int(math.floor(boundsmaxx - tilematrixminx) / tilespanx) + # max tile coord corresponds to the miny coordinate + tile_coord_maxy = int(math.floor(tilematrixmaxy - boundsminy) / tilespany) + + for x in range(tile_coord_minx, tile_coord_maxx + 1): + for y in range(tile_coord_miny, tile_coord_maxy + 1): + tile_coords.append([x, y]) + + return tile_coords + + def get_level_for_targetpixelspan(self, target_pixelspan): + level = None + for _level in self.levels: + is_level_under_minscaledenominator = False + minscaledenominator = self.options.get("minscaledenominator") + if minscaledenominator: + is_level_under_minscaledenominator = _level["scaledenominator"] < self.options.get( + "minscaledenominator" + ) + if _level["pixelspan"] < target_pixelspan or is_level_under_minscaledenominator: + return level + level = _level + + def get_target_pixelspan(self, bbox): + x_min, y_min, x_max, y_max = bbox + return (x_max - x_min) / self.thumbnail_width + + def get_levels_for_tilematrix(self): + url = self.options["url"] + tilematrixset = self.options["tilematrixset"] + global WMTS_TILEMATRIXSET_LEVELS + if not WMTS_TILEMATRIXSET_LEVELS: + service = WebMapTileService(url=url) + tilematrixsset = service.tilematrixsets[tilematrixset] + + levels = [] + for index, tilematrix in tilematrixsset.tilematrix.items(): + scaledenominator = tilematrix.scaledenominator * 1 # here we assume 3857 + matrixheight = tilematrix.matrixheight + matrixwidth = tilematrix.matrixwidth + tileheight = tilematrix.tileheight + tilewidth = tilematrix.tilewidth + tilematrixminx = tilematrix.topleftcorner[0] # here we assume 3857 + tilematrixmaxy = tilematrix.topleftcorner[1] # here we assume 3857 + + pixelspan = scaledenominator * 0.00028 # OGC standardized rendering pixel size + tilespanx = tilewidth * pixelspan + tilespany = tileheight * pixelspan + tilematrixmaxx = tilematrixminx + tilespanx * matrixwidth + tilematrixminy = tilematrixmaxy - tilespany * matrixheight + + levels.append( + { + "zoom": int(index), + "bounds": [ + tilematrixminx, + tilematrixminy, + tilematrixmaxx, + tilematrixmaxy, + ], + "scaledenominator": scaledenominator, + "tilewidth": tilewidth, + "tileheight": tileheight, + "pixelspan": pixelspan, + "tilespanx": tilespanx, + "tilespany": tilespany, + } + ) + WMTS_TILEMATRIXSET_LEVELS = levels + return WMTS_TILEMATRIXSET_LEVELS diff --git a/geonode/thumbs/tests/expected_results/tiles/background.png b/geonode/thumbs/tests/expected_results/tiles/background.png new file mode 100644 index 0000000000000000000000000000000000000000..d345f1ce362a31a6ae5cb0d430ffcf9171d6e9ef GIT binary patch literal 118362 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 literal 0 HcmV?d00001 diff --git a/geonode/thumbs/tests/expected_results/tiles/wmts_7_6_4.png b/geonode/thumbs/tests/expected_results/tiles/wmts_7_6_4.png new file mode 100644 index 0000000000000000000000000000000000000000..de1b9c8d700161e07939d6a6d6bfba462b76beed GIT binary patch literal 34620 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

aH<~Cfk*WP+~QDS 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

R_7_EE0gB23crg4a-#}71OZ$N; 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. +# +######################################################################### +import os +import logging +from unittest.mock import patch + +from pixelmatch.contrib.PIL import pixelmatch +from PIL import Image + +from django.test import override_settings + +from geonode.tests.base import GeoNodeBaseTestSupport +from geonode.thumbs.background import GenericWMTSBackground + +logger = logging.getLogger(__name__) + +WMTS_TILEMATRIX_LEVELS = [ + { + "zoom": 0, + "bounds": [-20037508.342787, -60112525.02833891, 20037508.342775952, 20037508.342787], + "scaledenominator": 559082264.028501, + "tilewidth": 256, + "tileheight": 256, + "pixelspan": 156543.0339279803, + "tilespanx": 40075016.68556295, + "tilespany": 40075016.68556295, + }, + { + "zoom": 1, + "bounds": [-20037508.342787, -40075016.68555735, 20037508.3427759, 20037508.342787], + "scaledenominator": 279541132.01425016, + "tilewidth": 256, + "tileheight": 256, + "pixelspan": 78271.51696399004, + "tilespanx": 20037508.34278145, + "tilespany": 20037508.34278145, + }, + { + "zoom": 2, + "bounds": [-20037508.342787, -40075016.685557604, 20037508.342776064, 20037508.342787], + "scaledenominator": 139770566.00712565, + "tilewidth": 256, + "tileheight": 256, + "pixelspan": 39135.75848199518, + "tilespanx": 10018754.171390766, + "tilespany": 10018754.171390766, + }, + { + "zoom": 3, + "bounds": [-20037508.342787, -35065639.599861786, 20037508.34277575, 20037508.342787], + "scaledenominator": 69885283.00356229, + "tilewidth": 256, + "tileheight": 256, + "pixelspan": 19567.879240997438, + "tilespanx": 5009377.085695344, + "tilespany": 5009377.085695344, + }, + { + "zoom": 4, + "bounds": [-20037508.342787, -32560951.057014164, 20037508.34277579, 20037508.342787], + "scaledenominator": 34942641.50178117, + "tilewidth": 256, + "tileheight": 256, + "pixelspan": 9783.939620498728, + "tilespanx": 2504688.5428476743, + "tilespany": 2504688.5428476743, + }, + { + "zoom": 5, + "bounds": [-20037508.342787, -31308606.785590325, 20037508.34277579, 20037508.342787], + "scaledenominator": 17471320.750890587, + "tilewidth": 256, + "tileheight": 256, + "pixelspan": 4891.969810249364, + "tilespanx": 1252344.2714238372, + "tilespany": 1252344.2714238372, + }, + { + "zoom": 6, + "bounds": [-20037508.342787, -30682434.6498784, 20037508.34277579, 20037508.342787], + "scaledenominator": 8735660.375445293, + "tilewidth": 256, + "tileheight": 256, + "pixelspan": 2445.984905124682, + "tilespanx": 626172.1357119186, + "tilespany": 626172.1357119186, + }, + { + "zoom": 7, + "bounds": [-20037508.342787, -30369348.58202224, 20037508.342775624, 20037508.342787], + "scaledenominator": 4367830.187722629, + "tilewidth": 256, + "tileheight": 256, + "pixelspan": 1222.992452562336, + "tilespanx": 313086.067855958, + "tilespany": 313086.067855958, + }, + { + "zoom": 8, + "bounds": [-20037508.342787, -30369348.58203337, 20037508.342784476, 20037508.342787], + "scaledenominator": 2183915.093861797, + "tilewidth": 256, + "tileheight": 256, + "pixelspan": 611.496226281303, + "tilespanx": 156543.03392801358, + "tilespany": 156543.03392801358, + }, + { + "zoom": 9, + "bounds": [-20037508.342787, -30291077.06504764, 20037508.342767175, 20037508.342787], + "scaledenominator": 1091957.546930427, + "tilewidth": 256, + "tileheight": 256, + "pixelspan": 305.74811314051954, + "tilespanx": 78271.516963973, + "tilespany": 78271.516963973, + }, + { + "zoom": 10, + "bounds": [-20037508.342787, -30251941.306609083, 20037508.342801783, 20037508.342787], + "scaledenominator": 545978.773465685, + "tilewidth": 256, + "tileheight": 256, + "pixelspan": 152.8740565703918, + "tilespanx": 39135.7584820203, + "tilespany": 39135.7584820203, + }, + { + "zoom": 11, + "bounds": [-20037508.342787, -30251941.30652203, 20037508.34273241, 20037508.342787], + "scaledenominator": 272989.38673236995, + "tilewidth": 256, + "tileheight": 256, + "pixelspan": 76.43702828506358, + "tilespanx": 19567.879240976275, + "tilespany": 19567.879240976275, + }, + { + "zoom": 12, + "bounds": [-20037508.342787, -30242157.366901536, 20037508.34273241, 20037508.342787], + "scaledenominator": 136494.69336618498, + "tilewidth": 256, + "tileheight": 256, + "pixelspan": 38.21851414253179, + "tilespanx": 9783.939620488138, + "tilespany": 9783.939620488138, + }, + { + "zoom": 13, + "bounds": [-20037508.342787, -30242157.366901536, 20037508.34273241, 20037508.342787], + "scaledenominator": 68247.34668309249, + "tilewidth": 256, + "tileheight": 256, + "pixelspan": 19.109257071265894, + "tilespanx": 4891.969810244069, + "tilespany": 4891.969810244069, + }, + { + "zoom": 14, + "bounds": [-20037508.342787, -30242157.366901536, 20037508.34273241, 20037508.342787], + "scaledenominator": 34123.673341546244, + "tilewidth": 256, + "tileheight": 256, + "pixelspan": 9.554628535632947, + "tilespanx": 2445.9849051220344, + "tilespany": 2445.9849051220344, + }, + { + "zoom": 15, + "bounds": [-20037508.342787, -30242157.3682939, 20037508.343842182, 20037508.342787], + "scaledenominator": 17061.836671245605, + "tilewidth": 256, + "tileheight": 256, + "pixelspan": 4.777314267948769, + "tilespanx": 1222.9924525948848, + "tilespany": 1222.9924525948848, + }, + { + "zoom": 16, + "bounds": [-20037508.342787, -30241545.8720675, 20037508.3438421, 20037508.342787], + "scaledenominator": 8530.918335622784, + "tilewidth": 256, + "tileheight": 256, + "pixelspan": 2.3886571339743794, + "tilespanx": 611.4962262974411, + "tilespany": 611.4962262974411, + }, + { + "zoom": 17, + "bounds": [-20037508.342787, -30241240.11838522, 20037508.339403186, 20037508.342787], + "scaledenominator": 4265.459167338928, + "tilewidth": 256, + "tileheight": 256, + "pixelspan": 1.1943285668548997, + "tilespanx": 305.74811311485433, + "tilespany": 305.74811311485433, + }, + { + "zoom": 18, + "bounds": [-20037508.342787, -30241087.25546706, 20037508.34828115, 20037508.342787], + "scaledenominator": 2132.7295841419354, + "tilewidth": 256, + "tileheight": 256, + "pixelspan": 0.5971642835597418, + "tilespanx": 152.8740565912939, + "tilespany": 152.8740565912939, + }, + { + "zoom": 19, + "bounds": [-20037508.342787, -30241010.79616208, 20037508.330525283, 20037508.342787], + "scaledenominator": 1066.364791598498, + "tilewidth": 256, + "tileheight": 256, + "pixelspan": 0.2985821416475794, + "tilespanx": 76.43702826178033, + "tilespany": 76.43702826178033, + }, + { + "zoom": 20, + "bounds": [-20037508.342787, -30240972.57764789, 20037508.330525238, 20037508.342787], + "scaledenominator": 533.1823957992484, + "tilewidth": 256, + "tileheight": 256, + "pixelspan": 0.14929107082378953, + "tilespanx": 38.21851413089012, + "tilespany": 38.21851413089012, + }, + { + "zoom": 21, + "bounds": [-20037508.342787, -30240972.57764789, 20037508.330525238, 20037508.342787], + "scaledenominator": 266.5911978996242, + "tilewidth": 256, + "tileheight": 256, + "pixelspan": 0.07464553541189477, + "tilespanx": 19.10925706544506, + "tilespany": 19.10925706544506, + }, + { + "zoom": 22, + "bounds": [-20037508.342787, -30240972.57764789, 20037508.330525238, 20037508.342787], + "scaledenominator": 133.2955989498121, + "tilewidth": 256, + "tileheight": 256, + "pixelspan": 0.037322767705947384, + "tilespanx": 9.55462853272253, + "tilespany": 9.55462853272253, + }, + { + "zoom": 23, + "bounds": [-20037508.342787, -30240972.57764789, 20037508.330525238, 20037508.342787], + "scaledenominator": 66.64779947490605, + "tilewidth": 256, + "tileheight": 256, + "pixelspan": 0.018661383852973692, + "tilespanx": 4.777314266361265, + "tilespany": 4.777314266361265, + }, +] + +THUMBNAIL_BACKGROUND = { + "class": "geonode.thumbs.background.GenericWMTSBackground", + "options": { + "url": "myserver.com/WMTS", + "layer": "Hosted_basemap_inforac_3857", + "style": "default", + "tilematrixset": "default028mm", + "minscaledenominator": 272989.38673236995, + }, +} + +EXPECTED_RESULTS_DIR = "geonode/thumbs/tests/expected_results/" + +base_request_url = "https://myserver.com/WMTS?&Service=WMTS&Request=GetTile&Version=1.0.0&Format=image/png&layer=Hosted_basemap_inforac_3857&style=default&tilematrixset=default028mm&" +mocked_requests = { + base_request_url + "TileMatrix=4&TileRow=5&TileCol=7": f"{EXPECTED_RESULTS_DIR}/tiles/wmts_7_5_4.png", + base_request_url + "TileMatrix=4&TileRow=6&TileCol=7": f"{EXPECTED_RESULTS_DIR}/tiles/wmts_7_6_4.png", + base_request_url + "TileMatrix=4&TileRow=5&TileCol=8": f"{EXPECTED_RESULTS_DIR}/tiles/wmts_8_5_4.png", + base_request_url + "TileMatrix=4&TileRow=6&TileCol=8": f"{EXPECTED_RESULTS_DIR}/tiles/wmts_8_6_4.png", + base_request_url + "TileMatrix=4&TileRow=5&TileCol=9": f"{EXPECTED_RESULTS_DIR}/tiles/wmts_9_5_4.png", + base_request_url + "TileMatrix=4&TileRow=6&TileCol=9": f"{EXPECTED_RESULTS_DIR}/tiles/wmts_9_6_4.png", +} + + +class Response: + def __init__(self, status_code=200, content=None) -> None: + self.status_code = status_code + self.content = content + + +def get_mock(*args): + file_path = mocked_requests.get(args[0]) + if file_path and os.path.exists(file_path): + with open(file_path, "rb") as fin: + return Response(200, fin.read()) + + +class GeoNodeThumbnailWMTSBackground(GeoNodeBaseTestSupport): + @classmethod + def setUpClass(cls): + super().setUpClass() + + @override_settings(THUMBNAIL_BACKGROUND=THUMBNAIL_BACKGROUND) + @patch("geonode.thumbs.background.WMTS_TILEMATRIXSET_LEVELS", WMTS_TILEMATRIX_LEVELS) + def test_get_target_pixelspan(self, *args): + bbox = [-757689.8225283397, 4231175.960993547, 3557041.3914652625, 5957068.446590988] + expected_target_pixelspan = 8629.462427987204 + background = GenericWMTSBackground(thumbnail_width=500, thumbnail_height=200) + target_pixelspan = background.get_target_pixelspan(bbox) + self.assertAlmostEqual(expected_target_pixelspan, target_pixelspan) + + @override_settings(THUMBNAIL_BACKGROUND=THUMBNAIL_BACKGROUND) + @patch("geonode.thumbs.background.WMTS_TILEMATRIXSET_LEVELS", WMTS_TILEMATRIX_LEVELS) + def test_get_level_for_targetpixelspan(self, *args): + target_pixelspan = 8629.462427987204 + background = GenericWMTSBackground(thumbnail_width=500, thumbnail_height=200) + level = background.get_level_for_targetpixelspan(target_pixelspan) + self.assertDictEqual(level, WMTS_TILEMATRIX_LEVELS[4]) + + @override_settings(THUMBNAIL_BACKGROUND=THUMBNAIL_BACKGROUND) + @patch("geonode.thumbs.background.WMTS_TILEMATRIXSET_LEVELS", WMTS_TILEMATRIX_LEVELS) + def test_get_tiles_coords(self, *args): + bbox = [-757689.8225283397, 4231175.960993547, 3557041.3914652625, 5957068.446590988] + level = WMTS_TILEMATRIX_LEVELS[4] + expected_tile_rowcols = [[7, 5], [7, 6], [8, 5], [8, 6], [9, 5], [9, 6]] + background = GenericWMTSBackground(thumbnail_width=500, thumbnail_height=200) + tile_rowcols = background.get_tiles_coords(level, bbox) + self.assertListEqual(expected_tile_rowcols, tile_rowcols) + + @override_settings(THUMBNAIL_BACKGROUND=THUMBNAIL_BACKGROUND) + @patch("geonode.thumbs.background.WMTS_TILEMATRIXSET_LEVELS", WMTS_TILEMATRIX_LEVELS) + def test_build_request(self, *args): + expected_imgurl = "https://myserver.com/WMTS?&Service=WMTS&Request=GetTile&Version=1.0.0&Format=image/png& \ + layer=Hosted_basemap_inforac_3857&style=default&tilematrixset=default028mm&TileMatrix=4&TileRow=5&TileCol=7" + background = GenericWMTSBackground(thumbnail_width=500, thumbnail_height=200) + imgurl = background.build_request((7, 5, 4)) + self.assertEqual(expected_imgurl, imgurl) + + @override_settings(THUMBNAIL_BACKGROUND=THUMBNAIL_BACKGROUND) + @patch("geonode.thumbs.background.WMTS_TILEMATRIXSET_LEVELS", WMTS_TILEMATRIX_LEVELS) + @patch("geonode.thumbs.background.requests.get", get_mock) + def test_tile_request(self, *args): + bbox = [-757689.8225283397, 3557041.3914652625, 4231175.960993547, 5957068.446590988, "EPSG:3857"] + background = GenericWMTSBackground(thumbnail_width=500, thumbnail_height=200) + image = background.fetch(bbox) + expected_image = Image.open(f"{EXPECTED_RESULTS_DIR}/tiles/background.png") + diff = Image.new("RGB", image.size) + + mismatch = pixelmatch(image, expected_image, diff) + if mismatch >= expected_image.size[0] * expected_image.size[1] * 0.01: + logger.warn("Mismatch, it was not possible to bump the bg!") + else: + self.assertTrue( + mismatch < expected_image.size[0] * expected_image.size[1] * 0.01, + "Expected test and pre-generated backgrounds to differ up to 1%", + ) From 8fbad2c0a4f164c61bed89eb52f12a393cdd6757 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 5 Oct 2023 14:14:33 +0200 Subject: [PATCH 26/70] Bump ipython from 8.15.0 to 8.16.1 (#11561) Bumps [ipython](https://github.com/ipython/ipython) from 8.15.0 to 8.16.1. - [Release notes](https://github.com/ipython/ipython/releases) - [Commits](https://github.com/ipython/ipython/commits) --- updated-dependencies: - dependency-name: ipython dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 10f3976e521..399f9b596af 100644 --- a/requirements.txt +++ b/requirements.txt @@ -145,7 +145,7 @@ pycountry # production uWSGI==2.0.22 gunicorn==21.2.0 -ipython==8.15.0 +ipython==8.16.1 docker==6.1.3 invoke==2.2.0 From dd66c76518ca4d096f3b4fe8dd7125f02080b928 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 5 Oct 2023 14:15:02 +0200 Subject: [PATCH 27/70] Bump psycopg2 from 2.9.7 to 2.9.9 (#11562) Bumps [psycopg2](https://github.com/psycopg/psycopg2) from 2.9.7 to 2.9.9. - [Changelog](https://github.com/psycopg/psycopg2/blob/master/NEWS) - [Commits](https://github.com/psycopg/psycopg2/compare/2.9.7...2.9.9) --- updated-dependencies: - dependency-name: psycopg2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Giovanni Allegri --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 399f9b596af..96d9277889b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ # native dependencies Pillow==10.0.1 lxml==4.9.3 -psycopg2==2.9.8 +psycopg2==2.9.9 Django==3.2.21 # Other From 38c2c3942f77d344e75867455ad594325a582b09 Mon Sep 17 00:00:00 2001 From: Alessio Fabiani Date: Thu, 5 Oct 2023 14:16:49 +0200 Subject: [PATCH 28/70] fix: requirements.txt to reduce vulnerabilities (#11558) The following vulnerabilities are fixed by pinning transitive dependencies: - https://snyk.io/vuln/SNYK-PYTHON-URLLIB3-5926907 Co-authored-by: snyk-bot Co-authored-by: Giovanni Allegri --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 96d9277889b..55007ddc19b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,7 +10,7 @@ beautifulsoup4==4.12.2 httplib2<0.22.1 hyperlink==21.0.0 idna>=2.5,<3.5 -urllib3==1.26.15 +urllib3==1.26.17 Paver==1.3.4 python-slugify==8.0.1 decorator==5.1.1 From 24d34cde04d31211c9109d673787792b34bcdd79 Mon Sep 17 00:00:00 2001 From: Alessio Fabiani Date: Thu, 5 Oct 2023 14:21:30 +0200 Subject: [PATCH 29/70] [Snyk] Security upgrade django from 3.2.21 to 3.2.22 (#11563) * fix: requirements.txt to reduce vulnerabilities The following vulnerabilities are fixed by pinning transitive dependencies: - https://snyk.io/vuln/SNYK-PYTHON-DJANGO-5932095 * - Align setup.cfg to requirements.txt * upgrade spsycopg2 etup.cfg * - Align setup.cfg to requirements.txt --------- Co-authored-by: snyk-bot Co-authored-by: Giovanni Allegri --- requirements.txt | 2 +- setup.cfg | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/requirements.txt b/requirements.txt index 55007ddc19b..39864fb3294 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ Pillow==10.0.1 lxml==4.9.3 psycopg2==2.9.9 -Django==3.2.21 +Django==3.2.22 # Other amqp==5.1.1 diff --git a/setup.cfg b/setup.cfg index 2b22c939e0f..3c2147edf46 100644 --- a/setup.cfg +++ b/setup.cfg @@ -27,8 +27,8 @@ install_requires = # native dependencies Pillow==10.0.1 lxml==4.9.3 - psycopg2==2.9.7 - Django==3.2.21 + psycopg2==2.9.9 + Django==3.2.22 # Other amqp==5.1.1 @@ -36,7 +36,7 @@ install_requires = httplib2<0.22.1 hyperlink==21.0.0 idna>=2.5,<3.5 - urllib3==1.26.15 + urllib3==1.26.17 Paver==1.3.4 python-slugify==8.0.1 decorator==5.1.1 @@ -134,7 +134,7 @@ install_requires = django-bootstrap3-datetimepicker-2==2.8.3 # storage manager dependencies - django-storages==1.14 + django-storages==1.14.1 dropbox==11.36.2 google-cloud-storage==2.11.0 google-cloud-core==2.3.3 @@ -170,7 +170,7 @@ install_requires = # production uWSGI==2.0.22 gunicorn==21.2.0 - ipython==8.15.0 + ipython==8.16.1 docker==6.1.3 invoke==2.2.0 @@ -195,7 +195,7 @@ install_requires = webdriver_manager==4.0.1 # Security and audit - mistune==3.0.1 + mistune==3.0.2 protobuf==3.20.3 mako==1.2.4 paramiko==3.3.1 # not directly required, fixes Blowfish deprecation warning From 0f26dd32cfbd550c0df967652910dda5f1e3123a Mon Sep 17 00:00:00 2001 From: mattiagiupponi <51856725+mattiagiupponi@users.noreply.github.com> Date: Thu, 5 Oct 2023 14:26:36 +0200 Subject: [PATCH 30/70] adding hostname to celery state db (#11557) Co-authored-by: Giovanni Allegri --- celery-cmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/celery-cmd b/celery-cmd index a1c7fbd98fc..a600163fc77 100644 --- a/celery-cmd +++ b/celery-cmd @@ -3,7 +3,7 @@ # Luca Pasquali CELERY_BIN=${CELERY_BIN:-"$(which celery||echo celery)"} CELERY_APP=${CELERY_APP:-"geonode.celery_app:app"} -CELERY__STATE_DB=${CELERY__STATE_DB:-"/mnt/volumes/statics/worker.state"} +CELERY__STATE_DB=${CELERY__STATE_DB:-"/mnt/volumes/statics/worker@%h.state"} # expressed in KB CELERY__MAX_MEMORY_PER_CHILD=${CELERY__MAX_MEMORY_PER_CHILD:-"200000"} CELERY__AUTOSCALE_VALUES=${CELERY__AUTOSCALE_VALUES:-"15,10"} From 10c39c577065abb371258d146a1386bdbe9e9c41 Mon Sep 17 00:00:00 2001 From: Giovanni Allegri Date: Thu, 5 Oct 2023 16:25:37 +0200 Subject: [PATCH 31/70] Fix requires bucket name for AWS tests (#11564) * Fix requires bucket name for AWS tests * Fix requires bucket name for AWS tests --------- Co-authored-by: afabiani --- geonode/storage/tests.py | 1 + 1 file changed, 1 insertion(+) diff --git a/geonode/storage/tests.py b/geonode/storage/tests.py index 89eea61d4ad..48d1f3ebfe2 100644 --- a/geonode/storage/tests.py +++ b/geonode/storage/tests.py @@ -197,6 +197,7 @@ def test_google_size(self, gcs): gcs.assert_called_once_with("name") +@override_settings(AWS_STORAGE_BUCKET_NAME="my-bucket-name") class TestAwsStorageManager(SimpleTestCase): def setUp(self): self.sut = AwsStorageManager From 8913d8e653819704984f5bf3dd9076e151322a24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20Wallschl=C3=A4ger?= Date: Fri, 6 Oct 2023 12:35:21 +0200 Subject: [PATCH 32/70] issue#11566_pre-commit_hook_black_isnt_working_on_Ubuntu_22_04_3 (#11567) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4527a569c31..f6a72993d13 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,6 +9,6 @@ repos: - id: check-yaml - id: check-added-large-files - repo: https://github.com/psf/black - rev: 19.10b0 + rev: 23.9.1 hooks: - id: black From fbee36cb4515c39b4d117333980011e56f7ffffb Mon Sep 17 00:00:00 2001 From: Emanuele Tajariol Date: Tue, 10 Oct 2023 17:52:46 +0200 Subject: [PATCH 33/70] [Fixes #11494] Implement relations between resources (#11565) * [Fixes #11494] Implement relations between resources * [Fixes #11494] Implement relations between resources - tests and improvs * [Fixes #11494] Implement relations between resources - fix formatting * [Fixes #11494] Implement relations between resources - fix flake * [Fixes #11494] Implement relations between resources * [Fixes #11494] Implement relations between resources - fix formatting * [Fixes #11494] Implement relations between resources - fix flake * [Fixes #11494] Implement relations between resources - more tests and fixes * [Fixes #11494] Implement relations between resources - test fixings * [Fixes #11494] Implement relations between resources - test fixings * [Fixes #11494] Implement relations between resources - test fixings * [Fixes #11494] Implement relations between resources - minor fix --- geonode/base/api/serializers.py | 38 ++ geonode/base/api/tests.py | 386 +++++++----------- geonode/base/api/views.py | 98 ++--- geonode/base/forms.py | 35 +- .../base/migrations/0086_linkedresource.py | 23 ++ geonode/base/models.py | 53 +++ geonode/documents/api/views.py | 20 +- geonode/documents/forms.py | 56 +-- .../0037_delete_documentresourcelink.py | 20 + geonode/documents/models.py | 37 -- .../documents/document_metadata.html | 4 +- .../templates/layouts/doc_panels.html | 8 +- geonode/documents/tests.py | 50 +-- geonode/documents/views.py | 2 +- .../geoapps/templates/apps/app_metadata.html | 16 + .../geoapps/templates/layouts/app_panels.html | 7 + geonode/geoapps/views.py | 3 + geonode/layers/models.py | 17 +- .../templates/datasets/dataset_metadata.html | 16 + geonode/layers/templates/layouts/panels.html | 6 + geonode/layers/views.py | 2 + geonode/maps/models.py | 20 +- .../maps/templates/layouts/map_panels.html | 6 + geonode/maps/templates/maps/map_metadata.html | 16 + geonode/maps/views.py | 2 + geonode/resource/manager.py | 19 +- geonode/resource/utils.py | 20 - 27 files changed, 513 insertions(+), 467 deletions(-) create mode 100644 geonode/base/migrations/0086_linkedresource.py create mode 100644 geonode/documents/migrations/0037_delete_documentresourcelink.py diff --git a/geonode/base/api/serializers.py b/geonode/base/api/serializers.py index 74d74e9a236..077c605361b 100644 --- a/geonode/base/api/serializers.py +++ b/geonode/base/api/serializers.py @@ -20,6 +20,7 @@ from slugify import slugify from urllib.parse import urljoin import json +import warnings from django.db.models import Q from django.conf import settings @@ -54,6 +55,7 @@ ThesaurusKeyword, ThesaurusKeywordLabel, ExtraMetadata, + LinkedResource, ) from geonode.documents.models import Document from geonode.geoapps.models import GeoApp @@ -787,7 +789,43 @@ class Meta: class SimpleResourceSerializer(DynamicModelSerializer): + warnings.warn("SimpleResourceSerializer is deprecated", DeprecationWarning, stacklevel=2) + class Meta: name = "linked_resources" model = ResourceBase fields = ("pk", "title", "resource_type", "detail_url", "thumbnail_url") + + def to_representation(self, instance: LinkedResource): + return { + "pk": instance.pk, + "title": f"{'>>>' if instance.is_target else '<<<'} {instance.title}", + "resource_type": instance.resource_type, + "detail_url": instance.detail_url, + "thumbnail_url": instance.thumbnail_url, + } + + +class LinkedResourceSerializer(DynamicModelSerializer): + def __init__(self, *kargs, serialize_source: bool = False, **kwargs): + super().__init__(*kargs, **kwargs) + self.serialize_target = not serialize_source + + class Meta: + name = "linked_resources" + model = LinkedResource + fields = ("internal",) + + def to_representation(self, instance: LinkedResource): + data = super().to_representation(instance) + item: ResourceBase = instance.target if self.serialize_target else instance.source + data.update( + { + "pk": item.pk, + "title": item.title, + "resource_type": item.resource_type, + "detail_url": item.detail_url, + "thumbnail_url": item.thumbnail_url, + } + ) + return data diff --git a/geonode/base/api/tests.py b/geonode/base/api/tests.py index 677c7e06d8a..4833a955484 100644 --- a/geonode/base/api/tests.py +++ b/geonode/base/api/tests.py @@ -22,7 +22,8 @@ import sys import json import logging -from django.contrib.contenttypes.models import ContentType +from typing import Iterable + from django.test import RequestFactory, override_settings import gisdata @@ -62,11 +63,12 @@ RestrictionCodeType, License, Group, + LinkedResource, ) from geonode.layers.models import Dataset from geonode.favorite.models import Favorite -from geonode.documents.models import Document, DocumentResourceLink +from geonode.documents.models import Document from geonode.geoapps.models import GeoApp from geonode.utils import build_absolute_uri from geonode.resource.api.tasks import ExecutionRequest @@ -2607,53 +2609,12 @@ def test_only_get_method_is_available(self): response = self.client.put(url) self.assertEqual(response.status_code, 403) - def test_linked_resource_raise_error_for_geoapps(self): - geo_app = GeoApp.objects.create( - title="Test GeoApp", - owner=get_user_model().objects.first(), - resource_type="geostory", - blob='{"test_data": {"test": ["test_1","test_2","test_3"]}}', - ) - geo_app.set_default_permissions() - url = reverse("base-resources-linked_resources", args=[geo_app.id]) - - response = self.client.get(url) - - self.assertEqual(response.status_code, 501) - - def test_linked_resource_for_document_should_return_the_expected_ouput(self): + def test_linked_resource_for_document(self): + _d = [] try: # data preparation - ctype = ContentType.objects.get_for_model(self.map) - ctype_dataset = ContentType.objects.get_for_model(self.dataset) - _d = DocumentResourceLink.objects.create(document_id=self.doc.id, content_type=ctype, object_id=self.map.id) - _d = DocumentResourceLink.objects.create( - document_id=self.doc.id, content_type=ctype_dataset, object_id=self.dataset.id - ) - - # expected output from api - expected_payload = { - "links": {"next": None, "previous": None}, - "total": 2, - "page": 1, - "page_size": 10, - "resources": [ - { - "detail_url": self.map.detail_url, - "pk": self.map.id, - "resource_type": self.map.resource_type, - "thumbnail_url": self.map.thumbnail_url, - "title": self.map.title, - }, - { - "detail_url": self.dataset.detail_url, - "pk": self.dataset.id, - "resource_type": self.dataset.resource_type, - "thumbnail_url": self.dataset.thumbnail_url, - "title": self.dataset.title, - }, - ], - } + _d.append(LinkedResource.objects.create(source_id=self.doc.id, target_id=self.map.id)) + _d.append(LinkedResource.objects.create(source_id=self.doc.id, target_id=self.dataset.id)) # call the API url = reverse("base-resources-linked_resources", args=[self.doc.id]) @@ -2661,50 +2622,59 @@ def test_linked_resource_for_document_should_return_the_expected_ouput(self): # validation self.assertEqual(response.status_code, 200) - self.assertDictEqual(expected_payload, response.json()) + payload = response.json() + self.assert_linkedres_size(payload, "resources", 2) + self.assert_linkedres_contains( + payload, + "resources", + ( + {"pk": self.map.id, "title": ">>> " + self.map.title}, + {"pk": self.dataset.id, "title": ">>> " + self.dataset.title}, + ), + ) + self.assert_linkedres_size(payload, "linked_to", 2) + self.assert_linkedres_contains( + payload, + "linked_to", + ({"pk": self.map.id, "title": self.map.title}, {"pk": self.dataset.id, "title": self.dataset.title}), + ) + self.assert_linkedres_size(payload, "linked_by", 0) finally: - if _d: - _d.delete() - - def test_linked_resource_for_maps_with_mixed_resources(self): + for d in _d: + d.delete() + + def assert_linkedres_size(self, payload, element: str, expected_size: int): + self.assertEqual(expected_size, len(payload[element]), f"Mismatching payload size of {element}") + + def assert_linkedres_contains(self, payload, element: str, expected_elements: Iterable): + res_list = payload[element] + for dikt in expected_elements: + found = False + for res in res_list: + try: + if dikt.items() <= res.items(): + found = True + break + except AttributeError: + self.fail(f"\nError while comparing \n EXPECTED: {dikt}\n FOUND: {res}") + + if not found: + self.fail(f"Elements {dikt} could not be found in output: {payload}") + + def test_linked_resource_for_maps_mixed(self): + _d = [] try: # data preparation - ctype_dataset = ContentType.objects.get_for_model(self.dataset) - _d = DocumentResourceLink.objects.create( - document_id=self.doc.id, content_type=ctype_dataset, object_id=self.map.id + _d.append(LinkedResource.objects.create(source_id=self.doc.id, target_id=self.map.id)) + _d.append( + MapLayer.objects.create( + map=self.map, + dataset=self.dataset, + name=self.dataset.name, + current_style="test_style", + ows_url="https://maps.geosolutionsgroup.com/geoserver/wms", + ) ) - # data preparation - MapLayer( - map=self.map, - dataset=self.dataset, - name=self.dataset.name, - current_style="test_style", - ows_url="https://maps.geosolutionsgroup.com/geoserver/wms", - ).save() - - # expected output from api - expected_payload = { - "links": {"next": None, "previous": None}, - "total": 2, - "page": 1, - "page_size": 10, - "resources": [ - { - "detail_url": self.doc.detail_url, - "pk": self.doc.id, - "resource_type": self.doc.resource_type, - "thumbnail_url": self.doc.thumbnail_url, - "title": self.doc.title, - }, - { - "detail_url": self.dataset.detail_url, - "pk": self.dataset.id, - "resource_type": self.dataset.resource_type, - "thumbnail_url": self.dataset.thumbnail_url, - "title": self.dataset.title, - }, - ], - } # call the API url = reverse("base-resources-linked_resources", args=[self.map.id]) @@ -2712,71 +2682,38 @@ def test_linked_resource_for_maps_with_mixed_resources(self): # validation self.assertEqual(response.status_code, 200) - self.assertDictEqual(expected_payload, response.json()) - finally: - if _d: - _d.delete() - def test_linked_resource_should_return_the_paginated_result(self): - try: - # data preparation - ctype = ContentType.objects.get_for_model(self.map) - ctype_dataset = ContentType.objects.get_for_model(self.dataset) - _d = DocumentResourceLink.objects.create(document_id=self.doc.id, content_type=ctype, object_id=self.map.id) - _d = DocumentResourceLink.objects.create( - document_id=self.doc.id, content_type=ctype_dataset, object_id=self.dataset.id + payload = response.json() + self.assert_linkedres_size(payload, "resources", 2) + self.assert_linkedres_contains( + payload, + "resources", + ( + {"pk": self.doc.id, "title": "<<< " + self.doc.title}, + {"pk": self.dataset.id, "title": ">>> " + self.dataset.title}, + ), ) - # call the API - url = reverse("base-resources-linked_resources", args=[self.doc.id]) - response = self.client.get(f"{url}?page_size=1") - - # validation - self.assertEqual(response.status_code, 200) - next_url = response.json().get("links", {}).get("next", None) - self.assertIsNotNone(next_url) - self.assertTrue("page=2" in next_url) - # calling next_page to be sure that the url works - response = self.client.get(next_url) - # verify that now it has a prev_page - prev_url = response.json().get("links", {}).get("previous", None) - self.assertIsNotNone(prev_url) - - # verify that it works - # calling next_page to be sure that the url works - response = self.client.get(prev_url) - self.assertEqual(response.status_code, 200) + self.assert_linkedres_size(payload, "linked_to", 1) + self.assert_linkedres_contains( + payload, "linked_to", ({"pk": self.dataset.id, "title": self.dataset.title},) + ) + self.assert_linkedres_size(payload, "linked_by", 1) + self.assert_linkedres_contains(payload, "linked_by", ({"pk": self.doc.id, "title": self.doc.title},)) finally: - if _d: - _d.delete() + for d in _d: + d.delete() - def test_linked_resources_maps_should_return_the_expected_ouput(self): + def test_linked_resources_for_maps(self): try: # data preparation - _m = MapLayer( + _m = MapLayer.objects.create( map=self.map, dataset=self.dataset, name=self.dataset.name, current_style="test_style", ows_url="https://maps.geosolutionsgroup.com/geoserver/wms", - ).save() - - # expected output from api - expected_payload = { - "links": {"next": None, "previous": None}, - "total": 1, - "page": 1, - "page_size": 10, - "resources": [ - { - "detail_url": self.dataset.detail_url, - "pk": self.dataset.id, - "resource_type": self.dataset.resource_type, - "thumbnail_url": self.dataset.thumbnail_url, - "title": self.dataset.title, - } - ], - } + ) # call the API url = reverse("base-resources-linked_resources", args=[self.map.id]) @@ -2784,38 +2721,33 @@ def test_linked_resources_maps_should_return_the_expected_ouput(self): # validation self.assertEqual(response.status_code, 200) - self.assertDictEqual(expected_payload, response.json()) + + payload = response.json() + self.assert_linkedres_size(payload, "resources", 1) + self.assert_linkedres_contains( + payload, "resources", ({"pk": self.dataset.id, "title": ">>> " + self.dataset.title},) + ) + self.assert_linkedres_size(payload, "linked_to", 1) + self.assert_linkedres_contains( + payload, "linked_to", ({"pk": self.dataset.id, "title": self.dataset.title},) + ) + self.assert_linkedres_size(payload, "linked_by", 0) + finally: if _m: _m.delete() - def test_linked_resource_dataset_should_return_the_expected_ouput(self): + def test_linked_resource_for_dataset(self): + _m = None try: # data preparation - _m = MapLayer( + _m = MapLayer.objects.create( map=self.map, dataset=self.dataset, name=self.dataset.name, current_style="test_style", ows_url="https://maps.geosolutionsgroup.com/geoserver/wms", - ).save() - - # expected output from api - expected_payload = { - "links": {"next": None, "previous": None}, - "total": 1, - "page": 1, - "page_size": 10, - "resources": [ - { - "detail_url": self.map.detail_url, - "pk": self.map.id, - "resource_type": self.map.resource_type, - "thumbnail_url": self.map.thumbnail_url, - "title": self.map.title, - } - ], - } + ) # call the API url = reverse("base-resources-linked_resources", args=[self.dataset.id]) @@ -2823,50 +2755,34 @@ def test_linked_resource_dataset_should_return_the_expected_ouput(self): # validation self.assertEqual(response.status_code, 200) - self.assertDictEqual(expected_payload, response.json()) + + payload = response.json() + self.assert_linkedres_size(payload, "resources", 1) + self.assert_linkedres_contains( + payload, "resources", ({"pk": self.map.id, "title": "<<< " + self.map.title},) + ) + self.assert_linkedres_size(payload, "linked_to", 0) + self.assert_linkedres_size(payload, "linked_by", 1) + self.assert_linkedres_contains(payload, "linked_by", ({"pk": self.map.id, "title": self.map.title},)) + finally: if _m: _m.delete() - def test_linked_resource_for_datasets_with_mixed_resources(self): + def test_linked_resource_for_datasets_mixed(self): + _d = [] try: # data preparation - ctype = ContentType.objects.get_for_model(self.dataset) - _d = DocumentResourceLink.objects.create( - document_id=self.doc.id, content_type=ctype, object_id=self.dataset.id + _d.append(LinkedResource.objects.create(source_id=self.doc.id, target_id=self.dataset.id)) + _d.append( + MapLayer.objects.create( + map=self.map, + dataset=self.dataset, + name=self.dataset.name, + current_style="test_style", + ows_url="https://maps.geosolutionsgroup.com/geoserver/wms", + ) ) - # data preparation - MapLayer( - map=self.map, - dataset=self.dataset, - name=self.dataset.name, - current_style="test_style", - ows_url="https://maps.geosolutionsgroup.com/geoserver/wms", - ).save() - - # expected output from api - expected_payload = { - "links": {"next": None, "previous": None}, - "total": 2, - "page": 1, - "page_size": 10, - "resources": [ - { - "detail_url": self.doc.detail_url, - "pk": self.doc.id, - "resource_type": self.doc.resource_type, - "thumbnail_url": self.doc.thumbnail_url, - "title": self.doc.title, - }, - { - "detail_url": self.map.detail_url, - "pk": self.map.id, - "resource_type": self.map.resource_type, - "thumbnail_url": self.map.thumbnail_url, - "title": self.map.title, - }, - ], - } # call the API url = reverse("base-resources-linked_resources", args=[self.dataset.id]) @@ -2874,51 +2790,63 @@ def test_linked_resource_for_datasets_with_mixed_resources(self): # validation self.assertEqual(response.status_code, 200) - self.assertDictEqual(expected_payload, response.json()) + payload = response.json() + self.assert_linkedres_size(payload, "resources", 2) + self.assert_linkedres_contains( + payload, + "resources", + ( + {"pk": self.doc.id, "title": "<<< " + self.doc.title}, + {"pk": self.map.id, "title": "<<< " + self.map.title}, + ), + ) + self.assert_linkedres_size(payload, "linked_to", 0) + self.assert_linkedres_size(payload, "linked_by", 2) + self.assert_linkedres_contains( + payload, + "linked_by", + ( + {"pk": self.map.id, "title": self.map.title}, + {"pk": self.doc.id, "title": self.doc.title}, + ), + ) + finally: - if _d: - _d.delete() + for d in _d: + d.delete() - def test_linked_resource_filter_should_work(self): + def test_linked_resource_deprecated_pagination(self): + _d = [] try: # data preparation - ctype = ContentType.objects.get_for_model(self.map) - ctype_dataset = ContentType.objects.get_for_model(self.dataset) - _d = DocumentResourceLink.objects.create(document_id=self.doc.id, content_type=ctype, object_id=self.map.id) - _d = DocumentResourceLink.objects.create( - document_id=self.doc.id, content_type=ctype_dataset, object_id=self.dataset.id - ) + _d.append(LinkedResource.objects.create(source_id=self.doc.id, target_id=self.dataset.id)) + _d.append(LinkedResource.objects.create(source_id=self.doc.id, target_id=self.map.id)) - # call the API + # call the API w/ pagination url = reverse("base-resources-linked_resources", args=[self.doc.id]) - response = self.client.get(url) - # validation - self.assertEqual(response.status_code, 200, msg="no_filter_validation") - self.assertEqual(2, response.json().get("total", 0), msg="no_filter_validation") + response = self.client.get(f"{url}?page_size=1") - response = self.client.get(url + "?resource_type=map") # validation - self.assertEqual(response.status_code, 200, msg="map_filter_validation") - self.assertEqual(1, response.json().get("total", 0), msg="map_filter_validation") + self.assertEqual(response.status_code, 200) + payload = response.json() - response = self.client.get(url + "?title=single_layer") - # validation - self.assertEqual(response.status_code, 200, msg="dataset_filter_validation") - self.assertEqual(1, response.json().get("total", 0), msg="dataset_filter_validation") + self.assertIn("WARNINGS", payload, "Missing WARNINGS element") + self.assertIn("PAGINATION", payload["WARNINGS"], "Missing PAGINATION element") - response = self.client.get(url + "?resource_type=geoapp") - # validation - self.assertEqual(response.status_code, 200, msg="geoapp_filter_validation") - self.assertEqual(0, response.json().get("total", 0), msg="geoapp_filter_validation") + # call the API w/o pagination + url = reverse("base-resources-linked_resources", args=[self.doc.id]) + response = self.client.get(url) - response = self.client.get(url + "?invalid_filter=invalid") # validation - self.assertEqual(response.status_code, 500, msg="invalid_filter_validation") - self.assertEqual(0, response.json().get("total", 0), msg="invalid_filter_validation") + self.assertEqual(response.status_code, 200) + payload = response.json() + + self.assertIn("WARNINGS", payload, "Missing WARNINGS element") + self.assertNotIn("PAGINATION", payload["WARNINGS"], "Unexpected PAGINATION element") finally: - if _d: - _d.delete() + for d in _d: + d.delete() class TestApiAdditionalBBoxCalculation(GeoNodeBaseTestSupport): diff --git a/geonode/base/api/views.py b/geonode/base/api/views.py index fbbd2faec29..2721fd7c195 100644 --- a/geonode/base/api/views.py +++ b/geonode/base/api/views.py @@ -17,7 +17,6 @@ # ######################################################################### import ast -from geonode.geoapps.models import GeoApp import json import re @@ -110,6 +109,7 @@ RegionSerializer, ThesaurusKeywordSerializer, ExtraMetadataSerializer, + LinkedResourceSerializer, ) from .pagination import GeoNodeApiPagination from geonode.base.utils import validate_extra_metadata @@ -1489,48 +1489,54 @@ def _get_request_params(self, request, encode=False): url_name="linked_resources", ) def linked_resources(self, request, pk, *args, **kwargs): - try: - """ - To let the API be able to filter the linked result, we cannot rely on the DynamicFilterBackend - works on the resource and not on the linked one. - So if we want to filter the linked resource by "resource_type" - we have to search in the query params like in the following code: - _filters = { - x: y - for x, y - in request.query_params.items() - if x not in ["page_size", "page"] - } - We have to exclude the paging code or will raise the: - "Cannot resolve keyword into the field..." - """ - _obj = self.get_object().get_real_instance() - if issubclass(_obj.get_real_concrete_instance_class(), GeoApp): - raise NotImplementedError("Not implemented: this endpoint is not available for GeoApps") - # getting the resource dynamically list based on the above mapping - resources = _obj.linked_resources - - if request.query_params: - _filters = {x: y for x, y in request.query_params.items() if x not in ["page_size", "page"]} - if _filters: - resources = resources.filter(**_filters) - - resources = get_visible_resources( - resources, - user=request.user, - admin_approval_required=settings.ADMIN_MODERATE_UPLOADS, - unpublished_not_visible=settings.RESOURCE_PUBLISHING, - private_groups_not_visibile=settings.GROUP_PRIVATE_RESOURCES, - ).order_by("-pk") - - paginator = GeoNodeApiPagination() - paginator.page_size = request.GET.get("page_size", 10) - result_page = paginator.paginate_queryset(resources, request) - serializer = SimpleResourceSerializer(result_page, embed=True, many=True) - return paginator.get_paginated_response({"resources": serializer.data}) - except NotImplementedError as e: - logger.error(e) - return Response(data={"message": e.args[0], "success": False}, status=501, exception=True) - except Exception as e: - logger.error(e) - return Response(data={"message": e.args[0], "success": False}, status=500, exception=True) + return base_linked_resources(self.get_object().get_real_instance(), request.user, request.GET) + + +def base_linked_resources(instance, user, params): + try: + visibile_resources = get_visible_resources( + ResourceBase.objects, + user=user, + admin_approval_required=settings.ADMIN_MODERATE_UPLOADS, + unpublished_not_visible=settings.RESOURCE_PUBLISHING, + private_groups_not_visibile=settings.GROUP_PRIVATE_RESOURCES, + ).order_by("-pk") + visible_ids = [res.id for res in visibile_resources] + + linked_resources = [lres for lres in instance.get_linked_resources() if lres.target.id in visible_ids] + linked_by = [lres for lres in instance.get_linked_resources(as_target=True) if lres.source.id in visible_ids] + + warnings = { + "DEPRECATION": "'resources' field is deprecated, please use 'linked_to'", + } + + if "page_size" in params or "page" in params: + warnings["PAGINATION"] = "Pagination is not supported on this call" + + # "resources" will be deprecated, so next block is temporary + # "resources" at the moment it's the only element rendered, so we want to add there both the linked_resources and the linked_by + # we want to tell them apart, so we're adding an attr to store this info, that will be used in the SimpleResourceSerializer + resources = [] + for lres in linked_resources: + res = lres.target + setattr(res, "is_target", True) + resources.append(res) + for lres in linked_by: + res = lres.source + setattr(res, "is_target", False) + resources.append(res) + + ret = { + "WARNINGS": warnings, + "resources": SimpleResourceSerializer(resources, embed=True, many=True).data, # deprecated + "linked_to": LinkedResourceSerializer(linked_resources, embed=True, many=True).data, + "linked_by": LinkedResourceSerializer( + instance=linked_by, serialize_source=True, embed=True, many=True + ).data, + } + + return Response(ret) + + except Exception as e: + logger.exception(e) + return Response(data={"message": e.args[0], "success": False}, status=500, exception=True) diff --git a/geonode/base/forms.py b/geonode/base/forms.py index c888d816670..69da9e6bf50 100644 --- a/geonode/base/forms.py +++ b/geonode/base/forms.py @@ -46,6 +46,7 @@ from geonode.base.models import ( HierarchicalKeyword, License, + LinkedResource, Region, ResourceBase, Thesaurus, @@ -345,6 +346,38 @@ def _get_thesauro_title_label(item, lang): return tname.first() +class LinkedResourceForm(forms.ModelForm): + linked_resources = forms.MultipleChoiceField(label=_("Link to"), required=False) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.fields["linked_resources"].choices = self.generate_link_choices() + self.fields["linked_resources"].initial = LinkedResource.get_target_ids(self.instance) + + class Meta: + model = ResourceBase + fields = ["linked_resources"] + + def generate_link_choices(self, resources=None): + if resources is None: + resources = ResourceBase.objects.exclude(pk=self.instance.id).order_by("title") + + return [[obj.id, f"{obj.title} ({obj.polymorphic_ctype.model})"] for obj in resources] + + def save_linked_resources(self, links_field="linked_resources"): + # create and fetch desired links + target_ids = [] + for res_id in self.cleaned_data[links_field]: + linked, _ = LinkedResource.objects.get_or_create(source=self.instance, target_id=res_id, internal=False) + target_ids.append(res_id) + + # delete remaining links + # DocumentResourceLink.objects.filter(document_id=self.instance.id).exclude( + # pk__in=[i.pk for i in instances] + # ).delete() + (LinkedResource.objects.filter(source_id=self.instance.id).exclude(target_id__in=target_ids).delete()) + + class ResourceBaseDateTimePicker(DateTimePicker): def build_attrs(self, base_attrs=None, extra_attrs=None, **kwargs): "Helper function for building an attribute dictionary." @@ -355,7 +388,7 @@ def build_attrs(self, base_attrs=None, extra_attrs=None, **kwargs): # return base_attrs -class ResourceBaseForm(TranslationModelForm): +class ResourceBaseForm(TranslationModelForm, LinkedResourceForm): """Base form for metadata, should be inherited by childres classes of ResourceBase""" diff --git a/geonode/base/migrations/0086_linkedresource.py b/geonode/base/migrations/0086_linkedresource.py new file mode 100644 index 00000000000..cc5929e788d --- /dev/null +++ b/geonode/base/migrations/0086_linkedresource.py @@ -0,0 +1,23 @@ +# Generated by Django 3.2.21 on 2023-10-05 14:29 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('base', '0085_alter_resourcebase_uuid'), + ] + + operations = [ + migrations.CreateModel( + name='LinkedResource', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('source', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='linked_to', to='base.resourcebase')), + ('target', models.ForeignKey(blank=True, on_delete=django.db.models.deletion.CASCADE, related_name='linked_by', to='base.resourcebase')), + ('internal', models.BooleanField(default=False)), + ], + ), + ] diff --git a/geonode/base/models.py b/geonode/base/models.py index 1a2c8a38abd..b5907a902ba 100644 --- a/geonode/base/models.py +++ b/geonode/base/models.py @@ -1726,6 +1726,18 @@ def add_missing_metadata_author_or_poc(self): metadata_author = property(_get_metadata_author, _set_metadata_author) + def get_linked_resources(self, as_target: bool = False): + """ + Get all the linked resources to this ResourceBase instance. + This is implemented as a method so that derived classes can override it (for instance, Maps may add + related datasets) + """ + return ( + LinkedResource.get_linked_resources(target=self) + if as_target + else LinkedResource.get_linked_resources(source=self) + ) + class LinkManager(models.Manager): """Helper class to access links grouped by type""" @@ -1749,6 +1761,47 @@ def ows(self): return self.get_queryset().filter(link_type__in=["OGC:WMS", "OGC:WFS", "OGC:WCS"]) +class LinkedResource(models.Model): + source = models.ForeignKey( + ResourceBase, related_name="linked_to", blank=False, null=False, on_delete=models.CASCADE + ) + target = models.ForeignKey(ResourceBase, related_name="linked_by", blank=True, null=False, on_delete=models.CASCADE) + internal = models.BooleanField(null=False, default=False) + + @classmethod + def get_linked_resources(cls, source: ResourceBase = None, target: ResourceBase = None, is_internal: bool = None): + if source is None and target is None: + raise ValueError("Both source and target filters missing") + + qs = LinkedResource.objects + if source: + qs = qs.filter(source=source).select_related("target") + if target: + qs = qs.filter(target=target).select_related("source") + if is_internal is not None: + qs = qs.filter(internal=is_internal) + return qs + + @classmethod + def get_target_ids(cls, source: ResourceBase, is_internal: bool = None): + sub = LinkedResource.objects.filter(source=source).values_list("target_id", flat=True) + if is_internal is not None: + sub = sub.filter(internal=is_internal) + return sub + + @classmethod + def get_targets(cls, source: ResourceBase, is_internal: bool = None): + return ResourceBase.objects.filter(id__in=cls.get_target_ids(source, is_internal)) + + @classmethod + def resolve_targets(cls, linked_resources): + return (lr.target for lr in linked_resources) + + @classmethod + def resolve_sources(cls, linked_resources): + return (lr.source for lr in linked_resources) + + class Link(models.Model): """Auxiliary model for storing links for resources. diff --git a/geonode/documents/api/views.py b/geonode/documents/api/views.py index dd15a23e363..1e00ca5c12a 100644 --- a/geonode/documents/api/views.py +++ b/geonode/documents/api/views.py @@ -31,11 +31,11 @@ from geonode.base.api.filters import DynamicSearchFilter, ExtentFilter from geonode.base.api.pagination import GeoNodeApiPagination from geonode.base.api.permissions import UserHasPerms +from geonode.base.api.views import base_linked_resources from geonode.base import enumerations from geonode.documents.api.exceptions import DocumentException from geonode.documents.models import Document -from geonode.base.models import ResourceBase from geonode.base.api.serializers import ResourceBaseSerializer from geonode.resource.utils import resourcebase_post_save from geonode.storage.manager import StorageManager @@ -142,22 +142,8 @@ def perform_create(self, serializer): @extend_schema( methods=["get"], responses={200: ResourceBaseSerializer(many=True)}, - description="API endpoint allowing to retrieve the DocumentResourceLink(s).", + description="API endpoint allowing to retrieve linked resources", ) @action(detail=True, methods=["get"]) def linked_resources(self, request, pk=None, *args, **kwargs): - document = self.get_object() - resources_id = document.links.all().values("object_id") - resources = ResourceBase.objects.filter(id__in=resources_id) - exclude = [] - for resource in resources: - if not request.user.is_superuser and not request.user.has_perm( - "view_resourcebase", resource.get_self_resource() - ): - exclude.append(resource.id) - resources = resources.exclude(id__in=exclude) - paginator = GeoNodeApiPagination() - paginator.page_size = request.GET.get("page_size", 10) - result_page = paginator.paginate_queryset(resources, request) - serializer = ResourceBaseSerializer(result_page, embed=True, many=True) - return paginator.get_paginated_response({"resources": serializer.data}) + return base_linked_resources(self.get_object().get_real_instance(), request.user, request.GET) diff --git a/geonode/documents/forms.py b/geonode/documents/forms.py index 8da41217463..286f98e0a6b 100644 --- a/geonode/documents/forms.py +++ b/geonode/documents/forms.py @@ -18,7 +18,6 @@ ######################################################################### import os -import re import json import logging @@ -28,14 +27,10 @@ from django.conf import settings from django.forms import HiddenInput from django.utils.translation import ugettext as _ -from django.contrib.contenttypes.models import ContentType from django.template.defaultfilters import filesizeformat -from geonode.maps.models import Map -from geonode.layers.models import Dataset from geonode.base.forms import ResourceBaseForm, get_tree_data -from geonode.resource.utils import get_related_resources -from geonode.documents.models import Document, DocumentResourceLink +from geonode.documents.models import Document from geonode.upload.models import UploadSizeLimit from geonode.upload.api.exceptions import FileUploadLimitException @@ -82,54 +77,12 @@ def _get_max_size(self): return max_size_db_obj.max_size -class DocumentFormMixin: - def generate_link_choices(self, resources=None): - if resources is None: - resources = list(Dataset.objects.all()) - resources += list(Map.objects.all()) - resources.sort(key=lambda x: x.title) - - choices = [] - for obj in resources: - type_id = ContentType.objects.get_for_model(obj.__class__).id - choices.append([f"type:{type_id}-id:{obj.id}", f"{obj.title} ({obj.polymorphic_ctype.model})"]) - - return choices - - def generate_link_values(self, resources=None): - choices = self.generate_link_choices(resources=resources) - return [choice[0] for choice in choices] - - def save_many2many(self, links_field="links"): - # create and fetch desired links - instances = [] - for link in self.cleaned_data[links_field]: - matches = re.match(r"type:(\d+)-id:(\d+)", link) - if matches: - content_type = ContentType.objects.get(id=matches.group(1)) - instance, _ = DocumentResourceLink.objects.get_or_create( - document=self.instance, - content_type=content_type, - object_id=matches.group(2), - ) - instances.append(instance) - - # delete remaining links - DocumentResourceLink.objects.filter(document_id=self.instance.id).exclude( - pk__in=[i.pk for i in instances] - ).delete() - - -class DocumentForm(ResourceBaseForm, DocumentFormMixin): +class DocumentForm(ResourceBaseForm): title = forms.CharField(required=False) - links = forms.MultipleChoiceField(label=_("Link to"), required=False) - def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.fields["regions"].choices = get_tree_data() - self.fields["links"].choices = self.generate_link_choices() - self.fields["links"].initial = self.generate_link_values(resources=get_related_resources(self.instance)) for field in self.fields: help_text = self.fields[field].help_text self.fields[field].help_text = None @@ -163,7 +116,7 @@ class DocumentDescriptionForm(forms.Form): keywords = forms.CharField(max_length=500, required=False) -class DocumentCreateForm(TranslationModelForm, DocumentFormMixin): +class DocumentCreateForm(TranslationModelForm): """ The document upload form. @@ -173,8 +126,6 @@ class DocumentCreateForm(TranslationModelForm, DocumentFormMixin): widget=HiddenInput(attrs={"name": "permissions", "id": "permissions"}), required=False ) - links = forms.MultipleChoiceField(label=_("Link to"), required=False) - doc_file = SizeRestrictedFileField(label=_("File"), required=False, field_slug="document_upload_size") class Meta: @@ -186,7 +137,6 @@ class Meta: def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.fields["links"].choices = self.generate_link_choices() def clean_permissions(self): """ diff --git a/geonode/documents/migrations/0037_delete_documentresourcelink.py b/geonode/documents/migrations/0037_delete_documentresourcelink.py new file mode 100644 index 00000000000..a03389fd6b6 --- /dev/null +++ b/geonode/documents/migrations/0037_delete_documentresourcelink.py @@ -0,0 +1,20 @@ +# Generated by Django 3.2.21 on 2023-10-05 15:16 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('documents', '0036_clean_document_thumbnails'), + ('base', '0086_linkedresource'), + ] + + operations = [ + migrations.RunSQL("INSERT INTO base_linkedresource(source_id, target_id, internal)" + "SELECT document_id, object_id, false as internal " + "FROM documents_documentresourcelink;"), + migrations.DeleteModel( + name='DocumentResourceLink', + ), + ] diff --git a/geonode/documents/models.py b/geonode/documents/models.py index 5f5f41ab218..78292dfc8c9 100644 --- a/geonode/documents/models.py +++ b/geonode/documents/models.py @@ -25,14 +25,9 @@ from django.urls import reverse from django.utils.functional import classproperty from django.utils.translation import ugettext_lazy as _ -from django.contrib.contenttypes.models import ContentType -from django.contrib.contenttypes.fields import GenericForeignKey from geonode.client.hooks import hookset -from geonode.maps.models import Map -from geonode.layers.models import Dataset from geonode.base.models import ResourceBase -from geonode.maps.signals import map_changed_signal from geonode.groups.conf import settings as groups_settings from geonode.documents.enumerations import DOCUMENT_TYPE_MAP, DOCUMENT_MIMETYPE_MAP from geonode.security.permissions import VIEW_PERMISSIONS, OWNER_PERMISSIONS, DOWNLOAD_PERMISSIONS @@ -150,37 +145,5 @@ def download_url(self): return self.link_set.filter(resource=self.get_self_resource(), link_type="original").first().url return build_absolute_uri(reverse("document_download", args=(self.id,))) - @property - def linked_resources(self): - return ResourceBase.objects.filter(id__in=self.links.values_list("object_id", flat=True)) - class Meta(ResourceBase.Meta): pass - - -class DocumentResourceLink(models.Model): - # relation to the document model - document = models.ForeignKey(Document, null=True, blank=True, related_name="links", on_delete=models.CASCADE) - - # relation to the resource model - content_type = models.ForeignKey(ContentType, null=True, blank=True, on_delete=models.CASCADE) - object_id = models.PositiveIntegerField() - resource = GenericForeignKey("content_type", "object_id") - - -def get_related_documents(resource): - if isinstance(resource, Dataset) or isinstance(resource, Map): - content_type = ContentType.objects.get_for_model(resource) - return Document.objects.filter(links__content_type=content_type, links__object_id=resource.pk) - else: - return None - - -def update_documents_extent(sender, **kwargs): - documents = get_related_documents(sender) - if documents: - for document in documents: - document.save() - - -map_changed_signal.connect(update_documents_extent) diff --git a/geonode/documents/templates/documents/document_metadata.html b/geonode/documents/templates/documents/document_metadata.html index 2f4361c9be8..a04a7323b50 100644 --- a/geonode/documents/templates/documents/document_metadata.html +++ b/geonode/documents/templates/documents/document_metadata.html @@ -88,13 +88,13 @@

{% trans "Metadata Provider" %}

{% block extra_script %} {{ block.super }} +{% endblock extra_script %} \ No newline at end of file diff --git a/geonode/geoapps/templates/layouts/app_panels.html b/geonode/geoapps/templates/layouts/app_panels.html index e5ea2378882..4763d7a1257 100644 --- a/geonode/geoapps/templates/layouts/app_panels.html +++ b/geonode/geoapps/templates/layouts/app_panels.html @@ -297,6 +297,13 @@ {{ geoapp_form.title }} {% endblock %} + {% block geoapp_linked_resources %} +
+ + {{ geoapp_form.linked_resources }} +
+ {% endblock geoapp_linked_resources %} +
diff --git a/geonode/geoapps/views.py b/geonode/geoapps/views.py index eb23dee862a..788dcaccbe1 100644 --- a/geonode/geoapps/views.py +++ b/geonode/geoapps/views.py @@ -323,6 +323,9 @@ def geoapp_metadata( geoapp_form.cleaned_data.pop("metadata") extra_metadata = geoapp_form.cleaned_data.pop("extra_metadata") + geoapp_form.save_linked_resources() + geoapp_form.cleaned_data.pop("linked_resources") + geoapp_obj = geoapp_form.instance _vals = dict(**geoapp_form.cleaned_data, **additional_vals) diff --git a/geonode/layers/models.py b/geonode/layers/models.py index 05df8956868..22eb2eff0cd 100644 --- a/geonode/layers/models.py +++ b/geonode/layers/models.py @@ -16,6 +16,7 @@ # along with this program. If not, see . # ######################################################################### +import itertools import re import logging @@ -38,7 +39,7 @@ DOWNLOAD_PERMISSIONS, DATASET_ADMIN_PERMISSIONS, ) -from geonode.base.models import ResourceBase, ResourceBaseManager +from geonode.base.models import ResourceBase, ResourceBaseManager, LinkedResource logger = logging.getLogger("geonode.layers.models") @@ -317,13 +318,15 @@ def maps(self): map_ids = list(self.maplayers.values_list("map__id", flat=True)) return Map.objects.filter(id__in=map_ids) - @property - def linked_resources(self): - from geonode.documents.models import DocumentResourceLink + def get_linked_resources(self, as_target: bool = False): + ret = super().get_linked_resources(as_target) + + if as_target: + # create LinkedResources on the fly to report MapLayer relationship + res = (LinkedResource(source=map, target=self, internal=True) for map in self.maps) + ret = itertools.chain(ret, res) - _map_ids = list(self.maplayers.values_list("map__id", flat=True)) - _doc_ids = list(DocumentResourceLink.objects.filter(object_id=self.pk).values_list("document__pk", flat=True)) - return ResourceBase.objects.filter(id__in=list(set(_map_ids + _doc_ids))) + return ret @property def download_url(self): diff --git a/geonode/layers/templates/datasets/dataset_metadata.html b/geonode/layers/templates/datasets/dataset_metadata.html index cfb423709ac..c01955351ff 100644 --- a/geonode/layers/templates/datasets/dataset_metadata.html +++ b/geonode/layers/templates/datasets/dataset_metadata.html @@ -109,3 +109,19 @@

{% trans "Metadata Provider" %}

{{ block.super }} {% endblock body_outer %} + +{% block extra_script %} +{{ block.super }} + + +{% endblock extra_script %} \ No newline at end of file diff --git a/geonode/layers/templates/layouts/panels.html b/geonode/layers/templates/layouts/panels.html index 579b5f46ea6..d49f35726b2 100644 --- a/geonode/layers/templates/layouts/panels.html +++ b/geonode/layers/templates/layouts/panels.html @@ -331,6 +331,12 @@ {{ dataset_form.title }}
{% endblock dataset_title %} + {% block dataset_linked_resources %} +
+ + {{ dataset_form.linked_resources }} +
+ {% endblock dataset_linked_resources %} {% block dataset_abstract %}
diff --git a/geonode/layers/views.py b/geonode/layers/views.py index 3aa3bb91ff8..e4a7f21fb7b 100644 --- a/geonode/layers/views.py +++ b/geonode/layers/views.py @@ -612,6 +612,8 @@ def dataset_metadata( if up_sessions.exists() and up_sessions[0].user != layer.owner: up_sessions.update(user=layer.owner) + dataset_form.save_linked_resources() + register_event(request, EventType.EVENT_CHANGE_METADATA, layer) if not ajax: return HttpResponseRedirect(layer.get_absolute_url()) diff --git a/geonode/maps/models.py b/geonode/maps/models.py index 90b18bc98ab..6cee9d21f64 100644 --- a/geonode/maps/models.py +++ b/geonode/maps/models.py @@ -19,6 +19,8 @@ import json import logging +import itertools + from deprecated import deprecated from django.db import models from django.template.defaultfilters import slugify @@ -26,7 +28,7 @@ from django.utils.translation import ugettext_lazy as _ from geonode import geoserver # noqa -from geonode.base.models import ResourceBase +from geonode.base.models import ResourceBase, LinkedResource from geonode.client.hooks import hookset from geonode.layers.models import Dataset, Style from geonode.utils import check_ogc_backend @@ -59,13 +61,17 @@ def datasets(self): dataset_names = MapLayer.objects.filter(map__id=self.id).values("name") return Dataset.objects.filter(alternate__in=dataset_names) | Dataset.objects.filter(name__in=dataset_names) - @property - def linked_resources(self): - from geonode.documents.models import DocumentResourceLink + def get_linked_resources(self, as_target: bool = False): + ret = super().get_linked_resources(as_target) + + if not as_target: + dataset_ids = MapLayer.objects.filter(map__id=self.id).values("dataset_id") + datasets = ResourceBase.objects.filter(id__in=dataset_ids) + # create LinkedResources on the fly to report MapLayer relationship + res = (LinkedResource(source=self, target=d, internal=True) for d in datasets) + ret = itertools.chain(ret, res) - _dataset_id = list(self.datasets.values_list("pk", flat=True)) - _doc_ids = list(DocumentResourceLink.objects.filter(object_id=self.pk).values_list("document__pk", flat=True)) - return ResourceBase.objects.filter(id__in=list(set(_dataset_id + _doc_ids))) + return ret def json(self, dataset_filter): """ diff --git a/geonode/maps/templates/layouts/map_panels.html b/geonode/maps/templates/layouts/map_panels.html index dce48088967..96b3892117c 100644 --- a/geonode/maps/templates/layouts/map_panels.html +++ b/geonode/maps/templates/layouts/map_panels.html @@ -317,6 +317,12 @@ {{ map_form.title }}
{% endblock map_title %} + {% block map_linked_resources %} +
+ + {{ map_form.linked_resources }} +
+ {% endblock map_linked_resources %} {% block map_abstract %}
diff --git a/geonode/maps/templates/maps/map_metadata.html b/geonode/maps/templates/maps/map_metadata.html index dcc99f734e7..0fece0b382f 100644 --- a/geonode/maps/templates/maps/map_metadata.html +++ b/geonode/maps/templates/maps/map_metadata.html @@ -87,3 +87,19 @@

{% trans "Metadata Provider" %}

{{ block.super }} {% endblock body_outer %} + +{% block extra_script %} +{{ block.super }} + + +{% endblock extra_script %} diff --git a/geonode/maps/views.py b/geonode/maps/views.py index 00c25225a62..c79c1986f40 100644 --- a/geonode/maps/views.py +++ b/geonode/maps/views.py @@ -211,6 +211,8 @@ def map_metadata( new_m = ExtraMetadata.objects.create(resource=map_obj, metadata=_m) map_obj.metadata.add(new_m) + map_form.save_linked_resources() + register_event(request, EventType.EVENT_CHANGE_METADATA, map_obj) if not ajax: return HttpResponseRedirect(hookset.map_detail_url(map_obj)) diff --git a/geonode/resource/manager.py b/geonode/resource/manager.py index 245350d6cbf..6b2cead54ca 100644 --- a/geonode/resource/manager.py +++ b/geonode/resource/manager.py @@ -47,10 +47,10 @@ from .utils import update_resource, resourcebase_post_save from ..base import enumerations -from ..base.models import ResourceBase +from ..base.models import ResourceBase, LinkedResource from ..security.utils import AdvancedSecurityWorkflowManager from ..layers.metadata import parse_metadata -from ..documents.models import Document, DocumentResourceLink +from ..documents.models import Document from ..layers.models import Dataset, Attribute from ..maps.models import Map from ..storage.manager import storage_manager @@ -512,12 +512,15 @@ def copy( if "name" in defaults: defaults.pop("name") _resource.save() - if isinstance(instance.get_real_instance(), Document): - for resource_link in DocumentResourceLink.objects.filter(document=instance.get_real_instance()): - _resource_link = copy.copy(resource_link) - _resource_link.pk = _resource_link.id = None - _resource_link.document = _resource.get_real_instance() - _resource_link.save() + for lr in LinkedResource.get_linked_resources(source=instance.pk, is_internal=False): + LinkedResource.object.get_or_create( + source_id=_resource.pk, target_id=lr.target.pk, internal=False + ) + for lr in LinkedResource.get_linked_resources(target=instance.pk, is_internal=False): + LinkedResource.object.get_or_create( + source_id=lr.source.pk, target_id=_resource.pk, internal=False + ) + if isinstance(instance.get_real_instance(), Dataset): for attribute in Attribute.objects.filter(dataset=instance.get_real_instance()): _attribute = copy.copy(attribute) diff --git a/geonode/resource/utils.py b/geonode/resource/utils.py index 5a557f8ceb9..aa0b7f36f3c 100644 --- a/geonode/resource/utils.py +++ b/geonode/resource/utils.py @@ -29,7 +29,6 @@ from django.utils import timezone from django.core.exceptions import FieldDoesNotExist from django.utils.translation import ugettext_lazy as _ -from django.contrib.gis.geos import MultiPolygon from geonode.utils import OGC_Servers_Handler from django.utils.module_loading import import_string @@ -316,16 +315,6 @@ def get_alternate_name(instance): return instance.alternate -def get_related_resources(document): - if document.links: - try: - return [link.content_type.get_object_for_this_type(id=link.object_id) for link in document.links.all()] - except Exception: - return [] - else: - return [] - - def document_post_save(instance, *args, **kwargs): instance.csw_type = "document" @@ -375,15 +364,6 @@ def document_post_save(instance, *args, **kwargs): ), ) - resources = get_related_resources(instance) - - # if there are (new) linked resources update the bbox computed by their bboxes - if resources: - bbox = MultiPolygon([r.bbox_polygon for r in resources]) - instance.set_bbox_polygon(bbox.extent, instance.srid) - elif not instance.bbox_polygon: - instance.set_bbox_polygon((-180, -90, 180, 90), "EPSG:4326") - def dataset_post_save(instance, *args, **kwargs): base_file, info = instance.get_base_file() From 912f845b8bf5fcafefd281afc92211e2949890c9 Mon Sep 17 00:00:00 2001 From: Giovanni Allegri Date: Wed, 7 Jun 2023 15:35:01 +0200 Subject: [PATCH 34/70] updated changelog --- CHANGELOG.md | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee54d4a6d2e..799dbb6035c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,50 @@ # Change Log +## [4.1.0](https://github.com/GeoNode/geonode/tree/4.1.0) (2023-06-05) +### New upload engine +GeoNode integrates a brand new importer module based on [GDAL/OGR](https://gdal.org/), which offers increased robustness and reliability to the upload UI and API services. GeoPackage (vector), GeoJSON, KML/KMZ formats and a new CSV handler have been implemented. + +### Thesaurus faceting and date filtering +If thesaurus and thesaurus keywords are configured and assigned to resources, they will be available inside the filters panel, along with the number of associated resources. +Date filtering (from/top) has also been added. + +### Time series configurable after the upload +The configuration of (potential) time series at upload time was confusing for users, and not very robust. +With the new importer, the optional configuration of vector time series can be done afterward, through the Settings tab inside the Metadata editing page +Only vector fomats that provide date(time) fields natively are supported. Conversion from string fields is not implemented. + +### Related resources +This restore a functionality available in previous versions of GeoNode. +A tab inside the info panel has been added where relationships between datasets, maps and documents are reported. + +### Vector dataset attributes +A tab inside the info panel has been added showing the attributes of vector datasets + +### Remote documents +The API has been extended to permit the creation of document resources referencing remote URLs + +### ISO-19115 XML upload via API +The API now supports the upload of a metadata XML file along with the resource data + +### Software upgrades + + - [Geoserver 2.23.0](https://geoserver.org/announcements/2023/04/05/geoserver-2-23-0-released.html) is now the reference version. This version includes Geofence WPS rules which are employed by GeoNode to strengthen the security of the OGC/WPS processes. +- [MapStore 2022.02.xx](https://github.com/geosolutions-it/MapStore2/tree/2022.02.xx) +- [Django 3.2.19](https://docs.djangoproject.com/en/4.2/releases/3.2.19/) +- PostgreSQL 13 and PostGIS 3.3.3 + + +## Security and Bug Fixes +- [CVE-2023-26043](https://github.com/GeoNode/geonode/security/advisories/GHSA-mcmc-c59m-pqq8) +Fixed a vulnerability to XML External Entity (XXE) injection +- [CVE-2023-28442](https://github.com/GeoNode/geonode/security/advisories/GHSA-87mh-vw7c-5v6w) +Fixed information leak + +You can see the **full list of closed issues [here](https://github.com/GeoNode/geonode/compare/4.1.0...4.0.3)**. + +## System requirements +Python >3.9 is required to run GeoNode 4.1.0, since many of its dependencies have dropped support for older versions. + ## [4.0.2](https://github.com/GeoNode/geonode/tree/4.0.2) (2022-12-20) ### Breaking Changes From e022610858391c62aa3ca63e830b8fee24ecca9c Mon Sep 17 00:00:00 2001 From: Giovanni Allegri Date: Tue, 8 Aug 2023 16:02:52 +0200 Subject: [PATCH 35/70] changelog and fixes for packaging (#11355) --- CHANGELOG.md | 9 +++++++++ setup.py | 5 +++++ 2 files changed, 14 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 799dbb6035c..b440a931782 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Change Log +## [4.1.1](https://github.com/GeoNode/geonode/tree/4.1.0) (2023-06-05) +## Security and Bug Fixes +- Upgrade to Ubuntu 22.10 +- Upgrade to Django 3.2.20 +- Fixed direct download URL not working in some cases when local files are not available +- Fixed assignment of regions crossing the dateline +- Fixed harvesting of ArcGIS REST ImageServer services +- Fixed some italian translations +- Disabling of the (deprecated) Monitoring module ## [4.1.0](https://github.com/GeoNode/geonode/tree/4.1.0) (2023-06-05) ### New upload engine GeoNode integrates a brand new importer module based on [GDAL/OGR](https://gdal.org/), which offers increased robustness and reliability to the upload UI and API services. GeoPackage (vector), GeoJSON, KML/KMZ formats and a new CSV handler have been implemented. diff --git a/setup.py b/setup.py index 498d391199e..86f10350f9e 100644 --- a/setup.py +++ b/setup.py @@ -28,6 +28,7 @@ setup( version=__import__("geonode").get_version(), long_description=open("README.md").read(), + long_description_content_type='text/markdown', package_data={ "": ["*.*"], # noqa "": ["static/*.*"], # noqa @@ -35,4 +36,8 @@ "": ["templates/*.*"], # noqa "templates": ["*.*"], }, + exclude_package_data={ + "": ["uploaded/*.*"], # noqa + "uploaded": ["*.*"], + } ) From d58070fa1cd8801184ca6ce7a63fc0f794695563 Mon Sep 17 00:00:00 2001 From: Henning Bredel Date: Wed, 9 Aug 2023 16:15:37 +0200 Subject: [PATCH 36/70] Init workflow file --- .github/workflows/build-and-push-services.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .github/workflows/build-and-push-services.yml diff --git a/.github/workflows/build-and-push-services.yml b/.github/workflows/build-and-push-services.yml new file mode 100644 index 00000000000..8c5b5736fb1 --- /dev/null +++ b/.github/workflows/build-and-push-services.yml @@ -0,0 +1,12 @@ +name: Build and push Images +on: + push: + branches: + - "52n-istg" + +jobs: + hello: + runs-on: ubuntu-22.04 + steps: + - name: Say Hello IStG + run: echo "Hello IStG GeoNode!" \ No newline at end of file From 915fd64eca12062d97f51cc82ffad87b3a6b2e3b Mon Sep 17 00:00:00 2001 From: Henning Bredel Date: Thu, 10 Aug 2023 14:03:07 +0200 Subject: [PATCH 37/70] Add docker container registry workflow --- .github/workflows/build-and-push-services.yml | 73 ++++++++++++++++++- .gitignore | 2 +- 2 files changed, 70 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build-and-push-services.yml b/.github/workflows/build-and-push-services.yml index 8c5b5736fb1..f857620fb14 100644 --- a/.github/workflows/build-and-push-services.yml +++ b/.github/workflows/build-and-push-services.yml @@ -1,12 +1,77 @@ -name: Build and push Images +name: Release Docker Images + +env: + TITLE: "52°North GeoNode Deployment Image for IStG" + VENDOR: "52°North GmbH" + AUTHORS: "https://52North.org/" + DESCRIPTION: "52°North GeoNode Deployment Image" + LICENSE: "GPL-3.0" + on: push: branches: - "52n-istg" + # release: + # types: + # - "created" + # branches: + # - "52n-istg" + # tags: + # - "istg-v*.*.*" jobs: - hello: + build_images: runs-on: ubuntu-22.04 steps: - - name: Say Hello IStG - run: echo "Hello IStG GeoNode!" \ No newline at end of file + - + name: Checkout + uses: actions/checkout@v3 + - + name: Set up QEMU + uses: docker/setup-qemu-action@v2 + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + - + name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v4 + with: + images: 52north/istg_geonode + labels: | + "org.opencontainers.image.authors=${{ env.AUTHORS }}" + "org.opencontainers.image.vendor=${{ env.VENDOR }}" + "org.opencontainers.image.description=${{ env.DESCRIPTION }}" + "org.opencontainers.image.title=${{ env.TITLE }}" + "org.opencontainers.image.licenses=${{ env.LICENSE }}" + tags: | + latest + # type=match,pattern=v(.*),group=1,value=${{ github.event.inputs.tags }} + # type=semver,pattern={{version}} + # type=semver,pattern={{major}}.{{minor}} + - + name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN_ISTG }} + - + name: Build and push + uses: docker/build-push-action@v4 + with: + context: . + file: ./Dockerfile + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=registry,ref=52north/istg_geonode:buildcache + cache-to: type=registry,ref=52north/istg_geonode:buildcache,mode=max + + # - name: Build and push + # uses: docker/build-push-action@v4 + # with: + # context: . + # push: true + # tags: 52north/geonode_istg:latest + # cache-from: type=registry,ref=52north/geonode_istg:buildcache + # cache-to: type=registry,ref=52north/geonode_istg:buildcache,mode=max \ No newline at end of file diff --git a/.gitignore b/.gitignore index 7a455624878..60f95d0efc8 100644 --- a/.gitignore +++ b/.gitignore @@ -96,4 +96,4 @@ scripts/spcgeonode/_volume_* !hooks/* .env - +.secret From 7ec8347f74d40f7fe32934a80838234c437e72d5 Mon Sep 17 00:00:00 2001 From: Henning Bredel Date: Thu, 10 Aug 2023 14:57:57 +0200 Subject: [PATCH 38/70] Update meta tags in workflow --- .github/workflows/build-and-push-services.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-push-services.yml b/.github/workflows/build-and-push-services.yml index f857620fb14..98fa7c0a45b 100644 --- a/.github/workflows/build-and-push-services.yml +++ b/.github/workflows/build-and-push-services.yml @@ -46,9 +46,9 @@ jobs: "org.opencontainers.image.licenses=${{ env.LICENSE }}" tags: | latest + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} # type=match,pattern=v(.*),group=1,value=${{ github.event.inputs.tags }} - # type=semver,pattern={{version}} - # type=semver,pattern={{major}}.{{minor}} - name: Login to Docker Hub uses: docker/login-action@v2 From 9117e8dcba5f2d7cd67ce506d943654cbd1cad00 Mon Sep 17 00:00:00 2001 From: Henning Bredel Date: Thu, 10 Aug 2023 16:26:03 +0200 Subject: [PATCH 39/70] Add version tag 4.1 --- .github/workflows/build-and-push-services.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build-and-push-services.yml b/.github/workflows/build-and-push-services.yml index 98fa7c0a45b..4a8e7f0a282 100644 --- a/.github/workflows/build-and-push-services.yml +++ b/.github/workflows/build-and-push-services.yml @@ -45,6 +45,7 @@ jobs: "org.opencontainers.image.title=${{ env.TITLE }}" "org.opencontainers.image.licenses=${{ env.LICENSE }}" tags: | + 4.1 latest type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} From fae80c952c386c4b3b6f5114580431eff757c698 Mon Sep 17 00:00:00 2001 From: Henning Bredel Date: Thu, 10 Aug 2023 17:54:50 +0200 Subject: [PATCH 40/70] Add further images to build --- .github/workflows/build-and-push-services.yml | 121 ++++++++++++-- scripts/docker/geoserver/Dockerfile | 113 +++++++++++++ scripts/docker/geoserver/README.md | 132 +++++++++++++++ scripts/docker/geoserver/docker-compose.yml | 61 +++++++ scripts/docker/geoserver/entrypoint.sh | 152 ++++++++++++++++++ scripts/docker/geoserver/get_dockerhost_ip.py | 24 +++ scripts/docker/geoserver/get_nginxhost_ip.py | 45 ++++++ scripts/docker/geoserver/multidump-alt.sh | 16 ++ scripts/docker/geoserver/multidump.sh | 18 +++ scripts/docker/geoserver/requirements.txt | 1 + .../docker/geoserver/set_geoserver_auth.sh | 91 +++++++++++ scripts/docker/geoserver/setup_auth.sh | 3 + .../geofence-datasource-ovr.properties.j2 | 12 ++ 13 files changed, 775 insertions(+), 14 deletions(-) create mode 100644 scripts/docker/geoserver/Dockerfile create mode 100644 scripts/docker/geoserver/README.md create mode 100644 scripts/docker/geoserver/docker-compose.yml create mode 100644 scripts/docker/geoserver/entrypoint.sh create mode 100644 scripts/docker/geoserver/get_dockerhost_ip.py create mode 100644 scripts/docker/geoserver/get_nginxhost_ip.py create mode 100644 scripts/docker/geoserver/multidump-alt.sh create mode 100644 scripts/docker/geoserver/multidump.sh create mode 100644 scripts/docker/geoserver/requirements.txt create mode 100644 scripts/docker/geoserver/set_geoserver_auth.sh create mode 100644 scripts/docker/geoserver/setup_auth.sh create mode 100644 scripts/docker/geoserver/templates/geofence/geofence-datasource-ovr.properties.j2 diff --git a/.github/workflows/build-and-push-services.yml b/.github/workflows/build-and-push-services.yml index 4a8e7f0a282..7a0738dc687 100644 --- a/.github/workflows/build-and-push-services.yml +++ b/.github/workflows/build-and-push-services.yml @@ -20,8 +20,11 @@ on: # - "istg-v*.*.*" jobs: - build_images: + build_and_push_geonode: runs-on: ubuntu-22.04 + env: + IMAGE: 52north/istg_geonode + VERSION: "4.1" steps: - name: Checkout @@ -37,7 +40,7 @@ jobs: id: meta uses: docker/metadata-action@v4 with: - images: 52north/istg_geonode + images: ${{ env.IMAGE }} labels: | "org.opencontainers.image.authors=${{ env.AUTHORS }}" "org.opencontainers.image.vendor=${{ env.VENDOR }}" @@ -45,11 +48,10 @@ jobs: "org.opencontainers.image.title=${{ env.TITLE }}" "org.opencontainers.image.licenses=${{ env.LICENSE }}" tags: | - 4.1 latest + ${{ env.VERSION }} type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} - # type=match,pattern=v(.*),group=1,value=${{ github.event.inputs.tags }} - name: Login to Docker Hub uses: docker/login-action@v2 @@ -65,14 +67,105 @@ jobs: push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} - cache-from: type=registry,ref=52north/istg_geonode:buildcache - cache-to: type=registry,ref=52north/istg_geonode:buildcache,mode=max + cache-from: type=registry,ref=${{ env.IMAGE }}:buildcache + cache-to: type=registry,ref=${{ env.IMAGE }}:buildcache,mode=max - # - name: Build and push - # uses: docker/build-push-action@v4 - # with: - # context: . - # push: true - # tags: 52north/geonode_istg:latest - # cache-from: type=registry,ref=52north/geonode_istg:buildcache - # cache-to: type=registry,ref=52north/geonode_istg:buildcache,mode=max \ No newline at end of file + build_and_push_nginx: + runs-on: ubuntu-22.04 + env: + IMAGE: 52north/istg_nginx + VERSION: "4.1" + steps: + - + name: Checkout + uses: actions/checkout@v3 + - + name: Set up QEMU + uses: docker/setup-qemu-action@v2 + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + - + name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v4 + with: + images: ${{ env.IMAGE }} + labels: | + "org.opencontainers.image.authors=${{ env.AUTHORS }}" + "org.opencontainers.image.vendor=${{ env.VENDOR }}" + "org.opencontainers.image.description=${{ env.DESCRIPTION }}" + "org.opencontainers.image.title=${{ env.TITLE }}" + "org.opencontainers.image.licenses=${{ env.LICENSE }}" + tags: | + latest + ${{ env.VERSION }} + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + - + name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN_ISTG }} + - + name: Build and push + uses: docker/build-push-action@v4 + with: + context: ./scripts/docker/nginx/ + file: ./scripts/docker/nginx/Dockerfile + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=registry,ref=${{ env.IMAGE }}:buildcache + cache-to: type=registry,ref=${{ env.IMAGE }}:buildcache,mode=max + + build_and_push_geoserver: + runs-on: ubuntu-22.04 + env: + IMAGE: 52north/istg_geoserver + VERSION: "2.23.0" + steps: + - + name: Checkout + uses: actions/checkout@v3 + - + name: Set up QEMU + uses: docker/setup-qemu-action@v2 + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + - + name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v4 + with: + images: "${{ env.IMAGE }}" + labels: | + "org.opencontainers.image.authors=${{ env.AUTHORS }}" + "org.opencontainers.image.vendor=${{ env.VENDOR }}" + "org.opencontainers.image.description=${{ env.DESCRIPTION }}" + "org.opencontainers.image.title=${{ env.TITLE }}" + "org.opencontainers.image.licenses=${{ env.LICENSE }}" + tags: | + latest + ${{ env.VERSION }} + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + - + name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN_ISTG }} + - + name: Build and push + uses: docker/build-push-action@v4 + with: + context: ./scripts/docker/nginx/ + file: ./scripts/docker/nginx/Dockerfile + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=registry,ref=${{ env.IMAGE }}:buildcache + cache-to: type=registry,ref=${{ env.IMAGE }}:buildcache,mode=max \ No newline at end of file diff --git a/scripts/docker/geoserver/Dockerfile b/scripts/docker/geoserver/Dockerfile new file mode 100644 index 00000000000..cf69384629f --- /dev/null +++ b/scripts/docker/geoserver/Dockerfile @@ -0,0 +1,113 @@ +ARG IMAGE_VERSION=9.0-jdk11-openjdk-slim-bullseye +ARG JAVA_HOME=/usr/local/openjdk-11 +FROM tomcat:$IMAGE_VERSION +LABEL GeoNode Development Team + +ARG GEOSERVER_CORS_ENABLED=False +ARG GEOSERVER_CORS_ALLOWED_ORIGINS=* +ARG GEOSERVER_CORS_ALLOWED_METHODS=GET,POST,PUT,DELETE,HEAD,OPTIONS +ARG GEOSERVER_CORS_ALLOWED_HEADERS=* +# +# Set GeoServer version and data directory +# +ENV GEOSERVER_VERSION=2.23.0 +ENV GEOSERVER_DATA_DIR="/geoserver_data/data" +ENV GEOSERVER_CORS_ENABLED=$GEOSERVER_CORS_ENABLED +ENV GEOSERVER_CORS_ALLOWED_ORIGINS=$GEOSERVER_CORS_ALLOWED_ORIGINS +ENV GEOSERVER_CORS_ALLOWED_METHODS=$GEOSERVER_CORS_ALLOWED_METHODS +ENV GEOSERVER_CORS_ALLOWED_HEADERS=$GEOSERVER_CORS_ALLOWED_HEADERS +# +# Download and install GeoServer +# +RUN apt-get update -y && apt-get install curl wget unzip -y +RUN cd /usr/local/tomcat/webapps \ + && wget --no-check-certificate --progress=bar:force:noscroll https://artifacts.geonode.org/geoserver/${GEOSERVER_VERSION}/geoserver.war -O geoserver.war \ + && unzip -q geoserver.war -d geoserver \ + && rm geoserver.war \ + && mkdir -p $GEOSERVER_DATA_DIR + +VOLUME $GEOSERVER_DATA_DIR + +# added by simonelanucara https://github.com/simonelanucara +# Optionally add JAI, ImageIO and Marlin Render for improved Geoserver performance +WORKDIR /tmp + +RUN wget --no-check-certificate https://repo1.maven.org/maven2/org/postgis/postgis-jdbc/1.3.3/postgis-jdbc-1.3.3.jar -O postgis-jdbc-1.3.3.jar && \ + wget --no-check-certificate https://maven.geo-solutions.it/org/hibernatespatial/hibernate-spatial-postgis/1.1.3.2/hibernate-spatial-postgis-1.1.3.2.jar -O hibernate-spatial-postgis-1.1.3.2.jar && \ + rm /usr/local/tomcat/webapps/geoserver/WEB-INF/lib/hibernate-spatial-h2-geodb-1.1.3.2.jar && \ + mv hibernate-spatial-postgis-1.1.3.2.jar /usr/local/tomcat/webapps/geoserver/WEB-INF/lib/ && \ + mv postgis-jdbc-1.3.3.jar /usr/local/tomcat/webapps/geoserver/WEB-INF/lib/ + +###########docker host############### +# Set DOCKERHOST variable if DOCKER_HOST exists +ARG DOCKERHOST=${DOCKERHOST} +# for debugging +RUN echo -n #1===>DOCKERHOST=${DOCKERHOST} +# +ENV DOCKERHOST ${DOCKERHOST} +# for debugging +RUN echo -n #2===>DOCKERHOST=${DOCKERHOST} + +###########docker host ip############# +# Set GEONODE_HOST_IP address if it exists +ARG GEONODE_HOST_IP=${GEONODE_HOST_IP} +# for debugging +RUN echo -n #1===>GEONODE_HOST_IP=${GEONODE_HOST_IP} +# +ENV GEONODE_HOST_IP ${GEONODE_HOST_IP} +# for debugging +RUN echo -n #2===>GEONODE_HOST_IP=${GEONODE_HOST_IP} +# If empty set DOCKER_HOST_IP to GEONODE_HOST_IP +ENV DOCKER_HOST_IP=${DOCKER_HOST_IP:-${GEONODE_HOST_IP}} +# for debugging +RUN echo -n #1===>DOCKER_HOST_IP=${DOCKER_HOST_IP} +# Trying to set the value of DOCKER_HOST_IP from DOCKER_HOST +RUN if ! [ -z ${DOCKER_HOST_IP} ]; \ + then echo export DOCKER_HOST_IP=${DOCKERHOST} | \ + sed 's/tcp:\/\/\([^:]*\).*/\1/' >> /root/.bashrc; \ + else echo "DOCKER_HOST_IP is already set!"; fi +# for debugging +RUN echo -n #2===>DOCKER_HOST_IP=${DOCKER_HOST_IP} + +# Set WEBSERVER public port +ARG PUBLIC_PORT=${PUBLIC_PORT} +# for debugging +RUN echo -n #1===>PUBLIC_PORT=${PUBLIC_PORT} +# +ENV PUBLIC_PORT=${PUBLIC_PORT} +# for debugging +RUN echo -n #2===>PUBLIC_PORT=${PUBLIC_PORT} + +# set nginx base url for geoserver +RUN echo export NGINX_BASE_URL=http://${NGINX_HOST}:${NGINX_PORT}/ | \ + sed 's/tcp:\/\/\([^:]*\).*/\1/' >> /root/.bashrc + +# copy the script and perform the run of scripts from entrypoint.sh +RUN mkdir -p /usr/local/tomcat/tmp +WORKDIR /usr/local/tomcat/tmp +COPY set_geoserver_auth.sh /usr/local/tomcat/tmp +COPY setup_auth.sh /usr/local/tomcat/tmp +COPY requirements.txt /usr/local/tomcat/tmp +COPY get_dockerhost_ip.py /usr/local/tomcat/tmp +COPY get_nginxhost_ip.py /usr/local/tomcat/tmp +COPY entrypoint.sh /usr/local/tomcat/tmp +COPY ./templates /templates +COPY multidump.sh /usr/local/tomcat/tmp +COPY multidump-alt.sh /usr/local/tomcat/tmp + +RUN apt-get update \ + && apt-get install -y procps less \ + && apt-get install -y python3 python3-pip python3-dev \ + && chmod +x /usr/local/tomcat/tmp/set_geoserver_auth.sh \ + && chmod +x /usr/local/tomcat/tmp/setup_auth.sh \ + && chmod +x /usr/local/tomcat/tmp/entrypoint.sh \ + && pip3 install pip --upgrade \ + && pip3 install -r requirements.txt \ + && chmod +x /usr/local/tomcat/tmp/get_dockerhost_ip.py \ + && chmod +x /usr/local/tomcat/tmp/get_nginxhost_ip.py + +RUN pip install j2cli + +ENV JAVA_OPTS="-Djava.awt.headless=true -Dgwc.context.suffix=gwc -XX:+UnlockDiagnosticVMOptions -XX:+LogVMOutput -XX:LogFile=/var/log/jvm.log -XX:MaxPermSize=512m -XX:PermSize=256m -Xms512m -Xmx2048m -XX:+UseConcMarkSweepGC -XX:ParallelGCThreads=4 -Dfile.encoding=UTF8 -Djavax.servlet.request.encoding=UTF-8 -Djavax.servlet.response.encoding=UTF-8 -Duser.timezone=GMT -Dorg.geotools.shapefile.datetime=false -DGS-SHAPEFILE-CHARSET=UTF-8 -DGEOSERVER_CSRF_DISABLED=true -DPRINT_BASE_URL=http://geoserver:8080/geoserver/pdf -Xbootclasspath/a:/usr/local/tomcat/webapps/geoserver/WEB-INF/lib/marlin-0.9.3.jar -Dsun.java2d.renderer=org.marlin.pisces.MarlinRenderingEngine" + +CMD ["/usr/local/tomcat/tmp/entrypoint.sh"] \ No newline at end of file diff --git a/scripts/docker/geoserver/README.md b/scripts/docker/geoserver/README.md new file mode 100644 index 00000000000..9d00a465066 --- /dev/null +++ b/scripts/docker/geoserver/README.md @@ -0,0 +1,132 @@ +# geoserver-docker + + +**The scripts/docker/geonode folder is a copy from geonode-project* to be able to build GeoServer image from this repository directly. In case of an update, just replace the whole folder.** + + +[GeoServer](http://geoserver.org) is an open source server for sharing geospatial data. +This is a docker image that eases setting up a GeoServer running specifically for [GeoNode](https://github.com/GeoNode/geoserver-geonode-ext) with an additional separated data directory. + +The image is based on the official Tomcat 9 image + +## Installation + +This image is available as a [trusted build on the docker hub](https://registry.hub.docker.com/r/geonode/geoserver/), and is the recommended method of installation. +Simple pull the image from the docker hub. + +```bash +$ docker pull geonode/geoserver +``` + +Alternatively you can build the image locally + +```bash +$ git clone https://github.com/geonode/geoserver-docker.git +$ cd geoserver-docker +$ docker build -t "geonode/geoserver" . +``` + +## Quick start + +You can quick start the image using the command line + +```bash +$ docker run --name "geoserver" -v /var/run/docker.sock:/var/run/docker.sock -d -p 8080:8080 geonode/geoserver +``` + +Point your browser to `http://localhost:8080/geoserver` and login using GeoServer's default username and password: + +* Username: admin +* Password: geoserver + +## How to use different versions + +There are mainly two different versions of this image which are useful for running **GeoNode** with different authentication system types. These versions are released as specific tags for two authentication mechanisms: + +**Cookie based authn**: +- [geonode/geoserver:2.9.x](https://hub.docker.com/r/geonode/geoserver/builds/bx7ydhghnlrfnsppduyva73/) + +**Oauth2 based authn**: +- [geonode/geoserver:2.9.x-oauth2](https://hub.docker.com/r/geonode/geoserver/builds/bwca5rtexeoegzgroavftdr/) +- [geonode/geoserver:2.10.x](https://hub.docker.com/r/geonode/geoserver/builds/bjohcnc29vm69acqjrvndxf/) +- [geonode/geoserver:2.12.x](https://hub.docker.com/r/geonode/geoserver/builds/bh7pyw5atmkcljurwsnzbs7/) +- [geonode/geoserver:2.13.x](https://hub.docker.com/r/geonode/geoserver/builds/btmjctbuvrjfnnrxrs4wyrs/) +- [geonode/geoserver:2.14.x](https://hub.docker.com/r/geonode/geoserver/builds/bj53pi8he8uksz6ggvrs3wc/) + +You can declare what version to use along with the data directory tag which corresponds to the same version. + +## Configuration + +### Data volume + +This GeoServer container keeps its configuration data at `/geoserver_data/data` which is exposed as volume in the dockerfile. +The volume allows for stopping and starting new containers from the same image without losing all the data and custom configuration. + +You may want to map this volume to a directory on the host. It will also ease the upgrade process in the future. Volumes can be mounted by passing the `-v` flag to the docker run command: + +```bash +-v /your/host/data/path:/geoserver_data/data +``` + +### Data volume container + +In case you are running Compose for automatically having GeoServer up and running then a data volume container will be mounted with a default preloaded *GEOSERVER_DATA_DIR* at the configuration data directory of the container. +Make sure that the image from the repository [data-docker](https://github.com/GeoNode/data-docker) is available from the [GeoNode Docker Hub](https://hub.docker.com/u/geonode/) or has been built locally: + +```bash +docker build -t geonode/geoserver_data . +``` + +#### Persistance behavior + +If you run: + +```bash +docker-compose stop +``` + +Data are retained in the *GEOSERVER_DATA_DIR* and can then be mounted in a new GeoServer instance by running again: + +```bash +docker-compose up +``` + +If you run: + +```bash +docker-compose down +``` + +Data are completely gone but you can ever start from the base GeoServer Data Directory built for Geonode. + +#### Data directory versions + +There has to be a correspondence one-to-one between the data directory version and the tag of the GeoServer image used in the Docker compose file. So at the end you can consume these images below: + +* **2.9.x**: [geonode/geoserver_data:2.9.x](https://hub.docker.com/r/geonode/geoserver_data/builds/bsus6alnddg4bc7icwymevp/) +* **2.9.x-oauth2**: [geonode/geoserver_data:2.9.x-oauth2](https://hub.docker.com/r/geonode/geoserver_data/builds/bwkxcupsunvuitzusi9gsnt/) +* **2.10.x**: [geonode/geoserver_data:2.10.x](https://hub.docker.com/r/geonode/geoserver_data/builds/b5jqhpzapkqxzyevjizccug/) +* **2.12.x**: [geonode/geoserver_data:2.12.x](https://hub.docker.com/r/geonode/geoserver_data/builds/byaaalw3lnasunpveyg3x4i/) +* **2.13.x**: [geonode/geoserver_data:2.13.x](https://hub.docker.com/r/geonode/geoserver_data/builds/bunuqzq7a7dk65iumjhkbtc/) +* **2.14.x**: [geonode/geoserver_data:2.14.x](https://hub.docker.com/r/geonode/geoserver_data/builds/blpdjzkrv7pm3stunzpn4pp/) + +### Database + +GeoServer recommends the usage of a spatial database + +#### PostGIS container (PostgreSQL + GIS Extension) + +If you want to use a [PostGIS](http://postgis.org/) container, you can link it to this image. You're free to use any PostGIS container. +An example with [kartooza/postgis](https://registry.hub.docker.com/u/kartoza/postgis/) image: + +```bash +$ docker run -d --name="postgis" kartoza/postgis +``` + +For further information see [kartooza/postgis](https://registry.hub.docker.com/u/kartoza/postgis/). + +Now start the GeoServer instance by adding the `--link` option to the docker run command: + +```bash +--link postgis:postgis +``` diff --git a/scripts/docker/geoserver/docker-compose.yml b/scripts/docker/geoserver/docker-compose.yml new file mode 100644 index 00000000000..5f3dc1cf34e --- /dev/null +++ b/scripts/docker/geoserver/docker-compose.yml @@ -0,0 +1,61 @@ +version: '3.9' + +services: + + postgis: + image: geonode/postgis:13 + ports: + - "25432:5432" + volumes: + - /srv/docker/geoserver/postgis:/var/lib/postgresql + #volumes_from: + #- pgstore + healthcheck: + test: "pg_isready -d postgres -U postgres" + restart: on-failure + + geoserver: + image: geonode/geoserver:2.23.0 + build: + context: . + args: + - DOCKERHOST + - GEONODE_HOST_IP + - PUBLIC_PORT=80 + links: + - postgis + ports: + - "8080:8080" + volumes: + - /geoserver_data/data + environment: + - DOCKERHOST + - GEONODE_HOST_IP + - PUBLIC_PORT=80 + - DOCKER_HOST_IP + - DJANGO_URL=http://localhost/ + depends_on: + postgis: + condition: service_completed_successfully + data-dir-conf: + condition: service_healthy + healthcheck: + test: curl --fail -s http://localhost:8080/geoserver/rest/workspaces/geonode.html || exit 1 + interval: 1m30s + timeout: 10s + retries: 3 + restart: on-failure + + data-dir-conf: + image: geonode/geoserver_data:2.23.0 + container_name: geoserver_data_dir # named data container + entrypoint: sleep infinity + volumes: + - /geoserver_data/data + healthcheck: + test: "ls -A '/geoserver_data/data' | wc -l" + restart: on-failure + +volumes: + # reference to the named data container that holds the preloaded geoserver data directory + geoserver_data_dir: \ No newline at end of file diff --git a/scripts/docker/geoserver/entrypoint.sh b/scripts/docker/geoserver/entrypoint.sh new file mode 100644 index 00000000000..f9af5f42024 --- /dev/null +++ b/scripts/docker/geoserver/entrypoint.sh @@ -0,0 +1,152 @@ +#!/bin/bash +set -e + +source /root/.bashrc + +# control the value of DOCKER_HOST_IP variable +if [ -z ${DOCKER_HOST_IP} ] +then + + echo "DOCKER_HOST_IP is empty so I'll run the python utility \n" + echo export DOCKER_HOST_IP=`python3 /usr/local/tomcat/tmp/get_dockerhost_ip.py` >> /root/.override_env + echo "The calculated value is now DOCKER_HOST_IP='$DOCKER_HOST_IP' \n" + +else + + echo "DOCKER_HOST_IP is filled so I'll leave the found value '$DOCKER_HOST_IP' \n" + +fi + +# control the values of LB settings if present +if [ ${GEONODE_LB_HOST_IP} ] +then + + echo "GEONODE_LB_HOST_IP is filled so I replace the value of '$DOCKER_HOST_IP' with '$GEONODE_LB_HOST_IP' \n" + echo export DOCKER_HOST_IP=${GEONODE_LB_HOST_IP} >> /root/.override_env + +fi + +if [ ${GEONODE_LB_PORT} ] +then + + echo "GEONODE_LB_PORT is filled so I replace the value of '$PUBLIC_PORT' with '$GEONODE_LB_PORT' \n" + echo export PUBLIC_PORT=${GEONODE_LB_PORT} >> /root/.override_env + +fi + +if [ ! -z "${GEOSERVER_JAVA_OPTS}" ] +then + + echo "GEOSERVER_JAVA_OPTS is filled so I replace the value of '$JAVA_OPTS' with '$GEOSERVER_JAVA_OPTS' \n" + JAVA_OPTS=${GEOSERVER_JAVA_OPTS} + +fi + +# control the value of NGINX_BASE_URL variable +if [ -z `echo ${NGINX_BASE_URL} | sed 's/http:\/\/\([^:]*\).*/\1/'` ] +then + echo "NGINX_BASE_URL is empty so I'll use the static nginx hostname \n" + # echo export NGINX_BASE_URL=`python3 /usr/local/tomcat/tmp/get_nginxhost_ip.py` >> /root/.override_env + # TODO rework get_nginxhost_ip to get URL with static hostname from nginx service name + # + exposed port of that container i.e. http://geonode:80 + echo export NGINX_BASE_URL=http://geonode:80 >> /root/.override_env + echo "The calculated value is now NGINX_BASE_URL='$NGINX_BASE_URL' \n" +else + echo "NGINX_BASE_URL is filled so I'll leave the found value '$NGINX_BASE_URL' \n" +fi + +# set basic tagname +TAGNAME=( "baseUrl" ) + +if ! [ -f ${GEOSERVER_DATA_DIR}/security/auth/geonodeAuthProvider/config.xml ] +then + + echo "Configuration file '$GEOSERVER_DATA_DIR'/security/auth/geonodeAuthProvider/config.xml is not available so it is gone to skip \n" + +else + + # backup geonodeAuthProvider config.xml + cp ${GEOSERVER_DATA_DIR}/security/auth/geonodeAuthProvider/config.xml ${GEOSERVER_DATA_DIR}/security/auth/geonodeAuthProvider/config.xml.orig + # run the setting script for geonodeAuthProvider + /usr/local/tomcat/tmp/set_geoserver_auth.sh ${GEOSERVER_DATA_DIR}/security/auth/geonodeAuthProvider/config.xml ${GEOSERVER_DATA_DIR}/security/auth/geonodeAuthProvider/ ${TAGNAME} > /dev/null 2>&1 + +fi + +# backup geonode REST role service config.xml +cp "${GEOSERVER_DATA_DIR}/security/role/geonode REST role service/config.xml" "${GEOSERVER_DATA_DIR}/security/role/geonode REST role service/config.xml.orig" +# run the setting script for geonode REST role service +/usr/local/tomcat/tmp/set_geoserver_auth.sh "${GEOSERVER_DATA_DIR}/security/role/geonode REST role service/config.xml" "${GEOSERVER_DATA_DIR}/security/role/geonode REST role service/" ${TAGNAME} > /dev/null 2>&1 + +# set oauth2 filter tagname +TAGNAME=( "accessTokenUri" "userAuthorizationUri" "redirectUri" "checkTokenEndpointUrl" "logoutUri" ) + +# backup geonode-oauth2 config.xml +cp ${GEOSERVER_DATA_DIR}/security/filter/geonode-oauth2/config.xml ${GEOSERVER_DATA_DIR}/security/filter/geonode-oauth2/config.xml.orig +# run the setting script for geonode-oauth2 +/usr/local/tomcat/tmp/set_geoserver_auth.sh ${GEOSERVER_DATA_DIR}/security/filter/geonode-oauth2/config.xml ${GEOSERVER_DATA_DIR}/security/filter/geonode-oauth2/ "${TAGNAME[@]}" > /dev/null 2>&1 + +# set global tagname +TAGNAME=( "proxyBaseUrl" ) + +# backup global.xml +cp ${GEOSERVER_DATA_DIR}/global.xml ${GEOSERVER_DATA_DIR}/global.xml.orig +# run the setting script for global configuration +/usr/local/tomcat/tmp/set_geoserver_auth.sh ${GEOSERVER_DATA_DIR}/global.xml ${GEOSERVER_DATA_DIR}/ ${TAGNAME} > /dev/null 2>&1 + +# set correct amqp broker url +sed -i -e 's/localhost/rabbitmq/g' ${GEOSERVER_DATA_DIR}/notifier/notifier.xml + +# exclude wrong dependencies +sed -i -e 's/xom-\*\.jar/xom-\*\.jar,bcprov\*\.jar/g' /usr/local/tomcat/conf/catalina.properties + +# J2 templating for this docker image we should also do it for other configuration files in /usr/local/tomcat/tmp + +declare -a geoserver_datadir_template_dirs=("geofence") + +for template in in ${geoserver_datadir_template_dirs[*]}; do + #Geofence templates + if [ "$template" == "geofence" ]; then + cp -R /templates/$template/* ${GEOSERVER_DATA_DIR}/geofence + + for f in $(find ${GEOSERVER_DATA_DIR}/geofence/ -type f -name "*.j2"); do + echo -e "Evaluating template\n\tSource: $f\n\tDest: ${f%.j2}" + /usr/local/bin/j2 $f > ${f%.j2} + rm -f $f + done + + fi +done + +# configure CORS (inspired by https://github.com/oscarfonts/docker-geoserver) +# if enabled, this will add the filter definitions +# to the end of the web.xml +# (this will only happen if our filter has not yet been added before) +if [ "${GEOSERVER_CORS_ENABLED}" = "true" ] || [ "${GEOSERVER_CORS_ENABLED}" = "True" ]; then + if ! grep -q DockerGeoServerCorsFilter "$CATALINA_HOME/webapps/geoserver/WEB-INF/web.xml"; then + echo "Enable CORS for $CATALINA_HOME/webapps/geoserver/WEB-INF/web.xml" + sed -i "\::i\\ + \n\ + DockerGeoServerCorsFilter\n\ + org.apache.catalina.filters.CorsFilter\n\ + \n\ + cors.allowed.origins\n\ + ${GEOSERVER_CORS_ALLOWED_ORIGINS}\n\ + \n\ + \n\ + cors.allowed.methods\n\ + ${GEOSERVER_CORS_ALLOWED_METHODS}\n\ + \n\ + \n\ + cors.allowed.headers\n\ + ${GEOSERVER_CORS_ALLOWED_HEADERS}\n\ + \n\ + \n\ + \n\ + DockerGeoServerCorsFilter\n\ + /*\n\ + " "$CATALINA_HOME/webapps/geoserver/WEB-INF/web.xml"; + fi +fi + +# start tomcat +exec env JAVA_OPTS="${JAVA_OPTS}" catalina.sh run \ No newline at end of file diff --git a/scripts/docker/geoserver/get_dockerhost_ip.py b/scripts/docker/geoserver/get_dockerhost_ip.py new file mode 100644 index 00000000000..7b5a42ed310 --- /dev/null +++ b/scripts/docker/geoserver/get_dockerhost_ip.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 + +import logging + +import docker + +BOOTSTRAP_IMAGE_CHEIP = 'codenvy/che-ip:nightly' +# AF: why call before definition? print _docker_host_ip() + +def _docker_host_ip(): + client = docker.from_env() + ip_list = client.containers.run(BOOTSTRAP_IMAGE_CHEIP, + network_mode='host' + ).split("\n") + if len(ip_list) > 1: + logging.info("Docker daemon is running on more than one \ +address {0}".format(ip_list)) + logging.info("Only the first address:{0} will be returned!".format( + ip_list[0] + )) + else: + logging.info("Docker daemon is running at the following \ +address {0}".format(ip_list[0])) + return ip_list[0] diff --git a/scripts/docker/geoserver/get_nginxhost_ip.py b/scripts/docker/geoserver/get_nginxhost_ip.py new file mode 100644 index 00000000000..c6a67d8490d --- /dev/null +++ b/scripts/docker/geoserver/get_nginxhost_ip.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python3 + +import logging +import os + +import docker + +client = docker.from_env() +# print(client.info()) +# TODO avoid this script can fail and fall in the loop where the geoserver +# service is not available and consequently the nginx too which has geoserver +# as a reference link +for network in client.networks.list(): + if 'geonode' in network.name: + geonode_network = network.name + else: + geonode_network = 'geonode_default' + +try: + containers = { + c.attrs['Config']['Image']: c.attrs['NetworkSettings']['\ +Networks'][geonode_network]['\ +IPAddress'] for c in client.containers.list() if c.status in 'running' + } + for item in containers.items(): + if "geonode/nginx" in item[0]: + ipaddr = item[1] + + try: + os.environ["NGINX_BASE_URL"] = "http://" + ipaddr + ":" + "80" + nginx_base_url = "http://{}:80".format(ipaddr) + except NameError as er: + logging.info("NGINX container is not running maybe exited! Running\ +containers are:{0}".format(containers)) +except KeyError as ke: + logging.info("There has been a problem with the docker\ +network which has raised the following exception: {0}".format(ke)) +else: + # nginx_base_url = None + pass +finally: + try: + print(nginx_base_url) + except NameError as ne: + print("http://geonode:80") diff --git a/scripts/docker/geoserver/multidump-alt.sh b/scripts/docker/geoserver/multidump-alt.sh new file mode 100644 index 00000000000..cc237e17bec --- /dev/null +++ b/scripts/docker/geoserver/multidump-alt.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +if [ $# -ne 3 ]; then + echo "Usage: $0 pid interval count" + exit 1 +fi + +PID=$1 +INTERVAL=$2 +COUNT=$3 + +top -bH -d $INTERVAL -n $COUNT -p $PID >> top.out 2>&1 & +for i in `seq $COUNT`; do + kill -3 $PID + sleep $INTERVAL +done diff --git a/scripts/docker/geoserver/multidump.sh b/scripts/docker/geoserver/multidump.sh new file mode 100644 index 00000000000..21dfd2ba660 --- /dev/null +++ b/scripts/docker/geoserver/multidump.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +if [ $# -ne 3 ]; then + echo "Usage: $0 pid interval count" + exit 1 +fi + +PID=$1 +INTERVAL=$2 +COUNT=$3 + +top -bH -d $INTERVAL -n $COUNT -p $PID >> top.out 2>&1 & +for i in `seq $COUNT`; do + echo "stack trace $i of $COUNT" >> jstack.out + jstack -l $PID >> jstack.out + echo "--------------------" >> jstack.out + sleep $INTERVAL +done diff --git a/scripts/docker/geoserver/requirements.txt b/scripts/docker/geoserver/requirements.txt new file mode 100644 index 00000000000..0b31242fdae --- /dev/null +++ b/scripts/docker/geoserver/requirements.txt @@ -0,0 +1 @@ +docker==3.1.1 diff --git a/scripts/docker/geoserver/set_geoserver_auth.sh b/scripts/docker/geoserver/set_geoserver_auth.sh new file mode 100644 index 00000000000..27dd11ef54e --- /dev/null +++ b/scripts/docker/geoserver/set_geoserver_auth.sh @@ -0,0 +1,91 @@ +#!/bin/bash + +auth_conf_source="$1" +auth_conf_target="$2" +# Creating a temporary file for sed to write the changes to +temp_file="xml.tmp" +touch $temp_file + +source /root/.bashrc +source /root/.override_env + +test -z "$auth_conf_source" && echo "You must specify a source file" && exit 1 +test -z "$auth_conf_target" && echo "You must specify a target conf directory" && exit 1 + +test ! -f "$auth_conf_source" && echo "Source $auth_conf_source does not exist or is not a file" && exit 1 +test ! -d "$auth_conf_target" && echo "Target directory $auth_conf_target does not exist or is not a directory" && exit 1 + +# for debugging +echo -e "NGINX_BASE_URL=${NGINX_BASE_URL}\n" +if [ "$PUBLIC_PORT" == "443" ]; then + SUBSTITUTION_URL="https://${DOCKER_HOST_IP}" + if [ "$PUBLIC_PORT" != "443" ]; then + SUBSTITUTION_URL="https://${DOCKER_HOST_IP}:${PUBLIC_PORT}" + fi +else + SUBSTITUTION_URL="http://${DOCKER_HOST_IP}" + if [ "$PUBLIC_PORT" != "80" ]; then + SUBSTITUTION_URL="http://${DOCKER_HOST_IP}:${PUBLIC_PORT}" + fi +fi + +echo -e "SUBSTITUTION_URL=$SUBSTITUTION_URL\n" +echo -e "auth_conf_source=$auth_conf_source\n" +echo -e "auth_conf_target=$auth_conf_target\n" + +# Elegance is the key -> adding an empty last line for Mr. “sed” to pick up +echo " " >> "$auth_conf_source" + +cat "$auth_conf_source" + +tagname=( ${@:3:5} ) + +# for debugging +for i in "${tagname[@]}" +do + echo "tagname=<$i>" +done + +echo "DEBUG: Starting... [Ok]\n" + +for i in "${tagname[@]}" +do + echo "DEBUG: Working on '$auth_conf_source' for tagname <$i>" + # Extracting the value from the <$tagname> element + # echo -ne "<$i>$tagvalue" | xmlstarlet sel -t -m "//a" -v . -n + tagvalue=`grep "<$i>.*<.$i>" "$auth_conf_source" | sed -e "s/^.*<$i/<$i/" | cut -f2 -d">"| cut -f1 -d"<"` + + echo "DEBUG: Found the current value for the element <$i> - '$tagvalue'" + + # Setting new substituted value + case $i in + proxyBaseUrl ) + if [ ${GEONODE_LB_HOST_IP} ] + then + echo "DEBUG: Editing '$auth_conf_source' for tagname <$i> and replacing its value with '$SUBSTITUTION_URL'" + newvalue=`echo -ne "$tagvalue" | sed -re "s@http://localhost(:8.*0)@$SUBSTITUTION_URL@"` + else + echo "DEBUG: Editing '$auth_conf_source' for tagname <$i> and replacing its value with '$NGINX_BASE_URL'" + newvalue=`echo -ne "$tagvalue" | sed -re "s@http://localhost(:8.*0)@$NGINX_BASE_URL@"` + fi;; + accessTokenUri | checkTokenEndpointUrl | baseUrl ) + echo "DEBUG: Editing '$auth_conf_source' for tagname <$i> and replacing its value with '$NGINX_BASE_URL'" + newvalue=`echo -ne "$tagvalue" | sed -re "s@http://localhost(:8.*0)@$NGINX_BASE_URL@"`;; + userAuthorizationUri | redirectUri | logoutUri ) + echo "DEBUG: Editing '$auth_conf_source' for tagname <$i> and replacing its value with '$SUBSTITUTION_URL'" + newvalue=`echo -ne "$tagvalue" | sed -re "s@http://localhost(:8.*0)@$SUBSTITUTION_URL@"`;; + *) echo -n "an unknown variable has been found";; + esac + + echo "DEBUG: Found the new value for the element <$i> - '$newvalue'" + # Replacing element’s value with $SUBSTITUTION_URL + # echo -ne "<$i>$tagvalue" | xmlstarlet sel -t -m "//a" -v . -n + sed -e "s@<$i>$tagvalue<\/$i>@<$i>$newvalue<\/$i>@g" "$auth_conf_source" > "$temp_file" + cp "$temp_file" "$auth_conf_source" +done +# Writing our changes back to the original file ($auth_conf_source) +# no longer needed +# mv $temp_file $auth_conf_source + +echo "DEBUG: Finished... [Ok] --- Final xml file is \n" +cat "$auth_conf_source" diff --git a/scripts/docker/geoserver/setup_auth.sh b/scripts/docker/geoserver/setup_auth.sh new file mode 100644 index 00000000000..6f9373b978c --- /dev/null +++ b/scripts/docker/geoserver/setup_auth.sh @@ -0,0 +1,3 @@ +#!/bin/sh +sed -i.bak 's@\([^<][^<]*\)@'"$DJANGO_URL"'@'\ + /geoserver_data/data/security/auth/geonodeAuthProvider/config.xml \ No newline at end of file diff --git a/scripts/docker/geoserver/templates/geofence/geofence-datasource-ovr.properties.j2 b/scripts/docker/geoserver/templates/geofence/geofence-datasource-ovr.properties.j2 new file mode 100644 index 00000000000..7b18d3e55f3 --- /dev/null +++ b/scripts/docker/geoserver/templates/geofence/geofence-datasource-ovr.properties.j2 @@ -0,0 +1,12 @@ +geofenceVendorAdapter.databasePlatform=org.hibernatespatial.postgis.PostgisDialect +geofenceDataSource.driverClassName=org.postgresql.Driver +geofenceDataSource.url=jdbc:postgresql://{{ DATABASE_HOST }}:{{ DATABASE_PORT }}/{{ GEONODE_GEODATABASE }} +geofenceDataSource.username={{ GEONODE_GEODATABASE }} +geofenceDataSource.password={{ GEONODE_GEODATABASE_PASSWORD }} +geofenceEntityManagerFactory.jpaPropertyMap[hibernate.default_schema]={{ GEONODE_GEODATABASE_SCHEMA }} + +# avoid hibernate transaction issues +geofenceDataSource.testOnBorrow=true +geofenceDataSource.validationQuery=SELECT 1 +geofenceEntityManagerFactory.jpaPropertyMap[hibernate.testOnBorrow]=true +geofenceEntityManagerFactory.jpaPropertyMap[hibernate.validationQuery]=SELECT 1 \ No newline at end of file From a5c84a0117899c009a6d43b8c42aadf0e7b9fe98 Mon Sep 17 00:00:00 2001 From: Henning Bredel Date: Thu, 10 Aug 2023 18:16:48 +0200 Subject: [PATCH 41/70] Fix geoserver's context path --- .github/workflows/build-and-push-services.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-push-services.yml b/.github/workflows/build-and-push-services.yml index 7a0738dc687..dd38db3aae5 100644 --- a/.github/workflows/build-and-push-services.yml +++ b/.github/workflows/build-and-push-services.yml @@ -162,8 +162,8 @@ jobs: name: Build and push uses: docker/build-push-action@v4 with: - context: ./scripts/docker/nginx/ - file: ./scripts/docker/nginx/Dockerfile + context: ./scripts/docker/geoserver/ + file: ./scripts/docker/geoserver/Dockerfile push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} From 41ce5b7f37c6fa1c2b92f1ca36583e1dc3b41cd2 Mon Sep 17 00:00:00 2001 From: Henning Bredel Date: Fri, 11 Aug 2023 14:29:19 +0200 Subject: [PATCH 42/70] Add tags for mayor, minor, and bugfix version --- .github/workflows/build-and-push-services.yml | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-and-push-services.yml b/.github/workflows/build-and-push-services.yml index dd38db3aae5..a1ef2e50d90 100644 --- a/.github/workflows/build-and-push-services.yml +++ b/.github/workflows/build-and-push-services.yml @@ -24,7 +24,9 @@ jobs: runs-on: ubuntu-22.04 env: IMAGE: 52north/istg_geonode - VERSION: "4.1" + MAJOR_VERSION: "4" + MINOR_VERSION: "4.1" + BUGFIX_VERSION: "4.1.1" steps: - name: Checkout @@ -49,7 +51,9 @@ jobs: "org.opencontainers.image.licenses=${{ env.LICENSE }}" tags: | latest - ${{ env.VERSION }} + ${{ env.MAJOR_VERSION }} + ${{ env.MINOR_VERSION }} + ${{ env.BUGFIX_VERSION }} type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} - @@ -74,7 +78,9 @@ jobs: runs-on: ubuntu-22.04 env: IMAGE: 52north/istg_nginx - VERSION: "4.1" + MAJOR_VERSION: "4" + MINOR_VERSION: "4.1" + BUGFIX_VERSION: "4.1.1" steps: - name: Checkout @@ -99,7 +105,9 @@ jobs: "org.opencontainers.image.licenses=${{ env.LICENSE }}" tags: | latest - ${{ env.VERSION }} + ${{ env.MAJOR_VERSION }} + ${{ env.MINOR_VERSION }} + ${{ env.BUGFIX_VERSION }} type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} - From 537ac90d60b830e93d65034a78156b361b272512 Mon Sep 17 00:00:00 2001 From: Giovanni Allegri Date: Fri, 11 Aug 2023 11:51:41 +0200 Subject: [PATCH 43/70] BUmp to 4.1.x (#11371) --- CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b440a931782..e2ac7e72bd1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ # Change Log -## [4.1.1](https://github.com/GeoNode/geonode/tree/4.1.0) (2023-06-05) +## [4.1.2](https://github.com/GeoNode/geonode/tree/4.1.2) (2023-08-11) +## Bug Fixes +- Upgrade to importer 1.0.5 which fixes the import with filenames longer then 63 chars +- Fixed parsing and rendering of ISO TC211 spatial representetion type +## [4.1.1](https://github.com/GeoNode/geonode/tree/4.1.1) (2023-06-05) ## Security and Bug Fixes - Upgrade to Ubuntu 22.10 - Upgrade to Django 3.2.20 From dd53272e5cdb9eb4d8b0df601fe705de274a3042 Mon Sep 17 00:00:00 2001 From: Henning Bredel Date: Fri, 11 Aug 2023 14:40:46 +0200 Subject: [PATCH 44/70] Update geonode version to 4.1.2 --- .github/workflows/build-and-push-services.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-push-services.yml b/.github/workflows/build-and-push-services.yml index a1ef2e50d90..1d2922c6ec7 100644 --- a/.github/workflows/build-and-push-services.yml +++ b/.github/workflows/build-and-push-services.yml @@ -26,7 +26,7 @@ jobs: IMAGE: 52north/istg_geonode MAJOR_VERSION: "4" MINOR_VERSION: "4.1" - BUGFIX_VERSION: "4.1.1" + BUGFIX_VERSION: "4.1.2" steps: - name: Checkout @@ -80,7 +80,7 @@ jobs: IMAGE: 52north/istg_nginx MAJOR_VERSION: "4" MINOR_VERSION: "4.1" - BUGFIX_VERSION: "4.1.1" + BUGFIX_VERSION: "4.1.2" steps: - name: Checkout From 75859d835ea955a0351a51c58531ba8f778946fe Mon Sep 17 00:00:00 2001 From: Henning Bredel Date: Tue, 15 Aug 2023 10:55:13 +0200 Subject: [PATCH 45/70] Clean up versions metadata --- .github/workflows/build-and-push-services.yml | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/.github/workflows/build-and-push-services.yml b/.github/workflows/build-and-push-services.yml index 1d2922c6ec7..ea522e691ea 100644 --- a/.github/workflows/build-and-push-services.yml +++ b/.github/workflows/build-and-push-services.yml @@ -1,6 +1,7 @@ name: Release Docker Images env: + SHA: ${{ github.sha }} TITLE: "52°North GeoNode Deployment Image for IStG" VENDOR: "52°North GmbH" AUTHORS: "https://52North.org/" @@ -11,13 +12,6 @@ on: push: branches: - "52n-istg" - # release: - # types: - # - "created" - # branches: - # - "52n-istg" - # tags: - # - "istg-v*.*.*" jobs: build_and_push_geonode: @@ -51,11 +45,10 @@ jobs: "org.opencontainers.image.licenses=${{ env.LICENSE }}" tags: | latest + ${{ env.SHA }} ${{ env.MAJOR_VERSION }} ${{ env.MINOR_VERSION }} ${{ env.BUGFIX_VERSION }} - type=semver,pattern={{version}} - type=semver,pattern={{major}}.{{minor}} - name: Login to Docker Hub uses: docker/login-action@v2 @@ -105,11 +98,10 @@ jobs: "org.opencontainers.image.licenses=${{ env.LICENSE }}" tags: | latest + ${{ env.SHA }} ${{ env.MAJOR_VERSION }} ${{ env.MINOR_VERSION }} ${{ env.BUGFIX_VERSION }} - type=semver,pattern={{version}} - type=semver,pattern={{major}}.{{minor}} - name: Login to Docker Hub uses: docker/login-action@v2 @@ -157,9 +149,8 @@ jobs: "org.opencontainers.image.licenses=${{ env.LICENSE }}" tags: | latest + ${{ env.SHA }} ${{ env.VERSION }} - type=semver,pattern={{version}} - type=semver,pattern={{major}}.{{minor}} - name: Login to Docker Hub uses: docker/login-action@v2 From ae6c47480d950055a2079dcaf83441c6172b21ab Mon Sep 17 00:00:00 2001 From: Henning Bredel Date: Tue, 15 Aug 2023 12:43:41 +0200 Subject: [PATCH 46/70] Push core images to dedicated repos --- .github/workflows/build-and-push-services.yml | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build-and-push-services.yml b/.github/workflows/build-and-push-services.yml index ea522e691ea..e32093c1729 100644 --- a/.github/workflows/build-and-push-services.yml +++ b/.github/workflows/build-and-push-services.yml @@ -1,23 +1,23 @@ -name: Release Docker Images +name: Release GeoNode Docker Images env: SHA: ${{ github.sha }} - TITLE: "52°North GeoNode Deployment Image for IStG" + TITLE: "52°North GeoNode Docker Image" VENDOR: "52°North GmbH" AUTHORS: "https://52North.org/" - DESCRIPTION: "52°North GeoNode Deployment Image" + DESCRIPTION: "Builds and publishes the Docker images GeoNode, GeoServer, Nginx" LICENSE: "GPL-3.0" on: push: branches: - - "52n-istg" + - "52n-master" jobs: build_and_push_geonode: runs-on: ubuntu-22.04 env: - IMAGE: 52north/istg_geonode + IMAGE: 52north/geonode-geonode MAJOR_VERSION: "4" MINOR_VERSION: "4.1" BUGFIX_VERSION: "4.1.2" @@ -54,7 +54,7 @@ jobs: uses: docker/login-action@v2 with: username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN_ISTG }} + password: ${{ secrets.DOCKERHUB_TOKEN_52N_MASTER }} - name: Build and push uses: docker/build-push-action@v4 @@ -70,7 +70,7 @@ jobs: build_and_push_nginx: runs-on: ubuntu-22.04 env: - IMAGE: 52north/istg_nginx + IMAGE: 52north/geonode-nginx MAJOR_VERSION: "4" MINOR_VERSION: "4.1" BUGFIX_VERSION: "4.1.2" @@ -107,7 +107,7 @@ jobs: uses: docker/login-action@v2 with: username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN_ISTG }} + password: ${{ secrets.DOCKERHUB_TOKEN_52N_MASTER }} - name: Build and push uses: docker/build-push-action@v4 @@ -123,7 +123,7 @@ jobs: build_and_push_geoserver: runs-on: ubuntu-22.04 env: - IMAGE: 52north/istg_geoserver + IMAGE: 52north/geonode-geoserver VERSION: "2.23.0" steps: - @@ -156,7 +156,7 @@ jobs: uses: docker/login-action@v2 with: username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN_ISTG }} + password: ${{ secrets.DOCKERHUB_TOKEN_52N_MASTER }} - name: Build and push uses: docker/build-push-action@v4 From 9f6504832fcf5943f88e1e3e2bacecfc4044f97a Mon Sep 17 00:00:00 2001 From: Henning Bredel Date: Tue, 15 Aug 2023 16:01:26 +0200 Subject: [PATCH 47/70] Push geonode image to 52north/geonode --- .github/workflows/build-and-push-services.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-push-services.yml b/.github/workflows/build-and-push-services.yml index e32093c1729..73bdab615b7 100644 --- a/.github/workflows/build-and-push-services.yml +++ b/.github/workflows/build-and-push-services.yml @@ -17,7 +17,7 @@ jobs: build_and_push_geonode: runs-on: ubuntu-22.04 env: - IMAGE: 52north/geonode-geonode + IMAGE: 52north/geonode MAJOR_VERSION: "4" MINOR_VERSION: "4.1" BUGFIX_VERSION: "4.1.2" From 065aa07bfd3b7b9730c79c8a032f0ac0f3b671e0 Mon Sep 17 00:00:00 2001 From: Henning Bredel Date: Thu, 17 Aug 2023 10:07:32 +0200 Subject: [PATCH 48/70] Upload a dockerhub description --- .github/workflows/dockerhub-desciption.yml | 22 ++++++++++++++++++++++ README_52n.md | 6 ++++++ 2 files changed, 28 insertions(+) create mode 100644 .github/workflows/dockerhub-desciption.yml create mode 100644 README_52n.md diff --git a/.github/workflows/dockerhub-desciption.yml b/.github/workflows/dockerhub-desciption.yml new file mode 100644 index 00000000000..d4b52d051d3 --- /dev/null +++ b/.github/workflows/dockerhub-desciption.yml @@ -0,0 +1,22 @@ +name: Update Docker Hub Description +on: + push: + branches: + - 52n-master + paths: + - README_52n.md + - .github/workflows/dockerhub-description.yml +jobs: + dockerHubDescription: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Docker Hub Description + uses: peter-evans/dockerhub-description@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN_52N_MASTER }} + repository: peterevans/dockerhub-description + short-description: ${{ github.event.repository.description }} + enable-url-completion: true \ No newline at end of file diff --git a/README_52n.md b/README_52n.md new file mode 100644 index 00000000000..42ef8337913 --- /dev/null +++ b/README_52n.md @@ -0,0 +1,6 @@ +# 52°North Fork of GeoNode + +This is a fork of [Geonode](https://github.com/geonode/geonode). +[52°North GmbH](https://52north.org) maintains an own fork of GeoNode in order to make necessary adjustments within projects which are not part of GeoNode core. + +However, we are interested to stay as close to upstream as possible, to benefit from ongoing development, but also to contribute features and fixes we develop in our projects. From 77cd1cf1da8270bb3cb9327d802d082f920bfbeb Mon Sep 17 00:00:00 2001 From: Henning Bredel Date: Thu, 17 Aug 2023 10:12:00 +0200 Subject: [PATCH 49/70] Update dockerhub description workflow config --- .github/workflows/dockerhub-desciption.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/dockerhub-desciption.yml b/.github/workflows/dockerhub-desciption.yml index d4b52d051d3..294e9535d0d 100644 --- a/.github/workflows/dockerhub-desciption.yml +++ b/.github/workflows/dockerhub-desciption.yml @@ -18,5 +18,6 @@ jobs: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN_52N_MASTER }} repository: peterevans/dockerhub-description - short-description: ${{ github.event.repository.description }} + short-description: "Geospatial content management system" + readme-filepath: ./README_52n.md enable-url-completion: true \ No newline at end of file From dcbd06030fdb39ce7860a68231cc48a23f12f2d0 Mon Sep 17 00:00:00 2001 From: Henning Bredel Date: Thu, 17 Aug 2023 10:16:47 +0200 Subject: [PATCH 50/70] Update 52n readme --- README_52n.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README_52n.md b/README_52n.md index 42ef8337913..4b748e91ba5 100644 --- a/README_52n.md +++ b/README_52n.md @@ -1,6 +1,6 @@ # 52°North Fork of GeoNode -This is a fork of [Geonode](https://github.com/geonode/geonode). +This image is built from a fork of [Geonode](https://github.com/geonode/geonode). [52°North GmbH](https://52north.org) maintains an own fork of GeoNode in order to make necessary adjustments within projects which are not part of GeoNode core. However, we are interested to stay as close to upstream as possible, to benefit from ongoing development, but also to contribute features and fixes we develop in our projects. From 650cbb19ef0f3510d5d8871870ce5fed69f79ab7 Mon Sep 17 00:00:00 2001 From: Henning Bredel Date: Thu, 17 Aug 2023 10:18:06 +0200 Subject: [PATCH 51/70] Fix image repository config --- .github/workflows/dockerhub-desciption.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dockerhub-desciption.yml b/.github/workflows/dockerhub-desciption.yml index 294e9535d0d..3dbe8fbb583 100644 --- a/.github/workflows/dockerhub-desciption.yml +++ b/.github/workflows/dockerhub-desciption.yml @@ -17,7 +17,7 @@ jobs: with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN_52N_MASTER }} - repository: peterevans/dockerhub-description + repository: 52north/geonode short-description: "Geospatial content management system" readme-filepath: ./README_52n.md enable-url-completion: true \ No newline at end of file From 57e10649452f4798aaa62afdb9b54ac7f783ef62 Mon Sep 17 00:00:00 2001 From: Henning Bredel Date: Thu, 17 Aug 2023 10:19:24 +0200 Subject: [PATCH 52/70] Fix workflow name --- .../{dockerhub-desciption.yml => dockerhub-description.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{dockerhub-desciption.yml => dockerhub-description.yml} (100%) diff --git a/.github/workflows/dockerhub-desciption.yml b/.github/workflows/dockerhub-description.yml similarity index 100% rename from .github/workflows/dockerhub-desciption.yml rename to .github/workflows/dockerhub-description.yml From 76539f8b9484e26e546c0f6219b23e3524113532 Mon Sep 17 00:00:00 2001 From: Henning Bredel Date: Thu, 17 Aug 2023 10:25:17 +0200 Subject: [PATCH 53/70] Link to 52n fork on github --- README_52n.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README_52n.md b/README_52n.md index 4b748e91ba5..d340a6a6e6c 100644 --- a/README_52n.md +++ b/README_52n.md @@ -4,3 +4,6 @@ This image is built from a fork of [Geonode](https://github.com/geonode/geonode) [52°North GmbH](https://52north.org) maintains an own fork of GeoNode in order to make necessary adjustments within projects which are not part of GeoNode core. However, we are interested to stay as close to upstream as possible, to benefit from ongoing development, but also to contribute features and fixes we develop in our projects. + +This image is built from the `52n-master` branch of the [`52north/geonode` repository](https://github.com/52North/geonode/tree/52n-master). +Depending on our current project contexts we merge regularly from upstream, and create new pull requests from this fork. From a592ddbc06fe7d0e06ee6c6e80bd2171abbf4749 Mon Sep 17 00:00:00 2001 From: Henning Bredel Date: Thu, 17 Aug 2023 11:03:46 +0200 Subject: [PATCH 54/70] Add a note to version 3 tags --- README_52n.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README_52n.md b/README_52n.md index d340a6a6e6c..7f100e89118 100644 --- a/README_52n.md +++ b/README_52n.md @@ -5,5 +5,9 @@ This image is built from a fork of [Geonode](https://github.com/geonode/geonode) However, we are interested to stay as close to upstream as possible, to benefit from ongoing development, but also to contribute features and fixes we develop in our projects. -This image is built from the `52n-master` branch of the [`52north/geonode` repository](https://github.com/52North/geonode/tree/52n-master). +Starting from version `4` this image is built from the `52n-master` branch of the [`52north/geonode` repository](https://github.com/52North/geonode/tree/52n-master). Depending on our current project contexts we merge regularly from upstream, and create new pull requests from this fork. + +> :warning: **Note on `3`** +> +> Images containing a `3.x` version tag do have different code base. \ No newline at end of file From 2ea3b29a2c161f4e308eaceb66acbec840149143 Mon Sep 17 00:00:00 2001 From: Henning Bredel Date: Thu, 17 Aug 2023 11:09:23 +0200 Subject: [PATCH 55/70] Add a note to version 3 tags --- README_52n.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README_52n.md b/README_52n.md index 7f100e89118..56ecf449f93 100644 --- a/README_52n.md +++ b/README_52n.md @@ -8,6 +8,7 @@ However, we are interested to stay as close to upstream as possible, to benefit Starting from version `4` this image is built from the `52n-master` branch of the [`52north/geonode` repository](https://github.com/52North/geonode/tree/52n-master). Depending on our current project contexts we merge regularly from upstream, and create new pull requests from this fork. -> :warning: **Note on `3`** +> **Note on version `3` tags** > -> Images containing a `3.x` version tag do have different code base. \ No newline at end of file +> Images containing a `3.x` version tag were experimental and do have a different code base. +> These image are considered to be removed in the near future. \ No newline at end of file From 22063711ee075fa95e595cae605e7c2bd3568e93 Mon Sep 17 00:00:00 2001 From: Henning Bredel Date: Thu, 17 Aug 2023 11:43:28 +0200 Subject: [PATCH 56/70] Update dockerhub readme --- README_52n.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/README_52n.md b/README_52n.md index 56ecf449f93..3e92b9009b5 100644 --- a/README_52n.md +++ b/README_52n.md @@ -6,7 +6,18 @@ This image is built from a fork of [Geonode](https://github.com/geonode/geonode) However, we are interested to stay as close to upstream as possible, to benefit from ongoing development, but also to contribute features and fixes we develop in our projects. Starting from version `4` this image is built from the `52n-master` branch of the [`52north/geonode` repository](https://github.com/52North/geonode/tree/52n-master). -Depending on our current project contexts we merge regularly from upstream, and create new pull requests from this fork. +The repository builds and publishes three images: + +* [`52north/geonode`](https://hub.docker.com/r/52north/geonode) (this image) +* [`52north/geonode-nginx`](https://hub.docker.com/r/52north/geonode-nginx) +* [`52north/geonode-geoserver`](https://hub.docker.com/r/52north/geonode-geoserver) + +The Dockerfiles can be found under the [`./scripts/docker` folder](https://github.com/52North/geonode/tree/52n-master/scripts/docker). + +The official Docker configuration of [GeoServer for GeoNode](https://github.com/GeoNode/geoserver-docker) seems to be outdated. +Therefore, our fork adds a `./scripts/docker/geoserver` Docker config which is based on [the geonode-project](https://github.com/geonode/geonode-project) template. + +Depending on our current project contexts we merge regularly from upstream, and create new pull requests based on this fork. > **Note on version `3` tags** > From 605a873d2be36ffa5c873c5e671ed6b13358c266 Mon Sep 17 00:00:00 2001 From: Henning Bredel Date: Mon, 4 Sep 2023 11:55:49 +0200 Subject: [PATCH 57/70] Do not use commit SHA for labels --- .github/workflows/build-and-push-services.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/build-and-push-services.yml b/.github/workflows/build-and-push-services.yml index 73bdab615b7..472c1dc9931 100644 --- a/.github/workflows/build-and-push-services.yml +++ b/.github/workflows/build-and-push-services.yml @@ -1,7 +1,6 @@ name: Release GeoNode Docker Images env: - SHA: ${{ github.sha }} TITLE: "52°North GeoNode Docker Image" VENDOR: "52°North GmbH" AUTHORS: "https://52North.org/" @@ -45,7 +44,6 @@ jobs: "org.opencontainers.image.licenses=${{ env.LICENSE }}" tags: | latest - ${{ env.SHA }} ${{ env.MAJOR_VERSION }} ${{ env.MINOR_VERSION }} ${{ env.BUGFIX_VERSION }} @@ -98,7 +96,6 @@ jobs: "org.opencontainers.image.licenses=${{ env.LICENSE }}" tags: | latest - ${{ env.SHA }} ${{ env.MAJOR_VERSION }} ${{ env.MINOR_VERSION }} ${{ env.BUGFIX_VERSION }} @@ -149,7 +146,6 @@ jobs: "org.opencontainers.image.licenses=${{ env.LICENSE }}" tags: | latest - ${{ env.SHA }} ${{ env.VERSION }} - name: Login to Docker Hub From 649085bcdaea80be1d4526fb9f63fa3c6a49e6b9 Mon Sep 17 00:00:00 2001 From: Henning Bredel Date: Wed, 13 Sep 2023 10:12:19 +0200 Subject: [PATCH 58/70] Separates 4.1.x and a release builds --- ...-push-services.yml => 52n-build-4.1.x.yml} | 29 ++------ .github/workflows/52n-release.yaml | 73 +++++++++++++++++++ 2 files changed, 78 insertions(+), 24 deletions(-) rename .github/workflows/{build-and-push-services.yml => 52n-build-4.1.x.yml} (86%) create mode 100644 .github/workflows/52n-release.yaml diff --git a/.github/workflows/build-and-push-services.yml b/.github/workflows/52n-build-4.1.x.yml similarity index 86% rename from .github/workflows/build-and-push-services.yml rename to .github/workflows/52n-build-4.1.x.yml index 472c1dc9931..28303f5be2a 100644 --- a/.github/workflows/build-and-push-services.yml +++ b/.github/workflows/52n-build-4.1.x.yml @@ -1,4 +1,4 @@ -name: Release GeoNode Docker Images +name: Builds GeoNode Docker Images 4.1.x env: TITLE: "52°North GeoNode Docker Image" @@ -6,6 +6,7 @@ env: AUTHORS: "https://52North.org/" DESCRIPTION: "Builds and publishes the Docker images GeoNode, GeoServer, Nginx" LICENSE: "GPL-3.0" + TAG: 4.1.x on: push: @@ -17,16 +18,10 @@ jobs: runs-on: ubuntu-22.04 env: IMAGE: 52north/geonode - MAJOR_VERSION: "4" - MINOR_VERSION: "4.1" - BUGFIX_VERSION: "4.1.2" steps: - name: Checkout uses: actions/checkout@v3 - - - name: Set up QEMU - uses: docker/setup-qemu-action@v2 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 @@ -44,9 +39,7 @@ jobs: "org.opencontainers.image.licenses=${{ env.LICENSE }}" tags: | latest - ${{ env.MAJOR_VERSION }} - ${{ env.MINOR_VERSION }} - ${{ env.BUGFIX_VERSION }} + ${{ env.TAG }} - name: Login to Docker Hub uses: docker/login-action@v2 @@ -69,16 +62,10 @@ jobs: runs-on: ubuntu-22.04 env: IMAGE: 52north/geonode-nginx - MAJOR_VERSION: "4" - MINOR_VERSION: "4.1" - BUGFIX_VERSION: "4.1.2" steps: - name: Checkout uses: actions/checkout@v3 - - - name: Set up QEMU - uses: docker/setup-qemu-action@v2 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 @@ -96,9 +83,7 @@ jobs: "org.opencontainers.image.licenses=${{ env.LICENSE }}" tags: | latest - ${{ env.MAJOR_VERSION }} - ${{ env.MINOR_VERSION }} - ${{ env.BUGFIX_VERSION }} + ${{ env.TAG }} - name: Login to Docker Hub uses: docker/login-action@v2 @@ -121,14 +106,10 @@ jobs: runs-on: ubuntu-22.04 env: IMAGE: 52north/geonode-geoserver - VERSION: "2.23.0" steps: - name: Checkout uses: actions/checkout@v3 - - - name: Set up QEMU - uses: docker/setup-qemu-action@v2 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 @@ -146,7 +127,7 @@ jobs: "org.opencontainers.image.licenses=${{ env.LICENSE }}" tags: | latest - ${{ env.VERSION }} + ${{ env.TAG }} - name: Login to Docker Hub uses: docker/login-action@v2 diff --git a/.github/workflows/52n-release.yaml b/.github/workflows/52n-release.yaml new file mode 100644 index 00000000000..75d17eeb48e --- /dev/null +++ b/.github/workflows/52n-release.yaml @@ -0,0 +1,73 @@ +name: Release GeoNode Docker Images + +env: + TITLE: "52°North GeoNode Docker Image" + VENDOR: "52°North GmbH" + AUTHORS: "https://52North.org/" + DESCRIPTION: "Builds and publishes the Docker images GeoNode, GeoServer, Nginx" + LICENSE: "GPL-3.0" + +on: + push: + tags: + - "v*-52n" + +jobs: + build_and_push_geonode: + runs-on: ubuntu-22.04 + env: + IMAGE: 52north/geonode + steps: + - + name: Checkout + uses: actions/checkout@v3 + - + name: Parse semver string + id: semver_parser + uses: booxmedialtd/ws-action-parse-semver@v1 + with: + input_string: "${{github.ref_name}}" + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + - + name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v4 + env: + MAJOR_VERSION: ${{ steps.semver_parser.outputs.major }} + MAJOR_MINOR_VERSION: ${{ steps.semver_parser.outputs.major }}-${{ steps.semver_parser.outputs.minor }} + MAJOR_MINOR_PATCH_VERSION: ${{ steps.semver_parser.outputs.major }}-${{ steps.semver_parser.outputs.minor }}-${{ steps.semver_parser.outputs.patch }} + with: + images: ${{ env.IMAGE }} + labels: | + "org.opencontainers.image.authors=${{ env.AUTHORS }}" + "org.opencontainers.image.vendor=${{ env.VENDOR }}" + "org.opencontainers.image.description=${{ env.DESCRIPTION }}" + "org.opencontainers.image.title=${{ env.TITLE }}" + "org.opencontainers.image.licenses=${{ env.LICENSE }}" + tags: | + ${{ env.MAJOR_VERSION }} + ${{ env.MAJOR_MINOR_VERSION }} + ${{ env.MAJOR_MINOR_PATCH_VERSION }} + - + name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - + name: Fail in case fully tagged version already exists + run: docker manifest inspect ${{ env.IMAGE }}:${{ steps.meta.env.MAJOR_MINOR_PATCH_VERSION }} > /dev/null ; test $? != 0 + - + name: Build and push + uses: docker/build-push-action@v4 + with: + context: . + file: ./Dockerfile + push: false + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=registry,ref=${{ env.IMAGE }}:buildcache + cache-to: type=registry,ref=${{ env.IMAGE }}:buildcache,mode=max + From 44095c3314bc878c814c173b8df7abe67e9ea028 Mon Sep 17 00:00:00 2001 From: Henning Bredel Date: Wed, 13 Sep 2023 10:19:51 +0200 Subject: [PATCH 59/70] Cancel running builds --- .github/workflows/52n-build-4.1.x.yml | 4 ++++ .github/workflows/52n-release.yaml | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/.github/workflows/52n-build-4.1.x.yml b/.github/workflows/52n-build-4.1.x.yml index 28303f5be2a..c6bcccc0906 100644 --- a/.github/workflows/52n-build-4.1.x.yml +++ b/.github/workflows/52n-build-4.1.x.yml @@ -1,5 +1,9 @@ name: Builds GeoNode Docker Images 4.1.x +concurrency: + group: "geonode_build_4.1.x" + cancel-in-progress: true + env: TITLE: "52°North GeoNode Docker Image" VENDOR: "52°North GmbH" diff --git a/.github/workflows/52n-release.yaml b/.github/workflows/52n-release.yaml index 75d17eeb48e..04c742cae94 100644 --- a/.github/workflows/52n-release.yaml +++ b/.github/workflows/52n-release.yaml @@ -1,5 +1,9 @@ name: Release GeoNode Docker Images +concurrency: + group: "geonode_build_release" + cancel-in-progress: true + env: TITLE: "52°North GeoNode Docker Image" VENDOR: "52°North GmbH" From afba6aaaf96488c913527a0d1125734b99390dcf Mon Sep 17 00:00:00 2001 From: Henning Bredel Date: Wed, 13 Sep 2023 10:55:06 +0200 Subject: [PATCH 60/70] Trigger release build on tag having -52n suffix --- .github/workflows/52n-release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/52n-release.yaml b/.github/workflows/52n-release.yaml index 04c742cae94..c32061ef692 100644 --- a/.github/workflows/52n-release.yaml +++ b/.github/workflows/52n-release.yaml @@ -14,7 +14,7 @@ env: on: push: tags: - - "v*-52n" + - "*-52n" jobs: build_and_push_geonode: From a169074fa2548144db7921af23f7929a03016774 Mon Sep 17 00:00:00 2001 From: Henning Bredel Date: Wed, 13 Sep 2023 10:58:04 +0200 Subject: [PATCH 61/70] Fix dockerhub secret refs --- .github/workflows/52n-release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/52n-release.yaml b/.github/workflows/52n-release.yaml index c32061ef692..f3fec8adebc 100644 --- a/.github/workflows/52n-release.yaml +++ b/.github/workflows/52n-release.yaml @@ -59,7 +59,7 @@ jobs: uses: docker/login-action@v2 with: username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} + password: ${{ secrets.DOCKERHUB_TOKEN_52N_MASTER }} - name: Fail in case fully tagged version already exists run: docker manifest inspect ${{ env.IMAGE }}:${{ steps.meta.env.MAJOR_MINOR_PATCH_VERSION }} > /dev/null ; test $? != 0 From 4a50a9c065d2b8406decef7cfb8bdc071530fa5d Mon Sep 17 00:00:00 2001 From: Henning Bredel Date: Wed, 13 Sep 2023 11:00:04 +0200 Subject: [PATCH 62/70] Failing action tested successfully --- .github/workflows/52n-release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/52n-release.yaml b/.github/workflows/52n-release.yaml index f3fec8adebc..d3329ba23e0 100644 --- a/.github/workflows/52n-release.yaml +++ b/.github/workflows/52n-release.yaml @@ -69,7 +69,7 @@ jobs: with: context: . file: ./Dockerfile - push: false + push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=registry,ref=${{ env.IMAGE }}:buildcache From 952f0bb1e67097c47c7e1ceeafb25deb1ba27330 Mon Sep 17 00:00:00 2001 From: Henning Bredel Date: Wed, 13 Sep 2023 11:06:53 +0200 Subject: [PATCH 63/70] Adds release build jobs for nginx and geoserver --- .github/workflows/52n-build-4.1.x.yml | 4 +- .github/workflows/52n-release.yaml | 114 ++++++++++++++++++++++++++ 2 files changed, 117 insertions(+), 1 deletion(-) diff --git a/.github/workflows/52n-build-4.1.x.yml b/.github/workflows/52n-build-4.1.x.yml index c6bcccc0906..193eacfa7c8 100644 --- a/.github/workflows/52n-build-4.1.x.yml +++ b/.github/workflows/52n-build-4.1.x.yml @@ -3,7 +3,7 @@ name: Builds GeoNode Docker Images 4.1.x concurrency: group: "geonode_build_4.1.x" cancel-in-progress: true - + env: TITLE: "52°North GeoNode Docker Image" VENDOR: "52°North GmbH" @@ -16,6 +16,8 @@ on: push: branches: - "52n-master" + paths: + - "!.github/workflow/*-release.yaml" jobs: build_and_push_geonode: diff --git a/.github/workflows/52n-release.yaml b/.github/workflows/52n-release.yaml index d3329ba23e0..ecb8267b7aa 100644 --- a/.github/workflows/52n-release.yaml +++ b/.github/workflows/52n-release.yaml @@ -75,3 +75,117 @@ jobs: cache-from: type=registry,ref=${{ env.IMAGE }}:buildcache cache-to: type=registry,ref=${{ env.IMAGE }}:buildcache,mode=max + + build_and_push_nginx: + runs-on: ubuntu-22.04 + env: + IMAGE: 52north/geonode-nginx + steps: + - + name: Checkout + uses: actions/checkout@v3 + - + name: Parse semver string + id: semver_parser + uses: booxmedialtd/ws-action-parse-semver@v1 + with: + input_string: "${{github.ref_name}}" + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + - + name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v4 + env: + MAJOR_VERSION: ${{ steps.semver_parser.outputs.major }} + MAJOR_MINOR_VERSION: ${{ steps.semver_parser.outputs.major }}-${{ steps.semver_parser.outputs.minor }} + MAJOR_MINOR_PATCH_VERSION: ${{ steps.semver_parser.outputs.major }}-${{ steps.semver_parser.outputs.minor }}-${{ steps.semver_parser.outputs.patch }} + with: + images: ${{ env.IMAGE }} + labels: | + "org.opencontainers.image.authors=${{ env.AUTHORS }}" + "org.opencontainers.image.vendor=${{ env.VENDOR }}" + "org.opencontainers.image.description=${{ env.DESCRIPTION }}" + "org.opencontainers.image.title=${{ env.TITLE }}" + "org.opencontainers.image.licenses=${{ env.LICENSE }}" + tags: | + latest + ${{ env.TAG }} + - + name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN_52N_MASTER }} + - + name: Fail in case fully tagged version already exists + run: docker manifest inspect ${{ env.IMAGE }}:${{ steps.meta.env.MAJOR_MINOR_PATCH_VERSION }} > /dev/null ; test $? != 0 + - + name: Build and push + uses: docker/build-push-action@v4 + with: + context: ./scripts/docker/nginx/ + file: ./scripts/docker/nginx/Dockerfile + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=registry,ref=${{ env.IMAGE }}:buildcache + cache-to: type=registry,ref=${{ env.IMAGE }}:buildcache,mode=max + + build_and_push_geoserver: + runs-on: ubuntu-22.04 + env: + IMAGE: 52north/geonode-geoserver + steps: + - + name: Checkout + uses: actions/checkout@v3 + - + name: Parse semver string + id: semver_parser + uses: booxmedialtd/ws-action-parse-semver@v1 + with: + input_string: "${{github.ref_name}}" + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + - + name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v4 + env: + MAJOR_VERSION: ${{ steps.semver_parser.outputs.major }} + MAJOR_MINOR_VERSION: ${{ steps.semver_parser.outputs.major }}-${{ steps.semver_parser.outputs.minor }} + MAJOR_MINOR_PATCH_VERSION: ${{ steps.semver_parser.outputs.major }}-${{ steps.semver_parser.outputs.minor }}-${{ steps.semver_parser.outputs.patch }} + with: + images: "${{ env.IMAGE }}" + labels: | + "org.opencontainers.image.authors=${{ env.AUTHORS }}" + "org.opencontainers.image.vendor=${{ env.VENDOR }}" + "org.opencontainers.image.description=${{ env.DESCRIPTION }}" + "org.opencontainers.image.title=${{ env.TITLE }}" + "org.opencontainers.image.licenses=${{ env.LICENSE }}" + tags: | + latest + ${{ env.TAG }} + - + name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN_52N_MASTER }} + - + name: Fail in case fully tagged version already exists + run: docker manifest inspect ${{ env.IMAGE }}:${{ steps.meta.env.MAJOR_MINOR_PATCH_VERSION }} > /dev/null ; test $? != 0 + - + name: Build and push + uses: docker/build-push-action@v4 + with: + context: ./scripts/docker/geoserver/ + file: ./scripts/docker/geoserver/Dockerfile + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=registry,ref=${{ env.IMAGE }}:buildcache + cache-to: type=registry,ref=${{ env.IMAGE }}:buildcache,mode=max \ No newline at end of file From ebddab741ed94bad63e1292c59d9af032be381b3 Mon Sep 17 00:00:00 2001 From: Henning Bredel Date: Wed, 13 Sep 2023 11:12:34 +0200 Subject: [PATCH 64/70] Add missing image tags in meta step --- .github/workflows/52n-release.yaml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/52n-release.yaml b/.github/workflows/52n-release.yaml index ecb8267b7aa..4def073f7e6 100644 --- a/.github/workflows/52n-release.yaml +++ b/.github/workflows/52n-release.yaml @@ -51,6 +51,7 @@ jobs: "org.opencontainers.image.title=${{ env.TITLE }}" "org.opencontainers.image.licenses=${{ env.LICENSE }}" tags: | + latest ${{ env.MAJOR_VERSION }} ${{ env.MAJOR_MINOR_VERSION }} ${{ env.MAJOR_MINOR_PATCH_VERSION }} @@ -111,7 +112,9 @@ jobs: "org.opencontainers.image.licenses=${{ env.LICENSE }}" tags: | latest - ${{ env.TAG }} + ${{ env.MAJOR_VERSION }} + ${{ env.MAJOR_MINOR_VERSION }} + ${{ env.MAJOR_MINOR_PATCH_VERSION }} - name: Login to Docker Hub uses: docker/login-action@v2 @@ -168,7 +171,9 @@ jobs: "org.opencontainers.image.licenses=${{ env.LICENSE }}" tags: | latest - ${{ env.TAG }} + ${{ env.MAJOR_VERSION }} + ${{ env.MAJOR_MINOR_VERSION }} + ${{ env.MAJOR_MINOR_PATCH_VERSION }} - name: Login to Docker Hub uses: docker/login-action@v2 From ba23dcd60f6ee61322e6be75f67438641fef9485 Mon Sep 17 00:00:00 2001 From: Henning Bredel Date: Thu, 12 Oct 2023 16:47:55 +0200 Subject: [PATCH 65/70] Build latest from master --- .github/workflows/52n-build-4.1.x.yml | 60 ++++++++++----------------- 1 file changed, 21 insertions(+), 39 deletions(-) diff --git a/.github/workflows/52n-build-4.1.x.yml b/.github/workflows/52n-build-4.1.x.yml index 193eacfa7c8..75ad35baa8b 100644 --- a/.github/workflows/52n-build-4.1.x.yml +++ b/.github/workflows/52n-build-4.1.x.yml @@ -1,7 +1,7 @@ -name: Builds GeoNode Docker Images 4.1.x +name: Builds GeoNode Docker Images master/latest -concurrency: - group: "geonode_build_4.1.x" +concurrency: + group: "geonode_build_master" cancel-in-progress: true env: @@ -10,13 +10,13 @@ env: AUTHORS: "https://52North.org/" DESCRIPTION: "Builds and publishes the Docker images GeoNode, GeoServer, Nginx" LICENSE: "GPL-3.0" - TAG: 4.1.x + TAG: latest on: push: branches: - "52n-master" - paths: + paths: - "!.github/workflow/*-release.yaml" jobs: @@ -25,14 +25,11 @@ jobs: env: IMAGE: 52north/geonode steps: - - - name: Checkout + - name: Checkout uses: actions/checkout@v3 - - - name: Set up Docker Buildx + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 - - - name: Extract metadata (tags, labels) for Docker + - name: Extract metadata (tags, labels) for Docker id: meta uses: docker/metadata-action@v4 with: @@ -44,16 +41,13 @@ jobs: "org.opencontainers.image.title=${{ env.TITLE }}" "org.opencontainers.image.licenses=${{ env.LICENSE }}" tags: | - latest ${{ env.TAG }} - - - name: Login to Docker Hub + - name: Login to Docker Hub uses: docker/login-action@v2 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN_52N_MASTER }} - - - name: Build and push + - name: Build and push uses: docker/build-push-action@v4 with: context: . @@ -69,14 +63,11 @@ jobs: env: IMAGE: 52north/geonode-nginx steps: - - - name: Checkout + - name: Checkout uses: actions/checkout@v3 - - - name: Set up Docker Buildx + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 - - - name: Extract metadata (tags, labels) for Docker + - name: Extract metadata (tags, labels) for Docker id: meta uses: docker/metadata-action@v4 with: @@ -88,16 +79,13 @@ jobs: "org.opencontainers.image.title=${{ env.TITLE }}" "org.opencontainers.image.licenses=${{ env.LICENSE }}" tags: | - latest ${{ env.TAG }} - - - name: Login to Docker Hub + - name: Login to Docker Hub uses: docker/login-action@v2 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN_52N_MASTER }} - - - name: Build and push + - name: Build and push uses: docker/build-push-action@v4 with: context: ./scripts/docker/nginx/ @@ -113,14 +101,11 @@ jobs: env: IMAGE: 52north/geonode-geoserver steps: - - - name: Checkout + - name: Checkout uses: actions/checkout@v3 - - - name: Set up Docker Buildx + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 - - - name: Extract metadata (tags, labels) for Docker + - name: Extract metadata (tags, labels) for Docker id: meta uses: docker/metadata-action@v4 with: @@ -132,16 +117,13 @@ jobs: "org.opencontainers.image.title=${{ env.TITLE }}" "org.opencontainers.image.licenses=${{ env.LICENSE }}" tags: | - latest ${{ env.TAG }} - - - name: Login to Docker Hub + - name: Login to Docker Hub uses: docker/login-action@v2 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN_52N_MASTER }} - - - name: Build and push + - name: Build and push uses: docker/build-push-action@v4 with: context: ./scripts/docker/geoserver/ @@ -150,4 +132,4 @@ jobs: tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=registry,ref=${{ env.IMAGE }}:buildcache - cache-to: type=registry,ref=${{ env.IMAGE }}:buildcache,mode=max \ No newline at end of file + cache-to: type=registry,ref=${{ env.IMAGE }}:buildcache,mode=max From 8d471c8b994996dba4d2c09b195cee724c7fea5f Mon Sep 17 00:00:00 2001 From: Henning Bredel Date: Thu, 12 Oct 2023 16:59:05 +0200 Subject: [PATCH 66/70] Remove path exclusions --- .github/workflows/52n-build-4.1.x.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/52n-build-4.1.x.yml b/.github/workflows/52n-build-4.1.x.yml index 75ad35baa8b..ade8a296b79 100644 --- a/.github/workflows/52n-build-4.1.x.yml +++ b/.github/workflows/52n-build-4.1.x.yml @@ -16,8 +16,6 @@ on: push: branches: - "52n-master" - paths: - - "!.github/workflow/*-release.yaml" jobs: build_and_push_geonode: From e8f27b599cc513f44f6f588c0b59d31ac28fadd5 Mon Sep 17 00:00:00 2001 From: Henning Bredel Date: Fri, 13 Oct 2023 12:13:51 +0200 Subject: [PATCH 67/70] Rename workflow build --- .github/workflows/52n-build-4.1.x.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/52n-build-4.1.x.yml b/.github/workflows/52n-build-4.1.x.yml index ade8a296b79..59a3ce8954b 100644 --- a/.github/workflows/52n-build-4.1.x.yml +++ b/.github/workflows/52n-build-4.1.x.yml @@ -1,4 +1,4 @@ -name: Builds GeoNode Docker Images master/latest +name: "[52n_master -> lastest] Builds GeoNode Docker Images" concurrency: group: "geonode_build_master" From c315d4504a7621e603c52f7639df391ccc244d32 Mon Sep 17 00:00:00 2001 From: Henning Bredel Date: Fri, 13 Oct 2023 12:22:07 +0200 Subject: [PATCH 68/70] Rename workflow file --- .github/workflows/{52n-build-4.1.x.yml => 52n-build-master.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{52n-build-4.1.x.yml => 52n-build-master.yml} (100%) diff --git a/.github/workflows/52n-build-4.1.x.yml b/.github/workflows/52n-build-master.yml similarity index 100% rename from .github/workflows/52n-build-4.1.x.yml rename to .github/workflows/52n-build-master.yml From cf80dce37950e30158fb3cea3be51e4dd4ca70b6 Mon Sep 17 00:00:00 2001 From: Henning Bredel Date: Fri, 13 Oct 2023 12:22:23 +0200 Subject: [PATCH 69/70] Release are built from dedicated branches --- .github/workflows/52n-release.yaml | 196 ----------------------------- 1 file changed, 196 deletions(-) delete mode 100644 .github/workflows/52n-release.yaml diff --git a/.github/workflows/52n-release.yaml b/.github/workflows/52n-release.yaml deleted file mode 100644 index 4def073f7e6..00000000000 --- a/.github/workflows/52n-release.yaml +++ /dev/null @@ -1,196 +0,0 @@ -name: Release GeoNode Docker Images - -concurrency: - group: "geonode_build_release" - cancel-in-progress: true - -env: - TITLE: "52°North GeoNode Docker Image" - VENDOR: "52°North GmbH" - AUTHORS: "https://52North.org/" - DESCRIPTION: "Builds and publishes the Docker images GeoNode, GeoServer, Nginx" - LICENSE: "GPL-3.0" - -on: - push: - tags: - - "*-52n" - -jobs: - build_and_push_geonode: - runs-on: ubuntu-22.04 - env: - IMAGE: 52north/geonode - steps: - - - name: Checkout - uses: actions/checkout@v3 - - - name: Parse semver string - id: semver_parser - uses: booxmedialtd/ws-action-parse-semver@v1 - with: - input_string: "${{github.ref_name}}" - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 - - - name: Extract metadata (tags, labels) for Docker - id: meta - uses: docker/metadata-action@v4 - env: - MAJOR_VERSION: ${{ steps.semver_parser.outputs.major }} - MAJOR_MINOR_VERSION: ${{ steps.semver_parser.outputs.major }}-${{ steps.semver_parser.outputs.minor }} - MAJOR_MINOR_PATCH_VERSION: ${{ steps.semver_parser.outputs.major }}-${{ steps.semver_parser.outputs.minor }}-${{ steps.semver_parser.outputs.patch }} - with: - images: ${{ env.IMAGE }} - labels: | - "org.opencontainers.image.authors=${{ env.AUTHORS }}" - "org.opencontainers.image.vendor=${{ env.VENDOR }}" - "org.opencontainers.image.description=${{ env.DESCRIPTION }}" - "org.opencontainers.image.title=${{ env.TITLE }}" - "org.opencontainers.image.licenses=${{ env.LICENSE }}" - tags: | - latest - ${{ env.MAJOR_VERSION }} - ${{ env.MAJOR_MINOR_VERSION }} - ${{ env.MAJOR_MINOR_PATCH_VERSION }} - - - name: Login to Docker Hub - uses: docker/login-action@v2 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN_52N_MASTER }} - - - name: Fail in case fully tagged version already exists - run: docker manifest inspect ${{ env.IMAGE }}:${{ steps.meta.env.MAJOR_MINOR_PATCH_VERSION }} > /dev/null ; test $? != 0 - - - name: Build and push - uses: docker/build-push-action@v4 - with: - context: . - file: ./Dockerfile - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - cache-from: type=registry,ref=${{ env.IMAGE }}:buildcache - cache-to: type=registry,ref=${{ env.IMAGE }}:buildcache,mode=max - - - build_and_push_nginx: - runs-on: ubuntu-22.04 - env: - IMAGE: 52north/geonode-nginx - steps: - - - name: Checkout - uses: actions/checkout@v3 - - - name: Parse semver string - id: semver_parser - uses: booxmedialtd/ws-action-parse-semver@v1 - with: - input_string: "${{github.ref_name}}" - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 - - - name: Extract metadata (tags, labels) for Docker - id: meta - uses: docker/metadata-action@v4 - env: - MAJOR_VERSION: ${{ steps.semver_parser.outputs.major }} - MAJOR_MINOR_VERSION: ${{ steps.semver_parser.outputs.major }}-${{ steps.semver_parser.outputs.minor }} - MAJOR_MINOR_PATCH_VERSION: ${{ steps.semver_parser.outputs.major }}-${{ steps.semver_parser.outputs.minor }}-${{ steps.semver_parser.outputs.patch }} - with: - images: ${{ env.IMAGE }} - labels: | - "org.opencontainers.image.authors=${{ env.AUTHORS }}" - "org.opencontainers.image.vendor=${{ env.VENDOR }}" - "org.opencontainers.image.description=${{ env.DESCRIPTION }}" - "org.opencontainers.image.title=${{ env.TITLE }}" - "org.opencontainers.image.licenses=${{ env.LICENSE }}" - tags: | - latest - ${{ env.MAJOR_VERSION }} - ${{ env.MAJOR_MINOR_VERSION }} - ${{ env.MAJOR_MINOR_PATCH_VERSION }} - - - name: Login to Docker Hub - uses: docker/login-action@v2 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN_52N_MASTER }} - - - name: Fail in case fully tagged version already exists - run: docker manifest inspect ${{ env.IMAGE }}:${{ steps.meta.env.MAJOR_MINOR_PATCH_VERSION }} > /dev/null ; test $? != 0 - - - name: Build and push - uses: docker/build-push-action@v4 - with: - context: ./scripts/docker/nginx/ - file: ./scripts/docker/nginx/Dockerfile - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - cache-from: type=registry,ref=${{ env.IMAGE }}:buildcache - cache-to: type=registry,ref=${{ env.IMAGE }}:buildcache,mode=max - - build_and_push_geoserver: - runs-on: ubuntu-22.04 - env: - IMAGE: 52north/geonode-geoserver - steps: - - - name: Checkout - uses: actions/checkout@v3 - - - name: Parse semver string - id: semver_parser - uses: booxmedialtd/ws-action-parse-semver@v1 - with: - input_string: "${{github.ref_name}}" - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 - - - name: Extract metadata (tags, labels) for Docker - id: meta - uses: docker/metadata-action@v4 - env: - MAJOR_VERSION: ${{ steps.semver_parser.outputs.major }} - MAJOR_MINOR_VERSION: ${{ steps.semver_parser.outputs.major }}-${{ steps.semver_parser.outputs.minor }} - MAJOR_MINOR_PATCH_VERSION: ${{ steps.semver_parser.outputs.major }}-${{ steps.semver_parser.outputs.minor }}-${{ steps.semver_parser.outputs.patch }} - with: - images: "${{ env.IMAGE }}" - labels: | - "org.opencontainers.image.authors=${{ env.AUTHORS }}" - "org.opencontainers.image.vendor=${{ env.VENDOR }}" - "org.opencontainers.image.description=${{ env.DESCRIPTION }}" - "org.opencontainers.image.title=${{ env.TITLE }}" - "org.opencontainers.image.licenses=${{ env.LICENSE }}" - tags: | - latest - ${{ env.MAJOR_VERSION }} - ${{ env.MAJOR_MINOR_VERSION }} - ${{ env.MAJOR_MINOR_PATCH_VERSION }} - - - name: Login to Docker Hub - uses: docker/login-action@v2 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN_52N_MASTER }} - - - name: Fail in case fully tagged version already exists - run: docker manifest inspect ${{ env.IMAGE }}:${{ steps.meta.env.MAJOR_MINOR_PATCH_VERSION }} > /dev/null ; test $? != 0 - - - name: Build and push - uses: docker/build-push-action@v4 - with: - context: ./scripts/docker/geoserver/ - file: ./scripts/docker/geoserver/Dockerfile - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - cache-from: type=registry,ref=${{ env.IMAGE }}:buildcache - cache-to: type=registry,ref=${{ env.IMAGE }}:buildcache,mode=max \ No newline at end of file From 3e7fdd4035b4adf4759aaa9b54b9f0a51411d76a Mon Sep 17 00:00:00 2001 From: Henning Bredel Date: Mon, 30 Oct 2023 14:28:10 +0100 Subject: [PATCH 70/70] Deduplicates code by using composite action --- .github/actions/build_and_push/action.yml | 85 +++++++++++++ .github/workflows/52n-build-master.yml | 140 ++++++---------------- 2 files changed, 124 insertions(+), 101 deletions(-) create mode 100644 .github/actions/build_and_push/action.yml diff --git a/.github/actions/build_and_push/action.yml b/.github/actions/build_and_push/action.yml new file mode 100644 index 00000000000..355ba5741a6 --- /dev/null +++ b/.github/actions/build_and_push/action.yml @@ -0,0 +1,85 @@ +name: Builds and pushes Docker image +description: Action to build and push images to docker + + +inputs: + dockerfile: + description: Path to the Dockerfile + default: ./Dockerfile + required: false + dockercontext: + description: Path to the Docker context + default: ./ + required: false + # image coordinates + image: + description: Name of the image to build + required: true + tags: + description: Image Tag(s) + required: false + default: latest + # OCI metadata annotations + oci_title: + description: Image Title (OCI annotation) + required: true + oci_description: + description: Image Description (OCI annotation) + required: true + # registry credentials + registry_username: + description: The username for Docker hub sign-in + required: true + registry_password: + description: The password for Docker hub sign-in + required: true + + +runs: + using: "composite" + steps: + - + name: Checkout + uses: actions/checkout@v3 + - + uses: dorny/paths-filter@v2 + id: changes + with: + filters: | + src: + - '${{ inputs.dockercontext }}/**' + # - + # name: Set up Docker Buildx + # uses: docker/setup-buildx-action@v2 + # - + # name: Extract metadata (tags, labels) for Docker + # id: meta + # uses: docker/metadata-action@v4 + # with: + # images: ${{ inputs.image }} + # labels: | + # "org.opencontainers.image.vendor=52°North GmbH" + # "org.opencontainers.image.authors=https://52North.org/" + # "org.opencontainers.image.source=https://github.com/52North/geonode" + # "org.opencontainers.image.description=${{ inputs.oci_description }}" + # "org.opencontainers.image.title=${{ inputs.oci_title }}" + # "org.opencontainers.image.licenses=GPL-3.0" + # tags: | + # ${{ inputs.tags }} + # - + # name: Login to Docker registry + # uses: docker/login-action@v2 + # with: + # username: ${{ inputs.registry_username }} + # password: ${{ inputs.registry_password }} + # - + # name: Build and push + # uses: docker/build-push-action@v4 + # with: + # context: . + # file: ${{ inputs.dockerfile }} + # push: true + # tags: ${{ steps.meta.outputs.tags }} + # labels: ${{ steps.meta.outputs.labels }} + # cache-from: type=registry,ref=${{ inputs.image }}:buildcache + # cache-to: type=registry,ref=${{ inputs.image }}:buildcache,mode=max diff --git a/.github/workflows/52n-build-master.yml b/.github/workflows/52n-build-master.yml index 59a3ce8954b..9c19abc1d4c 100644 --- a/.github/workflows/52n-build-master.yml +++ b/.github/workflows/52n-build-master.yml @@ -1,15 +1,10 @@ -name: "[52n_master -> lastest] Builds GeoNode Docker Images" +name: "[52n-master -> latest] Builds GeoNode Docker Images" concurrency: group: "geonode_build_master" cancel-in-progress: true env: - TITLE: "52°North GeoNode Docker Image" - VENDOR: "52°North GmbH" - AUTHORS: "https://52North.org/" - DESCRIPTION: "Builds and publishes the Docker images GeoNode, GeoServer, Nginx" - LICENSE: "GPL-3.0" TAG: latest on: @@ -20,114 +15,57 @@ on: jobs: build_and_push_geonode: runs-on: ubuntu-22.04 - env: - IMAGE: 52north/geonode steps: - - name: Checkout + - + name: Checkout uses: actions/checkout@v3 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 - - name: Extract metadata (tags, labels) for Docker - id: meta - uses: docker/metadata-action@v4 - with: - images: ${{ env.IMAGE }} - labels: | - "org.opencontainers.image.authors=${{ env.AUTHORS }}" - "org.opencontainers.image.vendor=${{ env.VENDOR }}" - "org.opencontainers.image.description=${{ env.DESCRIPTION }}" - "org.opencontainers.image.title=${{ env.TITLE }}" - "org.opencontainers.image.licenses=${{ env.LICENSE }}" - tags: | - ${{ env.TAG }} - - name: Login to Docker Hub - uses: docker/login-action@v2 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN_52N_MASTER }} - - name: Build and push - uses: docker/build-push-action@v4 + - + name: build and push geonode + uses: ./.github/actions/build_and_push with: - context: . - file: ./Dockerfile - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - cache-from: type=registry,ref=${{ env.IMAGE }}:buildcache - cache-to: type=registry,ref=${{ env.IMAGE }}:buildcache,mode=max - + image: 52north/geonode + tags: ${{ env.TAG }} + oci_title: "52°North GeoNode image" + oci_description: "GeoNode built from 52n fork" + registry_username: ${{ secrets.DOCKERHUB_USERNAME }} + registry_password: ${{ secrets.DOCKERHUB_TOKEN_52N_MASTER }} + build_and_push_nginx: runs-on: ubuntu-22.04 - env: - IMAGE: 52north/geonode-nginx steps: - - name: Checkout + - + name: Checkout uses: actions/checkout@v3 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 - - name: Extract metadata (tags, labels) for Docker - id: meta - uses: docker/metadata-action@v4 + - + name: build and push nginx + uses: ./.github/actions/build_and_push with: - images: ${{ env.IMAGE }} - labels: | - "org.opencontainers.image.authors=${{ env.AUTHORS }}" - "org.opencontainers.image.vendor=${{ env.VENDOR }}" - "org.opencontainers.image.description=${{ env.DESCRIPTION }}" - "org.opencontainers.image.title=${{ env.TITLE }}" - "org.opencontainers.image.licenses=${{ env.LICENSE }}" - tags: | - ${{ env.TAG }} - - name: Login to Docker Hub - uses: docker/login-action@v2 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN_52N_MASTER }} - - name: Build and push - uses: docker/build-push-action@v4 - with: - context: ./scripts/docker/nginx/ - file: ./scripts/docker/nginx/Dockerfile - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - cache-from: type=registry,ref=${{ env.IMAGE }}:buildcache - cache-to: type=registry,ref=${{ env.IMAGE }}:buildcache,mode=max + dockerfile: ./scripts/docker/nginx/Dockerfile + dockercontext: ./scripts/docker/nginx/ + image: 52north/geonode-nginx + tags: ${{ env.TAG }} + oci_title: "52°North Nginx image for GeoNode" + oci_description: "Nginx built for GeoNode from a 52n fork" + registry_username: ${{ secrets.DOCKERHUB_USERNAME }} + registry_password: ${{ secrets.DOCKERHUB_TOKEN_52N_MASTER }} build_and_push_geoserver: runs-on: ubuntu-22.04 env: IMAGE: 52north/geonode-geoserver steps: - - name: Checkout + - + name: Checkout uses: actions/checkout@v3 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 - - name: Extract metadata (tags, labels) for Docker - id: meta - uses: docker/metadata-action@v4 - with: - images: "${{ env.IMAGE }}" - labels: | - "org.opencontainers.image.authors=${{ env.AUTHORS }}" - "org.opencontainers.image.vendor=${{ env.VENDOR }}" - "org.opencontainers.image.description=${{ env.DESCRIPTION }}" - "org.opencontainers.image.title=${{ env.TITLE }}" - "org.opencontainers.image.licenses=${{ env.LICENSE }}" - tags: | - ${{ env.TAG }} - - name: Login to Docker Hub - uses: docker/login-action@v2 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN_52N_MASTER }} - - name: Build and push - uses: docker/build-push-action@v4 + - + name: build and push geoserver + uses: ./.github/actions/build_and_push with: - context: ./scripts/docker/geoserver/ - file: ./scripts/docker/geoserver/Dockerfile - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - cache-from: type=registry,ref=${{ env.IMAGE }}:buildcache - cache-to: type=registry,ref=${{ env.IMAGE }}:buildcache,mode=max + dockerfile: ./scripts/docker/geoserver/Dockerfile + dockercontext: ./scripts/docker/geoserver/ + image: 52north/geonode-geoserver + tags: ${{ env.TAG }} + oci_title: "52°North GeoServer image for GeoNode" + oci_description: "GeoServer built for GeoNode from a 52n fork" + registry_username: ${{ secrets.DOCKERHUB_USERNAME }} + registry_password: ${{ secrets.DOCKERHUB_TOKEN_52N_MASTER }}