From 630ca48f27d930265287c3acf65c1c2659ccc50f Mon Sep 17 00:00:00 2001 From: Mikko Nieminen Date: Fri, 1 Mar 2024 10:11:39 +0100 Subject: [PATCH] upgrade to django 4.2, postgres 16 and python 3.11 (#880, #1074, #1157) --- .github/workflows/build.yml | 11 +++--- CHANGELOG.rst | 18 +++++++++ config/settings/base.py | 26 +++++++------ config/settings/local_target.py | 2 +- config/settings/local_target2.py | 2 +- config/urls.py | 14 ++++--- docs/source/app_projectroles_settings.rst | 7 ++++ docs/source/conf.py | 4 +- docs/source/dev_core_install.rst | 3 +- docs/source/dev_project_app.rst | 4 +- docs/source/getting_started.rst | 6 +-- docs/source/index.rst | 4 +- docs/source/major_changes.rst | 47 +++++++++++++++++++++++ example_project_app/urls.py | 15 ++++---- projectroles/forms.py | 4 +- projectroles/models.py | 9 +++-- projectroles/views.py | 5 --- requirements/base.txt | 10 ++--- 18 files changed, 133 insertions(+), 58 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 98f5b549..25b0065f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,9 +10,10 @@ jobs: - '3.8' - '3.9' - '3.10' + - '3.11' services: postgres: - image: postgres:11 + image: postgres:16 env: POSTGRES_DB: sodar_core POSTGRES_USER: sodar_core @@ -44,7 +45,7 @@ jobs: run: git fetch --prune --unshallow - name: Install project Python dependencies run: | - pip install "wheel>=0.38.4, <0.39" + pip install "wheel>=0.40.0, <0.41" pip install -r requirements/local.txt pip install -r requirements/test.txt - name: Download icons @@ -58,13 +59,13 @@ jobs: coverage report - name: Check linting run: flake8 . - if: ${{ matrix.python-version == '3.8' }} + if: ${{ matrix.python-version == '3.11' }} - name: Check formatting run: make black arg=--check - if: ${{ matrix.python-version == '3.8' }} + if: ${{ matrix.python-version == '3.11' }} - name: Report coverage with Coveralls uses: coverallsapp/github-action@master with: github-token: ${{ secrets.GITHUB_TOKEN }} path-to-lcov: './coverage.lcov' - if: ${{ matrix.python-version == '3.8' }} + if: ${{ matrix.python-version == '3.11' }} diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 6e2562aa..5b20cdb5 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,6 +5,24 @@ Changelog for the **SODAR Core** Django app package. Loosely follows the `Keep a Changelog `_ guidelines. +Unreleased +========== + +Added +----- + +- **General** + - Python v3.11 support (#1157) + +Changed +------- + +- **General** + - Upgrade to Django v4.2 (#880) + - Upgrade minimum PostgreSQL version to v12 (#1074) + - Upgrade to PostgreSQL v16 in CI (#1074) + + v0.13.4 (2024-02-16) ==================== diff --git a/config/settings/base.py b/config/settings/base.py index bef23cfd..b5dd591c 100644 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -2,10 +2,10 @@ Django settings for the SODAR Core Example Site project. For more information on this file, see -https://docs.djangoproject.com/en/dev/topics/settings/ +https://docs.djangoproject.com/en/4.2/topics/settings/ For the full list of settings and their values, see -https://docs.djangoproject.com/en/3.2/ref/settings/ +https://docs.djangoproject.com/en/4.2/ref/settings/ """ import environ import os @@ -65,7 +65,7 @@ 'dal', # For user search combo box 'dal_select2', 'dj_iconify.apps.DjIconifyConfig', # Iconify for SVG icons - 'django_saml2_auth', # SAML2 support + # 'django_saml2_auth', # SAML2 support, temp disabled (see #597, #880) ] # Project apps @@ -143,12 +143,12 @@ for x in env.list('ADMINS', default=['Admin User:admin@example.com']) ] -# See: https://docs.djangoproject.com/en/3.2/ref/settings/#managers +# See: https://docs.djangoproject.com/en/4.2/ref/settings/#managers MANAGERS = ADMINS # DATABASE CONFIGURATION # ------------------------------------------------------------------------------ -# See: https://docs.djangoproject.com/en/3.2/ref/settings/#databases +# See: https://docs.djangoproject.com/en/4.2/ref/settings/#databases # Uses django-environ to accept uri format # See: https://django-environ.readthedocs.io/en/latest/#supported-types DATABASES = { @@ -171,24 +171,24 @@ # In a Windows environment this must be set to your system time zone. TIME_ZONE = 'Europe/Berlin' -# See: https://docs.djangoproject.com/en/3.2/ref/settings/#language-code +# See: https://docs.djangoproject.com/en/4.2/ref/settings/#language-code LANGUAGE_CODE = 'en-us' -# See: https://docs.djangoproject.com/en/3.2/ref/settings/#site-id +# See: https://docs.djangoproject.com/en/4.2/ref/settings/#site-id SITE_ID = 1 -# See: https://docs.djangoproject.com/en/3.2/ref/settings/#use-i18n +# See: https://docs.djangoproject.com/en/4.2/ref/settings/#use-i18n USE_I18N = False -# See: https://docs.djangoproject.com/en/3.2/ref/settings/#use-l10n +# See: https://docs.djangoproject.com/en/4.2/ref/settings/#use-l10n USE_L10N = True -# See: https://docs.djangoproject.com/en/3.2/ref/settings/#use-tz +# See: https://docs.djangoproject.com/en/4.2/ref/settings/#use-tz USE_TZ = True # TEMPLATE CONFIGURATION # ------------------------------------------------------------------------------ -# See: https://docs.djangoproject.com/en/3.2/ref/settings/#templates +# See: https://docs.djangoproject.com/en/4.2/ref/settings/#templates TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', @@ -428,7 +428,9 @@ # ------------------------------------------------------------------------------ -ENABLE_SAML = env.bool('ENABLE_SAML', False) +# SAML support temporarily disabled (see #597, #880) +ENABLE_SAML = False # env.bool('ENABLE_SAML', False) + SAML2_AUTH = { # Required setting # Pysaml2 Saml client settings diff --git a/config/settings/local_target.py b/config/settings/local_target.py index dfec48f1..78baa1f2 100644 --- a/config/settings/local_target.py +++ b/config/settings/local_target.py @@ -5,7 +5,7 @@ # DATABASE CONFIGURATION # ------------------------------------------------------------------------------ -# See: https://docs.djangoproject.com/en/3.2/ref/settings/#databases +# See: https://docs.djangoproject.com/en/4.2/ref/settings/#databases # Uses django-environ to accept uri format # See: https://django-environ.readthedocs.io/en/latest/#supported-types DATABASES['default']['NAME'] = 'sodar_core_target' diff --git a/config/settings/local_target2.py b/config/settings/local_target2.py index 95a86cac..09272985 100644 --- a/config/settings/local_target2.py +++ b/config/settings/local_target2.py @@ -5,7 +5,7 @@ # DATABASE CONFIGURATION # ------------------------------------------------------------------------------ -# See: https://docs.djangoproject.com/en/3.2/ref/settings/#databases +# See: https://docs.djangoproject.com/en/4.2/ref/settings/#databases # Uses django-environ to accept uri format # See: https://django-environ.readthedocs.io/en/latest/#supported-types DATABASES['default']['NAME'] = 'sodar_core_target2' diff --git a/config/urls.py b/config/urls.py index 6a66b18a..6de17e35 100644 --- a/config/urls.py +++ b/config/urls.py @@ -7,7 +7,8 @@ from django.urls import path from django.views import defaults as default_views -import django_saml2_auth.views +# SAML support temporarily disabled (see #597, #880) +# import django_saml2_auth.views # Projectroles dependency from projectroles.views import HomeView @@ -54,21 +55,22 @@ path('examples/project/', include('example_project_app.urls')), # Example site app URLs path('examples/site/', include('example_site_app.urls')), + # SAML support temporarily disabled (see #597, #880) # These are the SAML2 related URLs. You can change "^saml2_auth/" regex to # any path you want, like "^sso_auth/", "^sso_login/", etc. (required) - path('saml2_auth/', include('django_saml2_auth.urls')), + # path('saml2_auth/', include('django_saml2_auth.urls')), # The following line will replace the default user login with SAML2 (optional) # If you want to specific the after-login-redirect-URL, use parameter "?next=/the/path/you/want" # with this view. - path('sso/login/', django_saml2_auth.views.signin), + # path('sso/login/', django_saml2_auth.views.signin), # The following line will replace the admin login with SAML2 (optional) # If you want to specific the after-login-redirect-URL, use parameter "?next=/the/path/you/want" # with this view. - path('sso/admin/login/', django_saml2_auth.views.signin), + # path('sso/admin/login/', django_saml2_auth.views.signin), # The following line will replace the default user logout with the signout page (optional) - path('sso/logout/', django_saml2_auth.views.signout), + # path('sso/logout/', django_saml2_auth.views.signout), # The following line will replace the default admin user logout with the signout page (optional) - path('sso/admin/logout/', django_saml2_auth.views.signout), + # path('sso/admin/logout/', django_saml2_auth.views.signout), ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) diff --git a/docs/source/app_projectroles_settings.rst b/docs/source/app_projectroles_settings.rst index 27341534..3231a458 100644 --- a/docs/source/app_projectroles_settings.rst +++ b/docs/source/app_projectroles_settings.rst @@ -478,6 +478,13 @@ This part of the setup is **optional**. SAML SSO Configuration (Optional) ================================= +.. danger:: + + In the current dev version of SODAR Core (v1.1.0-WIP), SAML support has been + temporarily disabled. The repository must be upgraded to a new SAML library + with support for Django v4.2+. This may also cause changes for configuring + SAML authentication. + Optional Single Sign-On (SSO) authorization via SAML is also available. To enable this feature, set ``ENABLE_SAML=1`` in your environment. Configuring SAML for SSO requires proper configuration of the Keycloak SSO server and the SAML diff --git a/docs/source/conf.py b/docs/source/conf.py index c0712f2d..83c27486 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -27,9 +27,9 @@ author = 'BIH Core Unit Bioinformatics' # The short X.Y version -version = '0.13' +version = '1.0' # The full version, including alpha/beta/rc tags -release = '0.13.4' +release = '1.0-WIP' # -- General configuration --------------------------------------------------- diff --git a/docs/source/dev_core_install.rst b/docs/source/dev_core_install.rst index 5992aeb5..60cd7754 100644 --- a/docs/source/dev_core_install.rst +++ b/docs/source/dev_core_install.rst @@ -26,7 +26,8 @@ system of choice. System Dependencies =================== -To get started, install the OS dependencies, PostgreSQL >=11 and Python >=3.8. +To get started, install the OS dependencies, Python >=3.8 (3.11 recommended) and +PostgreSQL >=12. .. code-block:: console diff --git a/docs/source/dev_project_app.rst b/docs/source/dev_project_app.rst index 79118d40..d9a141f6 100644 --- a/docs/source/dev_project_app.rst +++ b/docs/source/dev_project_app.rst @@ -53,7 +53,7 @@ to set up a fresh app generated in the standard way with It is also assumed that apps are more or less created according to best practices defined by `Two Scoops `_, with the -use of `Class-Based Views `_ +use of `Class-Based Views `_ being a requirement. @@ -96,7 +96,7 @@ To provide a unique identifier for objects in the SODAR context, add a When updating an existing Django model with an existing database, the ``sodar_uuid`` field needs to be populated. See - `instructions in Django documentation `_ + `instructions in Django documentation `_ on how to create the required migrations. Model Example diff --git a/docs/source/getting_started.rst b/docs/source/getting_started.rst index c7704d46..25ec8717 100644 --- a/docs/source/getting_started.rst +++ b/docs/source/getting_started.rst @@ -56,9 +56,9 @@ your Django site are listed below. For a complete requirement list, see the - Ubuntu (20.04 Focal recommended and supported) / CentOS 7 - System library requirements (see the ``utility`` directory and/or your own Django project) -- Python >=3.8 (**NOTE:** Python 3.7 no longer supported in SODAR Core v0.10.8+) -- Django 3.2 -- PostgreSQL >=11 and psycopg2-binary +- Python 3.8-3.11 (3.11 recommended) +- Django 4.2 +- PostgreSQL >=12 and psycopg2-binary - Bootstrap 4.x - JQuery 3.3.x - Shepherd and Tether diff --git a/docs/source/index.rst b/docs/source/index.rst index d264491f..1f7be576 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -79,8 +79,8 @@ Python Programming any. Django Development - For learning about Django, head over to the `excellent documentation of the - Django Project `_. + For learning about Django, head over to the + `official Django documentation `_. HTML / Javascript / CSS / Bootstrap 4 Together with Django, SODAR Core provides a framework to plug in your own diff --git a/docs/source/major_changes.rst b/docs/source/major_changes.rst index 32e52cca..69454c06 100644 --- a/docs/source/major_changes.rst +++ b/docs/source/major_changes.rst @@ -10,6 +10,53 @@ older SODAR Core version. For a complete list of changes in current and previous releases, see the :ref:`full changelog`. +v1.0.0 (WIP) +************ + +Release Highlights +================== + +- Upgrade to Django v4.2 and Postgres v16 +- Add Python 3.11 support + +Breaking Changes +================ + +Django v4.2 Upgrade +------------------- + +This release updates SODAR Core from Django v3.2 to v4.2. This is a breaking +change which causes many updates and also potentially requires updating several +dependencies. + +To upgrade, please update the Django requirement along with your site's other +Python requirements to match ones in ``requirements/*.txt``. See +`Django deprecation documentation `_ +for details about what has been deprecated in Django and which changes are +mandatory. + +Common known issues: + +- Minimum version of PostgreSQL has been bumped to v12. +- Replace ``django.utils.translation.ugettext_lazy`` imports with + ``gettext_lazy``. +- Replace ``django.conf.urls.url`` imports with ``django.urls.re_path``. +- Calls for ``related_managers`` for unsaved objects raises ``ValueError``. This + can be handled by e.g. calling ``model.save(commit=False)`` before trying to + access foreign key relations. + +System Prerequisites +-------------------- + +The minimum required PostgreSQL version has been bumped to v12. In CI we +currently use PostgreSQL v16, but anything from v12 to above should work with +this SODAR Core release. It is strongly recommended to make backups of your +production databases before upgrading. + +Python v3.11 support has been officially added in this version. 3.11 is now also +the recommended Python version to use. + + v0.13.4 (2024-02-16) ******************** diff --git a/example_project_app/urls.py b/example_project_app/urls.py index 3f3e6d8c..e6778d01 100644 --- a/example_project_app/urls.py +++ b/example_project_app/urls.py @@ -1,5 +1,4 @@ -from django.conf.urls import url -from django.urls import path +from django.urls import path, re_path from example_project_app import views, views_api @@ -10,14 +9,14 @@ # NOTE: If referring to a model from another app, notation is "app__model" urls = [ - url( - regex=r'^(?P[0-9a-f-]+)$', + re_path( + r'^(?P[0-9a-f-]+)$', view=views.ExampleView.as_view(), name='example', ), # Example view with model from an external app - url( - regex=r'^ext/(?P[0-9a-f-]+)$', + re_path( + r'^ext/(?P[0-9a-f-]+)$', view=views.ExampleView.as_view(), name='example_ext_model', ), @@ -36,8 +35,8 @@ ] urls_api = [ - url( - regex=r'^api/hello/(?P[0-9a-f-]+)$', + re_path( + r'^api/hello/(?P[0-9a-f-]+)$', view=views_api.HelloExampleProjectAPIView.as_view(), name='example_api_hello', ) diff --git a/projectroles/forms.py b/projectroles/forms.py index fcbd4ff6..2eb11b4e 100644 --- a/projectroles/forms.py +++ b/projectroles/forms.py @@ -697,8 +697,8 @@ def __init__(self, project=None, current_user=None, *args, **kwargs): def clean(self): """Function for custom form validation and cleanup""" self.instance_owner_as = ( - self.instance.get_owner() if self.instance else None - ) + self.instance.get_owner() if self.instance.pk else None + ) # Must check pk, get_owner() with unsaved model fails in Django v4+ disable_categories = getattr( settings, 'PROJECTROLES_DISABLE_CATEGORIES', False ) diff --git a/projectroles/models.py b/projectroles/models.py index 290e4342..e0c37160 100644 --- a/projectroles/models.py +++ b/projectroles/models.py @@ -12,7 +12,7 @@ from django.db import models from django.db.models import Q from django.urls import reverse -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from djangoplugins.models import Plugin from markupfield.fields import MarkupField @@ -197,13 +197,16 @@ def save(self, *args, **kwargs): self._validate_archive() # Update full title of self and children self.full_title = self._get_full_title() + # TODO: Save with commit=False with other args to avoid double save()? + super().save(*args, **kwargs) if self.type == PROJECT_TYPE_CATEGORY: for child in self.children.all(): child.save() # Update public children # NOTE: Parents will be updated in ProjectModifyMixin.modify_project() - self.has_public_children = self._has_public_children() - super().save(*args, **kwargs) + if self._has_public_children(): + self.has_public_children = True + super().save(*args, **kwargs) def _validate_parent(self): """ diff --git a/projectroles/views.py b/projectroles/views.py index 22df03b4..034abb53 100644 --- a/projectroles/views.py +++ b/projectroles/views.py @@ -1904,7 +1904,6 @@ class RoleAssignmentDeleteView( RolePermissionMixin, ProjectModifyPermissionMixin, ProjectContextMixin, - CurrentUserFormMixin, RoleAssignmentDeleteMixin, DeleteView, ): @@ -3023,21 +3022,17 @@ class RemoteSiteUpdateView( class RemoteSiteDeleteView( LoginRequiredMixin, LoggedInPermissionMixin, - RemoteSiteModifyMixin, HTTPRefererMixin, - CurrentUserFormMixin, DeleteView, ): """RemoteSite deletion view""" model = RemoteSite - form_class = RemoteSiteForm permission_required = 'projectroles.update_remote' slug_url_kwarg = 'remotesite' slug_field = 'sodar_uuid' def get_success_url(self): - """Override get_success_url() to add message""" timeline = get_backend_api('timeline_backend') if timeline: event_name = '{}_site_delete'.format( diff --git a/requirements/base.txt b/requirements/base.txt index 7e04ef50..3d0182f7 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -8,7 +8,7 @@ setuptools>=67.6.0, <67.7 packaging>=23.0, <24.0 # Django -django>=3.2.24, <3.3 +django>=4.2.9, <5.0 # Configuration django-environ>=0.10.0, <0.11 @@ -48,8 +48,8 @@ versioneer==0.28 # Project app imports ###################### -# Django-plugins (with Django v3.0+ support) -django-plugins-bihealth==0.4.0 +# Django-plugins (with Django v4.2 support) +django-plugins-bihealth==0.5.2 # Rules for permissions rules>=3.3, <3.4 @@ -58,7 +58,7 @@ rules>=3.3, <3.4 djangorestframework>=3.14.0, <3.15 # Keyed list addon for DRF -drf-keyed-list-bihealth==0.1.1 +drf-keyed-list-bihealth==0.2.1 # Token authentication django-rest-knox>=4.2.0, <4.3 @@ -70,7 +70,7 @@ django-pagedown>=2.2.1, <2.3 mistune>=2.0.5, <2.1 # Database file storage for filesfolders -django-db-file-storage==0.5.5 +django-db-file-storage==0.5.6.1 # Celery dependency redis>=4.4.4