From 75cb667314559589aaa386b04c767b16a73dfe03 Mon Sep 17 00:00:00 2001
From: mike wakerly
Date: Thu, 14 Jul 2022 14:28:24 +0100
Subject: [PATCH 1/7] deps: update django 2.2 -> 3.0
---
poetry.lock | 36 ++++++++++++++++++++++++++----------
pyproject.toml | 2 +-
2 files changed, 27 insertions(+), 11 deletions(-)
diff --git a/poetry.lock b/poetry.lock
index cec6664c..ec0e6979 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -25,6 +25,17 @@ python-versions = ">=3.6"
[package.dependencies]
vine = ">=5.0.0"
+[[package]]
+name = "asgiref"
+version = "3.5.2"
+description = "ASGI specs, helper code, and adapters"
+category = "main"
+optional = false
+python-versions = ">=3.7"
+
+[package.extras]
+tests = ["pytest", "pytest-asyncio", "mypy (>=0.800)"]
+
[[package]]
name = "async-timeout"
version = "4.0.2"
@@ -290,13 +301,14 @@ python-versions = "*"
[[package]]
name = "django"
-version = "2.2.28"
+version = "3.0"
description = "A high-level Python Web framework that encourages rapid development and clean, pragmatic design."
category = "main"
optional = false
-python-versions = ">=3.5"
+python-versions = ">=3.6"
[package.dependencies]
+asgiref = ">=3.2,<4.0"
pytz = "*"
sqlparse = ">=0.2.2"
@@ -366,15 +378,15 @@ hiredis = ["redis[hiredis] (>=3,!=4.0.0,!=4.0.1)"]
[[package]]
name = "django-registration"
-version = "3.2"
+version = "3.1.2"
description = "An extensible user-registration application for Django"
category = "main"
optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.5"
[package.dependencies]
confusable-homoglyphs = ">=3.0,<4.0"
-Django = ">=2.2,<3.0.0 || >=3.1.0"
+Django = ">=2.2"
[[package]]
name = "docutils"
@@ -1141,7 +1153,7 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"]
[metadata]
lock-version = "1.1"
python-versions = "^3.10.5"
-content-hash = "1f7e3cd78dce77caebcc887f16193126e3f68af3aa80ef84c9959012569b4370"
+content-hash = "5d8dcab39210c911d3a2c5cd5e327ff7650e9397be136612827786420fdb06bd"
[metadata.files]
addict = [
@@ -1156,6 +1168,10 @@ amqp = [
{file = "amqp-5.1.1-py3-none-any.whl", hash = "sha256:6f0956d2c23d8fa6e7691934d8c3930eadb44972cbbd1a7ae3a520f735d43359"},
{file = "amqp-5.1.1.tar.gz", hash = "sha256:2c1b13fecc0893e946c65cbd5f36427861cffa4ea2201d8f6fca22e2a373b5e2"},
]
+asgiref = [
+ {file = "asgiref-3.5.2-py3-none-any.whl", hash = "sha256:1d2880b792ae8757289136f1db2b7b99100ce959b2aa57fd69dab783d05afac4"},
+ {file = "asgiref-3.5.2.tar.gz", hash = "sha256:4a29362a6acebe09bf1d6640db38c1dc3d9217c68e6f9f6204d72667fc19a424"},
+]
async-timeout = [
{file = "async-timeout-4.0.2.tar.gz", hash = "sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15"},
{file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"},
@@ -1319,8 +1335,8 @@ dj-email-url = [
{file = "dj_email_url-1.0.5-py2.py3-none-any.whl", hash = "sha256:64257c4f9d8139a4af8e5267229d32260e433fbf257b0cf8fc855bb0cc39ca7d"},
]
django = [
- {file = "Django-2.2.28-py3-none-any.whl", hash = "sha256:365429d07c1336eb42ba15aa79f45e1c13a0b04d5c21569e7d596696418a6a45"},
- {file = "Django-2.2.28.tar.gz", hash = "sha256:0200b657afbf1bc08003845ddda053c7641b9b24951e52acd51f6abda33a7413"},
+ {file = "Django-3.0-py3-none-any.whl", hash = "sha256:6f857bd4e574442ba35a7172f1397b303167dae964cf18e53db5e85fe248d000"},
+ {file = "Django-3.0.tar.gz", hash = "sha256:d98c9b6e5eed147bc51f47c014ff6826bd1ab50b166956776ee13db5a58804ae"},
]
django-appconf = [
{file = "django-appconf-1.0.5.tar.gz", hash = "sha256:be3db0be6c81fa84742000b89a81c016d70ae66a7ccb620cdef592b1f1a6aaa4"},
@@ -1343,8 +1359,8 @@ django-redis = [
{file = "django_redis-5.2.0-py3-none-any.whl", hash = "sha256:1d037dc02b11ad7aa11f655d26dac3fb1af32630f61ef4428860a2e29ff92026"},
]
django-registration = [
- {file = "django-registration-3.2.tar.gz", hash = "sha256:2ea8c7d89a8760ccde41dfd335aa28ba89073d09aab5a0f5f3d7c8c148fcc518"},
- {file = "django_registration-3.2-py3-none-any.whl", hash = "sha256:e79fdbfa22bfaf4182efccb6604391391a7de19438d2669c5b9520a7708efbd2"},
+ {file = "django-registration-3.1.2.tar.gz", hash = "sha256:c9985f9ffd123534026bf5f39adb0b48fd7bf930b965f27f9a487d135f377ac6"},
+ {file = "django_registration-3.1.2-py3-none-any.whl", hash = "sha256:dde525b08880da1d72b556f19dfd1c6588233a43f8bc354481f2d3e8896c44f8"},
]
docutils = [
{file = "docutils-0.18.1-py2.py3-none-any.whl", hash = "sha256:23010f129180089fbcd3bc08cfefccb3b890b0050e1ca00c867036e9d161b98c"},
diff --git a/pyproject.toml b/pyproject.toml
index d68a516e..bd76c464 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -43,7 +43,7 @@ redis = "*"
requests-oauthlib = "*"
requests = "*"
whitenoise = "*"
-Django = "<3"
+Django = "3.0"
Pillow = "*"
PyYAML = "*"
mysqlclient = "*"
From a95ca9783219cf36f15c69fca7d90a8598465693 Mon Sep 17 00:00:00 2001
From: mike wakerly
Date: Thu, 14 Jul 2022 14:30:35 +0100
Subject: [PATCH 2/7] deps: update django 3.0 -> 3.1
---
poetry.lock | 30 +++++++++++++++---------------
pyproject.toml | 2 +-
2 files changed, 16 insertions(+), 16 deletions(-)
diff --git a/poetry.lock b/poetry.lock
index ec0e6979..d6e0a452 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -27,14 +27,14 @@ vine = ">=5.0.0"
[[package]]
name = "asgiref"
-version = "3.5.2"
+version = "3.2.10"
description = "ASGI specs, helper code, and adapters"
category = "main"
optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.5"
[package.extras]
-tests = ["pytest", "pytest-asyncio", "mypy (>=0.800)"]
+tests = ["pytest", "pytest-asyncio"]
[[package]]
name = "async-timeout"
@@ -301,14 +301,14 @@ python-versions = "*"
[[package]]
name = "django"
-version = "3.0"
+version = "3.1"
description = "A high-level Python Web framework that encourages rapid development and clean, pragmatic design."
category = "main"
optional = false
python-versions = ">=3.6"
[package.dependencies]
-asgiref = ">=3.2,<4.0"
+asgiref = ">=3.2.10,<3.3.0"
pytz = "*"
sqlparse = ">=0.2.2"
@@ -378,15 +378,15 @@ hiredis = ["redis[hiredis] (>=3,!=4.0.0,!=4.0.1)"]
[[package]]
name = "django-registration"
-version = "3.1.2"
+version = "3.2"
description = "An extensible user-registration application for Django"
category = "main"
optional = false
-python-versions = ">=3.5"
+python-versions = ">=3.6"
[package.dependencies]
confusable-homoglyphs = ">=3.0,<4.0"
-Django = ">=2.2"
+Django = ">=2.2,<3.0.0 || >=3.1.0"
[[package]]
name = "docutils"
@@ -1153,7 +1153,7 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"]
[metadata]
lock-version = "1.1"
python-versions = "^3.10.5"
-content-hash = "5d8dcab39210c911d3a2c5cd5e327ff7650e9397be136612827786420fdb06bd"
+content-hash = "85d1b9d4a42699a2352dc991f49ec92d01de83a46f68e0ac946194b765635d09"
[metadata.files]
addict = [
@@ -1169,8 +1169,8 @@ amqp = [
{file = "amqp-5.1.1.tar.gz", hash = "sha256:2c1b13fecc0893e946c65cbd5f36427861cffa4ea2201d8f6fca22e2a373b5e2"},
]
asgiref = [
- {file = "asgiref-3.5.2-py3-none-any.whl", hash = "sha256:1d2880b792ae8757289136f1db2b7b99100ce959b2aa57fd69dab783d05afac4"},
- {file = "asgiref-3.5.2.tar.gz", hash = "sha256:4a29362a6acebe09bf1d6640db38c1dc3d9217c68e6f9f6204d72667fc19a424"},
+ {file = "asgiref-3.2.10-py3-none-any.whl", hash = "sha256:9fc6fb5d39b8af147ba40765234fa822b39818b12cc80b35ad9b0cef3a476aed"},
+ {file = "asgiref-3.2.10.tar.gz", hash = "sha256:7e51911ee147dd685c3c8b805c0ad0cb58d360987b56953878f8c06d2d1c6f1a"},
]
async-timeout = [
{file = "async-timeout-4.0.2.tar.gz", hash = "sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15"},
@@ -1335,8 +1335,8 @@ dj-email-url = [
{file = "dj_email_url-1.0.5-py2.py3-none-any.whl", hash = "sha256:64257c4f9d8139a4af8e5267229d32260e433fbf257b0cf8fc855bb0cc39ca7d"},
]
django = [
- {file = "Django-3.0-py3-none-any.whl", hash = "sha256:6f857bd4e574442ba35a7172f1397b303167dae964cf18e53db5e85fe248d000"},
- {file = "Django-3.0.tar.gz", hash = "sha256:d98c9b6e5eed147bc51f47c014ff6826bd1ab50b166956776ee13db5a58804ae"},
+ {file = "Django-3.1-py3-none-any.whl", hash = "sha256:1a63f5bb6ff4d7c42f62a519edc2adbb37f9b78068a5a862beff858b68e3dc8b"},
+ {file = "Django-3.1.tar.gz", hash = "sha256:2d390268a13c655c97e0e2ede9d117007996db692c1bb93eabebd4fb7ea7012b"},
]
django-appconf = [
{file = "django-appconf-1.0.5.tar.gz", hash = "sha256:be3db0be6c81fa84742000b89a81c016d70ae66a7ccb620cdef592b1f1a6aaa4"},
@@ -1359,8 +1359,8 @@ django-redis = [
{file = "django_redis-5.2.0-py3-none-any.whl", hash = "sha256:1d037dc02b11ad7aa11f655d26dac3fb1af32630f61ef4428860a2e29ff92026"},
]
django-registration = [
- {file = "django-registration-3.1.2.tar.gz", hash = "sha256:c9985f9ffd123534026bf5f39adb0b48fd7bf930b965f27f9a487d135f377ac6"},
- {file = "django_registration-3.1.2-py3-none-any.whl", hash = "sha256:dde525b08880da1d72b556f19dfd1c6588233a43f8bc354481f2d3e8896c44f8"},
+ {file = "django-registration-3.2.tar.gz", hash = "sha256:2ea8c7d89a8760ccde41dfd335aa28ba89073d09aab5a0f5f3d7c8c148fcc518"},
+ {file = "django_registration-3.2-py3-none-any.whl", hash = "sha256:e79fdbfa22bfaf4182efccb6604391391a7de19438d2669c5b9520a7708efbd2"},
]
docutils = [
{file = "docutils-0.18.1-py2.py3-none-any.whl", hash = "sha256:23010f129180089fbcd3bc08cfefccb3b890b0050e1ca00c867036e9d161b98c"},
diff --git a/pyproject.toml b/pyproject.toml
index bd76c464..1bea01aa 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -43,7 +43,7 @@ redis = "*"
requests-oauthlib = "*"
requests = "*"
whitenoise = "*"
-Django = "3.0"
+Django = "3.1"
Pillow = "*"
PyYAML = "*"
mysqlclient = "*"
From 7379dbf622551ec1fa1b33e7050715594fc6209f Mon Sep 17 00:00:00 2001
From: mike wakerly
Date: Thu, 14 Jul 2022 15:19:04 +0100
Subject: [PATCH 3/7] deps: update django 3.1 -> 3.2
---
poetry.lock | 32 ++++++++++++++++----------------
pykeg/settings.py | 2 ++
pyproject.toml | 2 +-
3 files changed, 19 insertions(+), 17 deletions(-)
diff --git a/poetry.lock b/poetry.lock
index d6e0a452..df065008 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -27,14 +27,14 @@ vine = ">=5.0.0"
[[package]]
name = "asgiref"
-version = "3.2.10"
+version = "3.5.2"
description = "ASGI specs, helper code, and adapters"
category = "main"
optional = false
-python-versions = ">=3.5"
+python-versions = ">=3.7"
[package.extras]
-tests = ["pytest", "pytest-asyncio"]
+tests = ["pytest", "pytest-asyncio", "mypy (>=0.800)"]
[[package]]
name = "async-timeout"
@@ -301,19 +301,19 @@ python-versions = "*"
[[package]]
name = "django"
-version = "3.1"
+version = "3.2"
description = "A high-level Python Web framework that encourages rapid development and clean, pragmatic design."
category = "main"
optional = false
python-versions = ">=3.6"
[package.dependencies]
-asgiref = ">=3.2.10,<3.3.0"
+asgiref = ">=3.3.2,<4"
pytz = "*"
sqlparse = ">=0.2.2"
[package.extras]
-argon2 = ["argon2-cffi (>=16.1.0)"]
+argon2 = ["argon2-cffi (>=19.1.0)"]
bcrypt = ["bcrypt"]
[[package]]
@@ -378,15 +378,15 @@ hiredis = ["redis[hiredis] (>=3,!=4.0.0,!=4.0.1)"]
[[package]]
name = "django-registration"
-version = "3.2"
+version = "3.3"
description = "An extensible user-registration application for Django"
category = "main"
optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
[package.dependencies]
confusable-homoglyphs = ">=3.0,<4.0"
-Django = ">=2.2,<3.0.0 || >=3.1.0"
+Django = ">=3.2"
[[package]]
name = "docutils"
@@ -1153,7 +1153,7 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"]
[metadata]
lock-version = "1.1"
python-versions = "^3.10.5"
-content-hash = "85d1b9d4a42699a2352dc991f49ec92d01de83a46f68e0ac946194b765635d09"
+content-hash = "a946e85e305e60f70a80cf29bb56b934feffbc514b5ca6b48035f530e8a7115e"
[metadata.files]
addict = [
@@ -1169,8 +1169,8 @@ amqp = [
{file = "amqp-5.1.1.tar.gz", hash = "sha256:2c1b13fecc0893e946c65cbd5f36427861cffa4ea2201d8f6fca22e2a373b5e2"},
]
asgiref = [
- {file = "asgiref-3.2.10-py3-none-any.whl", hash = "sha256:9fc6fb5d39b8af147ba40765234fa822b39818b12cc80b35ad9b0cef3a476aed"},
- {file = "asgiref-3.2.10.tar.gz", hash = "sha256:7e51911ee147dd685c3c8b805c0ad0cb58d360987b56953878f8c06d2d1c6f1a"},
+ {file = "asgiref-3.5.2-py3-none-any.whl", hash = "sha256:1d2880b792ae8757289136f1db2b7b99100ce959b2aa57fd69dab783d05afac4"},
+ {file = "asgiref-3.5.2.tar.gz", hash = "sha256:4a29362a6acebe09bf1d6640db38c1dc3d9217c68e6f9f6204d72667fc19a424"},
]
async-timeout = [
{file = "async-timeout-4.0.2.tar.gz", hash = "sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15"},
@@ -1335,8 +1335,8 @@ dj-email-url = [
{file = "dj_email_url-1.0.5-py2.py3-none-any.whl", hash = "sha256:64257c4f9d8139a4af8e5267229d32260e433fbf257b0cf8fc855bb0cc39ca7d"},
]
django = [
- {file = "Django-3.1-py3-none-any.whl", hash = "sha256:1a63f5bb6ff4d7c42f62a519edc2adbb37f9b78068a5a862beff858b68e3dc8b"},
- {file = "Django-3.1.tar.gz", hash = "sha256:2d390268a13c655c97e0e2ede9d117007996db692c1bb93eabebd4fb7ea7012b"},
+ {file = "Django-3.2-py3-none-any.whl", hash = "sha256:0604e84c4fb698a5e53e5857b5aea945b2f19a18f25f10b8748dbdf935788927"},
+ {file = "Django-3.2.tar.gz", hash = "sha256:21f0f9643722675976004eb683c55d33c05486f94506672df3d6a141546f389d"},
]
django-appconf = [
{file = "django-appconf-1.0.5.tar.gz", hash = "sha256:be3db0be6c81fa84742000b89a81c016d70ae66a7ccb620cdef592b1f1a6aaa4"},
@@ -1359,8 +1359,8 @@ django-redis = [
{file = "django_redis-5.2.0-py3-none-any.whl", hash = "sha256:1d037dc02b11ad7aa11f655d26dac3fb1af32630f61ef4428860a2e29ff92026"},
]
django-registration = [
- {file = "django-registration-3.2.tar.gz", hash = "sha256:2ea8c7d89a8760ccde41dfd335aa28ba89073d09aab5a0f5f3d7c8c148fcc518"},
- {file = "django_registration-3.2-py3-none-any.whl", hash = "sha256:e79fdbfa22bfaf4182efccb6604391391a7de19438d2669c5b9520a7708efbd2"},
+ {file = "django-registration-3.3.tar.gz", hash = "sha256:884a4cc9ec87b9f1c0ceb6b6c4b7ba491c1877997a3cd29cc923697dac785eb8"},
+ {file = "django_registration-3.3-py3-none-any.whl", hash = "sha256:dfa176f594fb465c93495caa55686be723a15829769511383e25172d2efbd0e6"},
]
docutils = [
{file = "docutils-0.18.1-py2.py3-none-any.whl", hash = "sha256:23010f129180089fbcd3bc08cfefccb3b890b0050e1ca00c867036e9d161b98c"},
diff --git a/pykeg/settings.py b/pykeg/settings.py
index 6c002760..df2697b0 100644
--- a/pykeg/settings.py
+++ b/pykeg/settings.py
@@ -291,3 +291,5 @@
# Override any user-specified timezone: As of Kegbot 0.9.12, this is
# specified in site settings.
TIME_ZONE = "UTC"
+
+DEFAULT_AUTO_FIELD = "django.db.models.AutoField"
diff --git a/pyproject.toml b/pyproject.toml
index 1bea01aa..94911178 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -43,7 +43,7 @@ redis = "*"
requests-oauthlib = "*"
requests = "*"
whitenoise = "*"
-Django = "3.1"
+Django = "3.2"
Pillow = "*"
PyYAML = "*"
mysqlclient = "*"
From 87101a78414d64747a7139021e8e1ebad9d59e50 Mon Sep 17 00:00:00 2001
From: mike wakerly
Date: Thu, 14 Jul 2022 15:37:32 +0100
Subject: [PATCH 4/7] chore: update url maps to use `path`/`re_path`
Required in Django 4.0
---
pykeg/web/account/urls.py | 24 +++---
pykeg/web/api/urls.py | 121 ++++++++++++++++---------------
pykeg/web/kbregistration/urls.py | 24 +++---
pykeg/web/kegadmin/urls.py | 88 +++++++++++-----------
pykeg/web/kegweb/urls.py | 48 ++++++------
pykeg/web/setup_wizard/urls.py | 16 ++--
pykeg/web/urls.py | 3 +-
7 files changed, 162 insertions(+), 162 deletions(-)
diff --git a/pykeg/web/account/urls.py b/pykeg/web/account/urls.py
index c8065b1a..f2fa3d78 100644
--- a/pykeg/web/account/urls.py
+++ b/pykeg/web/account/urls.py
@@ -1,24 +1,24 @@
-from django.conf.urls import url
from django.contrib.auth.views import PasswordChangeDoneView, PasswordChangeView
+from django.urls import path
from pykeg.plugin import util
from pykeg.web.account import views
urlpatterns = [
- url(r"^$", views.account_main, name="kb-account-main"),
- url(
- r"^activate/(?P[0-9a-zA-Z]+)/$",
+ path("", views.account_main, name="kb-account-main"),
+ path(
+ "activate//",
views.activate_account,
name="activate-account",
),
- url(r"^password/done/$", PasswordChangeDoneView.as_view(), name="password_change_done"),
- url(r"^password/$", PasswordChangeView.as_view(), name="password_change"),
- url(r"^profile/$", views.edit_profile, name="account-profile"),
- url(r"^invite/$", views.invite, name="account-invite"),
- url(r"^confirm-email/(?P.+)$", views.confirm_email, name="account-confirm-email"),
- url(r"^notifications/$", views.notifications, name="account-notifications"),
- url(r"^regenerate-api-key/$", views.regenerate_api_key, name="regen-api-key"),
- url(r"^plugin/(?P\w+)/$", views.plugin_settings, name="account-plugin-settings"),
+ path("password/done/", PasswordChangeDoneView.as_view(), name="password_change_done"),
+ path("password/", PasswordChangeView.as_view(), name="password_change"),
+ path("profile/", views.edit_profile, name="account-profile"),
+ path("invite/", views.invite, name="account-invite"),
+ path("confirm-email/", views.confirm_email, name="account-confirm-email"),
+ path("notifications/", views.notifications, name="account-notifications"),
+ path("regenerate-api-key/", views.regenerate_api_key, name="regen-api-key"),
+ path("plugin//", views.plugin_settings, name="account-plugin-settings"),
]
urlpatterns += util.get_account_urls()
diff --git a/pykeg/web/api/urls.py b/pykeg/web/api/urls.py
index 08b8aa56..165a493d 100644
--- a/pykeg/web/api/urls.py
+++ b/pykeg/web/api/urls.py
@@ -1,72 +1,73 @@
-from django.conf.urls import url
+from django.urls import path
from . import views
urlpatterns = [
# General endpoints
- url(r"^status/?$", views.get_status),
- url(r"^version/?$", views.get_version),
+ path("status/", views.get_status),
+ path("version/", views.get_version),
# API authorization
- url(r"^login/?$", views.login),
- url(r"^logout/?$", views.logout),
- url(r"^get-api-key/?$", views.get_api_key),
- url(r"^devices/link/?$", views.link_device_new),
- url(r"^devices/link/status/(?P[^/]+)?$", views.link_device_status),
+ path("login/", views.login),
+ path("logout/", views.logout),
+ path("get-api-key/", views.get_api_key),
+ path("devices/link/", views.link_device_new),
+ path("devices/link/status/", views.link_device_status),
+ path("devices/link/status/", views.link_device_status),
# Kegbot objects
- url(r"^auth-tokens/(?P[\w\.]+)/(?P\w+)/?$", views.get_auth_token),
- url(
- r"^auth-tokens/(?P[\w\.]+)/(?P\w+)/assign/?$",
+ path("auth-tokens///", views.get_auth_token),
+ path(
+ "auth-tokens///assign/",
views.assign_auth_token,
),
- url(r"^controllers/?$", views.all_controllers),
- url(r"^controllers/(?P\d+)/?$", views.get_controller),
- url(r"^drinks/?$", views.all_drinks),
- url(r"^drinks/last/?$", views.last_drink),
- url(r"^drinks/(?P\d+)/?$", views.get_drink),
- url(r"^drinks/(?P\d+)/add-photo/?$", views.add_drink_photo),
- url(r"^cancel-drink/?$", views.cancel_drink),
- url(r"^events/?$", views.all_events),
- url(r"^flow-meters/?$", views.all_flow_meters),
- url(r"^flow-meters/(?P\d+)/?$", views.get_flow_meter),
- url(r"^flow-toggles/?$", views.all_flow_toggles),
- url(r"^flow-toggles/(?P\d+)/?$", views.get_flow_toggle),
- url(r"^kegs/?$", views.all_kegs),
- url(r"^kegs/(?P\d+)/?$", views.get_keg),
- url(r"^kegs/(?P\d+)/end/?$", views.end_keg),
- url(r"^kegs/(?P\d+)/drinks/?$", views.get_keg_drinks),
- url(r"^kegs/(?P\d+)/events/?$", views.get_keg_events),
- url(r"^kegs/(?P\d+)/sessions/?$", views.get_keg_sessions),
- url(r"^kegs/(?P\d+)/stats/?$", views.get_keg_stats),
- url(r"^keg-sizes/?$", views.get_keg_sizes),
- url(r"^pictures/?$", views.pictures),
- url(r"^sessions/?$", views.all_sessions),
- url(r"^sessions/current/?$", views.current_session),
- url(r"^sessions/(?P\d+)/?$", views.get_session),
- url(r"^sessions/(?P\d+)/stats/?$", views.get_session_stats),
- url(r"^taps/?$", views.all_taps),
- url(r"^taps/(?P[\w\.-]+)/activate/?$", views.tap_activate),
- url(r"^taps/(?P[\w\.-]+)/calibrate/?$", views.tap_calibrate),
- url(r"^taps/(?P[\w\.-]+)/spill/?$", views.tap_spill),
- url(r"^taps/(?P[\w\.-]+)/connect-meter/?$", views.tap_connect_meter),
- url(r"^taps/(?P[\w\.-]+)/disconnect-meter/?$", views.tap_disconnect_meter),
- url(r"^taps/(?P[\w\.-]+)/connect-toggle/?$", views.tap_connect_toggle),
- url(r"^taps/(?P[\w\.-]+)/disconnect-toggle/?$", views.tap_disconnect_toggle),
- url(r"^taps/(?P[\w\.-]+)/?$", views.tap_detail),
- url(r"^thermo-sensors/?$", views.all_thermo_sensors),
- url(r"^thermo-sensors/(?P[^/]+)/?$", views.get_thermo_sensor),
- url(r"^thermo-sensors/(?P[^/]+)/logs/?$", views.get_thermo_sensor_logs),
- url(r"^taps/(?P[\w\.-]+)/connect-thermo/?$", views.tap_connect_thermo),
- url(r"^taps/(?P[\w\.-]+)/disconnect-thermo/?$", views.tap_disconnect_thermo),
- url(r"^users/?$", views.user_list),
- url(r"^users/(?P[\w@.+-_]+)/drinks/?$", views.get_user_drinks),
- url(r"^users/(?P[\w@.+-_]+)/events/?$", views.get_user_events),
- url(r"^users/(?P[\w@.+-_]+)/stats/?$", views.get_user_stats),
- url(r"^users/(?P[\w@.+-_]+)/photo/?$", views.user_photo),
- url(r"^users/(?P[\w@.+-_]+)/?$", views.get_user),
- url(r"^new-user/?$", views.register),
- url(r"^stats/?$", views.get_system_stats),
+ path("controllers/", views.all_controllers),
+ path("controllers/", views.get_controller),
+ path("drinks/", views.all_drinks),
+ path("drinks/last/", views.last_drink),
+ path("drinks//", views.get_drink),
+ path("drinks//add-photo/", views.add_drink_photo),
+ path("cancel-drink/", views.cancel_drink),
+ path("events/", views.all_events),
+ path("flow-meters/", views.all_flow_meters),
+ path("flow-meters//", views.get_flow_meter),
+ path("flow-toggles/", views.all_flow_toggles),
+ path("flow-toggles//", views.get_flow_toggle),
+ path("kegs/", views.all_kegs),
+ path("kegs//", views.get_keg),
+ path("kegs//end/", views.end_keg),
+ path("kegs//drinks/", views.get_keg_drinks),
+ path("kegs//events/", views.get_keg_events),
+ path("kegs//sessions/", views.get_keg_sessions),
+ path("kegs//stats/", views.get_keg_stats),
+ path("keg-sizes/", views.get_keg_sizes),
+ path("pictures/", views.pictures),
+ path("sessions/", views.all_sessions),
+ path("sessions/current/", views.current_session),
+ path("sessions//", views.get_session),
+ path("sessions//stats/", views.get_session_stats),
+ path("taps/", views.all_taps),
+ path("taps//activate/", views.tap_activate),
+ path("taps//calibrate/", views.tap_calibrate),
+ path("taps//spill/", views.tap_spill),
+ path("taps//connect-meter/", views.tap_connect_meter),
+ path("taps//disconnect-meter/", views.tap_disconnect_meter),
+ path("taps//connect-toggle/", views.tap_connect_toggle),
+ path("taps//disconnect-toggle/", views.tap_disconnect_toggle),
+ path("taps//", views.tap_detail),
+ path("thermo-sensors/", views.all_thermo_sensors),
+ path("thermo-sensors//", views.get_thermo_sensor),
+ path("thermo-sensors//logs/", views.get_thermo_sensor_logs),
+ path("taps//connect-thermo/", views.tap_connect_thermo),
+ path("taps//disconnect-thermo/", views.tap_disconnect_thermo),
+ path("users/", views.user_list),
+ path("users//drinks/", views.get_user_drinks),
+ path("users//events/", views.get_user_events),
+ path("users//stats/", views.get_user_stats),
+ path("users//photo/", views.user_photo),
+ path("users//", views.get_user),
+ path("new-user/", views.register),
+ path("stats/", views.get_system_stats),
# Deprecated endpoints
- url(r"^sound-events/?$", views.all_sound_events),
+ path("sound-events/", views.all_sound_events),
# Catch-all
- url(r"", views.default_handler),
+ path(r"", views.default_handler),
]
diff --git a/pykeg/web/kbregistration/urls.py b/pykeg/web/kbregistration/urls.py
index a070c6ae..56aee4d9 100644
--- a/pykeg/web/kbregistration/urls.py
+++ b/pykeg/web/kbregistration/urls.py
@@ -1,4 +1,3 @@
-from django.conf.urls import include, url
from django.contrib.auth.views import (
PasswordChangeDoneView,
PasswordChangeView,
@@ -7,30 +6,31 @@
PasswordResetDoneView,
PasswordResetView,
)
+from django.urls import include, path
from pykeg.web.kbregistration import views
from pykeg.web.kbregistration.forms import PasswordResetForm
urlpatterns = [
- url(r"^register/?$", views.register, name="registration_register"),
- url(r"^password/change/$", PasswordChangeView.as_view(), name="password_change"),
- url(r"^password/change/done/$", PasswordChangeDoneView.as_view(), name="password_change_done"),
- url(
- r"^password/reset/$",
+ path("register/", views.register, name="registration_register"),
+ path("password/change/", PasswordChangeView.as_view(), name="password_change"),
+ path("password/change/done/", PasswordChangeDoneView.as_view(), name="password_change_done"),
+ path(
+ "password/reset/",
PasswordResetView.as_view(),
kwargs={"password_reset_form": PasswordResetForm},
name="password_reset",
),
- url(r"^password/reset/done/$", PasswordResetDoneView.as_view(), name="password_reset_done"),
- url(
- r"^password/reset/complete/$",
+ path("password/reset/done/", PasswordResetDoneView.as_view(), name="password_reset_done"),
+ path(
+ "password/reset/complete/",
PasswordResetCompleteView.as_view(),
name="password_reset_complete",
),
- url(
- r"^password/reset/confirm/(?P[0-9A-Za-z]+)-(?P.+)/$",
+ path(
+ "password/reset/confirm/-/",
PasswordResetConfirmView.as_view(),
name="password_reset_confirm",
),
- url("", include("django.contrib.auth.urls")),
+ path("", include("django.contrib.auth.urls")),
]
diff --git a/pykeg/web/kegadmin/urls.py b/pykeg/web/kegadmin/urls.py
index 61fa2505..7bef86dd 100644
--- a/pykeg/web/kegadmin/urls.py
+++ b/pykeg/web/kegadmin/urls.py
@@ -1,62 +1,62 @@
-from django.conf.urls import url
+from django.urls import path
from pykeg.plugin import util
from pykeg.web.kegadmin import views
urlpatterns = [
# main page
- url(r"^$", views.dashboard, name="kegadmin-dashboard"),
- url(r"^settings/general/$", views.general_settings, name="kegadmin-main"),
- url(r"^settings/location/$", views.location_settings, name="kegadmin-location-settings"),
- url(r"^settings/advanced/$", views.advanced_settings, name="kegadmin-advanced-settings"),
- url(r"^bugreport/$", views.bugreport, name="kegadmin-bugreport"),
- url(r"^export/$", views.export, name="kegadmin-export"),
- url(r"^beers/$", views.beverages_list, name="kegadmin-beverages"),
- url(r"^beers/add/$", views.beverage_add, name="kegadmin-add-beverage"),
- url(r"^beers/(?P\d+)/$", views.beverage_detail, name="kegadmin-edit-beverage"),
- url(r"^devices/link/$", views.link_device, name="kegadmin-link-device"),
- url(r"^kegs/$", views.keg_list, name="kegadmin-kegs"),
- url(r"^kegs/online/$", views.keg_list_online, name="kegadmin-kegs-online"),
- url(r"^kegs/available/$", views.keg_list_available, name="kegadmin-kegs-available"),
- url(r"^kegs/kicked/$", views.keg_list_kicked, name="kegadmin-kegs-kicked"),
- url(r"^kegs/add/$", views.keg_add, name="kegadmin-add-keg"),
- url(r"^kegs/(?P\d+)/$", views.keg_detail, name="kegadmin-edit-keg"),
- url(r"^brewers/$", views.beverage_producer_list, name="kegadmin-beverage-producers"),
- url(r"^brewers/add/$", views.beverage_producer_add, name="kegadmin-add-beverage-producer"),
- url(
- r"^brewers/(?P\d+)/$",
+ path(r"", views.dashboard, name="kegadmin-dashboard"),
+ path("settings/general/", views.general_settings, name="kegadmin-main"),
+ path("settings/location/", views.location_settings, name="kegadmin-location-settings"),
+ path("settings/advanced/", views.advanced_settings, name="kegadmin-advanced-settings"),
+ path("bugreport/", views.bugreport, name="kegadmin-bugreport"),
+ path("export/", views.export, name="kegadmin-export"),
+ path("beers/", views.beverages_list, name="kegadmin-beverages"),
+ path("beers/add/", views.beverage_add, name="kegadmin-add-beverage"),
+ path("beers//", views.beverage_detail, name="kegadmin-edit-beverage"),
+ path("devices/link/", views.link_device, name="kegadmin-link-device"),
+ path("kegs/", views.keg_list, name="kegadmin-kegs"),
+ path("kegs/online/", views.keg_list_online, name="kegadmin-kegs-online"),
+ path("kegs/available/", views.keg_list_available, name="kegadmin-kegs-available"),
+ path("kegs/kicked/", views.keg_list_kicked, name="kegadmin-kegs-kicked"),
+ path("kegs/add/", views.keg_add, name="kegadmin-add-keg"),
+ path("kegs//", views.keg_detail, name="kegadmin-edit-keg"),
+ path("brewers/", views.beverage_producer_list, name="kegadmin-beverage-producers"),
+ path("brewers/add/", views.beverage_producer_add, name="kegadmin-add-beverage-producer"),
+ path(
+ "brewers//",
views.beverage_producer_detail,
name="kegadmin-edit-beverage-producer",
),
- url(r"^controllers/$", views.controller_list, name="kegadmin-controllers"),
- url(r"^controllers/create/$", views.add_controller, name="kegadmin-add-controller"),
- url(
- r"^controllers/(?P\d+)/$",
+ path("controllers/", views.controller_list, name="kegadmin-controllers"),
+ path("controllers/create/", views.add_controller, name="kegadmin-add-controller"),
+ path(
+ "controllers//",
views.controller_detail,
name="kegadmin-edit-controller",
),
- url(r"^taps/$", views.tap_list, name="kegadmin-taps"),
- url(r"^taps/create/$", views.add_tap, name="kegadmin-add-tap"),
- url(r"^taps/(?P\d+)/$", views.tap_detail, name="kegadmin-edit-tap"),
- url(r"^users/$", views.user_list, name="kegadmin-users"),
- url(r"^users/(?P\d+)/$", views.user_detail, name="kegadmin-edit-user"),
- url(r"^drinks/$", views.drink_list, name="kegadmin-drinks"),
- url(r"^drinks/(?P\d+)/$", views.drink_edit, name="kegadmin-edit-drink"),
- url(r"^tokens/$", views.token_list, name="kegadmin-tokens"),
- url(r"^tokens/create/$", views.add_token, name="kegadmin-add-token"),
- url(r"^tokens/(?P\d+)/$", views.token_detail, name="kegadmin-edit-token"),
- url(
- r"^autocomplete/beverage/$",
+ path("taps/", views.tap_list, name="kegadmin-taps"),
+ path("taps/create/", views.add_tap, name="kegadmin-add-tap"),
+ path("taps//", views.tap_detail, name="kegadmin-edit-tap"),
+ path("users/", views.user_list, name="kegadmin-users"),
+ path("users//", views.user_detail, name="kegadmin-edit-user"),
+ path("drinks/", views.drink_list, name="kegadmin-drinks"),
+ path("drinks//", views.drink_edit, name="kegadmin-edit-drink"),
+ path("tokens/", views.token_list, name="kegadmin-tokens"),
+ path("tokens/create/", views.add_token, name="kegadmin-add-token"),
+ path("tokens//", views.token_detail, name="kegadmin-edit-token"),
+ path(
+ "autocomplete/beverage/",
views.autocomplete_beverage,
name="kegadmin-autocomplete-beverage",
),
- url(r"^autocomplete/user/$", views.autocomplete_user, name="kegadmin-autocomplete-user"),
- url(r"^autocomplete/token/$", views.autocomplete_token, name="kegadmin-autocomplete-token"),
- url(r"^plugin/(?P\w+)/$", views.plugin_settings, name="kegadmin-plugin-settings"),
- url(r"^email/$", views.email, name="kegadmin-email"),
- url(r"^logs/$", views.logs, name="kegadmin-logs"),
- url(r"^users/create/$", views.add_user, name="kegadmin-add-user"),
- url(r"^system/$", views.system_status, name="kegadmin-system-status"),
+ path("autocomplete/user/", views.autocomplete_user, name="kegadmin-autocomplete-user"),
+ path("autocomplete/token/", views.autocomplete_token, name="kegadmin-autocomplete-token"),
+ path("plugin//", views.plugin_settings, name="kegadmin-plugin-settings"),
+ path("email/", views.email, name="kegadmin-email"),
+ path("logs/", views.logs, name="kegadmin-logs"),
+ path("users/create/", views.add_user, name="kegadmin-add-user"),
+ path("system/", views.system_status, name="kegadmin-system-status"),
]
if util.get_plugins():
diff --git a/pykeg/web/kegweb/urls.py b/pykeg/web/kegweb/urls.py
index 25004bb3..d60bdfd7 100644
--- a/pykeg/web/kegweb/urls.py
+++ b/pykeg/web/kegweb/urls.py
@@ -1,50 +1,50 @@
-from django.conf.urls import url
+from django.urls import path
from . import views
urlpatterns = [
# main page
- url(r"^$", views.index, name="kb-home"),
+ path("", views.index, name="kb-home"),
# stats
- url(r"^stats/$", views.system_stats, name="kb-stats"),
+ path("stats/", views.system_stats, name="kb-stats"),
# kegs
- url(r"^kegs/$", views.KegListView.as_view(), name="kb-kegs"),
- url(r"^kegs/(?P\d+)/?$", views.keg_detail, name="kb-keg"),
- url(r"^kegs/(?P\d+)/sessions/?$", views.keg_sessions, name="kb-keg-sessions"),
+ path("kegs/", views.KegListView.as_view(), name="kb-kegs"),
+ path("kegs//", views.keg_detail, name="kb-keg"),
+ path("kegs//sessions/", views.keg_sessions, name="kb-keg-sessions"),
# fullscreen mode
- url(r"^fullscreen/?$", views.fullscreen, name="kb-fullscreen"),
+ path("fullscreen/", views.fullscreen, name="kb-fullscreen"),
# drinkers
- url(r"^drinkers/(?P[\w@\.+\-_]+)/?$", views.user_detail, name="kb-drinker"),
- url(
- r"^drinkers/(?P[\w@\.+\-_]+)/sessions/?$",
+ path("drinkers//", views.user_detail, name="kb-drinker"),
+ path(
+ "drinkers//sessions/",
views.drinker_sessions,
name="kb-drinker-sessions",
),
# drinks
- url(r"^drinks/(?P\d+)/?$", views.drink_detail, name="kb-drink"),
- url(r"^drink/(?P\d+)/?$", views.short_drink_detail),
- url(r"^d/(?P\d+)/?$", views.short_drink_detail, name="kb-drink-short"),
+ path("drinks//", views.drink_detail, name="kb-drink"),
+ path("drink//", views.short_drink_detail),
+ path("d//", views.short_drink_detail, name="kb-drink-short"),
# sessions
- url(r"^session/(?P\d+)/?$", views.short_session_detail),
- url(r"^s/(?P\d+)/?$", views.short_session_detail, name="kb-session-short"),
- url(r"^sessions/$", views.SessionArchiveIndexView.as_view(), name="kb-sessions"),
- url(
- r"^sessions/(?P\d{4})/$",
+ path("session//", views.short_session_detail),
+ path("s//", views.short_session_detail, name="kb-session-short"),
+ path("sessions/", views.SessionArchiveIndexView.as_view(), name="kb-sessions"),
+ path(
+ "sessions//",
views.SessionYearArchiveView.as_view(),
name="kb-sessions-year",
),
- url(
- r"^sessions/(?P\d{4})/(?P\d+)/$",
+ path(
+ "sessions///",
views.SessionMonthArchiveView.as_view(month_format="%m"),
name="kb-sessions-month",
),
- url(
- r"^sessions/(?P\d{4})/(?P\d+)/(?P\d+)/$",
+ path(
+ "sessions////",
views.SessionDayArchiveView.as_view(month_format="%m"),
name="kb-sessions-day",
),
- url(
- r"^sessions/(?P\d+)/(?P\d+)/(?P\d+)/(?P\d+)/?$",
+ path(
+ "sessions/////",
views.SessionDateDetailView.as_view(month_format="%m"),
name="kb-session-detail",
),
diff --git a/pykeg/web/setup_wizard/urls.py b/pykeg/web/setup_wizard/urls.py
index 134ac80f..03c3d488 100644
--- a/pykeg/web/setup_wizard/urls.py
+++ b/pykeg/web/setup_wizard/urls.py
@@ -1,13 +1,13 @@
-from django.conf.urls import url
+from django.urls import path
from pykeg.web.setup_wizard import views
urlpatterns = [
- url(r"^$", views.start, name="setup_wizard_start"),
- url(r"^upgrade/$", views.upgrade, name="setup_upgrade"),
- url(r"^mode/$", views.mode, name="setup_mode"),
- url(r"^setup-accounts/$", views.setup_accounts, name="setup_accounts"),
- url(r"^settings/$", views.site_settings, name="setup_site_settings"),
- url(r"^admin-user/$", views.admin, name="setup_admin"),
- url(r"^finished/$", views.finish, name="setup_finish"),
+ path("", views.start, name="setup_wizard_start"),
+ path("upgrade/", views.upgrade, name="setup_upgrade"),
+ path("mode/", views.mode, name="setup_mode"),
+ path("setup-accounts/", views.setup_accounts, name="setup_accounts"),
+ path("settings/", views.site_settings, name="setup_site_settings"),
+ path("admin-user/", views.admin, name="setup_admin"),
+ path("finished/", views.finish, name="setup_finish"),
]
diff --git a/pykeg/web/urls.py b/pykeg/web/urls.py
index fcc68372..33351c7c 100644
--- a/pykeg/web/urls.py
+++ b/pykeg/web/urls.py
@@ -1,5 +1,4 @@
from django.conf import settings
-from django.conf.urls import url
from django.conf.urls.static import static
from django.contrib import admin
from django.urls import include, path, re_path
@@ -18,7 +17,7 @@
path("accounts/", include(kbregistration_urls)),
path("kegadmin/", include(kegadmin_urls)),
# Shortcuts
- url(r"^link/?$", RedirectView.as_view(pattern_name="kegadmin-link-device")),
+ path("link", RedirectView.as_view(pattern_name="kegadmin-link-device")),
]
if "pykeg.web.setup_wizard" in settings.INSTALLED_APPS:
From 39bf31d0df1c15712d1e3a20f4d712378f2b7fe8 Mon Sep 17 00:00:00 2001
From: mike wakerly
Date: Thu, 14 Jul 2022 15:55:58 +0100
Subject: [PATCH 5/7] chore: fix py3 warnings
---
pykeg/backend/backends_test.py | 8 +++----
pykeg/backend/signals.py | 22 ++++++++++----------
pykeg/core/fields.py | 2 +-
pykeg/core/management/commands/upgrade.py | 6 +++---
pykeg/core/models.py | 6 +++---
pykeg/core/util.py | 10 ++++-----
pykeg/core/util_test.py | 10 ++++-----
pykeg/web/kbregistration/forms.py | 2 +-
pykeg/web/setup_wizard/setup_wizard_tests.py | 6 +++---
9 files changed, 36 insertions(+), 36 deletions(-)
diff --git a/pykeg/backend/backends_test.py b/pykeg/backend/backends_test.py
index 201b6892..31aa1ec3 100644
--- a/pykeg/backend/backends_test.py
+++ b/pykeg/backend/backends_test.py
@@ -222,7 +222,7 @@ def test_keg_management(self):
new_keg = self.backend.start_keg(METER_NAME, beverage=beverage)
tap = models.KegTap.get_from_meter_name(METER_NAME)
self.assertIsNotNone(new_keg)
- self.assertNotEquals(new_keg, keg)
+ self.assertNotEqual(new_keg, keg)
self.assertTrue(tap.is_active())
self.assertTrue(new_keg.is_on_tap())
@@ -240,7 +240,7 @@ def test_keg_management(self):
)
self.assertEqual(new_keg_2.type.producer, keg.type.producer)
self.assertEqual(new_keg_2.type.style, keg.type.style)
- self.assertNotEquals(new_keg_2.type, keg.type)
+ self.assertNotEqual(new_keg_2.type, keg.type)
# New brewer, identical beer name == new beer type.
tap = models.KegTap.get_from_meter_name(METER_NAME)
@@ -252,9 +252,9 @@ def test_keg_management(self):
producer_name="Other Brewer",
style_name=FAKE_BEER_STYLE,
)
- self.assertNotEquals(new_keg_3.type.producer, keg.type.producer)
+ self.assertNotEqual(new_keg_3.type.producer, keg.type.producer)
self.assertEqual(new_keg_3.type.name, keg.type.name)
- self.assertNotEquals(new_keg_3.type, keg.type)
+ self.assertNotEqual(new_keg_3.type, keg.type)
def test_meters(self):
tap = models.KegTap.objects.all()[0]
diff --git a/pykeg/backend/signals.py b/pykeg/backend/signals.py
index 3207f7dd..e23961ea 100644
--- a/pykeg/backend/signals.py
+++ b/pykeg/backend/signals.py
@@ -2,24 +2,24 @@
from django.dispatch import Signal
-user_created = Signal(providing_args=["user"])
+user_created = Signal()
-tap_created = Signal(providing_args=["tap"])
+tap_created = Signal()
-auth_token_created = Signal(providing_args=["token"])
+auth_token_created = Signal()
-drink_recorded = Signal(providing_args=["drink"])
+drink_recorded = Signal()
-drink_canceled = Signal(providing_args=["drink"])
+drink_canceled = Signal()
-drink_assigned = Signal(providing_args=["drink", "previous_user"])
+drink_assigned = Signal()
-drink_adjusted = Signal(providing_args=["drink", "previous_volume"])
+drink_adjusted = Signal()
-temperature_recorded = Signal(providing_args=["record"])
+temperature_recorded = Signal()
-keg_created = Signal(providing_args=["keg"])
+keg_created = Signal()
-keg_attached = Signal(providing_args=["keg", "tap"])
+keg_attached = Signal()
-keg_ended = Signal(providing_args=["keg"])
+keg_ended = Signal()
diff --git a/pykeg/core/fields.py b/pykeg/core/fields.py
index 221c161e..3af57824 100644
--- a/pykeg/core/fields.py
+++ b/pykeg/core/fields.py
@@ -1,5 +1,5 @@
from django.db import models
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
# CountryField
# Source: http://www.djangosnippets.org/snippets/1281/
diff --git a/pykeg/core/management/commands/upgrade.py b/pykeg/core/management/commands/upgrade.py
index e6d06f53..b6bf483c 100644
--- a/pykeg/core/management/commands/upgrade.py
+++ b/pykeg/core/management/commands/upgrade.py
@@ -1,10 +1,10 @@
import sys
from builtins import str
-from distutils.version import StrictVersion
from django.contrib.staticfiles.management.commands import collectstatic
from django.core.management.base import BaseCommand
from django.core.management.commands import migrate
+from packaging.version import Version
from pykeg.core import models
from pykeg.core.management.commands import regen_stats
@@ -14,7 +14,7 @@
# v0.9.35 - migrations rebased to 0001
# v1.1.1 - last release with South-based migrations
# v1.2.0 - first Django 1.7 migrations
-MINIMUM_INSTALLED_VERSION = StrictVersion("1.1.1")
+MINIMUM_INSTALLED_VERSION = Version("1.1.1")
def run(cmd, args=[]):
@@ -104,5 +104,5 @@ def handle(self, *args, **options):
print("Upgrade complete!")
def do_version_upgrades(self, installed_version):
- if installed_version.version < (1, 2, 0):
+ if installed_version.release < (1, 2, 0):
print("Upgrading from v1.1.x")
diff --git a/pykeg/core/models.py b/pykeg/core/models.py
index 1aef7324..3a794127 100644
--- a/pykeg/core/models.py
+++ b/pykeg/core/models.py
@@ -8,7 +8,6 @@
import re
import urllib.parse
from builtins import object, str
-from distutils.version import StrictVersion
from uuid import uuid4
import pytz
@@ -24,9 +23,10 @@
from django.db.models.signals import post_save, pre_save
from django.urls import reverse, reverse_lazy
from django.utils import timezone
-from django.utils.translation import ugettext_lazy as _
+from django.utils.translation import gettext_lazy as _
from imagekit.models import ImageSpecField
from imagekit.processors import Adjust, resize
+from packaging.version import Version
from pykeg.backend import get_kegbot_backend
from pykeg.core import colors, fields, kb_common, keg_sizes, managers
@@ -337,7 +337,7 @@ def get_installed_version(cls):
rows = cls.objects.filter(name="default").values("server_version")
if not rows:
return None
- return StrictVersion(rows[0].get("server_version", "0.0.0"))
+ return Version(rows[0].get("server_version", "0.0.0"))
def get_stats(self):
return Stats.get_latest_for_view()
diff --git a/pykeg/core/util.py b/pykeg/core/util.py
index d11e3cd6..d57bcd0a 100644
--- a/pykeg/core/util.py
+++ b/pykeg/core/util.py
@@ -6,17 +6,17 @@
import logging
import os
import pkgutil
-import sys
import tempfile
from builtins import object, str
from collections import OrderedDict
from contextlib import closing
-from distutils.version import StrictVersion
from importlib import metadata as importlib_metadata
+from importlib.metadata import version
from threading import current_thread
import requests
from django.core.exceptions import ImproperlyConfigured
+from packaging.version import Version
from redis.exceptions import RedisError
logger = logging.getLogger(__name__)
@@ -28,18 +28,18 @@
def get_version():
try:
- return importlib_metadata.version("kegbot")
+ return version("kegbot")
except importlib_metadata.PackageNotFoundError:
return "0.0.0"
def get_version_object():
- return StrictVersion(get_version())
+ return Version(get_version())
def must_upgrade(installed_version, new_version):
# Compare major and minor (only).
- return installed_version.version[:2] < new_version.version[:2]
+ return installed_version.release[:2] < new_version.release[:2]
def should_upgrade(installed_verison, new_version):
diff --git a/pykeg/core/util_test.py b/pykeg/core/util_test.py
index 22596577..738c2517 100644
--- a/pykeg/core/util_test.py
+++ b/pykeg/core/util_test.py
@@ -1,9 +1,9 @@
"""Test for util module."""
from builtins import str
-from distutils.version import StrictVersion
from django.test import TestCase
+from packaging.version import Version
from pykeg.core import util
@@ -15,12 +15,12 @@ def test_get_version(self):
util.get_version_object()
except ValueError as e:
self.fail("Illegal version: " + str(e))
- self.assertTrue(util.get_version_object().version >= (0, 9, 23))
+ self.assertTrue(util.get_version_object().release >= (0, 9, 23))
def test_must_upgrade(self):
- v100 = StrictVersion("1.0.0")
- v101 = StrictVersion("1.0.1")
- v110 = StrictVersion("1.1.0")
+ v100 = Version("1.0.0")
+ v101 = Version("1.0.1")
+ v110 = Version("1.1.0")
self.assertTrue(util.should_upgrade(v100, v101))
self.assertFalse(util.should_upgrade(v100, v100))
diff --git a/pykeg/web/kbregistration/forms.py b/pykeg/web/kbregistration/forms.py
index 82d35922..cc6d7346 100644
--- a/pykeg/web/kbregistration/forms.py
+++ b/pykeg/web/kbregistration/forms.py
@@ -7,7 +7,7 @@
from django.template import loader
from django.utils.encoding import force_bytes
from django.utils.http import urlsafe_base64_encode
-from django.utils.translation import ugettext_lazy as _
+from django.utils.translation import gettext_lazy as _
try:
from django.contrib.auth import get_user_model
diff --git a/pykeg/web/setup_wizard/setup_wizard_tests.py b/pykeg/web/setup_wizard/setup_wizard_tests.py
index 2eea4e15..a541eaa0 100644
--- a/pykeg/web/setup_wizard/setup_wizard_tests.py
+++ b/pykeg/web/setup_wizard/setup_wizard_tests.py
@@ -19,7 +19,7 @@ def test_settings_debug_false(self):
self.assertNotContains(response, "Start Setup", status_code=403)
response = self.client.get("/setup/")
- self.failUnlessEqual(response.status_code, 404)
+ self.assertEqual(response.status_code, 404)
@override_settings(DEBUG=True)
def test_settings_debug_true(self):
@@ -30,7 +30,7 @@ def test_settings_debug_true(self):
self.assertContains(response, "Start Setup", status_code=403)
response = self.client.get("/setup/")
- self.failUnlessEqual(response.status_code, 200)
+ self.assertEqual(response.status_code, 200)
def test_setup_not_shown(self):
"""Verify wizard is not shown on set-up site."""
@@ -44,4 +44,4 @@ def test_setup_not_shown(self):
self.assertNotContains(response, "Start Setup", status_code=200)
response = self.client.get("/setup/")
- self.failUnlessEqual(response.status_code, 404)
+ self.assertEqual(response.status_code, 404)
From 6519329599958ff8e622681a7429784270cd8840 Mon Sep 17 00:00:00 2001
From: mike wakerly
Date: Thu, 14 Jul 2022 17:12:28 +0100
Subject: [PATCH 6/7] chore: revise trailing slash handling
Prior url definitions installed routes with a `r".../?$"` path regex, meaning the same
view would be served regardless of trailing slash presence.
With the previous change, we use `path(..)` in most places, which provides a convenient
shorthand for declaring path parameters (`` etc). However we can no longer
specify a regex in that shorthand.
This creates a new problem: Routes that formerly got a direct response, for example
`GET /api/events/`, now get a 404. This can break existing API clients, of which I'm
not sure how many there are, nor do I know their slash-or-not behaviors.
To get around this we install a new middleware, `PathRewriteMiddleware`, which rewrites
the internal path -- without redirecting -- when a trailing slash is found.
We only activate this for `/api/` routes since browsers will deal with 301s as needed
just fine.
---
pykeg/backend/backends_test.py | 8 +-
pykeg/notification/backends/email_test.py | 16 ++--
pykeg/settings.py | 2 +
pykeg/web/api/urls.py | 112 +++++++++++-----------
pykeg/web/kegweb/kegweb_test.py | 11 ++-
pykeg/web/middleware.py | 48 +++++++++-
6 files changed, 119 insertions(+), 78 deletions(-)
diff --git a/pykeg/backend/backends_test.py b/pykeg/backend/backends_test.py
index 31aa1ec3..63d0db74 100644
--- a/pykeg/backend/backends_test.py
+++ b/pykeg/backend/backends_test.py
@@ -289,17 +289,17 @@ def test_urls(self):
producer_name=FAKE_BREWER_NAME,
style_name=FAKE_BEER_STYLE,
)
- self.assertEqual("http://example.com:8000/kegs/{}".format(keg.id), keg.full_url())
+ self.assertEqual("http://example.com:8000/kegs/{}/".format(keg.id), keg.full_url())
drink = self.backend.record_drink(METER_NAME, ticks=1, volume_ml=100, photo="foo")
- self.assertEqual("http://example.com:8000/d/{}".format(drink.id), drink.short_url())
+ self.assertEqual("http://example.com:8000/d/{}/".format(drink.id), drink.short_url())
self.assertEqual(
- "http://example.com:8000/s/{}".format(drink.session.id), drink.session.short_url()
+ "http://example.com:8000/s/{}/".format(drink.session.id), drink.session.short_url()
)
start = drink.session.start_time
datepart = "{}/{}/{}".format(start.year, start.month, start.day)
self.assertEqual(
- "http://example.com:8000/sessions/{}/{}".format(datepart, drink.session.id),
+ "http://example.com:8000/sessions/{}/{}/".format(datepart, drink.session.id),
drink.session.full_url(),
)
diff --git a/pykeg/notification/backends/email_test.py b/pykeg/notification/backends/email_test.py
index 86e69497..ea3df126 100644
--- a/pykeg/notification/backends/email_test.py
+++ b/pykeg/notification/backends/email_test.py
@@ -50,7 +50,7 @@ def test_keg_tapped(self):
expected_body_plain = """A new keg of Unknown by Unknown was just tapped on My Kegbot!
-Track it here: http://localhost:1234/kegs/%s
+Track it here: http://localhost:1234/kegs/%s/
You are receiving this e-mail because you have notifications enabled
on My Kegbot. To change your settings, visit http://localhost:1234/account.""" % (
@@ -65,7 +65,7 @@ def test_keg_tapped(self):
-Track it here.
+Track it here.
@@ -104,7 +104,7 @@ def test_session_started(self):
expected_body_plain = """A new session was just kicked off on My Kegbot.
-You can follow the session here: http://localhost:1234/s/%s
+You can follow the session here: http://localhost:1234/s/%s/
You are receiving this e-mail because you have notifications enabled
on My Kegbot. To change your settings, visit http://localhost:1234/account.""" % (
@@ -118,7 +118,7 @@ def test_session_started(self):
-You can follow the session here.
+You can follow the session here.
@@ -161,7 +161,7 @@ def test_keg_volume_low(self):
expected_body_plain = """Keg %s (Unknown by Unknown) is 15.0%% full.
-See full statistics here: http://localhost:1234/kegs/%s
+See full statistics here: http://localhost:1234/kegs/%s/
You are receiving this e-mail because you have notifications enabled
on My Kegbot. To change your settings, visit http://localhost:1234/account.""" % (
@@ -176,7 +176,7 @@ def test_keg_volume_low(self):
-See full statistics here.
+See full statistics here.
@@ -215,7 +215,7 @@ def test_keg_ended(self):
expected_body_plain = """Keg %s of Unknown by Unknown was just finished on My Kegbot.
-See final statistics here: http://localhost:1234/kegs/%s
+See final statistics here: http://localhost:1234/kegs/%s/
You are receiving this e-mail because you have notifications enabled
on My Kegbot. To change your settings, visit http://localhost:1234/account.""" % (
@@ -231,7 +231,7 @@ def test_keg_ended(self):
-See final statistics here.
+See final statistics here.
diff --git a/pykeg/settings.py b/pykeg/settings.py
index df2697b0..0c077326 100644
--- a/pykeg/settings.py
+++ b/pykeg/settings.py
@@ -124,6 +124,8 @@
"django.middleware.security.SecurityMiddleware",
"whitenoise.middleware.WhiteNoiseMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
+ "pykeg.web.middleware.ErrorLoggingMiddleware",
+ "pykeg.web.middleware.PathRewriteMiddleware",
"pykeg.web.middleware.IsSetupMiddleware",
"pykeg.web.middleware.CurrentRequestMiddleware",
"pykeg.web.middleware.KegbotSiteMiddleware",
diff --git a/pykeg/web/api/urls.py b/pykeg/web/api/urls.py
index 165a493d..b56bbaf3 100644
--- a/pykeg/web/api/urls.py
+++ b/pykeg/web/api/urls.py
@@ -4,70 +4,70 @@
urlpatterns = [
# General endpoints
- path("status/", views.get_status),
- path("version/", views.get_version),
+ path("status", views.get_status),
+ path("version", views.get_version),
# API authorization
- path("login/", views.login),
- path("logout/", views.logout),
- path("get-api-key/", views.get_api_key),
- path("devices/link/", views.link_device_new),
- path("devices/link/status/", views.link_device_status),
+ path("login", views.login),
+ path("logout", views.logout),
+ path("get-api-key", views.get_api_key),
+ path("devices/link", views.link_device_new),
+ path("devices/link/status", views.link_device_status),
path("devices/link/status/", views.link_device_status),
# Kegbot objects
- path("auth-tokens///", views.get_auth_token),
+ path("auth-tokens//", views.get_auth_token),
path(
- "auth-tokens///assign/",
+ "auth-tokens///assign",
views.assign_auth_token,
),
- path("controllers/", views.all_controllers),
+ path("controllers", views.all_controllers),
path("controllers/", views.get_controller),
- path("drinks/", views.all_drinks),
- path("drinks/last/", views.last_drink),
- path("drinks//", views.get_drink),
- path("drinks//add-photo/", views.add_drink_photo),
- path("cancel-drink/", views.cancel_drink),
- path("events/", views.all_events),
- path("flow-meters/", views.all_flow_meters),
- path("flow-meters//", views.get_flow_meter),
- path("flow-toggles/", views.all_flow_toggles),
- path("flow-toggles//", views.get_flow_toggle),
- path("kegs/", views.all_kegs),
- path("kegs//", views.get_keg),
- path("kegs//end/", views.end_keg),
- path("kegs//drinks/", views.get_keg_drinks),
- path("kegs//events/", views.get_keg_events),
- path("kegs//sessions/", views.get_keg_sessions),
- path("kegs//stats/", views.get_keg_stats),
- path("keg-sizes/", views.get_keg_sizes),
- path("pictures/", views.pictures),
- path("sessions/", views.all_sessions),
- path("sessions/current/", views.current_session),
- path("sessions//", views.get_session),
- path("sessions//stats/", views.get_session_stats),
- path("taps/", views.all_taps),
- path("taps//activate/", views.tap_activate),
- path("taps//calibrate/", views.tap_calibrate),
- path("taps//spill/", views.tap_spill),
- path("taps//connect-meter/", views.tap_connect_meter),
- path("taps//disconnect-meter/", views.tap_disconnect_meter),
- path("taps//connect-toggle/", views.tap_connect_toggle),
- path("taps//disconnect-toggle/", views.tap_disconnect_toggle),
- path("taps//", views.tap_detail),
- path("thermo-sensors/", views.all_thermo_sensors),
- path("thermo-sensors//", views.get_thermo_sensor),
- path("thermo-sensors//logs/", views.get_thermo_sensor_logs),
- path("taps//connect-thermo/", views.tap_connect_thermo),
- path("taps//disconnect-thermo/", views.tap_disconnect_thermo),
- path("users/", views.user_list),
- path("users//drinks/", views.get_user_drinks),
- path("users//events/", views.get_user_events),
- path("users//stats/", views.get_user_stats),
- path("users//photo/", views.user_photo),
- path("users//", views.get_user),
- path("new-user/", views.register),
- path("stats/", views.get_system_stats),
+ path("drinks", views.all_drinks),
+ path("drinks/last", views.last_drink),
+ path("drinks/", views.get_drink),
+ path("drinks//add-photo", views.add_drink_photo),
+ path("cancel-drink", views.cancel_drink),
+ path("events", views.all_events),
+ path("flow-meters", views.all_flow_meters),
+ path("flow-meters/", views.get_flow_meter),
+ path("flow-toggles", views.all_flow_toggles),
+ path("flow-toggles/", views.get_flow_toggle),
+ path("kegs", views.all_kegs),
+ path("kegs/", views.get_keg),
+ path("kegs//end", views.end_keg),
+ path("kegs//drinks", views.get_keg_drinks),
+ path("kegs//events", views.get_keg_events),
+ path("kegs//sessions", views.get_keg_sessions),
+ path("kegs//stats", views.get_keg_stats),
+ path("keg-sizes", views.get_keg_sizes),
+ path("pictures", views.pictures),
+ path("sessions", views.all_sessions),
+ path("sessions/current", views.current_session),
+ path("sessions/", views.get_session),
+ path("sessions//stats", views.get_session_stats),
+ path("taps", views.all_taps),
+ path("taps//activate", views.tap_activate),
+ path("taps//calibrate", views.tap_calibrate),
+ path("taps//spill", views.tap_spill),
+ path("taps//connect-meter", views.tap_connect_meter),
+ path("taps//disconnect-meter", views.tap_disconnect_meter),
+ path("taps//connect-toggle", views.tap_connect_toggle),
+ path("taps//disconnect-toggle", views.tap_disconnect_toggle),
+ path("taps/", views.tap_detail),
+ path("thermo-sensors", views.all_thermo_sensors),
+ path("thermo-sensors/", views.get_thermo_sensor),
+ path("thermo-sensors//logs", views.get_thermo_sensor_logs),
+ path("taps//connect-thermo", views.tap_connect_thermo),
+ path("taps//disconnect-thermo", views.tap_disconnect_thermo),
+ path("users", views.user_list),
+ path("users//drinks", views.get_user_drinks),
+ path("users//events", views.get_user_events),
+ path("users//stats", views.get_user_stats),
+ path("users//photo", views.user_photo),
+ path("users/", views.get_user),
+ path("new-user", views.register),
+ path("stats", views.get_system_stats),
# Deprecated endpoints
- path("sound-events/", views.all_sound_events),
+ path("sound-events", views.all_sound_events),
# Catch-all
path(r"", views.default_handler),
]
diff --git a/pykeg/web/kegweb/kegweb_test.py b/pykeg/web/kegweb/kegweb_test.py
index 46ef581a..fde6e423 100644
--- a/pykeg/web/kegweb/kegweb_test.py
+++ b/pykeg/web/kegweb/kegweb_test.py
@@ -40,7 +40,7 @@ def testBasicEndpoints(self):
drink_id = d.id
response = self.client.get("/d/%s" % drink_id, follow=True)
- self.assertRedirects(response, "/drinks/%s" % drink_id, status_code=301)
+ self.assertRedirects(response, "/drinks/%s/" % drink_id, status_code=301)
session_id = d.session.id
response = self.client.get("/s/%s" % session_id, follow=True)
@@ -76,8 +76,8 @@ def test_privacy(self):
"/kegs/": "Keg List",
"/stats/": "System Stats",
"/sessions/": "All Sessions",
- "/kegs/{}".format(keg.id): "Keg {}".format(keg.id),
- "/drinks/{}".format(d.id): "Drink {}".format(d.id),
+ "/kegs/{}/".format(keg.id): "Keg {}".format(keg.id),
+ "/drinks/{}/".format(d.id): "Drink {}".format(d.id),
}
def test_urls(expect_fail, urls=urls):
@@ -234,8 +234,9 @@ def test_registration(self):
},
follow=False,
)
- print(response)
- self.assertContains(response, "The two password fields didn't match.", status_code=200)
+ self.assertContains(
+ response, "The two password fields didn't match.", status_code=200, html=True
+ )
@override_settings(EMAIL_BACKEND="django.core.mail.backends.locmem.EmailBackend")
@override_settings(DEFAULT_FROM_EMAIL="test-from@example")
diff --git a/pykeg/web/middleware.py b/pykeg/web/middleware.py
index 8a571aef..f5eb7239 100644
--- a/pykeg/web/middleware.py
+++ b/pykeg/web/middleware.py
@@ -1,5 +1,4 @@
import logging
-from builtins import object, str
from django.conf import settings
from django.http import HttpResponse
@@ -37,7 +36,7 @@ def _path_allowed(path, kbsite):
return False
-class CurrentRequestMiddleware(object):
+class CurrentRequestMiddleware:
"""Set/clear the current request."""
def __init__(self, get_response):
@@ -52,7 +51,46 @@ def __call__(self, request):
return response
-class IsSetupMiddleware(object):
+class ErrorLoggingMiddleware:
+ """Log uncaught exceptions to python logging."""
+
+ logger = logging.getLogger(__name__)
+
+ def __init__(self, get_response):
+ self.get_response = get_response
+
+ def __call__(self, request):
+ try:
+ response = self.get_response(request)
+ return response
+ except:
+ self.logger.exception("Server error")
+ raise
+
+
+class PathRewriteMiddleware:
+ """Rewrites `request.path` to ignore trailing slashes for /api/ requests.
+
+ Earlier versions of kegbot-server tolerated an optional trailing slash.
+ We don't want to define every API url as an `re_path(r".../?")`.
+
+ Rewrite `request.{path,path_info}` so that onward request handling always
+ sees a path as if the client presented no trailing slash.
+ """
+
+ def __init__(self, get_response):
+ self.get_response = get_response
+
+ def __call__(self, request):
+ if request.path.startswith("/api") and not getattr(request, "path_rewritten", None):
+ if request.path.endswith("/"):
+ request.path = request.path[:-1]
+ request.path_info = request.path_info[:-1]
+ request.path_rewritten = True
+ return self.get_response(request)
+
+
+class IsSetupMiddleware:
"""Adds `.need_setup`, `.need_upgrade`, and `.kbsite` to the request."""
def __init__(self, get_response):
@@ -123,7 +161,7 @@ def _upgrade_required(self, request):
return render(request, "setup_wizard/upgrade_required.html", context=context, status=403)
-class KegbotSiteMiddleware(object):
+class KegbotSiteMiddleware:
def __init__(self, get_response):
self.get_response = get_response
@@ -138,7 +176,7 @@ def __call__(self, request):
return self.get_response(request)
-class PrivacyMiddleware(object):
+class PrivacyMiddleware:
"""Enforces site privacy settings.
Must be installed after ApiRequestMiddleware (in request order) to
From a86a315a196634889049c631892d2755c01d9e8c Mon Sep 17 00:00:00 2001
From: mike wakerly
Date: Thu, 14 Jul 2022 17:13:11 +0100
Subject: [PATCH 7/7] tests: fix flaky api_test: make insensitive to exact row
ids
---
pykeg/web/api/api_test.py | 72 +++++++++++++++++++++++----------------
1 file changed, 43 insertions(+), 29 deletions(-)
diff --git a/pykeg/web/api/api_test.py b/pykeg/web/api/api_test.py
index 39cfc640..4cf06a72 100644
--- a/pykeg/web/api/api_test.py
+++ b/pykeg/web/api/api_test.py
@@ -3,7 +3,7 @@
from builtins import str
from django.core import mail
-from django.test import TransactionTestCase
+from django.test import TestCase
from django.test.utils import override_settings
from django.urls import reverse
@@ -19,7 +19,7 @@ def create_site():
return defaults.set_defaults(set_is_setup=True, create_controller=True)
-class BaseApiTestCase(TransactionTestCase):
+class BaseApiTestCase(TestCase):
def get(self, subpath, data={}, follow=False, **extra):
response = self.client.get("/api/%s" % subpath, data=data, follow=follow, **extra)
return response, kbjson.loads(response.content)
@@ -66,6 +66,8 @@ def setUp(self):
self.apikey = models.ApiKey.objects.create(user=self.admin, key="123")
self.bad_apikey = models.ApiKey.objects.create(user=self.normal_user, key="456")
+ self.tap = models.KegTap.objects.all().first()
+
def test_defaults(self):
empty_endpoints = ("events/", "kegs/")
for endpoint in empty_endpoints:
@@ -146,7 +148,7 @@ def test_api_access(self):
self.assertEqual(data.meta.result, "ok")
def test_record_drink(self):
- response, data = self.get("taps/1")
+ response, data = self.get(f"taps/{self.tap.id}")
self.assertEqual(data.meta.result, "ok")
self.assertEqual(data.object.get("current_keg"), None)
@@ -160,22 +162,22 @@ def test_record_drink(self):
"producer_name": "Test Producer",
"style_name": "Test Style,",
}
- response, data = self.post("taps/1/activate", data=new_keg_data)
+ response, data = self.post(f"taps/{self.tap.id}/activate", data=new_keg_data)
self.assertEqual(data.meta.result, "error")
self.assertEqual(data.error.code, "NoAuthTokenError")
response, data = self.post(
- "taps/1/activate", data=new_keg_data, HTTP_X_KEGBOT_API_KEY=self.apikey.key
+ f"taps/{self.tap.id}/activate", data=new_keg_data, HTTP_X_KEGBOT_API_KEY=self.apikey.key
)
self.assertEqual(data.meta.result, "ok")
self.assertIsNotNone(data.object.get("current_keg"))
- response, data = self.post("taps/1", data={"ticks": 1000})
+ response, data = self.post(f"taps/{self.tap.id}", data={"ticks": 1000})
self.assertEqual(data.meta.result, "error")
self.assertEqual(data.error.code, "NoAuthTokenError")
response, data = self.post(
- "taps/1",
+ f"taps/{self.tap.id}",
HTTP_X_KEGBOT_API_KEY=self.apikey.key,
data={"ticks": 1000, "username": self.normal_user.username},
)
@@ -202,13 +204,13 @@ def test_record_drink_usernames(self):
"style_name": "Test Style,",
}
response, data = self.post(
- "taps/1/activate", data=new_keg_data, HTTP_X_KEGBOT_API_KEY=self.apikey.key
+ f"taps/{self.tap.id}/activate", data=new_keg_data, HTTP_X_KEGBOT_API_KEY=self.apikey.key
)
self.assertEqual(data.meta.result, "ok")
models.User.objects.create(username="test.123")
response, data = self.post(
- "taps/1",
+ f"taps/{self.tap.id}",
HTTP_X_KEGBOT_API_KEY=self.apikey.key,
data={"ticks": 1000, "username": "test.123"},
)
@@ -267,10 +269,11 @@ def test_controller_data(self):
response, data = self.get("controllers", HTTP_X_KEGBOT_API_KEY=self.apikey.key)
self.assertEqual(data.meta.result, "ok")
+ controllers = models.Controller.objects.all()
expected = {
"objects": [
{
- "id": 1,
+ "id": controllers[0].id,
"name": "kegboard",
}
],
@@ -282,23 +285,24 @@ def test_controller_data(self):
response, data = self.get("flow-meters", HTTP_X_KEGBOT_API_KEY=self.apikey.key)
self.assertEqual(data.meta.result, "ok")
+ meters = models.FlowMeter.objects.all()
expected = {
"objects": [
{
- "id": 1,
+ "id": meters[0].id,
"ticks_per_ml": 2.724,
"port_name": "flow0",
"controller": {
- "id": 1,
+ "id": controllers[0].id,
"name": "kegboard",
},
"name": "kegboard.flow0",
},
{
- "id": 2,
+ "id": meters[1].id,
"ticks_per_ml": 2.724,
"port_name": "flow1",
- "controller": {"id": 1, "name": "kegboard"},
+ "controller": {"id": controllers[0].id, "name": "kegboard"},
"name": "kegboard.flow1",
},
],
@@ -308,21 +312,22 @@ def test_controller_data(self):
response, data = self.get("flow-toggles", HTTP_X_KEGBOT_API_KEY=self.apikey.key)
self.assertEqual(data.meta.result, "ok")
+ toggles = models.FlowToggle.objects.all()
expected = {
"objects": [
{
- "id": 1,
+ "id": toggles[0].id,
"port_name": "relay0",
"controller": {
- "id": 1,
+ "id": controllers[0].id,
"name": "kegboard",
},
"name": "kegboard.relay0",
},
{
- "id": 2,
+ "id": toggles[1].id,
"port_name": "relay1",
- "controller": {"id": 1, "name": "kegboard"},
+ "controller": {"id": controllers[0].id, "name": "kegboard"},
"name": "kegboard.relay1",
},
],
@@ -331,40 +336,49 @@ def test_controller_data(self):
self.assertEqual(expected, data)
def test_add_remove_meters(self):
- response, data = self.get("taps/1", HTTP_X_KEGBOT_API_KEY=self.apikey.key)
+ response, data = self.get(f"taps/{self.tap.id}", HTTP_X_KEGBOT_API_KEY=self.apikey.key)
self.assertEqual(data.meta.result, "ok")
- self.assertEqual(data.object.meter.id, 1)
+ meters = models.FlowMeter.objects.all()
+ self.assertEqual(data.object.meter.id, meters[0].id)
original_data = data
- response, data = self.post("taps/1/disconnect-meter", HTTP_X_KEGBOT_API_KEY=self.apikey.key)
+ response, data = self.post(
+ f"taps/{self.tap.id}/disconnect-meter", HTTP_X_KEGBOT_API_KEY=self.apikey.key
+ )
self.assertEqual(data.meta.result, "ok")
self.assertEqual(data.object.get("meter"), None)
response, data = self.post(
- "taps/1/connect-meter", HTTP_X_KEGBOT_API_KEY=self.apikey.key, data={"meter": 1}
+ f"taps/{self.tap.id}/connect-meter",
+ HTTP_X_KEGBOT_API_KEY=self.apikey.key,
+ data={"meter": meters[0].id},
)
self.assertEqual(data.meta.result, "ok")
- self.assertEqual(data.object.meter.id, 1)
+ meters = models.FlowMeter.objects.all()
+ self.assertEqual(data.object.meter.id, meters[0].id)
self.assertEqual(original_data, data)
def test_add_remove_toggles(self):
- response, data = self.get("taps/1", HTTP_X_KEGBOT_API_KEY=self.apikey.key)
+ response, data = self.get(f"taps/{self.tap.id}", HTTP_X_KEGBOT_API_KEY=self.apikey.key)
self.assertEqual(data.meta.result, "ok")
- self.assertEqual(data.object.toggle.id, 1)
+ toggles = models.FlowToggle.objects.all()
+ self.assertEqual(data.object.toggle.id, toggles[0].id)
response, data = self.post(
- "taps/1/disconnect-toggle", HTTP_X_KEGBOT_API_KEY=self.apikey.key
+ f"taps/{self.tap.id}/disconnect-toggle", HTTP_X_KEGBOT_API_KEY=self.apikey.key
)
self.assertEqual(data.meta.result, "ok")
self.assertEqual(data.object.get("toggle"), None)
response, data = self.post(
- "taps/1/connect-toggle", HTTP_X_KEGBOT_API_KEY=self.apikey.key, data={"toggle": 1}
+ f"taps/{self.tap.id}/connect-toggle",
+ HTTP_X_KEGBOT_API_KEY=self.apikey.key,
+ data={"toggle": toggles[0].id},
)
- response, data = self.get("taps/1", HTTP_X_KEGBOT_API_KEY=self.apikey.key)
+ response, data = self.get(f"taps/{self.tap.id}", HTTP_X_KEGBOT_API_KEY=self.apikey.key)
self.assertEqual(data.meta.result, "ok")
self.assertIsNotNone(data.object.get("toggle"))
- self.assertEqual(data.object.toggle.id, 1)
+ self.assertEqual(data.object.toggle.id, toggles[0].id)
def test_get_version(self):
response, data = self.get("version")