From a972708334e7efa30475b029bc93ebbe47a48e03 Mon Sep 17 00:00:00 2001 From: petitminion Date: Sun, 4 Aug 2024 13:18:21 +0000 Subject: [PATCH] migrate frontend to api V2 (#2324) --- api/config/urls/__init__.py | 9 ++++++++- api/config/urls/api_v2.py | 16 +++++++++++++++ api/funkwhale_api/instance/urls_v2.py | 9 ++++++++- api/funkwhale_api/radios/urls_v2.py | 3 ++- changes/changelog.d/2324.enhancement | 1 + front/cypress/support/commands.ts | 2 +- front/src/components/AboutPod.vue | 20 +++++++++++++------ .../src/components/moderation/ReportModal.vue | 2 +- front/src/init/instance.ts | 6 +++--- front/src/store/instance.ts | 20 +++++++++++++------ front/src/views/ChooseInstance.vue | 2 +- front/src/views/admin/moderation/Base.vue | 2 +- 12 files changed, 70 insertions(+), 22 deletions(-) create mode 100644 changes/changelog.d/2324.enhancement diff --git a/api/config/urls/__init__.py b/api/config/urls/__init__.py index 257249b1f..1bb75b859 100644 --- a/api/config/urls/__init__.py +++ b/api/config/urls/__init__.py @@ -25,7 +25,14 @@ urlpatterns = [ ("funkwhale_api.federation.urls", "federation"), namespace="federation" ), ), - re_path(r"^api/v1/auth/", include("funkwhale_api.users.rest_auth_urls")), + re_path( + r"^api/v1/auth/", + include("funkwhale_api.users.rest_auth_urls"), + ), + re_path( + r"^api/v2/auth/", + include("funkwhale_api.users.rest_auth_urls"), + ), re_path(r"^accounts/", include("allauth.urls")), ] + plugins_patterns diff --git a/api/config/urls/api_v2.py b/api/config/urls/api_v2.py index a1d0befc8..1a2c05625 100644 --- a/api/config/urls/api_v2.py +++ b/api/config/urls/api_v2.py @@ -3,6 +3,8 @@ from django.urls import re_path from funkwhale_api.common import routers as common_routers +from . import api + router = common_routers.OptionalSlashRouter() v2_patterns = router.urls @@ -17,4 +19,18 @@ v2_patterns += [ ), ] +v2_paths = { + pattern.pattern.regex.pattern + for pattern in v2_patterns + if hasattr(pattern.pattern, "regex") +} + +filtered_v1_patterns = [ + pattern + for pattern in api.v1_patterns + if pattern.pattern.regex.pattern not in v2_paths +] + +v2_patterns += filtered_v1_patterns + urlpatterns = [re_path("", include((v2_patterns, "v2"), namespace="v2"))] diff --git a/api/funkwhale_api/instance/urls_v2.py b/api/funkwhale_api/instance/urls_v2.py index 3d4ed8b4e..e9d2f296d 100644 --- a/api/funkwhale_api/instance/urls_v2.py +++ b/api/funkwhale_api/instance/urls_v2.py @@ -1,7 +1,14 @@ from django.urls import re_path +from funkwhale_api.common import routers + from . import views +admin_router = routers.OptionalSlashRouter() +admin_router.register(r"admin/settings", views.AdminSettings, "admin-settings") + urlpatterns = [ re_path(r"^nodeinfo/2.1/?$", views.NodeInfo21.as_view(), name="nodeinfo-2.1"), -] + re_path(r"^settings/?$", views.InstanceSettings.as_view(), name="settings"), + re_path(r"^spa-manifest.json", views.SpaManifest.as_view(), name="spa-manifest"), +] + admin_router.urls diff --git a/api/funkwhale_api/radios/urls_v2.py b/api/funkwhale_api/radios/urls_v2.py index bac76f998..510b34b6c 100644 --- a/api/funkwhale_api/radios/urls_v2.py +++ b/api/funkwhale_api/radios/urls_v2.py @@ -5,6 +5,7 @@ from . import views router = routers.OptionalSlashRouter() router.register(r"sessions", views.V2_RadioSessionViewSet, "sessions") - +router.register(r"radios", views.RadioViewSet, "radios") +router.register(r"tracks", views.V1_RadioSessionTrackViewSet, "tracks") urlpatterns = router.urls diff --git a/changes/changelog.d/2324.enhancement b/changes/changelog.d/2324.enhancement new file mode 100644 index 000000000..c0e7c5f7f --- /dev/null +++ b/changes/changelog.d/2324.enhancement @@ -0,0 +1 @@ +Migrate frontend to api V2 (#2324) diff --git a/front/cypress/support/commands.ts b/front/cypress/support/commands.ts index f5036c174..18926018a 100644 --- a/front/cypress/support/commands.ts +++ b/front/cypress/support/commands.ts @@ -1,7 +1,7 @@ Cypress.Commands.add('login', () => { cy.fixture('testuser.json').then(({ username, password }) => { // We need to request a page that sets the csrf cookie - cy.request('/api/v1/instance/nodeinfo/2.0/') + cy.request('/api/v2/instance/nodeinfo/2.1/') cy.getCookie('csrftoken').then(($cookie) => { cy.request({ diff --git a/front/src/components/AboutPod.vue b/front/src/components/AboutPod.vue index 98d9b6c16..a4bbe09f6 100644 --- a/front/src/components/AboutPod.vue +++ b/front/src/components/AboutPod.vue @@ -22,12 +22,20 @@ const longDescription = useMarkdown(() => get(nodeinfo.value, 'metadata.longDesc const rules = useMarkdown(() => get(nodeinfo.value, 'metadata.rules', '')) const terms = useMarkdown(() => get(nodeinfo.value, 'metadata.terms', '')) const contactEmail = computed(() => get(nodeinfo.value, 'metadata.contactEmail')) -const anonymousCanListen = computed(() => get(nodeinfo.value, 'metadata.library.anonymousCanListen')) +const anonymousCanListen = computed(() => { + const features = get(nodeinfo.value, 'metadata.metadata.feature', []) as string[] + const hasAnonymousCanListen = features.includes('anonymousCanListen') + return hasAnonymousCanListen +}) const allowListEnabled = computed(() => get(nodeinfo.value, 'metadata.allowList.enabled')) const version = computed(() => get(nodeinfo.value, 'software.version')) const openRegistrations = computed(() => get(nodeinfo.value, 'openRegistrations')) const defaultUploadQuota = computed(() => get(nodeinfo.value, 'metadata.defaultUploadQuota')) -const federationEnabled = computed(() => get(nodeinfo.value, 'metadata.library.federationEnabled')) +const federationEnabled = computed(() => { + const features = get(nodeinfo.value, 'metadata.metadata.feature', []) as string[] + const hasAnonymousCanListen = features.includes('federation') + return hasAnonymousCanListen +}) const onDesktop = computed(() => window.innerWidth > 800) @@ -36,10 +44,10 @@ const stats = computed(() => { const data = { users: get(info, 'usage.users.activeMonth', null), - hours: get(info, 'metadata.library.music.hours', null), - artists: get(info, 'metadata.library.artists.total', null), - albums: get(info, 'metadata.library.albums.total', null), - tracks: get(info, 'metadata.library.tracks.total', null), + hours: get(info, 'metadata.content.local.hoursOfContent', null), + artists: get(info, 'metadata.content.local.artists.total', null), + albums: get(info, 'metadata.content.local.albums.total', null), + tracks: get(info, 'metadata.content.local.tracks.total', null), listenings: get(info, 'metadata.usage.listenings.total', null) } diff --git a/front/src/components/moderation/ReportModal.vue b/front/src/components/moderation/ReportModal.vue index 840f9d976..bd0496341 100644 --- a/front/src/components/moderation/ReportModal.vue +++ b/front/src/components/moderation/ReportModal.vue @@ -106,7 +106,7 @@ watchEffect(async () => { isLoadingReportTypes.value = true try { - const response = await axios.get('instance/nodeinfo/2.0/') + const response = await axios.get('instance/nodeinfo/2.1/') reportTypes.value = response.data.metadata.reportTypes ?? [] } catch (error) { store.commit('ui/addMessage', { diff --git a/front/src/init/instance.ts b/front/src/init/instance.ts index c2cd1c797..ef62e0677 100644 --- a/front/src/init/instance.ts +++ b/front/src/init/instance.ts @@ -15,12 +15,12 @@ export const install: InitModule = async ({ store, router }) => { const fetchNodeInfo = async () => { try { const [{ data }] = await Promise.all([ - axios.get('instance/nodeinfo/2.0/'), + axios.get('instance/nodeinfo/2.1/'), store.dispatch('instance/fetchSettings') ]) - if (data.metadata.library.music?.hours) { - data.metadata.library.music.hours = Math.floor(data.metadata.library.music.hours) + if (data.metadata.content?.local.hoursOfContent) { + data.metadata.content.local.hoursOfContent = Math.floor(data.metadata.content?.local.hoursOfContent) } store.commit('instance/nodeinfo', data) diff --git a/front/src/store/instance.ts b/front/src/store/instance.ts index 9bc117542..aa803daea 100644 --- a/front/src/store/instance.ts +++ b/front/src/store/instance.ts @@ -49,13 +49,20 @@ export interface NodeInfo { nodeName: string banner: string defaultUploadQuota: number - library: { + content: { federationEnabled: boolean anonymousCanListen: boolean - tracks?: TotalCount - artists?: TotalCount - albums?: TotalCount - music?: { hours: number } + local: { + tracks?: TotalCount + artists?: TotalCount + albums?: TotalCount + hoursOfContent?: number } + } + topMusicCategories: [] + topPodcastCategories: [] + federation: { + followedInstances: number + followingInstances: number } supportedUploadExtensions: string[] allowList: { @@ -79,6 +86,7 @@ export interface NodeInfo { listenings: TotalCount downloads: TotalCount } + features:[] } } @@ -223,7 +231,7 @@ const store: Module = { try { const { href } = new URL(value) state.instanceUrl = href - axios.defaults.baseURL = `${href}api/v1/` + axios.defaults.baseURL = `${href}api/v2/` // append the URL to the list (and remove existing one if needed) const index = state.knownInstances.indexOf(href) diff --git a/front/src/views/ChooseInstance.vue b/front/src/views/ChooseInstance.vue index 9214317f4..3daaef137 100644 --- a/front/src/views/ChooseInstance.vue +++ b/front/src/views/ChooseInstance.vue @@ -35,7 +35,7 @@ const checkAndSwitch = async (url: string) => { try { const instanceUrl = new URL(url.startsWith('https://') || url.startsWith('http://') ? url : `https://${url}`).origin - await axios.get(instanceUrl + '/api/v1/instance/nodeinfo/2.0/') + await axios.get(instanceUrl + '/api/v2/instance/nodeinfo/2.1/') store.commit('ui/addMessage', { content: t('views.ChooseInstance.message.newUrl', { url: instanceUrl }), diff --git a/front/src/views/admin/moderation/Base.vue b/front/src/views/admin/moderation/Base.vue index bbc741672..88afb504e 100644 --- a/front/src/views/admin/moderation/Base.vue +++ b/front/src/views/admin/moderation/Base.vue @@ -14,7 +14,7 @@ const labels = computed(() => ({ })) const fetchNodeInfo = async () => { - const response = await axios.get('instance/nodeinfo/2.0/') + const response = await axios.get('instance/nodeinfo/2.1/') allowListEnabled.value = get(response.data, 'metadata.allowList.enabled', false) }