From bae5d79ce8d18044e05edf09b3e9789c3723a085 Mon Sep 17 00:00:00 2001
From: "Edgar P. Burkhart"
Date: Sat, 14 Jun 2025 17:04:44 +0200
Subject: [PATCH 01/67] Add Celery configuration to settings and create Docker
Compose file for services
---
compose.yaml | 29 +++++++++++++++++++++++++++++
musik/settings.py | 2 ++
2 files changed, 31 insertions(+)
create mode 100644 compose.yaml
diff --git a/compose.yaml b/compose.yaml
new file mode 100644
index 0000000..1dadef9
--- /dev/null
+++ b/compose.yaml
@@ -0,0 +1,29 @@
+services:
+ musik:
+ image: code.edgarpierre.fr/edpibu/musik
+ container_name: musik
+ restart: unless-stopped
+ ports:
+ - 35001:8000
+ volumes:
+ - /docker/musik/config:/config
+ - /docker/musik/static:/app/static
+ environment:
+ CELERY_BROKER_URL: amqp://rabbitmq:5672//
+ depends_on:
+ - rabbitmq
+ - celery
+
+ celery:
+ image: code.edgarpierre.fr/edpibu/musik
+ container_name: musik_celery
+ restart: unless-stopped
+ command: uv run celery -A musik worker
+ environment:
+ CELERY_BROKER_URL: amqp://rabbitmq:5672//
+ depends_on:
+ - rabbitmq
+
+ rabbitmq:
+ image: rabbitmq
+ container_name: musik_rabbitmq
diff --git a/musik/settings.py b/musik/settings.py
index 370562b..61c9c8f 100644
--- a/musik/settings.py
+++ b/musik/settings.py
@@ -131,3 +131,5 @@ LOGIN_REDIRECT_URL = "/"
YOUTUBE_API_KEY = os.getenv("YOUTUBE_API_KEY", "")
YOUTUBE_OAUTH_SECRETS = os.getenv("YOUTUBE_OAUTH_SECRETS", "")
+
+CELERY_BROKER_URL = os.getenv("CELERY_BROKER_URL", None)
From ccf78c4820f005d2c679a8bc6c52616b6ed8490b Mon Sep 17 00:00:00 2001
From: "Edgar P. Burkhart"
Date: Sat, 14 Jun 2025 17:07:40 +0200
Subject: [PATCH 02/67] Update Docker Compose to mount config volume as
read-only
---
compose.yaml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/compose.yaml b/compose.yaml
index 1dadef9..95a2147 100644
--- a/compose.yaml
+++ b/compose.yaml
@@ -6,7 +6,7 @@ services:
ports:
- 35001:8000
volumes:
- - /docker/musik/config:/config
+ - /docker/musik/config:/config:ro
- /docker/musik/static:/app/static
environment:
CELERY_BROKER_URL: amqp://rabbitmq:5672//
From 46225701e43b770fa4efdf771a6d6ed03003c05d Mon Sep 17 00:00:00 2001
From: "Edgar P. Burkhart"
Date: Sat, 14 Jun 2025 17:09:13 +0200
Subject: [PATCH 03/67] Add env_file configuration for musik service in Docker
Compose
---
compose.yaml | 1 +
stack.env | 0
2 files changed, 1 insertion(+)
create mode 100644 stack.env
diff --git a/compose.yaml b/compose.yaml
index 95a2147..fe4cc9d 100644
--- a/compose.yaml
+++ b/compose.yaml
@@ -10,6 +10,7 @@ services:
- /docker/musik/static:/app/static
environment:
CELERY_BROKER_URL: amqp://rabbitmq:5672//
+ env_file: stack.env
depends_on:
- rabbitmq
- celery
diff --git a/stack.env b/stack.env
new file mode 100644
index 0000000..e69de29
From bcd3c723a8ad46d72f5c414c006da0ce47eaff2f Mon Sep 17 00:00:00 2001
From: "Edgar P. Burkhart"
Date: Sat, 14 Jun 2025 17:13:43 +0200
Subject: [PATCH 04/67] Update static volume path in Docker Compose
configuration
---
compose.yaml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/compose.yaml b/compose.yaml
index fe4cc9d..92f48f9 100644
--- a/compose.yaml
+++ b/compose.yaml
@@ -7,7 +7,7 @@ services:
- 35001:8000
volumes:
- /docker/musik/config:/config:ro
- - /docker/musik/static:/app/static
+ - /srv/musik/static:/app/static
environment:
CELERY_BROKER_URL: amqp://rabbitmq:5672//
env_file: stack.env
From 6046b7326ce6878fc5ded22a19d4d79cc81e7733 Mon Sep 17 00:00:00 2001
From: "Edgar P. Burkhart"
Date: Sat, 14 Jun 2025 17:19:36 +0200
Subject: [PATCH 05/67] Update DEBUG setting and configure allowed hosts in
settings.py
---
musik/settings.py | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/musik/settings.py b/musik/settings.py
index 61c9c8f..0471604 100644
--- a/musik/settings.py
+++ b/musik/settings.py
@@ -24,10 +24,11 @@ BASE_DIR = Path(__file__).resolve().parent.parent
SECRET_KEY = "django-insecure-&z*xu$^w8btr(%1!y#+0a98)l_q*+*6z54611pi678mdpsar_="
# SECURITY WARNING: don't run with debug turned on in production!
-DEBUG = True
+DEBUG = "DEBUG" in os.environ
-ALLOWED_HOSTS = []
-CSRF_TRUSTED_ORIGINS = ["https://localhost"]
+HOST = os.getenv("MUSIK_HOST", "localhost")
+ALLOWED_HOSTS = [HOST]
+CSRF_TRUSTED_ORIGINS = [f"https://{HOST}"]
# Application definition
From a0d6fb81cd5f0b1838be2d08aaeb0e1778a5e63f Mon Sep 17 00:00:00 2001
From: "Edgar P. Burkhart"
Date: Sat, 14 Jun 2025 17:24:10 +0200
Subject: [PATCH 06/67] Update static volume path in Docker Compose
configuration
---
compose.yaml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/compose.yaml b/compose.yaml
index 92f48f9..a4166dd 100644
--- a/compose.yaml
+++ b/compose.yaml
@@ -7,7 +7,7 @@ services:
- 35001:8000
volumes:
- /docker/musik/config:/config:ro
- - /srv/musik/static:/app/static
+ - /data/srv/musik/static:/app/static
environment:
CELERY_BROKER_URL: amqp://rabbitmq:5672//
env_file: stack.env
From fc1ec45ab4aef89ddcda22b78ea53a1ccf064fdc Mon Sep 17 00:00:00 2001
From: "Edgar P. Burkhart"
Date: Sat, 14 Jun 2025 17:37:37 +0200
Subject: [PATCH 07/67] Refactor YouTube authentication flow and update
settings for security enhancements
---
game/views.py | 34 +++++++++++++++++-----------------
musik/settings.py | 7 ++++++-
2 files changed, 23 insertions(+), 18 deletions(-)
diff --git a/game/views.py b/game/views.py
index 3c434a4..f6632f0 100644
--- a/game/views.py
+++ b/game/views.py
@@ -305,22 +305,6 @@ class GameDetailView(LoginRequiredMixin, DetailView):
)
-class YoutubeLoginView(LoginRequiredMixin, View):
- def get(self, request):
- flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
- settings.YOUTUBE_OAUTH_SECRETS,
- ["https://www.googleapis.com/auth/youtube.force-ssl"],
- )
- flow.redirect_uri = "https://localhost/youtube_callback/"
- auth_url, state = flow.authorization_url(
- access_type="offline",
- include_granted_scopes="true",
- prompt="consent",
- )
- self.request.session["state"] = state
- return redirect(auth_url)
-
-
class YoutubeCallbackView(LoginRequiredMixin, View):
def get(self, request):
if err := request.GET.get("error"):
@@ -335,7 +319,7 @@ class YoutubeCallbackView(LoginRequiredMixin, View):
["https://www.googleapis.com/auth/youtube.force-ssl"],
state=state,
)
- flow.redirect_uri = "https://localhost/youtube_callback/"
+ flow.redirect_uri = request.build_absolute_uri("/youtube_callback/")
flow.fetch_token(code=request.GET.get("code"))
@@ -358,6 +342,22 @@ class YoutubeCallbackView(LoginRequiredMixin, View):
return redirect("/")
+class YoutubeLoginView(LoginRequiredMixin, View):
+ def get(self, request):
+ flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
+ settings.YOUTUBE_OAUTH_SECRETS,
+ ["https://www.googleapis.com/auth/youtube.force-ssl"],
+ )
+ flow.redirect_uri = request.build_absolute_uri("/youtube_callback/")
+ auth_url, state = flow.authorization_url(
+ access_type="offline",
+ include_granted_scopes="true",
+ prompt="consent",
+ )
+ self.request.session["state"] = state
+ return redirect(auth_url)
+
+
class GroupClearBlacklistView(OwnerFilterMixin, SingleObjectMixin, View):
model = models.Group
diff --git a/musik/settings.py b/musik/settings.py
index 0471604..f4aac85 100644
--- a/musik/settings.py
+++ b/musik/settings.py
@@ -21,7 +21,10 @@ BASE_DIR = Path(__file__).resolve().parent.parent
# See https://docs.djangoproject.com/en/5.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
-SECRET_KEY = "django-insecure-&z*xu$^w8btr(%1!y#+0a98)l_q*+*6z54611pi678mdpsar_="
+SECRET_KEY = os.getenv(
+ "MUSIK_SECRET_KEY",
+ "django-insecure-&z*xu$^w8btr(%1!y#+0a98)l_q*+*6z54611pi678mdpsar_=",
+)
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = "DEBUG" in os.environ
@@ -29,6 +32,8 @@ DEBUG = "DEBUG" in os.environ
HOST = os.getenv("MUSIK_HOST", "localhost")
ALLOWED_HOSTS = [HOST]
CSRF_TRUSTED_ORIGINS = [f"https://{HOST}"]
+USE_X_FORWARDED_HOST = True
+SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
# Application definition
From c41c50e6730d32f8052d8572a8f617d228bf6884 Mon Sep 17 00:00:00 2001
From: "Edgar P. Burkhart"
Date: Sat, 14 Jun 2025 17:41:48 +0200
Subject: [PATCH 08/67] Update Docker Compose and settings for PostgreSQL
integration
---
compose.yaml | 6 +++++
musik/settings.py | 7 ++++--
pyproject.toml | 1 +
uv.lock | 58 +++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 70 insertions(+), 2 deletions(-)
diff --git a/compose.yaml b/compose.yaml
index a4166dd..06e1702 100644
--- a/compose.yaml
+++ b/compose.yaml
@@ -10,6 +10,7 @@ services:
- /data/srv/musik/static:/app/static
environment:
CELERY_BROKER_URL: amqp://rabbitmq:5672//
+ POSTGRES_HOST: postgres
env_file: stack.env
depends_on:
- rabbitmq
@@ -28,3 +29,8 @@ services:
rabbitmq:
image: rabbitmq
container_name: musik_rabbitmq
+
+ postgres:
+ image: postgres:17
+ container_name: musik_postgres
+ env_file: stack.env
diff --git a/musik/settings.py b/musik/settings.py
index f4aac85..f608bb0 100644
--- a/musik/settings.py
+++ b/musik/settings.py
@@ -84,8 +84,11 @@ WSGI_APPLICATION = "musik.wsgi.application"
DATABASES = {
"default": {
- "ENGINE": "django.db.backends.sqlite3",
- "NAME": BASE_DIR / "db.sqlite3",
+ "ENGINE": "django.db.backends.postgresql",
+ "HOST": os.getenv("POSTGRES_HOST", "localhost"),
+ "NAME": os.getenv("POSTGRES_DB", os.getenv("POSTGRES_USER", "musik")),
+ "USER": os.getenv("POSTGRES_USER", "musik"),
+ "PASSWORD": os.getenv("POSTGRES_PASSWORD"),
}
}
diff --git a/pyproject.toml b/pyproject.toml
index 204fa92..7656e66 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -12,6 +12,7 @@ dependencies = [
"google-auth-httplib2>=0.2.0",
"google-auth-oauthlib>=1.2.2",
"gunicorn>=23.0.0",
+ "psycopg[binary]>=3.2.9",
"requests>=2.32.4",
]
diff --git a/uv.lock b/uv.lock
index d4175cd..ce6f258 100644
--- a/uv.lock
+++ b/uv.lock
@@ -433,6 +433,7 @@ dependencies = [
{ name = "google-auth-httplib2" },
{ name = "google-auth-oauthlib" },
{ name = "gunicorn" },
+ { name = "psycopg", extra = ["binary"] },
{ name = "requests" },
]
@@ -451,6 +452,7 @@ requires-dist = [
{ name = "google-auth-httplib2", specifier = ">=0.2.0" },
{ name = "google-auth-oauthlib", specifier = ">=1.2.2" },
{ name = "gunicorn", specifier = ">=23.0.0" },
+ { name = "psycopg", extras = ["binary"], specifier = ">=3.2.9" },
{ name = "requests", specifier = ">=2.32.4" },
]
@@ -559,6 +561,53 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/f7/af/ab3c51ab7507a7325e98ffe691d9495ee3d3aa5f589afad65ec920d39821/protobuf-6.31.1-py3-none-any.whl", hash = "sha256:720a6c7e6b77288b85063569baae8536671b39f15cc22037ec7045658d80489e", size = 168724, upload-time = "2025-05-28T19:25:53.926Z" },
]
+[[package]]
+name = "psycopg"
+version = "3.2.9"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "typing-extensions", marker = "python_full_version < '3.13'" },
+ { name = "tzdata", marker = "sys_platform == 'win32'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/27/4a/93a6ab570a8d1a4ad171a1f4256e205ce48d828781312c0bbaff36380ecb/psycopg-3.2.9.tar.gz", hash = "sha256:2fbb46fcd17bc81f993f28c47f1ebea38d66ae97cc2dbc3cad73b37cefbff700", size = 158122, upload-time = "2025-05-13T16:11:15.533Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/44/b0/a73c195a56eb6b92e937a5ca58521a5c3346fb233345adc80fd3e2f542e2/psycopg-3.2.9-py3-none-any.whl", hash = "sha256:01a8dadccdaac2123c916208c96e06631641c0566b22005493f09663c7a8d3b6", size = 202705, upload-time = "2025-05-13T16:06:26.584Z" },
+]
+
+[package.optional-dependencies]
+binary = [
+ { name = "psycopg-binary", marker = "implementation_name != 'pypy'" },
+]
+
+[[package]]
+name = "psycopg-binary"
+version = "3.2.9"
+source = { registry = "https://pypi.org/simple" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/29/6f/ec9957e37a606cd7564412e03f41f1b3c3637a5be018d0849914cb06e674/psycopg_binary-3.2.9-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:be7d650a434921a6b1ebe3fff324dbc2364393eb29d7672e638ce3e21076974e", size = 4022205, upload-time = "2025-05-13T16:07:48.195Z" },
+ { url = "https://files.pythonhosted.org/packages/6b/ba/497b8bea72b20a862ac95a94386967b745a472d9ddc88bc3f32d5d5f0d43/psycopg_binary-3.2.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6a76b4722a529390683c0304501f238b365a46b1e5fb6b7249dbc0ad6fea51a0", size = 4083795, upload-time = "2025-05-13T16:07:50.917Z" },
+ { url = "https://files.pythonhosted.org/packages/42/07/af9503e8e8bdad3911fd88e10e6a29240f9feaa99f57d6fac4a18b16f5a0/psycopg_binary-3.2.9-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:96a551e4683f1c307cfc3d9a05fec62c00a7264f320c9962a67a543e3ce0d8ff", size = 4655043, upload-time = "2025-05-13T16:07:54.857Z" },
+ { url = "https://files.pythonhosted.org/packages/28/ed/aff8c9850df1648cc6a5cc7a381f11ee78d98a6b807edd4a5ae276ad60ad/psycopg_binary-3.2.9-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:61d0a6ceed8f08c75a395bc28cb648a81cf8dee75ba4650093ad1a24a51c8724", size = 4477972, upload-time = "2025-05-13T16:07:57.925Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/bd/8e9d1b77ec1a632818fe2f457c3a65af83c68710c4c162d6866947d08cc5/psycopg_binary-3.2.9-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad280bbd409bf598683dda82232f5215cfc5f2b1bf0854e409b4d0c44a113b1d", size = 4737516, upload-time = "2025-05-13T16:08:01.616Z" },
+ { url = "https://files.pythonhosted.org/packages/46/ec/222238f774cd5a0881f3f3b18fb86daceae89cc410f91ef6a9fb4556f236/psycopg_binary-3.2.9-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76eddaf7fef1d0994e3d536ad48aa75034663d3a07f6f7e3e601105ae73aeff6", size = 4436160, upload-time = "2025-05-13T16:08:04.278Z" },
+ { url = "https://files.pythonhosted.org/packages/37/78/af5af2a1b296eeca54ea7592cd19284739a844974c9747e516707e7b3b39/psycopg_binary-3.2.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:52e239cd66c4158e412318fbe028cd94b0ef21b0707f56dcb4bdc250ee58fd40", size = 3753518, upload-time = "2025-05-13T16:08:07.567Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/ac/8a3ed39ea069402e9e6e6a2f79d81a71879708b31cc3454283314994b1ae/psycopg_binary-3.2.9-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:08bf9d5eabba160dd4f6ad247cf12f229cc19d2458511cab2eb9647f42fa6795", size = 3313598, upload-time = "2025-05-13T16:08:09.999Z" },
+ { url = "https://files.pythonhosted.org/packages/da/43/26549af068347c808fbfe5f07d2fa8cef747cfff7c695136172991d2378b/psycopg_binary-3.2.9-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:1b2cf018168cad87580e67bdde38ff5e51511112f1ce6ce9a8336871f465c19a", size = 3407289, upload-time = "2025-05-13T16:08:12.66Z" },
+ { url = "https://files.pythonhosted.org/packages/67/55/ea8d227c77df8e8aec880ded398316735add8fda5eb4ff5cc96fac11e964/psycopg_binary-3.2.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:14f64d1ac6942ff089fc7e926440f7a5ced062e2ed0949d7d2d680dc5c00e2d4", size = 3472493, upload-time = "2025-05-13T16:08:15.672Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/02/6ff2a5bc53c3cd653d281666728e29121149179c73fddefb1e437024c192/psycopg_binary-3.2.9-cp312-cp312-win_amd64.whl", hash = "sha256:7a838852e5afb6b4126f93eb409516a8c02a49b788f4df8b6469a40c2157fa21", size = 2927400, upload-time = "2025-05-13T16:08:18.652Z" },
+ { url = "https://files.pythonhosted.org/packages/28/0b/f61ff4e9f23396aca674ed4d5c9a5b7323738021d5d72d36d8b865b3deaf/psycopg_binary-3.2.9-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:98bbe35b5ad24a782c7bf267596638d78aa0e87abc7837bdac5b2a2ab954179e", size = 4017127, upload-time = "2025-05-13T16:08:21.391Z" },
+ { url = "https://files.pythonhosted.org/packages/bc/00/7e181fb1179fbfc24493738b61efd0453d4b70a0c4b12728e2b82db355fd/psycopg_binary-3.2.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:72691a1615ebb42da8b636c5ca9f2b71f266be9e172f66209a361c175b7842c5", size = 4080322, upload-time = "2025-05-13T16:08:24.049Z" },
+ { url = "https://files.pythonhosted.org/packages/58/fd/94fc267c1d1392c4211e54ccb943be96ea4032e761573cf1047951887494/psycopg_binary-3.2.9-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25ab464bfba8c401f5536d5aa95f0ca1dd8257b5202eede04019b4415f491351", size = 4655097, upload-time = "2025-05-13T16:08:27.376Z" },
+ { url = "https://files.pythonhosted.org/packages/41/17/31b3acf43de0b2ba83eac5878ff0dea5a608ca2a5c5dd48067999503a9de/psycopg_binary-3.2.9-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e8aeefebe752f46e3c4b769e53f1d4ad71208fe1150975ef7662c22cca80fab", size = 4482114, upload-time = "2025-05-13T16:08:30.781Z" },
+ { url = "https://files.pythonhosted.org/packages/85/78/b4d75e5fd5a85e17f2beb977abbba3389d11a4536b116205846b0e1cf744/psycopg_binary-3.2.9-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b7e4e4dd177a8665c9ce86bc9caae2ab3aa9360b7ce7ec01827ea1baea9ff748", size = 4737693, upload-time = "2025-05-13T16:08:34.625Z" },
+ { url = "https://files.pythonhosted.org/packages/3b/95/7325a8550e3388b00b5e54f4ced5e7346b531eb4573bf054c3dbbfdc14fe/psycopg_binary-3.2.9-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7fc2915949e5c1ea27a851f7a472a7da7d0a40d679f0a31e42f1022f3c562e87", size = 4437423, upload-time = "2025-05-13T16:08:37.444Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/db/cef77d08e59910d483df4ee6da8af51c03bb597f500f1fe818f0f3b925d3/psycopg_binary-3.2.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a1fa38a4687b14f517f049477178093c39c2a10fdcced21116f47c017516498f", size = 3758667, upload-time = "2025-05-13T16:08:40.116Z" },
+ { url = "https://files.pythonhosted.org/packages/95/3e/252fcbffb47189aa84d723b54682e1bb6d05c8875fa50ce1ada914ae6e28/psycopg_binary-3.2.9-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5be8292d07a3ab828dc95b5ee6b69ca0a5b2e579a577b39671f4f5b47116dfd2", size = 3320576, upload-time = "2025-05-13T16:08:43.243Z" },
+ { url = "https://files.pythonhosted.org/packages/1c/cd/9b5583936515d085a1bec32b45289ceb53b80d9ce1cea0fef4c782dc41a7/psycopg_binary-3.2.9-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:778588ca9897b6c6bab39b0d3034efff4c5438f5e3bd52fda3914175498202f9", size = 3411439, upload-time = "2025-05-13T16:08:47.321Z" },
+ { url = "https://files.pythonhosted.org/packages/45/6b/6f1164ea1634c87956cdb6db759e0b8c5827f989ee3cdff0f5c70e8331f2/psycopg_binary-3.2.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f0d5b3af045a187aedbd7ed5fc513bd933a97aaff78e61c3745b330792c4345b", size = 3477477, upload-time = "2025-05-13T16:08:51.166Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/1d/bf54cfec79377929da600c16114f0da77a5f1670f45e0c3af9fcd36879bc/psycopg_binary-3.2.9-cp313-cp313-win_amd64.whl", hash = "sha256:2290bc146a1b6a9730350f695e8b670e1d1feb8446597bed0bbe7c3c30e0abcb", size = 2928009, upload-time = "2025-05-13T16:08:53.67Z" },
+]
+
[[package]]
name = "pyasn1"
version = "0.6.1"
@@ -735,6 +784,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2", size = 78540, upload-time = "2024-11-24T20:12:19.698Z" },
]
+[[package]]
+name = "typing-extensions"
+version = "4.14.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/d1/bc/51647cd02527e87d05cb083ccc402f93e441606ff1f01739a62c8ad09ba5/typing_extensions-4.14.0.tar.gz", hash = "sha256:8676b788e32f02ab42d9e7c61324048ae4c6d844a399eebace3d4979d75ceef4", size = 107423, upload-time = "2025-06-02T14:52:11.399Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/69/e0/552843e0d356fbb5256d21449fa957fa4eff3bbc135a74a691ee70c7c5da/typing_extensions-4.14.0-py3-none-any.whl", hash = "sha256:a1514509136dd0b477638fc68d6a91497af5076466ad0fa6c338e44e359944af", size = 43839, upload-time = "2025-06-02T14:52:10.026Z" },
+]
+
[[package]]
name = "tzdata"
version = "2025.2"
From 8ef2c6c310066b7367bd82b720ac7186a44bb234 Mon Sep 17 00:00:00 2001
From: "Edgar P. Burkhart"
Date: Sat, 14 Jun 2025 17:43:22 +0200
Subject: [PATCH 09/67] Add postgres to celery service dependencies in Docker
Compose
---
compose.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/compose.yaml b/compose.yaml
index 06e1702..f0df675 100644
--- a/compose.yaml
+++ b/compose.yaml
@@ -15,6 +15,7 @@ services:
depends_on:
- rabbitmq
- celery
+ - postgres
celery:
image: code.edgarpierre.fr/edpibu/musik
From fc2cd08b266e5fcb155f134328bf2c454f2ed2ea Mon Sep 17 00:00:00 2001
From: "Edgar P. Burkhart"
Date: Sat, 14 Jun 2025 17:50:03 +0200
Subject: [PATCH 10/67] Add env_file configuration for celery service in Docker
Compose
---
compose.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/compose.yaml b/compose.yaml
index f0df675..ab50ecb 100644
--- a/compose.yaml
+++ b/compose.yaml
@@ -24,6 +24,7 @@ services:
command: uv run celery -A musik worker
environment:
CELERY_BROKER_URL: amqp://rabbitmq:5672//
+ env_file: stack.env
depends_on:
- rabbitmq
From 3c401d4f7c08491dae049e300473d7aac8c1033a Mon Sep 17 00:00:00 2001
From: "Edgar P. Burkhart"
Date: Sat, 14 Jun 2025 17:53:35 +0200
Subject: [PATCH 11/67] Add print statement to output DATABASES configuration
for debugging
---
musik/settings.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/musik/settings.py b/musik/settings.py
index f608bb0..3ec7bc7 100644
--- a/musik/settings.py
+++ b/musik/settings.py
@@ -91,7 +91,7 @@ DATABASES = {
"PASSWORD": os.getenv("POSTGRES_PASSWORD"),
}
}
-
+print(DATABASES)
# Password validation
# https://docs.djangoproject.com/en/5.2/ref/settings/#auth-password-validators
From d8f60f40179c2972d784c18df9601acd697ffdaf Mon Sep 17 00:00:00 2001
From: "Edgar P. Burkhart"
Date: Sat, 14 Jun 2025 18:03:35 +0200
Subject: [PATCH 12/67] Remove print statement from DATABASES configuration and
ensure POSTGRES_HOST is set in celery service
---
compose.yaml | 1 +
musik/settings.py | 1 -
2 files changed, 1 insertion(+), 1 deletion(-)
diff --git a/compose.yaml b/compose.yaml
index ab50ecb..0510259 100644
--- a/compose.yaml
+++ b/compose.yaml
@@ -24,6 +24,7 @@ services:
command: uv run celery -A musik worker
environment:
CELERY_BROKER_URL: amqp://rabbitmq:5672//
+ POSTGRES_HOST: postgres
env_file: stack.env
depends_on:
- rabbitmq
diff --git a/musik/settings.py b/musik/settings.py
index 3ec7bc7..b12b987 100644
--- a/musik/settings.py
+++ b/musik/settings.py
@@ -91,7 +91,6 @@ DATABASES = {
"PASSWORD": os.getenv("POSTGRES_PASSWORD"),
}
}
-print(DATABASES)
# Password validation
# https://docs.djangoproject.com/en/5.2/ref/settings/#auth-password-validators
From bf8161a7fbfc022b0cd87214345c5826c1da4e22 Mon Sep 17 00:00:00 2001
From: "Edgar P. Burkhart"
Date: Sat, 14 Jun 2025 18:11:58 +0200
Subject: [PATCH 13/67] Add volume configuration for PostgreSQL service in
Docker Compose
---
compose.yaml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/compose.yaml b/compose.yaml
index 0510259..04838ec 100644
--- a/compose.yaml
+++ b/compose.yaml
@@ -37,3 +37,5 @@ services:
image: postgres:17
container_name: musik_postgres
env_file: stack.env
+ volumes:
+ - /docker/musik/postgres:/var/lib/postgresql/data
From 3069aab3f97b7ded13ed437012c736549c3074f5 Mon Sep 17 00:00:00 2001
From: "Edgar P. Burkhart"
Date: Sat, 14 Jun 2025 18:14:33 +0200
Subject: [PATCH 14/67] Add delete group link to group detail page and update
group creation header
---
game/templates/game/group_detail.html | 4 ++++
game/templates/game/group_form.html | 3 ---
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/game/templates/game/group_detail.html b/game/templates/game/group_detail.html
index 9931d35..b6f48d8 100644
--- a/game/templates/game/group_detail.html
+++ b/game/templates/game/group_detail.html
@@ -25,6 +25,10 @@
formaction="{% url "group_clear_blacklist" pk=group.pk %}">
Effacer la blacklist
+
+ Supprimer
diff --git a/game/templates/game/group_form.html b/game/templates/game/group_form.html
index 72ae8d9..ef6da8c 100644
--- a/game/templates/game/group_form.html
+++ b/game/templates/game/group_form.html
@@ -5,9 +5,6 @@
{{ group.name }}
-
- Supprimer le groupe
-
{% else %}
Créer un groupe
{% endif %}
From fbe24915fe4e5b6b7a46eacb3e1637a57b7f9208 Mon Sep 17 00:00:00 2001
From: "Edgar P. Burkhart"
Date: Sat, 14 Jun 2025 18:25:24 +0200
Subject: [PATCH 15/67] Update signup view to use reverse_lazy for success URL
---
base/views.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/base/views.py b/base/views.py
index e3618a0..29eb8b3 100644
--- a/base/views.py
+++ b/base/views.py
@@ -1,5 +1,6 @@
from django.contrib.auth.models import User
from django.contrib.messages.views import SuccessMessageMixin
+from django.urls import reverse_lazy
from django.views.generic.base import TemplateView
from django.views.generic.edit import CreateView
@@ -13,5 +14,5 @@ class HomePageView(TemplateView):
class SignupView(SuccessMessageMixin, CreateView):
model = User
form_class = forms.UserSignupForm
- success_url = "/"
+ success_url = reverse_lazy("login")
success_message = "Le compte %(username)s a été créé avec succès."
From ac07607dd0208a932b0b96af7537d771d15d6886 Mon Sep 17 00:00:00 2001
From: "Edgar P. Burkhart"
Date: Sat, 14 Jun 2025 19:00:01 +0200
Subject: [PATCH 16/67] Add privacy policy page and update URLs configuration
---
base/templates/privacy.html | 21 +++++++++++++++++++++
base/urls.py | 2 ++
2 files changed, 23 insertions(+)
create mode 100644 base/templates/privacy.html
diff --git a/base/templates/privacy.html b/base/templates/privacy.html
new file mode 100644
index 0000000..8e78465
--- /dev/null
+++ b/base/templates/privacy.html
@@ -0,0 +1,21 @@
+{% extends "base.html" %}
+{% block content %}
+ Mentions légales
+ Éditeur
+
+ Ce site est réalisé et hébergé par Edgar P. Burkhart .
+
+ Données Personnelles
+
+ Dans le cadre de la création d'un compte, un nom d'utilisateur, une adresse email et un mot de passe sont requis.
+ Ces données sont stockées dans le seul but de permettre la connexion et la réinitialisation du mot de passe de l'utilisateur (dans le cas de l'adresse mail).
+
+
+ La connexion à un compte Youtube est utilisée pour permettre la génération automatique de playlists, et sa suppression le cas échéant.
+ Elle n'est pas requise pour l'utilisation de Musik.
+ Youtube est une marque de Google LLC.
+
+
+ La suppression des données stockée par le service Musik pour son utilisation peut être demandée par email à Edgar P. Burkhart .
+
+{% endblock content %}
diff --git a/base/urls.py b/base/urls.py
index 2a6b2d5..e46107f 100644
--- a/base/urls.py
+++ b/base/urls.py
@@ -1,4 +1,5 @@
from django.urls import include, path
+from django.views.generic import TemplateView
from . import views
@@ -6,4 +7,5 @@ urlpatterns = [
path("", views.HomePageView.as_view(), name="index"),
path("accounts/signup/", views.SignupView.as_view(), name="signup"),
path("accounts/", include("django.contrib.auth.urls")),
+ path("legal/", TemplateView.as_view(template_name="privacy.html")),
]
From 5c99306f7429fcdd3fe5a5dc30dd75b9a8aad60f Mon Sep 17 00:00:00 2001
From: "Edgar P. Burkhart"
Date: Sat, 14 Jun 2025 19:05:53 +0200
Subject: [PATCH 17/67] Add footer template and include it in base and hero
templates; update legal URL path
Signed-off-by: Edgar P. Burkhart
---
base/static/css/main.css | 6 ++++++
base/templates/base.html | 3 +++
base/templates/footer.html | 1 +
base/templates/hero.html | 7 +++++--
base/urls.py | 2 +-
5 files changed, 16 insertions(+), 3 deletions(-)
create mode 100644 base/templates/footer.html
diff --git a/base/static/css/main.css b/base/static/css/main.css
index c329a18..99b0900 100644
--- a/base/static/css/main.css
+++ b/base/static/css/main.css
@@ -91,6 +91,7 @@ article.message {
color-mix(in hsl, var(--pico-primary-background) 10%, var(--pico-background-color)) 80%,
var(--pico-background-color));
display: grid;
+ grid-template-rows: 1fr min-content;
align-items: center;
padding: 4rem;
@@ -116,3 +117,8 @@ h6,
i.i {
margin-right: .5em;
}
+
+footer {
+ text-align: center;
+ font-weight: 350;
+}
diff --git a/base/templates/base.html b/base/templates/base.html
index 8e677eb..8c84913 100644
--- a/base/templates/base.html
+++ b/base/templates/base.html
@@ -68,6 +68,9 @@
{% block content %}
{% endblock content %}
+
+ {% include "footer.html" %}
+
{% endblock body %}