Skip to content
Snippets Groups Projects
Verified Commit ac7db737 authored by Eliot Berriot's avatar Eliot Berriot
Browse files

See #152: added management command to execute one-time migration scripts

parent a57d9751
No related branches found
No related tags found
No related merge requests found
from django.core.management.base import BaseCommand, CommandError
from funkwhale_api.common import scripts
class Command(BaseCommand):
help = 'Run a specific script from funkwhale_api/common/scripts/'
def add_arguments(self, parser):
parser.add_argument('script_name', nargs='?', type=str)
parser.add_argument(
'--noinput', '--no-input', action='store_false', dest='interactive',
help="Do NOT prompt the user for input of any kind.",
)
def handle(self, *args, **options):
name = options['script_name']
if not name:
self.show_help()
available_scripts = self.get_scripts()
try:
script = available_scripts[name]
except KeyError:
raise CommandError(
'{} is not a valid script. Run python manage.py script for a '
'list of available scripts'.format(name))
self.stdout.write('')
if options['interactive']:
message = (
'Are you sure you want to execute the script {}?\n\n'
"Type 'yes' to continue, or 'no' to cancel: "
).format(name)
if input(''.join(message)) != 'yes':
raise CommandError("Script cancelled.")
script['entrypoint'](self, **options)
def show_help(self):
indentation = 4
self.stdout.write('')
self.stdout.write('Available scripts:')
self.stdout.write('Launch with: python manage.py <script_name>')
available_scripts = self.get_scripts()
for name, script in sorted(available_scripts.items()):
self.stdout.write('')
self.stdout.write(self.style.SUCCESS(name))
self.stdout.write('')
for line in script['help'].splitlines():
self.stdout.write(' {}'.format(line))
self.stdout.write('')
def get_scripts(self):
available_scripts = [
k for k in sorted(scripts.__dict__.keys())
if not k.startswith('__')
]
data = {}
for name in available_scripts:
module = getattr(scripts, name)
data[name] = {
'name': name,
'help': module.__doc__.strip(),
'entrypoint': module.main
}
return data
from . import django_permissions_to_user_permissions
from . import test
"""
Convert django permissions to user permissions in the database,
following the work done in #152.
"""
from django.db.models import Q
from funkwhale_api.users import models
from django.contrib.auth.models import Permission
mapping = {
'dynamic_preferences.change_globalpreferencemodel': 'settings',
'music.add_importbatch': 'library',
'federation.change_library': 'federation',
}
def main(command, **kwargs):
for codename, user_permission in sorted(mapping.items()):
app_label, c = codename.split('.')
p = Permission.objects.get(
content_type__app_label=app_label, codename=c)
users = models.User.objects.filter(
Q(groups__permissions=p) | Q(user_permissions=p)).distinct()
total = users.count()
command.stdout.write('Updating {} users with {} permission...'.format(
total, user_permission
))
users.update(**{'permission_{}'.format(user_permission): True})
"""
This is a test script that does nothing.
You can launch it just to check how it works.
"""
def main(command, **kwargs):
command.stdout.write('Test script run successfully')
......@@ -57,7 +57,18 @@ class UserAdmin(AuthUserAdmin):
fieldsets = (
(None, {'fields': ('username', 'password', 'privacy_level')}),
(_('Personal info'), {'fields': ('first_name', 'last_name', 'email')}),
(_('Permissions'), {'fields': ('is_active', 'is_staff', 'is_superuser',
'permission_library', 'permission_settings', 'permission_federation')}),
(_('Permissions'), {
'fields': (
'is_active',
'is_staff',
'is_superuser',
'permission_library',
'permission_settings',
'permission_federation')}),
(_('Important dates'), {'fields': ('last_login', 'date_joined')}),
)
(_('Useless fields'), {
'fields': (
'user_permissions',
'groups',
)})
)
import factory
from funkwhale_api.factories import registry
from funkwhale_api.factories import registry, ManyToManyFromList
from django.contrib.auth.models import Permission
@registry.register
class GroupFactory(factory.django.DjangoModelFactory):
name = factory.Sequence(lambda n: 'group-{0}'.format(n))
class Meta:
model = 'auth.Group'
@factory.post_generation
def perms(self, create, extracted, **kwargs):
if not create:
# Simple build, do nothing.
return
if extracted:
perms = [
Permission.objects.get(
content_type__app_label=p.split('.')[0],
codename=p.split('.')[1],
)
for p in extracted
]
# A list of permissions were passed in, use them
self.permissions.add(*perms)
@registry.register
class UserFactory(factory.django.DjangoModelFactory):
username = factory.Sequence(lambda n: 'user-{0}'.format(n))
email = factory.Sequence(lambda n: 'user-{0}@example.com'.format(n))
password = factory.PostGenerationMethodCall('set_password', 'test')
subsonic_api_token = None
groups = ManyToManyFromList('groups')
class Meta:
model = 'users.User'
......
import pytest
from funkwhale_api.common.management.commands import script
from funkwhale_api.common import scripts
@pytest.fixture
def command():
return script.Command()
@pytest.mark.parametrize('script_name', [
'django_permissions_to_user_permissions',
'test',
])
def test_script_command_list(command, script_name, mocker):
mocked = mocker.patch(
'funkwhale_api.common.scripts.{}.main'.format(script_name))
command.handle(script_name=script_name, interactive=False)
mocked.assert_called_once_with(
command, script_name=script_name, interactive=False)
def test_django_permissions_to_user_permissions(factories, command):
group = factories['auth.Group'](
perms=[
'federation.change_library'
]
)
user1 = factories['users.User'](
perms=[
'dynamic_preferences.change_globalpreferencemodel',
'music.add_importbatch',
]
)
user2 = factories['users.User'](
perms=[
'music.add_importbatch',
],
groups=[group]
)
scripts.django_permissions_to_user_permissions.main(command)
user1.refresh_from_db()
user2.refresh_from_db()
assert user1.permission_settings is True
assert user1.permission_library is True
assert user1.permission_federation is False
assert user2.permission_settings is False
assert user2.permission_library is True
assert user2.permission_federation is True
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment