Skip to content

Commit

Permalink
[Fixes #10251] Review geonode management command set_layers_permissions
Browse files Browse the repository at this point in the history
  • Loading branch information
mattiagiupponi committed Nov 3, 2022
1 parent a3e22be commit 0f4a3b7
Showing 1 changed file with 130 additions and 47 deletions.
177 changes: 130 additions & 47 deletions geonode/layers/management/commands/set_layers_permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,18 @@
#
#########################################################################

from django.core.management.base import BaseCommand
import copy
import logging
from argparse import RawTextHelpFormatter
from geonode.layers.utils import set_datasets_permissions

from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group
from django.core.management.base import BaseCommand
from geonode.layers.models import Dataset
from geonode.resource.manager import resource_manager
from geonode.security.permissions import PermSpec, PermSpecCompact

logger = logging.getLogger("geonode.layers.management.set_layers_permissions")


class Command(BaseCommand):
Expand Down Expand Up @@ -48,67 +57,141 @@ def create_parser(self, *args, **kwargs):

def add_arguments(self, parser):
parser.add_argument(
'-r',
'--resources',
dest='resources',
nargs='*',
"-r",
"--resources",
dest="resources",
nargs="*",
type=str,
default=None,
help='Resources names for which permissions will be assigned to. '
'Default value: None (all the layers will be considered). '
'Multiple choices can be typed with white space separator.'
'A Note: names with white spaces must be typed inside quotation marks.'
help="Resources names for which permissions will be assigned to. "
"Default value: None (all the layers will be considered). "
"Multiple choices can be typed with white space separator."
"A Note: names with white spaces must be typed inside quotation marks.",
)
parser.add_argument(
'-p',
'--permission',
dest='permission',
"-p",
"--permission",
dest="permission",
type=str,
default=None,
help='Permissions to be assigned. '
'Allowed values are: read (r), write (w), download (d) and owner (o).'
help="Permissions to be assigned. " "Allowed values are: view (r), download (w), edit (d) and manage (m).",
)
parser.add_argument(
'-u',
'--users',
dest='users',
nargs='*',
"-u",
"--users",
dest="users",
nargs="*",
type=str,
default=None,
help='Users for which permissions will be assigned to. '
'Multiple choices can be typed with white space separator.'
default=[],
help="Users for which permissions will be assigned to. "
"Multiple choices can be typed with white space separator.",
)
parser.add_argument(
'-g',
'--groups',
dest='groups',
nargs='*',
"-g",
"--groups",
dest="groups",
nargs="*",
type=str,
default=None,
help='Groups for which permissions will be assigned to. '
'Multiple choices can be typed with white space separator.'
default=[],
help="Groups for which permissions will be assigned to. "
"Multiple choices can be typed with white space separator.",
)
parser.add_argument(
'-d',
'--delete',
dest='delete_flag',
action='store_true',
"-d",
"--delete",
dest="delete_flag",
action="store_true",
default=False,
help='Delete permission if it exists.'
help="Delete permission if it exists.",
)

def handle(self, *args, **options):
# Retrieving the arguments
resources_names = options.get('resources')
permissions_name = options.get('permission')
users_usernames = options.get('users')
groups_names = options.get('groups')
delete_flag = options.get('delete_flag')
set_datasets_permissions(
permissions_name,
resources_names,
users_usernames,
groups_names,
delete_flag,
verbose=True
)
permissions_name = options.get("permission").replace(" ", "")

resources_pk = [x.replace(" ", "") for x in options.get("resources", [])]
if resources_pk:
resources_pk = resources_pk[0].split(",")
users_usernames = [x.replace(" ", "") for x in options.get("users", [])]
if users_usernames:
users_usernames = users_usernames[0].split(",")

groups_names = [x.replace(" ", "") for x in options.get("groups", [])]
if groups_names:
groups_names = groups_names[0].split(",")

delete_flag = options.get("delete_flag")

if isinstance(permissions_name, list):
# it accept one kind of permission per request
raise Exception("Only one permission name must be specified")

if not users_usernames and not groups_names:
raise Exception("Groups or Usernames must be specified")

not_found = []
final_perms_payload = {}

for rpk in resources_pk:
resource = Dataset.objects.filter(pk=rpk)
if not resource.exists():
not_found.append(rpk)
logger.error(f"Resource named: {rpk} not found, skipping....")
continue
else:
# creating the payload from the CompactPermissions like we do in the UI.
# the result will be a payload with the compact permissions list required
# for the selected resource
resource = resource.first()
# getting the actual permissions available for the dataset
original_perms = PermSpec(resource.get_all_level_info(), resource)
new_perms_payload = {"organizations": [], "users": [], "groups": []}
# if the username is specified, we add them to the payload with the compact
# perm value
if users_usernames:
User = get_user_model()
for _user in users_usernames:
try:
new_perms_payload["users"].append(
{"id": User.objects.get(username=_user).pk, "permissions": permissions_name}
)
except User.DoesNotExist:
logger.warning(f"The user {_user} does not exists. " "It has been skipped.")
# GROUPS
# if the group is specified, we add them to the payload with the compact
# perm value
if groups_names:
for group_name in groups_names:
try:
new_perms_payload["groups"].append(
{"id": Group.objects.get(name=group_name).pk, "permissions": permissions_name}
)
except Group.DoesNotExist:
logger.warning(f"The group {group_name} does not exists. " "It has been skipped.")
# Using the compact permissions payload to calculate the permissions
# that we want to give for each user/group
# This part is in common with the permissions API
new_compact_perms = PermSpecCompact(new_perms_payload, resource)
copy_compact_perms = copy.deepcopy(new_compact_perms)

perms_spec_compact_resource = PermSpecCompact(original_perms.compact, resource)
perms_spec_compact_resource.merge(new_compact_perms)

final_perms_payload = perms_spec_compact_resource.extended
# if the delete flag is set, we must delete the permissions for the input user/group
if delete_flag:
# since is a delete operation, we must remove the users/group from the resource
# so this will return the updated dict without the user/groups to be removed
final_perms_payload["users"] = {
_user: _perms
for _user, _perms in perms_spec_compact_resource.extended["users"].items()
if _user not in copy_compact_perms.extended["users"]
}
final_perms_payload["groups"] = {
_group: _perms
for _group, _perms in perms_spec_compact_resource.extended["groups"].items()
if _user not in copy_compact_perms.extended["groups"]
}

# calling the resource manager to set the permissions
resource_manager.set_permissions(resource.uuid, instance=resource, permissions=final_perms_payload)

0 comments on commit 0f4a3b7

Please sign in to comment.