Compare commits

...

10 commits
0.15.1 ... main

Author SHA1 Message Date
Jan Dittberner 5882a98966 Remove missing exit module 2024-08-23 18:27:39 +02:00
Jan Dittberner 5b04c476c9 Fix missing renderer parameter support 2024-08-23 18:01:27 +02:00
Jan Dittberner 38b120b03e Update dependencies, fix tests
- replace assertTrue(mock.called_with(...)) with mock.assert_called_with
2024-08-23 17:57:40 +02:00
Jan Dittberner f3ef40df0b Move to environs[django] 2024-04-13 13:18:22 +02:00
Jan Dittberner a3feb92503 Update dependencies 2024-04-13 13:18:02 +02:00
Jan Dittberner 11c04df074 Add flatpage URL for /issues/
Jira has been decommissioned and replaced with a flatpage
2024-02-11 13:12:54 +01:00
Jan Dittberner 7c57b4cc94 Update docker setup 2024-02-11 13:12:26 +01:00
Jan Dittberner 78e06dd2b9 Update dependencies
- updated minimum version of several dependencies in pyproject.toml
- update of django-allauth required to add
  allauth.account.middleware.AccountMiddleware to MIDDLEWARE setting
2024-01-13 13:38:03 +01:00
Jan Dittberner 90795375e7 Update dependencies 2024-01-13 13:22:50 +01:00
Jan Dittberner c1b226e5a1 Update dependency versions 2023-08-03 09:24:42 +02:00
12 changed files with 1276 additions and 1035 deletions

View file

@ -1,8 +1,8 @@
ARG DEBIAN_RELEASE=buster ARG DEBIAN_RELEASE=bookworm
FROM debian:$DEBIAN_RELEASE AS builder FROM debian:$DEBIAN_RELEASE AS builder
ARG GVAAPP=gva ARG GVAAPP=gva
ARG POETRY_VERSION=1.3.1 ARG POETRY_VERSION=1.7.1
ENV LC_ALL=C.UTF-8 ENV LC_ALL=C.UTF-8
ENV LANG=C.UTF-8 ENV LANG=C.UTF-8
@ -26,7 +26,7 @@ WORKDIR /srv/$GVAAPP
COPY poetry.lock pyproject.toml /srv/$GVAAPP/ COPY poetry.lock pyproject.toml /srv/$GVAAPP/
RUN /root/.local/bin/poetry install --only=main RUN /root/.local/bin/poetry install --only=main --no-root
FROM debian:$DEBIAN_RELEASE FROM debian:$DEBIAN_RELEASE
LABEL maintainer="Jan Dittberner <jan@dittberner.info>" LABEL maintainer="Jan Dittberner <jan@dittberner.info>"

View file

@ -19,7 +19,7 @@ services:
volumes: volumes:
- "redis_data:/var/lib/redis" - "redis_data:/var/lib/redis"
gva: gva:
image: gnuviech/gva:buster image: gnuviech/gva:bookworm
build: build:
context: . context: .
args: args:
@ -67,7 +67,7 @@ services:
volumes: volumes:
- "../gvaldap/gvaldap:/srv/gvaldap/gvaldap" - "../gvaldap/gvaldap:/srv/gvaldap/gvaldap"
file: file:
image: gnuviech/gvafile:buster image: gnuviech/gvafile:bookworm
build: build:
context: ../gvafile context: ../gvafile
args: args:

View file

@ -6,9 +6,12 @@ Common settings and globals.
""" """
from os.path import abspath, basename, dirname, join, normpath from os.path import abspath, basename, dirname, join, normpath
from environs import Env
from django.contrib.messages import constants as messages from django.contrib.messages import constants as messages
from gvacommon.settings_utils import get_env_variable
env = Env()
env.read_env()
# ######### PATH CONFIGURATION # ######### PATH CONFIGURATION
# Absolute filesystem path to the Django project directory: # Absolute filesystem path to the Django project directory:
@ -17,12 +20,14 @@ DJANGO_ROOT = dirname(dirname(abspath(__file__)))
# Absolute filesystem path to the top-level project folder: # Absolute filesystem path to the top-level project folder:
SITE_ROOT = dirname(DJANGO_ROOT) SITE_ROOT = dirname(DJANGO_ROOT)
ROOT_DIR = dirname(DJANGO_ROOT)
# Site name: # Site name:
SITE_NAME = basename(DJANGO_ROOT) SITE_NAME = basename(DJANGO_ROOT)
# ######### END PATH CONFIGURATION # ######### END PATH CONFIGURATION
GVA_ENVIRONMENT = get_env_variable("GVA_ENVIRONMENT", default="prod") GVA_ENVIRONMENT = env.str("GVA_ENVIRONMENT", default="prod")
# ######### DEBUG CONFIGURATION # ######### DEBUG CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#debug # See: https://docs.djangoproject.com/en/dev/ref/settings/#debug
@ -34,8 +39,8 @@ DEBUG = GVA_ENVIRONMENT == "local"
# See: https://docs.djangoproject.com/en/dev/ref/settings/#admins # See: https://docs.djangoproject.com/en/dev/ref/settings/#admins
ADMINS = ( ADMINS = (
( (
get_env_variable("GVA_ADMIN_NAME", default="Admin"), env.str("GVA_ADMIN_NAME", default="Admin"),
get_env_variable("GVA_ADMIN_EMAIL", default="admin@example.org"), env.str("GVA_ADMIN_EMAIL", default="admin@example.org"),
), ),
) )
@ -47,14 +52,7 @@ MANAGERS = ADMINS
# ######### DATABASE CONFIGURATION # ######### DATABASE CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#databases # See: https://docs.djangoproject.com/en/dev/ref/settings/#databases
DATABASES = { DATABASES = {
"default": { "default": env.dj_db_url("GVA_DATABASE_URL"),
"ENGINE": "django.db.backends.postgresql",
"NAME": get_env_variable("GVA_PGSQL_DATABASE", default="gnuviechadmin"),
"USER": get_env_variable("GVA_PGSQL_USER", default="gnuviechadmin"),
"PASSWORD": get_env_variable("GVA_PGSQL_PASSWORD"),
"HOST": get_env_variable("GVA_PGSQL_HOSTNAME", default="db"),
"PORT": get_env_variable("GVA_PGSQL_PORT", int, default=5432),
}
} }
DEFAULT_AUTO_FIELD = "django.db.models.AutoField" DEFAULT_AUTO_FIELD = "django.db.models.AutoField"
@ -70,8 +68,8 @@ LANGUAGE_CODE = "en-us"
# See: https://docs.djangoproject.com/en/dev/ref/settings/#site-id # See: https://docs.djangoproject.com/en/dev/ref/settings/#site-id
SITE_ID = 1 SITE_ID = 1
SITES_DOMAIN_NAME = get_env_variable("GVA_DOMAIN_NAME") SITES_DOMAIN_NAME = env.str("GVA_DOMAIN_NAME")
SITES_SITE_NAME = get_env_variable("GVA_SITE_NAME") SITES_SITE_NAME = env.str("GVA_SITE_NAME")
# See: https://docs.djangoproject.com/en/dev/ref/settings/#use-i18n # See: https://docs.djangoproject.com/en/dev/ref/settings/#use-i18n
USE_I18N = True USE_I18N = True
@ -109,7 +107,7 @@ STATICFILES_FINDERS = (
# ######### SECRET CONFIGURATION # ######### SECRET CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#secret-key # See: https://docs.djangoproject.com/en/dev/ref/settings/#secret-key
# Note: This key should only be used for development and testing. # Note: This key should only be used for development and testing.
SECRET_KEY = get_env_variable("GVA_SITE_SECRET") SECRET_KEY = env.str("GVA_SITE_SECRET")
# ######### END SECRET CONFIGURATION # ######### END SECRET CONFIGURATION
@ -161,9 +159,9 @@ MIDDLEWARE = [
"django.contrib.sessions.middleware.SessionMiddleware", "django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.csrf.CsrfViewMiddleware", "django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware",
"allauth.account.middleware.AccountMiddleware",
"django.middleware.locale.LocaleMiddleware", "django.middleware.locale.LocaleMiddleware",
"django.contrib.messages.middleware.MessageMiddleware", "django.contrib.messages.middleware.MessageMiddleware",
# uncomment next line to enable translation to browser locale
"django.middleware.clickjacking.XFrameOptionsMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware",
] ]
# ######### END MIDDLEWARE CONFIGURATION # ######### END MIDDLEWARE CONFIGURATION
@ -308,7 +306,7 @@ LOGGING = {
"logfile": { "logfile": {
"level": "INFO", "level": "INFO",
"class": "logging.FileHandler", "class": "logging.FileHandler",
"filename": get_env_variable("GVA_LOG_FILE", default="gva.log"), "filename": env.str("GVA_LOG_FILE", default="gva.log"),
"formatter": "verbose", "formatter": "verbose",
}, },
"mail_admins": { "mail_admins": {
@ -351,7 +349,7 @@ WSGI_APPLICATION = "%s.wsgi.application" % SITE_NAME
# ######### CELERY CONFIGURATION # ######### CELERY CONFIGURATION
BROKER_URL = get_env_variable( BROKER_URL = env.str(
"GVA_BROKER_URL", default="amqp://gnuviechadmin:gnuviechadmin@mq/gnuviechadmin" "GVA_BROKER_URL", default="amqp://gnuviechadmin:gnuviechadmin@mq/gnuviechadmin"
) )
BROKER_TRANSPORT_OPTIONS = { BROKER_TRANSPORT_OPTIONS = {
@ -360,7 +358,7 @@ BROKER_TRANSPORT_OPTIONS = {
"interval_step": 0.2, "interval_step": 0.2,
"interval_max": 0.2, "interval_max": 0.2,
} }
CELERY_RESULT_BACKEND = get_env_variable( CELERY_RESULT_BACKEND = env.str(
"GVA_RESULTS_REDIS_URL", default="redis://:gnuviechadmin@redis:6379/0" "GVA_RESULTS_REDIS_URL", default="redis://:gnuviechadmin@redis:6379/0"
) )
CELERY_TASK_RESULT_EXPIRES = None CELERY_TASK_RESULT_EXPIRES = None
@ -374,32 +372,28 @@ CELERY_RESULT_SERIALIZER = "json"
# ######### CUSTOM APP CONFIGURATION # ######### CUSTOM APP CONFIGURATION
OSUSER_MINUID = get_env_variable("GVA_MIN_OS_UID", int, default=10000) OSUSER_MINUID = env.int("GVA_MIN_OS_UID", default=10000)
OSUSER_MINGID = get_env_variable("GVA_MIN_OS_GID", int, default=10000) OSUSER_MINGID = env.int("GVA_MIN_OS_GID", default=10000)
OSUSER_USERNAME_PREFIX = get_env_variable("GVA_OSUSER_PREFIX", default="usr") OSUSER_USERNAME_PREFIX = env.str("GVA_OSUSER_PREFIX", default="usr")
OSUSER_HOME_BASEPATH = get_env_variable("GVA_OSUSER_HOME_BASEPATH", default="/home") OSUSER_HOME_BASEPATH = env.str("GVA_OSUSER_HOME_BASEPATH", default="/home")
OSUSER_DEFAULT_SHELL = get_env_variable( OSUSER_DEFAULT_SHELL = env.str("GVA_OSUSER_DEFAULT_SHELL", default="/usr/bin/rssh")
"GVA_OSUSER_DEFAULT_SHELL", default="/usr/bin/rssh"
)
OSUSER_SFTP_GROUP = "sftponly" OSUSER_SFTP_GROUP = "sftponly"
OSUSER_SSH_GROUP = "sshusers" OSUSER_SSH_GROUP = "sshusers"
OSUSER_DEFAULT_GROUPS = [OSUSER_SFTP_GROUP] OSUSER_DEFAULT_GROUPS = [OSUSER_SFTP_GROUP]
OSUSER_UPLOAD_SERVER = get_env_variable("GVA_OSUSER_UPLOADSERVER", default="file") OSUSER_UPLOAD_SERVER = env.str("GVA_OSUSER_UPLOADSERVER", default="file")
GVA_LINK_WEBMAIL = get_env_variable( GVA_LINK_WEBMAIL = env.str("GVA_WEBMAIL_URL", default="https://webmail.example.org/")
"GVA_WEBMAIL_URL", default="https://webmail.example.org/" GVA_LINK_PHPMYADMIN = env.str(
)
GVA_LINK_PHPMYADMIN = get_env_variable(
"GVA_PHPMYADMIN_URL", default="https://phpmyadmin.example.org/" "GVA_PHPMYADMIN_URL", default="https://phpmyadmin.example.org/"
) )
GVA_LINK_PHPPGADMIN = get_env_variable( GVA_LINK_PHPPGADMIN = env.str(
"GVA_PHPPGADMIN_URL", default="https://phppgadmin.example.org/" "GVA_PHPPGADMIN_URL", default="https://phppgadmin.example.org/"
) )
# ######### END CUSTOM APP CONFIGURATION # ######### END CUSTOM APP CONFIGURATION
# ######### STATIC FILE CONFIGURATION # ######### STATIC FILE CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#static-root # See: https://docs.djangoproject.com/en/dev/ref/settings/#static-root
STATIC_ROOT = "/srv/gva/static/" STATIC_ROOT = env.str("GVA_STATIC_PATH", default=normpath(join(ROOT_DIR, "static")))
def show_debug_toolbar(request): def show_debug_toolbar(request):
@ -494,12 +488,10 @@ else:
EMAIL_SUBJECT_PREFIX = "[%s] " % SITE_NAME EMAIL_SUBJECT_PREFIX = "[%s] " % SITE_NAME
# See: https://docs.djangoproject.com/en/dev/ref/settings/#default-from-email # See: https://docs.djangoproject.com/en/dev/ref/settings/#default-from-email
DEFAULT_FROM_EMAIL = get_env_variable( DEFAULT_FROM_EMAIL = env.str("GVA_SITE_ADMINMAIL", default="admin@example.org")
"GVA_SITE_ADMINMAIL", default="admin@example.org"
)
# See: https://docs.djangoproject.com/en/dev/ref/settings/#server-email # See: https://docs.djangoproject.com/en/dev/ref/settings/#server-email
SERVER_EMAIL = get_env_variable("GVA_SITE_ADMINMAIL", default="admin@example.org") SERVER_EMAIL = env.str("GVA_SITE_ADMINMAIL", default="admin@example.org")
# ######### END EMAIL CONFIGURATION # ######### END EMAIL CONFIGURATION
# ######### CACHE CONFIGURATION # ######### CACHE CONFIGURATION

View file

@ -38,6 +38,7 @@ urlpatterns = [
path("contact/", include("contact_form.urls")), path("contact/", include("contact_form.urls")),
path("impressum/", views.flatpage, {"url": "/impressum/"}, name="imprint"), path("impressum/", views.flatpage, {"url": "/impressum/"}, name="imprint"),
path("datenschutz/", views.flatpage, {"url": "/datenschutz/"}, name="privacy"), path("datenschutz/", views.flatpage, {"url": "/datenschutz/"}, name="privacy"),
path("issues/", views.flatpage, {"url": "/issues/"}, name="support"),
] ]
# Uncomment the next line to serve media files in dev. # Uncomment the next line to serve media files in dev.

View file

@ -10,7 +10,7 @@ PASSWORD_MISMATCH_ERROR = _("Passwords don't match")
class ReadOnlyPasswordHashWidget(forms.Widget): class ReadOnlyPasswordHashWidget(forms.Widget):
def render(self, name, value, attrs): def render(self, name, value, attrs, renderer=None):
final_attrs = self.build_attrs(attrs) final_attrs = self.build_attrs(attrs)
summary = format_html("<strong>{0}</strong>: {1} ", _("Hash"), value) summary = format_html("<strong>{0}</strong>: {1} ", _("Hash"), value)
return format_html("<div{0}>{1}</div>", flatatt(final_attrs), summary) return format_html("<div{0}>{1}</div>", flatatt(final_attrs), summary)

View file

@ -119,13 +119,13 @@ class ActivationChangeMixinTest(TestCase):
querysetmock = Mock() querysetmock = Mock()
activationchange = ActivationChangeMixin() activationchange = ActivationChangeMixin()
activationchange.activate(Mock(), querysetmock) activationchange.activate(Mock(), querysetmock)
querysetmock.update.called_with(active=True) querysetmock.update.assert_called_with(active=True)
def test_deactivate(self): def test_deactivate(self):
querysetmock = Mock() querysetmock = Mock()
activationchange = ActivationChangeMixin() activationchange = ActivationChangeMixin()
activationchange.deactivate(Mock(), querysetmock) activationchange.deactivate(Mock(), querysetmock)
querysetmock.update.called_with(active=False) querysetmock.update.assert_called_with(active=False)
class MailBoxAdminTest(CustomerTestCase): class MailBoxAdminTest(CustomerTestCase):

View file

@ -35,8 +35,8 @@ class FetchTaskResultsCommandTest(TestCase):
Command().handle(verbosity=0) Command().handle(verbosity=0)
tr = TaskResult.objects.get(task_id=TEST_TASK_UUID) tr = TaskResult.objects.get(task_id=TEST_TASK_UUID)
self.assertTrue(asyncresult.called_with(TEST_TASK_UUID)) asyncresult.assert_called_with(TEST_TASK_UUID)
self.assertTrue(aresult.ready.called_with()) aresult.ready.assert_called_with()
self.assertFalse(tr.finished) self.assertFalse(tr.finished)
self.assertEqual(tr.result, "") self.assertEqual(tr.result, "")
self.assertEqual(tr.state, "PENDING") self.assertEqual(tr.state, "PENDING")
@ -58,9 +58,9 @@ class FetchTaskResultsCommandTest(TestCase):
Command().handle(verbosity=0) Command().handle(verbosity=0)
tr = TaskResult.objects.get(task_id=TEST_TASK_UUID) tr = TaskResult.objects.get(task_id=TEST_TASK_UUID)
self.assertTrue(asyncresult.called_with(TEST_TASK_UUID)) asyncresult.assert_called_with(TEST_TASK_UUID)
self.assertTrue(aresult.ready.called_with()) aresult.ready.assert_called_with()
self.assertTrue(aresult.get.called_with()) aresult.get.assert_called_with(propagate=False, timeout=5)
self.assertTrue(tr.finished) self.assertTrue(tr.finished)
self.assertEqual(tr.result, TEST_TASK_RESULT) self.assertEqual(tr.result, TEST_TASK_RESULT)
self.assertEqual(tr.state, "SUCCESS") self.assertEqual(tr.state, "SUCCESS")

View file

@ -41,7 +41,7 @@ class TaskResultTest(TestCase):
aresult.ready.return_value = True aresult.ready.return_value = True
aresult.get.return_value = TEST_TASK_RESULT aresult.get.return_value = TEST_TASK_RESULT
tr.fetch_result() tr.fetch_result()
self.assertTrue(aresult.get.called_with()) aresult.get.assert_called_with(propagate=False, timeout=5)
self.assertEqual(aresult.get.call_count, 1) self.assertEqual(aresult.get.call_count, 1)
self.assertTrue(tr.finished) self.assertTrue(tr.finished)
self.assertEqual(tr.result, str(TEST_TASK_RESULT)) self.assertEqual(tr.result, str(TEST_TASK_RESULT))

View file

@ -24,11 +24,9 @@ class DatabaseUserCreationFormTest(TestCase):
mockuser = Mock(name="osuser") mockuser = Mock(name="osuser")
form.cleaned_data = {"osuser": mockuser, "db_type": DB_TYPES.pgsql} form.cleaned_data = {"osuser": mockuser, "db_type": DB_TYPES.pgsql}
retval = form.save() retval = form.save()
self.assertTrue( create_database_user.assert_called_with(
create_database_user.called_with(
osuser=mockuser, db_type=DB_TYPES.pgsql, commit=True osuser=mockuser, db_type=DB_TYPES.pgsql, commit=True
) )
)
self.assertEqual(retval, create_database_user.return_value) self.assertEqual(retval, create_database_user.return_value)
def test_save_m2m_returns_none(self): def test_save_m2m_returns_none(self):
@ -44,7 +42,7 @@ class UserDatabaseCreationFormTest(TestCase):
mockuser = Mock(name="mockuser") mockuser = Mock(name="mockuser")
form.cleaned_data = {"db_user": mockuser} form.cleaned_data = {"db_user": mockuser}
retval = form.save() retval = form.save()
self.assertTrue(create_userdatabase.called_with(db_user=mockuser, commit=True)) create_userdatabase.assert_called_with(db_user=mockuser, commit=True)
self.assertEqual(retval, create_userdatabase.return_value) self.assertEqual(retval, create_userdatabase.return_value)
def test_save_m2m_returns_none(self): def test_save_m2m_returns_none(self):
@ -79,20 +77,20 @@ class DatabaseUserAdminTest(TestCase):
def test_save_model_change(self): def test_save_model_change(self):
objmock = Mock() objmock = Mock()
self.dbuadmin.save_model(Mock(name="request"), objmock, Mock(), True) self.dbuadmin.save_model(Mock(name="request"), objmock, Mock(), True)
self.assertTrue(objmock.create_in_database.not_called()) objmock.create_in_database.assert_not_called()
def test_save_model_no_change(self): def test_save_model_no_change(self):
objmock = Mock() objmock = Mock()
self.dbuadmin.save_model(Mock(name="request"), objmock, Mock(), False) self.dbuadmin.save_model(Mock(name="request"), objmock, Mock(), False)
self.assertTrue(objmock.create_in_database.called_with()) objmock.create_in_database.assert_called_with()
def test_perform_delete_selected(self): def test_perform_delete_selected(self):
usermock = Mock() usermock = Mock()
selected = Mock() selected = Mock()
selected.all.return_value = [usermock] selected.all.return_value = [usermock]
self.dbuadmin.perform_delete_selected(Mock(name="request"), selected) self.dbuadmin.perform_delete_selected(Mock(name="request"), selected)
self.assertTrue(selected.all.called_with()) selected.all.assert_called_with()
self.assertTrue(usermock.delete.called_with()) usermock.delete.assert_called_with()
def test_get_actions(self): def test_get_actions(self):
requestmock = MagicMock(name="request") requestmock = MagicMock(name="request")
@ -127,20 +125,20 @@ class UserDatabaseAdminTest(TestCase):
def test_save_model_change(self): def test_save_model_change(self):
objmock = Mock() objmock = Mock()
self.udbadmin.save_model(Mock(name="request"), objmock, Mock(), True) self.udbadmin.save_model(Mock(name="request"), objmock, Mock(), True)
self.assertTrue(objmock.create_in_database.not_called()) objmock.create_in_database.assert_not_called()
def test_save_model_no_change(self): def test_save_model_no_change(self):
objmock = Mock() objmock = Mock()
self.udbadmin.save_model(Mock(name="request"), objmock, Mock(), False) self.udbadmin.save_model(Mock(name="request"), objmock, Mock(), False)
self.assertTrue(objmock.create_in_database.called_with()) objmock.create_in_database.assert_called_with()
def test_perform_delete_selected(self): def test_perform_delete_selected(self):
userdbmock = Mock() userdbmock = Mock()
selected = Mock() selected = Mock()
selected.all.return_value = [userdbmock] selected.all.return_value = [userdbmock]
self.udbadmin.perform_delete_selected(Mock(name="request"), selected) self.udbadmin.perform_delete_selected(Mock(name="request"), selected)
self.assertTrue(selected.all.called_with()) selected.all.assert_called_with()
self.assertTrue(userdbmock.delete.called_with()) userdbmock.delete.assert_called_with()
def test_get_actions(self): def test_get_actions(self):
requestmock = MagicMock(name="request") requestmock = MagicMock(name="request")

View file

@ -82,14 +82,12 @@ class AddUserDatabaseFormTest(TestCase):
) )
form.cleaned_data = {"db_type": DB_TYPES.pgsql, "password1": "secret"} form.cleaned_data = {"db_type": DB_TYPES.pgsql, "password1": "secret"}
form.save() form.save()
self.assertTrue( create_userdatabase_with_user.assert_called_with(
create_userdatabase_with_user.called_with(
DB_TYPES.pgsql, DB_TYPES.pgsql,
self.hostingpackage.osuser, self.hostingpackage.osuser,
password="secret", password="secret",
commit=True, commit=True,
) )
)
class ChangeDatabaseUserPasswordFormTest(TestCase): class ChangeDatabaseUserPasswordFormTest(TestCase):
@ -131,4 +129,4 @@ class ChangeDatabaseUserPasswordFormTest(TestCase):
) )
form.cleaned_data = {"password1": "secret"} form.cleaned_data = {"password1": "secret"}
form.save() form.save()
self.assertTrue(instance.set_password.called_with("secret")) instance.set_password.assert_called_with("secret")

