126 lines
5.1 KiB
Python
126 lines
5.1 KiB
Python
"""
|
|
Management command `manage_group` is used to idempotently create Django groups
|
|
and set their permissions by name.
|
|
"""
|
|
|
|
|
|
from django.apps import apps
|
|
from django.contrib.auth.models import Group, Permission
|
|
from django.contrib.contenttypes.models import ContentType
|
|
from django.core.exceptions import ValidationError
|
|
from django.core.management.base import BaseCommand, CommandError
|
|
from django.db import transaction
|
|
from django.utils.translation import gettext as _
|
|
|
|
|
|
class Command(BaseCommand): # lint-amnesty, pylint: disable=missing-class-docstring
|
|
help = 'Creates the specified group, if it does not exist, and sets its permissions.'
|
|
|
|
def add_arguments(self, parser):
|
|
parser.add_argument('group_name')
|
|
parser.add_argument('--remove', dest='is_remove', action='store_true')
|
|
parser.add_argument('-p', '--permissions', nargs='*', default=[])
|
|
|
|
def _handle_remove(self, group_name): # lint-amnesty, pylint: disable=missing-function-docstring
|
|
|
|
try:
|
|
Group.objects.get(name=group_name).delete()
|
|
self.stderr.write(_('Removed group: "{}"').format(group_name))
|
|
except Group.DoesNotExist:
|
|
self.stderr.write(_('Did not find a group with name "{}" - skipping.').format(group_name))
|
|
|
|
@transaction.atomic
|
|
def handle(self, group_name, is_remove, permissions=None, *args, **options): # lint-amnesty, pylint: disable=arguments-differ, keyword-arg-before-vararg
|
|
|
|
if is_remove:
|
|
self._handle_remove(group_name)
|
|
return
|
|
|
|
old_permissions = set()
|
|
group, created = Group.objects.get_or_create(name=group_name)
|
|
|
|
if created:
|
|
try:
|
|
# Needed for sqlite backend (i.e. in tests) because
|
|
# name.max_length won't be enforced by the db.
|
|
# See also http://www.sqlite.org/faq.html#q9
|
|
group.full_clean()
|
|
except ValidationError as exc:
|
|
# give a more helpful error
|
|
raise CommandError( # lint-amnesty, pylint: disable=raise-missing-from
|
|
_(
|
|
'Invalid group name: "{group_name}". {messages}'
|
|
).format(
|
|
group_name=group_name,
|
|
messages=exc.messages[0]
|
|
)
|
|
)
|
|
self.stderr.write(_('Created new group: "{}"').format(group_name))
|
|
else:
|
|
self.stderr.write(_('Found existing group: "{}"').format(group_name))
|
|
old_permissions = set(group.permissions.all())
|
|
|
|
new_permissions = self._resolve_permissions(permissions or set())
|
|
|
|
add_permissions = new_permissions - old_permissions
|
|
remove_permissions = old_permissions - new_permissions
|
|
|
|
self.stderr.write(
|
|
_(
|
|
'Adding {codenames} permissions to group "{group}"'
|
|
).format(
|
|
codenames=[ap.name for ap in add_permissions],
|
|
group=group.name
|
|
)
|
|
)
|
|
self.stderr.write(
|
|
_(
|
|
'Removing {codenames} permissions from group "{group}"'
|
|
).format(
|
|
codenames=[rp.codename for rp in remove_permissions],
|
|
group=group.name
|
|
)
|
|
)
|
|
|
|
group.permissions.set(new_permissions)
|
|
|
|
group.save()
|
|
|
|
def _resolve_permissions(self, permissions): # lint-amnesty, pylint: disable=missing-function-docstring
|
|
new_permissions = set()
|
|
for permission in permissions:
|
|
try:
|
|
app_label, model_name, codename = permission.split(':')
|
|
except ValueError:
|
|
# give a more helpful error
|
|
raise CommandError(_( # lint-amnesty, pylint: disable=raise-missing-from
|
|
'Invalid permission option: "{}". Please specify permissions '
|
|
'using the format: app_label:model_name:permission_codename.'
|
|
).format(permission))
|
|
# this will raise a LookupError if it fails.
|
|
try:
|
|
model_class = apps.get_model(app_label, model_name)
|
|
except LookupError as exc:
|
|
raise CommandError(str(exc)) # lint-amnesty, pylint: disable=raise-missing-from
|
|
|
|
content_type = ContentType.objects.get_for_model(model_class)
|
|
try:
|
|
new_permission = Permission.objects.get(
|
|
content_type=content_type,
|
|
codename=codename,
|
|
)
|
|
except Permission.DoesNotExist:
|
|
# give a more helpful error
|
|
raise CommandError( # lint-amnesty, pylint: disable=raise-missing-from
|
|
_(
|
|
'Invalid permission codename: "{codename}". No such permission exists '
|
|
'for the model {module}.{model_name}.'
|
|
).format(
|
|
codename=codename,
|
|
module=model_class.__module__,
|
|
model_name=model_class.__name__,
|
|
)
|
|
)
|
|
new_permissions.add(new_permission)
|
|
return new_permissions
|