diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 31818be71..165de4765 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -62,3 +62,13 @@ repos: rev: v0.8.0.4 hooks: - id: shellcheck + + - repo: local + hooks: + - id: pwa-manifest.json + name: pwa-manifest.json + description: Sync pwa-manifest.json + entry: scripts/sync-pwa-manifest.sh + pass_filenames: false + language: script + files: pwa-manifest.json$ diff --git a/api/funkwhale_api/instance/pwa-manifest.json b/api/funkwhale_api/instance/pwa-manifest.json new file mode 100644 index 000000000..815076139 --- /dev/null +++ b/api/funkwhale_api/instance/pwa-manifest.json @@ -0,0 +1,48 @@ +{ + "name": "Funkwhale", + "categories": ["music", "entertainment"], + "short_name": "Funkwhale", + "description": "Your free and federated audio platform", + "icons": [ + { + "src": "android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "android-chrome-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "prefer_related_applications": true, + "related_applications": [ + { + "platform": "play", + "url": "https://play.google.com/store/apps/details?id=audio.funkwhale.ffa", + "id": "audio.funkwhale.ffa" + }, + { + "platform": "f-droid", + "url": "https://f-droid.org/en/packages/audio.funkwhale.ffa/", + "id": "audio.funkwhale.ffa" + } + ], + "shortcuts": [ + { + "name": "Search", + "url": "/search", + "icons": [] + }, + { + "name": "Library", + "url": "/library", + "icons": [] + }, + { + "name": "Channels", + "url": "/subscriptions", + "icons": [] + } + ] +} diff --git a/api/funkwhale_api/instance/views.py b/api/funkwhale_api/instance/views.py index 2a3e7010d..ffde3db4a 100644 --- a/api/funkwhale_api/instance/views.py +++ b/api/funkwhale_api/instance/views.py @@ -1,8 +1,8 @@ import json import logging +from pathlib import Path from cache_memoize import cache_memoize -from django.conf import settings from django.urls import reverse from django.utils.decorators import method_decorator from django.views.decorators.csrf import ensure_csrf_cookie @@ -14,7 +14,7 @@ from rest_framework import generics, views from rest_framework.response import Response from funkwhale_api import __version__ as funkwhale_version -from funkwhale_api.common import middleware, preferences +from funkwhale_api.common import preferences from funkwhale_api.common.renderers import ActivityStreamRenderer from funkwhale_api.federation.actors import get_service_actor from funkwhale_api.federation.models import Domain @@ -118,6 +118,10 @@ class NodeInfo(views.APIView): ) +PWA_MANIFEST_PATH = Path(__file__).parent / "pwa-manifest.json" +PWA_MANIFEST: dict = json.loads(PWA_MANIFEST_PATH.read_text(encoding="utf-8")) + + class SpaManifest(generics.GenericAPIView): permission_classes = [] authentication_classes = [] @@ -126,18 +130,15 @@ class SpaManifest(generics.GenericAPIView): @extend_schema(operation_id="get_spa_manifest") def get(self, request): - existing_manifest = middleware.get_spa_file( - settings.FUNKWHALE_SPA_HTML_ROOT, "manifest.json" - ) - parsed_manifest = json.loads(existing_manifest) + manifest = PWA_MANIFEST.copy() instance_name = preferences.get("instance__name") if instance_name: - parsed_manifest["short_name"] = instance_name - parsed_manifest["name"] = instance_name + manifest["short_name"] = instance_name + manifest["name"] = instance_name instance_description = preferences.get("instance__short_description") if instance_description: - parsed_manifest["description"] = instance_description - serializer = self.get_serializer(parsed_manifest) + manifest["description"] = instance_description + serializer = self.get_serializer(manifest) return Response( serializer.data, status=200, content_type="application/manifest+json" ) diff --git a/api/pyproject.toml b/api/pyproject.toml index ab94f224c..59ebc4766 100644 --- a/api/pyproject.toml +++ b/api/pyproject.toml @@ -14,9 +14,10 @@ packages = [ { include = "config" }, ] include = [ - { path = "*.txt" }, - { path = "*.png" }, - { path = "*.html" }, + { path = "*.html" }, + { path = "*.json" }, + { path = "*.png" }, + { path = "*.txt" }, ] exclude = ["tests"] diff --git a/api/tests/instance/test_views.py b/api/tests/instance/test_views.py index afb97ac77..f4a0d3d45 100644 --- a/api/tests/instance/test_views.py +++ b/api/tests/instance/test_views.py @@ -1,4 +1,4 @@ -import json +from unittest import mock from django.urls import reverse @@ -38,20 +38,21 @@ def test_admin_settings_correct_permission(db, logged_in_api_client, preferences assert len(response.data) == len(preferences.all()) -def test_manifest_endpoint(api_client, mocker, preferences, tmp_path, settings): - settings.FUNKWHALE_SPA_HTML_ROOT = str(tmp_path / "index.html") - preferences["instance__name"] = "Test pod" - preferences["instance__short_description"] = "Test description" - base_payload = {} - manifest = tmp_path / "manifest.json" - expected = { - "name": "Test pod", - "short_name": "Test pod", - "description": "Test description", - } - manifest.write_bytes(json.dumps(base_payload).encode()) +def test_manifest_endpoint(api_client, preferences): + with mock.patch( + "funkwhale_api.instance.views.PWA_MANIFEST", + {"lang": "unchanged"}, + ): + preferences["instance__name"] = "Test pod" + preferences["instance__short_description"] = "Test description" + expected = { + "lang": "unchanged", + "name": "Test pod", + "short_name": "Test pod", + "description": "Test description", + } - url = reverse("api:v1:instance:spa-manifest") - response = api_client.get(url) - assert response.status_code == 200 - assert response.data == expected + url = reverse("api:v1:instance:spa-manifest") + response = api_client.get(url) + assert response.status_code == 200 + assert response.data == expected diff --git a/changes/changelog.d/2006.bugfix b/changes/changelog.d/2006.bugfix new file mode 100644 index 000000000..3ac481a34 --- /dev/null +++ b/changes/changelog.d/2006.bugfix @@ -0,0 +1 @@ +Fix timeout on spa manifest requests diff --git a/front/pwa-manifest.json b/front/pwa-manifest.json new file mode 100644 index 000000000..815076139 --- /dev/null +++ b/front/pwa-manifest.json @@ -0,0 +1,48 @@ +{ + "name": "Funkwhale", + "categories": ["music", "entertainment"], + "short_name": "Funkwhale", + "description": "Your free and federated audio platform", + "icons": [ + { + "src": "android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "android-chrome-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "prefer_related_applications": true, + "related_applications": [ + { + "platform": "play", + "url": "https://play.google.com/store/apps/details?id=audio.funkwhale.ffa", + "id": "audio.funkwhale.ffa" + }, + { + "platform": "f-droid", + "url": "https://f-droid.org/en/packages/audio.funkwhale.ffa/", + "id": "audio.funkwhale.ffa" + } + ], + "shortcuts": [ + { + "name": "Search", + "url": "/search", + "icons": [] + }, + { + "name": "Library", + "url": "/library", + "icons": [] + }, + { + "name": "Channels", + "url": "/subscriptions", + "icons": [] + } + ] +} diff --git a/front/vite.config.ts b/front/vite.config.ts index 8045223b7..d9062160a 100644 --- a/front/vite.config.ts +++ b/front/vite.config.ts @@ -5,6 +5,8 @@ import VueI18n from '@intlify/vite-plugin-vue-i18n' import { VitePWA } from 'vite-plugin-pwa' import { resolve } from 'path' +import manifest from './pwa-manifest.json' + const port = +(process.env.VUE_PORT ?? 8080) // https://vitejs.dev/config/ @@ -35,56 +37,7 @@ export default defineConfig(({ mode }) => ({ type: 'module', navigateFallback: 'index.html' }, - manifest: { - name: 'Funkwhale', - categories: ['music', 'entertainment'], - start_url: undefined, - scope: undefined, - short_name: 'Funkwhale', - description: 'Your free and federated audio platform', - icons: [ - { - src: 'android-chrome-192x192.png', - sizes: '192x192', - type: 'image/png' - }, - { - src: 'android-chrome-512x512.png', - sizes: '512x512', - type: 'image/png' - } - ], - prefer_related_applications: true, - related_applications: [ - { - platform: 'play', - url: 'https://play.google.com/store/apps/details?id=audio.funkwhale.ffa', - id: 'audio.funkwhale.ffa' - }, - { - platform: 'f-droid', - url: 'https://f-droid.org/en/packages/audio.funkwhale.ffa/', - id: 'audio.funkwhale.ffa' - } - ], - shortcuts: [ - { - name: 'Search', - url: '/search', - icons: [] - }, - { - name: 'Library', - url: '/library', - icons: [] - }, - { - name: 'Channels', - url: '/subscriptions', - icons: [] - } - ] - } + manifest }) ], server: { diff --git a/scripts/sync-pwa-manifest.sh b/scripts/sync-pwa-manifest.sh new file mode 100755 index 000000000..3d549e24c --- /dev/null +++ b/scripts/sync-pwa-manifest.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +set -eu + +SRC="front/pwa-manifest.json" +DEST="api/funkwhale_api/instance/pwa-manifest.json" + +cp "$SRC" "$DEST"