Ejemplo n.º 1
0
    def test_group_from_id(self):
        self.assertEqual(utils.group_from_id(self.group),
                         self.group,
                         msg='group passthrough failed')

        self.assertEqual(utils.group_from_id('Hydroshare Author'),
                         self.group,
                         msg='lookup by group name failed')
Ejemplo n.º 2
0
    def test_group_from_id(self):
        self.assertEqual(
            utils.group_from_id(self.group),
            self.group,
            msg='group passthrough failed'
        )

        self.assertEqual(
            utils.group_from_id('group1'),
            self.group,
            msg='lookup by group name failed'
        )
Ejemplo n.º 3
0
    def delete(self, request, pk):
        view_utils.authorize(request, pk,
                             needed_permission=ACTION_TO_AUTHORIZE.EDIT_RESOURCE_ACCESS)
        keys = request.query_params.keys()
        user_access = UserAccess(user=request.user)
        resource = hydroshare.get_resource_by_shortkey(shortkey=pk)

        if "user_id" in keys and "group_id" in keys:
            message = "Request cannot contain both a 'user_id' and a 'group_id' parameter."
            return Response(
                data={'error': message},
                status=status.HTTP_400_BAD_REQUEST
            )

        if "user_id" in keys:
            user_to_remove = utils.user_from_id(request.query_params['user_id'])
            user_access.unshare_resource_with_user(resource, user_to_remove)
            return Response(
                data={'success': "Resource access privileges removed."},
                status=status.HTTP_202_ACCEPTED
            )

        if "group_id" in keys:
            group_to_remove = utils.group_from_id(request.query_params['group_id'])
            user_access.unshare_resource_with_group(resource, group_to_remove)
            return Response(
                data={'success': "Resource access privileges removed."},
                status=status.HTTP_202_ACCEPTED
            )

        message = "Request must contain a 'resource' ID as well as a 'user_id' or 'group_id'"
        return Response(
            data={'error': message},
            status=status.HTTP_400_BAD_REQUEST
        )
Ejemplo n.º 4
0
    def set_access_rules(self, request, pk):
        res, _, _ = authorize(request, pk, full=True, superuser=True)

        access_rules_form = utils.create_form(
            SetAccessRules.SetAccessRulesForm, request)
        if access_rules_form.is_valid():
            r = access_rules_form.cleaned_data

            # get the user or group by ID
            # try username first, then email address, then primary key
            if r['principalType'] == 'user':
                tgt = user_from_id(r['principalID'])
                ret = hydroshare.set_access_rules(user=tgt,
                                                  pk=res,
                                                  access=r['access'],
                                                  allow=r['allow'])
            else:
                tgt = group_from_id(r['principalID'])
                ret = hydroshare.set_access_rules(group=tgt,
                                                  pk=res,
                                                  access=r['access'],
                                                  allow=r['allow'])
        else:
            distribute_form = utils.create_form(
                SetAccessRules.SetDoNotDistributeForm, request)
            if distribute_form.is_valid():
                r = distribute_form.cleaned_data
                ret = hydroshare.set_access_rules(pk=res,
                                                  access=r['access'],
                                                  allow=r['allow'])
            else:
                return HttpResponseBadRequest('Invalid request')

        return HttpResponse(ret, content_type='text/plain')
Ejemplo n.º 5
0
    def delete(self, request, pk):
        view_utils.authorize(
            request,
            pk,
            needed_permission=ACTION_TO_AUTHORIZE.EDIT_RESOURCE_ACCESS)
        keys = request.query_params.keys()
        user_access = UserAccess(user=request.user)
        resource = hydroshare.get_resource_by_shortkey(shortkey=pk)

        if "user_id" in keys and "group_id" in keys:
            message = "Request cannot contain both a 'user_id' and a 'group_id' parameter."
            return Response(data={'error': message},
                            status=status.HTTP_400_BAD_REQUEST)

        if "user_id" in keys:
            user_to_remove = utils.user_from_id(
                request.query_params['user_id'])
            user_access.unshare_resource_with_user(resource, user_to_remove)
            return Response(
                data={'success': "Resource access privileges removed."},
                status=status.HTTP_202_ACCEPTED)

        if "group_id" in keys:
            group_to_remove = utils.group_from_id(
                request.query_params['group_id'])
            user_access.unshare_resource_with_group(resource, group_to_remove)
            return Response(
                data={'success': "Resource access privileges removed."},
                status=status.HTTP_202_ACCEPTED)

        message = "Request must contain a 'resource' ID as well as a 'user_id' or 'group_id'"
        return Response(data={'error': message},
                        status=status.HTTP_400_BAD_REQUEST)
Ejemplo n.º 6
0
    def set_group_owner(self, g, u):
        originator = get_user(self.request)
        g = group_from_id(g)

        if not GroupOwnership.objects.filter(group=g, user=originator).exists():
            raise exceptions.PermissionDenied("user must be a group owner to change group ownership.")
        else:
            hydroshare.set_group_owner(g, u)
            return HttpResponse(g.name, content_type='text/plain')
Ejemplo n.º 7
0
    def put(self, request, pk):
        view_utils.authorize(request, pk,
                             needed_permission=ACTION_TO_AUTHORIZE.EDIT_RESOURCE_ACCESS)
        user_access = UserAccess(user=request.user)
        resource = hydroshare.get_resource_by_shortkey(shortkey=pk)
        keys = request.data.keys()

        if "user_id" in keys and "group_id" in keys:
            return Response(
                data={
                    'error': "Request cannot contain both a 'user_id' and a 'group_id' parameter."
                },
                status=status.HTTP_400_BAD_REQUEST
            )

        if "user_id" in keys and "privilege" in keys:
            if int(request.data['privilege']) in (1, 2, 3, 4):
                try:
                    user_to_add = utils.user_from_id(request.data['user_id'])
                    user_access.share_resource_with_user(resource,
                                                         user_to_add,
                                                         request.data['privilege'])
                    return Response(
                        data={'success': "Resource access privileges added."},
                        status=status.HTTP_202_ACCEPTED
                    )
                except Exception:
                    return Response(
                        data={'error': "This resource may not be shared with that user."},
                        status=status.HTTP_400_BAD_REQUEST
                    )

        if "group_id" in keys and "privilege" in keys:
            if int(request.data['privilege']) in (1, 2, 3, 4):
                group_to_add = utils.group_from_id(request.data['group_id'])
                try:
                    user_access.share_resource_with_group(resource,
                                                          group_to_add,
                                                          request.data['privilege'])
                    return Response(
                        data={'success': "Resource access privileges added."},
                        status=status.HTTP_202_ACCEPTED
                    )
                except Exception:
                    return Response(
                        data={'error': "This group may not be added to any resources."},
                        status=status.HTTP_400_BAD_REQUEST
                    )

        message = "Request must contain a 'resource' ID as well as a 'user_id' or " \
                  "'group_id', and 'privilege' must be one of 1, 2, or 3."
        return Response(
            data={'error': message},
            status=status.HTTP_400_BAD_REQUEST
        )
Ejemplo n.º 8
0
    def put(self, request, pk):
        view_utils.authorize(
            request,
            pk,
            needed_permission=ACTION_TO_AUTHORIZE.EDIT_RESOURCE_ACCESS)
        user_access = UserAccess(user=request.user)
        resource = hydroshare.get_resource_by_shortkey(shortkey=pk)
        keys = request.data.keys()

        if "user_id" in keys and "group_id" in keys:
            return Response(data={
                'error':
                "Request cannot contain both a 'user_id' and a 'group_id' parameter."
            },
                            status=status.HTTP_400_BAD_REQUEST)

        if "user_id" in keys and "privilege" in keys:
            if int(request.data['privilege']) in (1, 2, 3, 4):
                try:
                    user_to_add = utils.user_from_id(request.data['user_id'])
                    user_access.share_resource_with_user(
                        resource, user_to_add, request.data['privilege'])
                    return Response(
                        data={'success': "Resource access privileges added."},
                        status=status.HTTP_202_ACCEPTED)
                except Exception:
                    return Response(data={
                        'error':
                        "This resource may not be shared with that user."
                    },
                                    status=status.HTTP_400_BAD_REQUEST)

        if "group_id" in keys and "privilege" in keys:
            if int(request.data['privilege']) in (1, 2, 3, 4):
                group_to_add = utils.group_from_id(request.data['group_id'])
                try:
                    user_access.share_resource_with_group(
                        resource, group_to_add, request.data['privilege'])
                    return Response(
                        data={'success': "Resource access privileges added."},
                        status=status.HTTP_202_ACCEPTED)
                except Exception:
                    return Response(data={
                        'error':
                        "This group may not be added to any resources."
                    },
                                    status=status.HTTP_400_BAD_REQUEST)

        message = "Request must contain a 'resource' ID as well as a 'user_id' or " \
                  "'group_id', and 'privilege' must be one of 1, 2, or 3."
        return Response(data={'error': message},
                        status=status.HTTP_400_BAD_REQUEST)
Ejemplo n.º 9
0
    def set_group_owner(self, g, u):
        originator = get_user(self.request)
        g = group_from_id(g)

        if not GroupOwnership.objects.filter(group=g,
                                             user=originator).exists():
            raise exceptions.PermissionDenied(
                "user must be a group owner to change group ownership.")
        else:
            hydroshare.set_group_owner(g, u)
            return HttpResponse(g.name,
                                content_type='text/plain',
                                status='204')
Ejemplo n.º 10
0
    def post(self, request, pk, privilege, group_id):
        res, _, user = authorize(request, pk,
                                 needed_permission=ACTION_TO_AUTHORIZE.VIEW_RESOURCE)
        to_group = hs_core_utils.group_from_id(group_id)
        privilege_code = PrivilegeCodes.from_string(privilege)
        if not privilege_code:
            raise ParseError("Bad privilege code")
        if privilege_code == PrivilegeCodes.NONE:
            user.uaccess.unshare_resource_with_group(res, to_group)
        else:
            user.uaccess.share_resource_with_group(res, to_group, privilege_code)

        return Response(status=status.HTTP_204_NO_CONTENT)
Ejemplo n.º 11
0
    def post(self, request, pk, privilege, group_id):
        res, _, user = authorize(request, pk,
                                 needed_permission=ACTION_TO_AUTHORIZE.VIEW_RESOURCE)
        to_group = hs_core_utils.group_from_id(group_id)
        privilege_code = PrivilegeCodes.from_string(privilege)
        if not privilege_code:
            raise ParseError("Bad privilege code")
        if privilege_code == PrivilegeCodes.NONE:
            user.uaccess.unshare_resource_with_group(res, to_group)
        else:
            user.uaccess.share_resource_with_group(res, to_group, privilege_code)

        return Response(status=status.HTTP_204_NO_CONTENT)
Ejemplo n.º 12
0
    def set_access_rules(self, request, pk):
        res, _, _ = authorize(request, pk, full=True, superuser=True)

        access_rules_form = SetAccessRules.SetAccessRulesForm(request.REQUEST)
        if access_rules_form.is_valid():
            r = access_rules_form.cleaned_data

            # get the user or group by ID
            # try username first, then email address, then primary key
            if r['principalType'] == 'user':
                tgt = user_from_id(r['principalID'])
                ret = hydroshare.set_access_rules(user=tgt, pk=res, access=r['access'], allow=r['allow'])
            else:
                tgt = group_from_id(r['principalID'])
                ret = hydroshare.set_access_rules(group=tgt, pk=res, access=r['access'], allow=r['allow'])
        else:
            distribute_form = SetAccessRules.SetDoNotDistributeForm(request.REQUEST)
            if distribute_form.is_valid():
                r = distribute_form.cleaned_data
                ret = hydroshare.set_access_rules(pk=res, access=r['access'], allow=r['allow'])
            else:
                return HttpResponseBadRequest('Invalid request')

        return HttpResponse(ret, content_type='text/plain')
Ejemplo n.º 13
0
def create_resource(
        resource_type, owner, title,
        edit_users=None, view_users=None, edit_groups=None, view_groups=None,
        keywords=(), metadata=None, extra_metadata=None,
        files=(), create_metadata=True, create_bag=True, unpack_file=False, full_paths={},
        auto_aggregate=True, **kwargs):
    """
    Called by a client to add a new resource to HydroShare. The caller must have authorization to
    write content to HydroShare. The pid for the resource is assigned by HydroShare upon inserting
    the resource.  The create method returns the newly-assigned pid.

    REST URL:  POST /resource

    Parameters:

    Returns:    The newly created resource

    Return Type:    BaseResource resource object

    Note:  The calling user will automatically be set as the owner of the created resource.

    Implementation notes:

    1. pid is called short_id.  This is because pid is a UNIX term for Process ID and could be
    confusing.

    2. return type is an instance of hs_core.models.BaseResource class. This is for efficiency in
    the native API.  The native API should return actual instance rather than IDs wherever possible
    to avoid repeated lookups in the database when they are unnecessary.

    3. resource_type is a string: see parameter list

    :param resource_type: string. the type of the resource such as GenericResource
    :param owner: email address, username, or User instance. The owner of the resource
    :param title: string. the title of the resource
    :param edit_users: list of email addresses, usernames, or User instances who will be given edit
    permissions
    :param view_users: list of email addresses, usernames, or User instances who will be given view
    permissions
    :param edit_groups: list of group names or Group instances who will be given edit permissions
    :param view_groups: list of group names or Group instances who will be given view permissions
    :param keywords: string list. list of keywords to add to the resource
    :param metadata: list of dicts containing keys (element names) and corresponding values as
    dicts { 'creator': {'name':'John Smith'}}.
    :param extra_metadata: one dict containing keys and corresponding values
         { 'Outlet Point Latitude': '40', 'Outlet Point Longitude': '-110'}.
    :param files: list of Django File or UploadedFile objects to be attached to the resource
    :param create_bag: whether to create a bag for the newly created resource or not.
        By default, the bag is created.
    :param unpack_file: boolean.  If files contains a single zip file, and unpack_file is True,
        the unpacked contents of the zip file will be added to the resource instead of the zip file.
    :param full_paths: Optional.  A map of paths keyed by the correlating resource file.  When
        this parameter is provided, a file will be placed at the path specified in the map.
    :param auto_aggregate: boolean, defaults to True.  Find and create aggregations during
        resource creation.
    :param kwargs: extra arguments to fill in required values in AbstractResource subclasses

    :return: a new resource which is an instance of BaseResource with specificed resource_type.
    """
    with transaction.atomic():
        cls = check_resource_type(resource_type)
        owner = utils.user_from_id(owner)

        # get the metadata class specific to resource type to set resource
        # content_object (metadata) attribute
        metadata_class = cls.get_metadata_class()
        metadata_obj = metadata_class()
        metadata_obj.save()

        # create the resource
        resource = cls.objects.create(
            resource_type=resource_type,
            user=owner,
            creator=owner,
            title=title,
            last_changed_by=owner,
            in_menus=[],
            content_object=metadata_obj,
            **kwargs
        )

        resource.resource_type = resource_type

        # by default make resource private
        resource.set_slug('resource{0}{1}'.format('/', resource.short_id))
        resource.save()

        if not metadata:
            metadata = []

        if extra_metadata is not None:
            resource.extra_metadata = extra_metadata
            resource.save()

        # by default resource is private
        resource_access = ResourceAccess(resource=resource)
        resource_access.save()
        # use the built-in share routine to set initial provenance.
        UserResourcePrivilege.share(resource=resource, grantor=owner, user=owner,
                                    privilege=PrivilegeCodes.OWNER)

        resource_labels = ResourceLabels(resource=resource)
        resource_labels.save()

        if edit_users:
            for user in edit_users:
                user = utils.user_from_id(user)
                owner.uaccess.share_resource_with_user(resource, user, PrivilegeCodes.CHANGE)

        if view_users:
            for user in view_users:
                user = utils.user_from_id(user)
                owner.uaccess.share_resource_with_user(resource, user, PrivilegeCodes.VIEW)

        if edit_groups:
            for group in edit_groups:
                group = utils.group_from_id(group)
                owner.uaccess.share_resource_with_group(resource, group, PrivilegeCodes.CHANGE)

        if view_groups:
            for group in view_groups:
                group = utils.group_from_id(group)
                owner.uaccess.share_resource_with_group(resource, group, PrivilegeCodes.VIEW)

        # set quota of this resource to this creator
        # quota holder has to be set before the files are added in order for real time iRODS
        # quota micro-services to work
        resource.set_quota_holder(owner, owner)

        if create_metadata:
            # prepare default metadata
            utils.prepare_resource_default_metadata(resource=resource, metadata=metadata,
                                                    res_title=title)

            for element in metadata:
                # here k is the name of the element
                # v is a dict of all element attributes/field names and field values
                k, v = element.items()[0]
                resource.metadata.create_element(k, **v)

            for keyword in keywords:
                resource.metadata.create_element('subject', value=keyword)

            resource.title = resource.metadata.title.value
            resource.save()

        if len(files) == 1 and unpack_file and zipfile.is_zipfile(files[0]):
            # Add contents of zipfile as resource files asynchronously
            # Note: this is done asynchronously as unzipping may take
            # a long time (~15 seconds to many minutes).
            add_zip_file_contents_to_resource_async(resource, files[0])
        else:
            # Add resource file(s) now
            # Note: this is done synchronously as it should only take a
            # few seconds.  We may want to add the option to do this
            # asynchronously if the file size is large and would take
            # more than ~15 seconds to complete.
            add_resource_files(resource.short_id, *files, full_paths=full_paths,
                               auto_aggregate=auto_aggregate)

        if create_bag:
            hs_bagit.create_bag(resource)

    # set the resource to private
    resource.setAVU('isPublic', resource.raccess.public)

    # set the resource type (which is immutable)
    resource.setAVU("resourceType", resource._meta.object_name)

    return resource
Ejemplo n.º 14
0
def create_resource(
        resource_type, owner, title,
        edit_users=None, view_users=None, edit_groups=None, view_groups=None,
        keywords=None, metadata=None, content=None,
        files=(), res_type_cls=None, resource=None, **kwargs):
    """
    Called by a client to add a new resource to HydroShare. The caller must have authorization to write content to
    HydroShare. The pid for the resource is assigned by HydroShare upon inserting the resource.  The create method
    returns the newly-assigned pid.

    REST URL:  POST /resource

    Parameters:
    resource - The data bytes of the resource to be added to HydroShare

    Returns:    The pid assigned to the newly created resource

    Return Type:    pid

    Raises:
    Exceptions.NotAuthorized - The user is not authorized to write to HydroShare
    Exceptions.InvalidContent - The content of the resource is incomplete
    Exception.ServiceFailure - The service is unable to process the request

    Note:  The calling user will automatically be set as the owner of the created resource.

    Implementation notes:

    1. pid is called short_id.  This is because pid is a UNIX term for Process ID and could be confusing.

    2. return type is an instance of a subclass of hs_core.models.AbstractResource.  This is for efficiency in the
       native API.  The native API should return actual instance rather than IDs wherever possible to avoid repeated
       lookups in the database when they are unnecessary.

    3. resource_type is a string: see parameter list

    :param resource_type: string. the classname of the resource type, such as GenericResource
    :param owner: email address, username, or User instance. The owner of the resource
    :param title: string. the title of the resource
    :param edit_users: list of email addresses, usernames, or User instances who will be given edit permissions
    :param view_users: list of email addresses, usernames, or User instances who will be given view permissions
    :param edit_groups: list of group names or Group instances who will be given edit permissions
    :param view_groups: list of group names or Group instances who will be given view permissions
    :param keywords: string list. list of keywords to add to the resource
    :param metadata: list of dicts containing keys (element names) and corresponding values as dicts { 'creator': {'name':'John Smith'}}.
    :param files: list of Django File or UploadedFile objects to be attached to the resource
    :param kwargs: extra arguments to fill in required values in AbstractResource subclasses

    :return: a new resource which is an instance of resource_type.
    """
    try:
        cls = check_resource_type(resource_type)
        owner = utils.user_from_id(owner)

        # create the resource
        resource = cls.objects.create(
            user=owner,
            creator=owner,
            title=title,
            last_changed_by=owner,
            in_menus=[],
            **kwargs
        )

        # by default make resource private
        resource.public = False
        resource.save()

        if not metadata:
            metadata = []

        add_resource_files(resource.short_id, *files)

        if 'owner' in kwargs:
            owner = utils.user_from_id(kwargs['owner'])
            resource.owners.add(owner)

        resource.owners.add(owner)

        if edit_users:
            for user in edit_users:
                user = utils.user_from_id(user)
                resource.edit_users.add(user)
                resource.view_users.add(user)
        if view_users:
            for user in view_users:
                user = utils.user_from_id(user)
                resource.view_users.add(user)

        if edit_groups:
            for group in edit_groups:
                group = utils.group_from_id(group)
                resource.edit_groups.add(group)
                resource.view_groups.add(group)
        if view_groups:
            for group in view_groups:
                group = utils.group_from_id(group)
                resource.view_groups.add(group)

        if keywords:
            ks = [Keyword.objects.get_or_create(title=k) for k in keywords]
            ks = zip(*ks)[0]  # ignore whether something was created or not.  zip is its own inverse

            for k in ks:
                AssignedKeyword.objects.create(content_object=resource, keyword=k)

        # prepare default metadata
        utils.prepare_resource_default_metadata(resource=resource, metadata=metadata, res_title=title)

        for element in metadata:
            # here k is the name of the element
            # v is a dict of all element attributes/field names and field values
            k, v = element.items()[0]
            resource.metadata.create_element(k, **v)

        # add the subject elements from the AssignedKeywords (new metadata implementation)
        for akw in AssignedKeyword.objects.filter(object_pk=resource.id).all():
            resource.metadata.create_element('subject', value=akw.keyword.title)

        hs_bagit.create_bag(resource)

    except Exception as ex:
        if resource:
            resource.delete()
        raise Exception(ex.message)

    return resource
Ejemplo n.º 15
0
def update_resource(
        pk,
        edit_users=None, view_users=None, edit_groups=None, view_groups=None,
        keywords=None, metadata=None,
        *files, **kwargs):
    """
    Called by clients to update a resource in HydroShare.

    REST URL:  PUT /resource/{pid}

    Parameters:
    pid - Unique HydroShare identifier for the resource that is to be updated.

    resource - The data bytes of the resource that will update the existing resource identified by pid

    Returns:    The pid assigned to the updated resource

    Return Type:    pid

    Raises:
    Exceptions.NotAuthorized - The user is not authorized
    Exceptions.InvalidContent - The content of the resource is incomplete
    Exception.ServiceFailure - The service is unable to process the request

    Notes:
    For mutable resources (resources that have not been formally published), the update overwrites existing data and
    metadata using the resource that is passed to this method. If a user wants to create a copy or modified version of a
    mutable resource this should be done using HydroShare.createResource().

    For immutable resources (formally published resources), this method creates a new resource that is a new version of
    formally published resource. HydroShare will record the update by storing the SystemMetadata.obsoletes and
    SystemMetadata.obsoletedBy fields for the respective resources in their system metadata.HydroShare MUST check or set
    the values of SystemMetadata.obsoletes and SystemMetadata.obsoletedBy so that they accurately represent the
    relationship between the new and old objects. HydroShare MUST also set SystemMetadata.dateSysMetadataModified. The
    modified system metadata entries must then be available in HydroShare.listObjects() to ensure that any cataloging
    systems pick up the changes when filtering on SystmeMetadata.dateSysMetadataModified. A formally published resource
    can only be obsoleted by one newer version. Once a resource is obsoleted, no other resources can obsolete it.
    """
    resource = utils.get_resource_by_shortkey(pk)

    if files:
        ResourceFile.objects.filter(object_id=resource.id).delete()
        for file in files:
            ResourceFile.objects.create(
                content_object=resource,
                resource_file=File(file) if not isinstance(file, UploadedFile) else file
            )

    if 'owner' in kwargs:
        owner = utils.user_from_id(kwargs['owner'])
        resource.owners.add(owner)

    if edit_users:
        resource.edit_users.clear()
        for user in edit_users:
            user = utils.user_from_id(user)
            resource.edit_users.add(user)
            resource.view_users.add(user)

    if view_users:
        resource.view_users.clear()
        for user in view_users:
            user = utils.user_from_id(user)
            resource.view_users.add(user)

    if edit_groups:
        resource.edit_groups.clear()
        for group in edit_groups:
            group = utils.group_from_id(group)
            resource.edit_groups.add(group)
            resource.view_groups.add(group)

    if view_groups:
        resource.edit_groups.clear()
        for group in view_groups:
            group = utils.group_from_id(group)
            resource.view_groups.add(group)

    if keywords:
        AssignedKeyword.objects.filter(object_pk=resource.id).delete()
        ks = [Keyword.objects.get_or_create(title=k) for k in keywords]
        ks = zip(*ks)[0]  # ignore whether something was created or not.  zip is its own inverse

        for k in ks:
            AssignedKeyword.objects.create(content_object=resource, keyword=k)

    # for creating metadata elements based on the new metadata implementation
    if metadata:
        _update_science_metadata(resource, metadata)

    return resource
Ejemplo n.º 16
0
def create_resource(resource_type,
                    owner,
                    title,
                    edit_users=None,
                    view_users=None,
                    edit_groups=None,
                    view_groups=None,
                    keywords=(),
                    metadata=None,
                    extra_metadata=None,
                    files=(),
                    source_names=[],
                    source_sizes=[],
                    fed_res_path='',
                    move=False,
                    is_file_reference=False,
                    create_metadata=True,
                    create_bag=True,
                    unpack_file=False,
                    **kwargs):
    """
    Called by a client to add a new resource to CommonsShare. The caller must have authorization to
    write content to CommonsShare. The pid for the resource is assigned by CommonsShare upon inserting
    the resource.  The create method returns the newly-assigned pid.

    REST URL:  POST /resource

    Parameters:

    Returns:    The newly created resource

    Return Type:    BaseResource resource object

    Note:  The calling user will automatically be set as the owner of the created resource.

    Implementation notes:

    1. pid is called short_id.  This is because pid is a UNIX term for Process ID and could be
    confusing.

    2. return type is an instance of hs_core.models.BaseResource class. This is for efficiency in
    the native API.  The native API should return actual instance rather than IDs wherever possible
    to avoid repeated lookups in the database when they are unnecessary.

    3. resource_type is a string: see parameter list

    :param resource_type: string. the type of the resource such as GenericResource
    :param owner: email address, username, or User instance. The owner of the resource
    :param title: string. the title of the resource
    :param edit_users: list of email addresses, usernames, or User instances who will be given edit
    permissions
    :param view_users: list of email addresses, usernames, or User instances who will be given view
    permissions
    :param edit_groups: list of group names or Group instances who will be given edit permissions
    :param view_groups: list of group names or Group instances who will be given view permissions
    :param keywords: string list. list of keywords to add to the resource
    :param metadata: list of dicts containing keys (element names) and corresponding values as
    dicts { 'creator': {'name':'John Smith'}}.
    :param extra_metadata: one dict containing keys and corresponding values
         { 'Outlet Point Latitude': '40', 'Outlet Point Longitude': '-110'}.
    :param files: list of Django File or UploadedFile objects to be attached to the resource
    :param source_names: a list of file names from a federated zone to be
         used to create the resource in the federated zone, default is empty list
    :param source_sizes: a list of file sizes corresponding to source_names if if_file_reference is True; otherwise,
         it is not of any use and should be empty.
    :param fed_res_path: the federated zone path in the format of
         /federation_zone/home/localHydroProxy that indicate where the resource
         is stored, default is empty string
    :param move: a value of False or True indicating whether the content files
         should be erased from the source directory. default is False.
    :param is_file_reference: a value of False or True indicating whether the files stored in
        source_files are references to external files without being physically stored in
        HydroShare internally. default is False.
    :param create_bag: whether to create a bag for the newly created resource or not.
        By default, the bag is created.
    :param unpack_file: boolean.  If files contains a single zip file, and unpack_file is True,
        the unpacked contents of the zip file will be added to the resource instead of the zip file.
    :param kwargs: extra arguments to fill in required values in AbstractResource subclasses

    :return: a new resource which is an instance of BaseResource with specificed resource_type.
    """
    if __debug__:
        assert (isinstance(source_names, list))

    with transaction.atomic():
        cls = check_resource_type(resource_type)
        owner = utils.user_from_id(owner)

        # create the resource
        resource = cls.objects.create(resource_type=resource_type,
                                      user=owner,
                                      creator=owner,
                                      title=title,
                                      last_changed_by=owner,
                                      in_menus=[],
                                      **kwargs)

        resource.resource_type = resource_type

        # by default make resource private
        resource.set_slug('resource{0}{1}'.format('/', resource.short_id))
        resource.save()

        if not metadata:
            metadata = []

        if extra_metadata is not None:
            resource.extra_metadata = extra_metadata
            resource.save()

        fed_zone_home_path = ''
        if fed_res_path:
            resource.resource_federation_path = fed_res_path
            fed_zone_home_path = fed_res_path
            resource.save()

        # TODO: It would be safer to require an explicit zone path rather than harvesting file path
        elif len(source_names) > 0 and fed_res_path:
            fed_zone_home_path = utils.get_federated_zone_home_path(
                source_names[0])
            resource.resource_federation_path = fed_zone_home_path
            resource.save()

        if len(files) == 1 and unpack_file and zipfile.is_zipfile(files[0]):
            # Add contents of zipfile as resource files asynchronously
            # Note: this is done asynchronously as unzipping may take
            # a long time (~15 seconds to many minutes).
            add_zip_file_contents_to_resource_async(resource, files[0])
        else:
            # Add resource file(s) now
            # Note: this is done synchronously as it should only take a
            # few seconds.  We may want to add the option to do this
            # asynchronously if the file size is large and would take
            # more than ~15 seconds to complete.
            add_resource_files(resource.short_id,
                               *files,
                               source_names=source_names,
                               source_sizes=source_sizes,
                               move=move,
                               is_file_reference=is_file_reference)

        # by default resource is private
        resource_access = ResourceAccess(resource=resource)
        resource_access.save()
        # use the built-in share routine to set initial provenance.
        UserResourcePrivilege.share(resource=resource,
                                    grantor=owner,
                                    user=owner,
                                    privilege=PrivilegeCodes.OWNER)

        resource_labels = ResourceLabels(resource=resource)
        resource_labels.save()

        if edit_users:
            for user in edit_users:
                user = utils.user_from_id(user)
                owner.uaccess.share_resource_with_user(resource, user,
                                                       PrivilegeCodes.CHANGE)

        if view_users:
            for user in view_users:
                user = utils.user_from_id(user)
                owner.uaccess.share_resource_with_user(resource, user,
                                                       PrivilegeCodes.VIEW)

        if edit_groups:
            for group in edit_groups:
                group = utils.group_from_id(group)
                owner.uaccess.share_resource_with_group(
                    resource, group, PrivilegeCodes.CHANGE)

        if view_groups:
            for group in view_groups:
                group = utils.group_from_id(group)
                owner.uaccess.share_resource_with_group(
                    resource, group, PrivilegeCodes.VIEW)

        if create_metadata:
            # prepare default metadata
            utils.prepare_resource_default_metadata(resource=resource,
                                                    metadata=metadata,
                                                    res_title=title)

            for element in metadata:
                # here k is the name of the element
                # v is a dict of all element attributes/field names and field values
                k, v = element.items()[0]
                resource.metadata.create_element(k, **v)

            for keyword in keywords:
                resource.metadata.create_element('subject', value=keyword)

            resource.title = resource.metadata.title.value
            resource.save()
        if create_bag:
            hs_bagit.create_bag(resource)

    # set the resource to private
    resource.setAVU('isPublic', resource.raccess.public)

    # set the resource type (which is immutable)
    resource.setAVU("resourceType", resource._meta.object_name)

    # set quota of this resource to this creator
    resource.set_quota_holder(owner, owner)

    return resource
Ejemplo n.º 17
0
for account in CZO_ACCOUNTS:

    u_name = account["uname"]
    czo = account["czo"]
    if czo.lower() == "default":
        continue
    g_name = "{}".format(account["group"])

    try:
        print("Sharing {}'s resource with Group {} with privilege code {}".
              format(u_name, g_name, SHARE_WITH_GROUP_PRIVILEGE))
        # user obj
        u = utils.user_from_id(u_name)

        # group obj
        g = utils.group_from_id(g_name)

        # res owned by u
        owned_resources = u.uaccess.get_resources_with_explicit_access(
            PrivilegeCodes.OWNER)

        czo_counter = 0
        for r in owned_resources:
            try:
                czo_counter += 1
                u.uaccess.share_resource_with_group(
                    r, g, SHARE_WITH_GROUP_PRIVILEGE)
                success_counter += 1
            except Exception as ex:
                failure_counter += 1
                print(ex.message)