Commit 9745b57f authored by Eliot Berriot's avatar Eliot Berriot
Browse files

Merge branch '236-default-permission' into 'develop'

Resolve "Implement default permissions for logged in users"

Closes #236

See merge request funkwhale/funkwhale!213
parents c6cd3abf e9fc220e
from django.conf import settings
from django import forms
from dynamic_preferences import serializers
from dynamic_preferences import types
from dynamic_preferences.registries import global_preferences_registry
......@@ -10,3 +14,38 @@ class DefaultFromSettingMixin(object):
def get(pref):
manager = global_preferences_registry.manager()
return manager[pref]
class StringListSerializer(serializers.BaseSerializer):
separator = ','
sort = True
@classmethod
def to_db(cls, value, **kwargs):
if not value:
return
if type(value) not in [list, tuple]:
raise cls.exception(
"Cannot serialize, value {} is not a list or a tuple".format(
value))
if cls.sort:
value = sorted(value)
return cls.separator.join(value)
@classmethod
def to_python(cls, value, **kwargs):
if not value:
return []
return value.split(',')
class StringListPreference(types.BasePreferenceType):
serializer = StringListSerializer
field_class = forms.MultipleChoiceField
def get_api_additional_data(self):
d = super(StringListPreference, self).get_api_additional_data()
d['choices'] = self.get('choices')
return d
from dynamic_preferences import types
from dynamic_preferences.registries import global_preferences_registry
from funkwhale_api.common import preferences as common_preferences
from . import models
users = types.Section('users')
......@@ -14,3 +18,23 @@ class RegistrationEnabled(types.BooleanPreference):
help_text = (
'When enabled, new users will be able to register on this instance.'
)
@global_preferences_registry.register
class DefaultPermissions(common_preferences.StringListPreference):
show_in_api = True
section = users
name = 'default_permissions'
default = []
verbose_name = 'Default permissions'
help_text = (
'A list of default preferences to give to all registered users.'
)
choices = [
(k, c['label'])
for k, c in models.PERMISSIONS_CONFIGURATION.items()
]
field_kwargs = {
'choices': choices,
'required': False,
}
......@@ -13,18 +13,33 @@ from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _
from funkwhale_api.common import fields
from funkwhale_api.common import preferences
def get_token():
return binascii.b2a_hex(os.urandom(15)).decode('utf-8')
PERMISSIONS = [
'federation',
'library',
'settings',
'upload',
]
PERMISSIONS_CONFIGURATION = {
'federation': {
'label': 'Manage library federation',
'help_text': 'Follow other instances, accept/deny library follow requests...',
},
'library': {
'label': 'Manage library',
'help_text': 'Manage library',
},
'settings': {
'label': 'Manage instance-level settings',
'help_text': '',
},
'upload': {
'label': 'Upload new content to the library',
'help_text': '',
},
}
PERMISSIONS = sorted(PERMISSIONS_CONFIGURATION.keys())
@python_2_unicode_compatible
......@@ -48,27 +63,34 @@ class User(AbstractUser):
# permissions
permission_federation = models.BooleanField(
'Manage library federation',
help_text='Follow other instances, accept/deny library follow requests...',
PERMISSIONS_CONFIGURATION['federation']['label'],
help_text=PERMISSIONS_CONFIGURATION['federation']['help_text'],
default=False)
permission_library = models.BooleanField(
'Manage library',
help_text='Manage library',
PERMISSIONS_CONFIGURATION['library']['label'],
help_text=PERMISSIONS_CONFIGURATION['library']['help_text'],
default=False)
permission_settings = models.BooleanField(
'Manage instance-level settings',
PERMISSIONS_CONFIGURATION['settings']['label'],
help_text=PERMISSIONS_CONFIGURATION['settings']['help_text'],
default=False)
permission_upload = models.BooleanField(
'Upload new content to the library',
PERMISSIONS_CONFIGURATION['upload']['label'],
help_text=PERMISSIONS_CONFIGURATION['upload']['help_text'],
default=False)
def __str__(self):
return self.username
def get_permissions(self):
defaults = preferences.get('users__default_permissions')
perms = {}
for p in PERMISSIONS:
v = self.is_superuser or getattr(self, 'permission_{}'.format(p))
v = (
self.is_superuser or
getattr(self, 'permission_{}'.format(p)) or
p in defaults
)
perms[p] = v
return perms
......
import pytest
from dynamic_preferences.registries import global_preferences_registry
from funkwhale_api.common import preferences as common_preferences
@pytest.fixture
def string_list_pref(preferences):
@global_preferences_registry.register
class P(common_preferences.StringListPreference):
default = ['hello']
section = 'test'
name = 'string_list'
yield
del global_preferences_registry['test']['string_list']
@pytest.mark.parametrize('input,output', [
(['a', 'b', 'c'], 'a,b,c'),
(['a', 'c', 'b'], 'a,b,c'),
(('a', 'c', 'b'), 'a,b,c'),
([], None),
])
def test_string_list_serializer_to_db(input, output):
s = common_preferences.StringListSerializer.to_db(input) == output
@pytest.mark.parametrize('input,output', [
('a,b,c', ['a', 'b', 'c'], ),
(None, []),
('', []),
])
def test_string_list_serializer_to_python(input, output):
s = common_preferences.StringListSerializer.to_python(input) == output
def test_string_list_pref_default(string_list_pref, preferences):
assert preferences['test__string_list'] == ['hello']
def test_string_list_pref_set(string_list_pref, preferences):
preferences['test__string_list'] = ['world', 'hello']
assert preferences['test__string_list'] == ['hello', 'world']
......@@ -41,6 +41,17 @@ def test_get_permissions_regular(factories):
assert perms[p] is False
def test_get_permissions_default(factories, preferences):
preferences['users__default_permissions'] = ['upload', 'federation']
user = factories['users.User']()
perms = user.get_permissions()
assert perms['upload'] is True
assert perms['federation'] is True
assert perms['library'] is False
assert perms['settings'] is False
@pytest.mark.parametrize('args,perms,expected', [
({'is_superuser': True}, ['federation', 'library'], True),
({'is_superuser': False}, ['federation'], False),
......
Admins can now configure default permissions that will be granted to all
registered users (#236)
......@@ -50,6 +50,13 @@
<label :for="setting.identifier">{{ setting.verbose_name }}</label>
<p v-if="setting.help_text">{{ setting.help_text }}</p>
</div>
<select
v-else-if="setting.field.class === 'MultipleChoiceField'"
v-model="values[setting.identifier]"
multiple
class="ui search selection dropdown">
<option v-for="v in setting.additional_data.choices" :value="v[0]">{{ v[1] }}</option>
</select>
</div>
<button
type="submit"
......
......@@ -81,6 +81,8 @@ axios.interceptors.response.use(function (response) {
}
if (error.response.status === 404) {
error.backendErrors.push('Resource not found')
} else if (error.response.status === 403) {
error.backendErrors.push('Permission denied')
} else if (error.response.status === 500) {
error.backendErrors.push('A server error occured')
} else if (error.response.data) {
......
......@@ -51,12 +51,12 @@ export default {
if (self.$store.state.route.hash) {
self.scrollTo(self.$store.state.route.hash.substr(1))
}
$('select.dropdown').dropdown()
})
})
},
methods: {
scrollTo (id) {
console.log(id, 'hello')
this.current = id
document.getElementById(id).scrollIntoView()
},
......@@ -86,7 +86,8 @@ export default {
id: 'users',
settings: [
'users__registration_enabled',
'common__api_authentication_required'
'common__api_authentication_required',
'users__default_permissions'
]
},
{
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment