diff --git a/CHANGELOG b/CHANGELOG index d010c076e34ef123fa2800eb7e541b9c8c3bd65b..c5928ced8afcf36b51a195e6196557253317ba47 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -12,6 +12,11 @@ Changelog - Front: Fixed broken redirection on login - Front: Fixed broken error handling on settings and login form +About page: + +There is a brand new about page on instances (/about), and instance +owner can now provide a name, a short and a long description for their instance via the admin (/api/admin/dynamic_preferences/globalpreferencemodel/). + Transcoding: Basic transcoding is now available to/from the following formats : ogg and mp3. diff --git a/api/funkwhale_api/instance/dynamic_preferences_registry.py b/api/funkwhale_api/instance/dynamic_preferences_registry.py index 1d93c383eb80372c507862a3b4f2e3450d792fca..1d11a2988ca1d76da7b61d8ef8657ac6cdee74df 100644 --- a/api/funkwhale_api/instance/dynamic_preferences_registry.py +++ b/api/funkwhale_api/instance/dynamic_preferences_registry.py @@ -1,8 +1,41 @@ +from django.forms import widgets + from dynamic_preferences import types from dynamic_preferences.registries import global_preferences_registry raven = types.Section('raven') +instance = types.Section('instance') + + +@global_preferences_registry.register +class InstanceName(types.StringPreference): + show_in_api = True + section = instance + name = 'name' + default = '' + help_text = 'Instance public name' + verbose_name = 'The public name of your instance' + +@global_preferences_registry.register +class InstanceShortDescription(types.StringPreference): + show_in_api = True + section = instance + name = 'short_description' + default = '' + verbose_name = 'Instance succinct description' + + +@global_preferences_registry.register +class InstanceLongDescription(types.StringPreference): + show_in_api = True + section = instance + name = 'long_description' + default = '' + help_text = 'Instance long description (markdown allowed)' + field_kwargs = { + 'widget': widgets.Textarea + } @global_preferences_registry.register class RavenDSN(types.StringPreference): diff --git a/api/tests/instance/test_preferences.py b/api/tests/instance/test_preferences.py index c89bfa3492091a93d0000f661bd83f2fc8ebedc0..beb8e6d33f810110c35ed14b164a76ed4c8bb019 100644 --- a/api/tests/instance/test_preferences.py +++ b/api/tests/instance/test_preferences.py @@ -1,3 +1,5 @@ +import pytest + from django.urls import reverse from dynamic_preferences.api import serializers @@ -20,3 +22,14 @@ def test_can_list_settings_via_api(preferences, api_client): for p in response.data: i = '__'.join([p['section'], p['name']]) assert i in expected_preferences + + +@pytest.mark.parametrize('pref,value', [ + ('instance__name', 'My instance'), + ('instance__short_description', 'For music lovers'), + ('instance__long_description', 'For real music lovers'), +]) +def test_instance_settings(pref, value, preferences): + preferences[pref] = value + + assert preferences[pref] == value diff --git a/front/src/App.vue b/front/src/App.vue index 98ad48d3ff41cd37cfa4df496c51c24f8dbd0544..8453aa33941813d6c451fa2184d05e7f9c669486 100644 --- a/front/src/App.vue +++ b/front/src/App.vue @@ -9,6 +9,9 @@ <div class="three wide column"> <h4 class="ui header">Links</h4> <div class="ui link list"> + <router-link class="item" to="/about"> + About this instance + </router-link> <a href="https://funkwhale.audio" class="item" target="_blank">Official website</a> <a href="https://docs.funkwhale.audio" class="item" target="_blank">Documentation</a> <a href="https://code.eliotberriot.com/funkwhale/funkwhale" class="item" target="_blank">Source code</a> diff --git a/front/src/components/About.vue b/front/src/components/About.vue new file mode 100644 index 0000000000000000000000000000000000000000..01ce6a294fdeb632d03e8eb23a4a4bbf83766223 --- /dev/null +++ b/front/src/components/About.vue @@ -0,0 +1,45 @@ +<template> + <div class="main pusher"> + <div class="ui vertical center aligned stripe segment"> + <div class="ui text container"> + <h1 class="ui huge header"> + <template v-if="instance.name.value">About {{ instance.name.value }}</template> + <template v-else="instance.name.value">About this instance</template> + </h1> + </div> + </div> + <div class="ui vertical stripe segment"> + <p v-if="!instance.short_description.value && !instance.long_description.value"> + Unfortunately, owners of this instance did not yet take the time to complete this page.</p> + <div + v-if="instance.short_description.value" + class="ui middle aligned stackable text container"> + <p>{{ instance.short_description.value }}</p> + </div> + <div + v-if="instance.long_description.value" + class="ui middle aligned stackable text container" + v-html="$options.filters.markdown(instance.long_description.value)"> + </div> + </div> + </div> +</template> + +<script> +import {mapState} from 'vuex' + +export default { + created () { + this.$store.dispatch('instance/fetchSettings') + }, + computed: { + ...mapState({ + instance: state => state.instance.settings.instance + }) + } +} +</script> + +<!-- Add "scoped" attribute to limit CSS to this component only --> +<style scoped> +</style> diff --git a/front/src/components/Home.vue b/front/src/components/Home.vue index dd324943feccf17c8e0a1e9a570c836b984cde7a..0cea1c25ab4361d019d6df6be7c4cdad4b1c43a5 100644 --- a/front/src/components/Home.vue +++ b/front/src/components/Home.vue @@ -6,6 +6,10 @@ Welcome on funkwhale </h1> <p>We think listening music should be simple.</p> + <router-link class="ui icon button" to="/about"> + <i class="info icon"></i> + Learn more about this instance + </router-link> <router-link class="ui icon teal button" to="/library"> Get me to the library <i class="right arrow icon"></i> diff --git a/front/src/router/index.js b/front/src/router/index.js index c1d03e059442ff98731bb903159d532b62ef4286..827afc21823687dc266a69c601435015757a9045 100644 --- a/front/src/router/index.js +++ b/front/src/router/index.js @@ -1,6 +1,7 @@ import Vue from 'vue' import Router from 'vue-router' import PageNotFound from '@/components/PageNotFound' +import About from '@/components/About' import Home from '@/components/Home' import Login from '@/components/auth/Login' import Signup from '@/components/auth/Signup' @@ -33,6 +34,11 @@ export default new Router({ name: 'index', component: Home }, + { + path: '/about', + name: 'about', + component: About + }, { path: '/login', name: 'login', diff --git a/front/src/store/instance.js b/front/src/store/instance.js index 80003db0dce3e1d27ff3de814a8149826dafd6db..a4dfcada65028f27a7fd4c61741b1f14d43d6dcd 100644 --- a/front/src/store/instance.js +++ b/front/src/store/instance.js @@ -6,6 +6,17 @@ export default { namespaced: true, state: { settings: { + instance: { + name: { + value: '' + }, + short_description: { + value: '' + }, + long_description: { + value: '' + } + }, users: { registration_enabled: { value: true @@ -40,7 +51,7 @@ export default { }) commit('settings', sections) if (payload && payload.callback) { - callback() + payload.callback() } }, response => { logger.default.error('Error while fetching settings', response.data)