2166
poetry.lock generated

File diff suppressed because it is too large Load diff

View file

@ -4,28 +4,30 @@ version = "0.15.1"
description = "gnuviechadmin web interface" description = "gnuviechadmin web interface"
authors = ["Jan Dittberner <jan@dittberner.info>"] authors = ["Jan Dittberner <jan@dittberner.info>"]
license = "AGPL-3+" license = "AGPL-3+"
readme = "README.md" readme = "README.rst"
package-mode = false
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "^3.8" python = "^3.8"
django = "^4.2" django = "^4.2"
psycopg2-binary = "^2.9" psycopg2-binary = "^2.9"
celery = "^5.2.7" celery = "^5.2.7"
django-allauth = "^0.52.0" django-allauth = "^0.60.0"
django-crispy-forms = "^2.0" django-crispy-forms = "^2.0"
django-debug-toolbar = "^3.8" django-debug-toolbar = "^4.2"
django-model-utils = "^4.1" django-model-utils = "^4.1"
gvacommon = {version = "^0.7.0", source = "gnuviech"} gvacommon = {version = "^0.7.0", source = "gnuviech"}
passlib = "^1.7.4" passlib = "^1.7.4"
redis = "^4.5.1" redis = "^5.0.1"
requests-oauthlib = "^1.3.1" requests-oauthlib = "^1.3.1"
django-impersonate = "^1.9.1" django-impersonate = "^1.9.1"
djangorestframework = "^3.14.0" djangorestframework = "^3.14.0"
markdown = "^3.4.3" markdown = "^3.4.3"
django-filter = "^23.1" django-filter = "^23.1"
crispy-bootstrap5 = "^0.7" crispy-bootstrap5 = "^2023.10"
python-magic = "^0.4.27" python-magic = "^0.4.27"
isort = "^5.12.0" isort = "^5.12.0"
environs = {extras = ["django"], version = "^11.0.0"}
[tool.poetry.group.dev.dependencies] [tool.poetry.group.dev.dependencies]