Ejemplo n.º 1
0
def update_metadata_element(request, hs_file_type, file_type_id, element_name,
                            element_id, **kwargs):
    err_msg = "Failed to update metadata element '{}'. {}."
    content_type = ContentType.objects.get(app_label="hs_file_types", model=hs_file_type.lower())
    logical_file_type_class = content_type.model_class()
    logical_file = logical_file_type_class.objects.filter(id=file_type_id).first()
    if logical_file is None:
        err_msg = "No matching logical file type was found."
        ajax_response_data = {'status': 'error', 'message': err_msg}
        return JsonResponse(ajax_response_data, status=status.HTTP_200_OK)

    resource_id = logical_file.resource.short_id
    resource, authorized, _ = authorize(request, resource_id,
                                        needed_permission=ACTION_TO_AUTHORIZE.EDIT_RESOURCE,
                                        raises_exception=False)

    if not authorized:
        ajax_response_data = {'status': 'error', 'logical_file_type': logical_file.type_name(),
                              'element_name': element_name, 'message': "Permission denied"}
        return JsonResponse(ajax_response_data, status=status.HTTP_200_OK)

    validation_response = logical_file.metadata.validate_element_data(request, element_name)
    is_update_success = False
    if validation_response['is_valid']:
        element_data_dict = validation_response['element_data_dict']
        try:
            logical_file.metadata.update_element(element_name, element_id, **element_data_dict)
            resource_modified(resource, request.user, overwrite_bag=False)
            is_update_success = True
        except ValidationError as ex:
            err_msg = err_msg.format(element_name, ex.message)
        except Error as ex:
            err_msg = err_msg.format(element_name, ex.message)
    else:
        err_msg = err_msg.format(element_name, validation_response['errors'])

    if is_update_success:
        if resource.can_be_public_or_discoverable:
            metadata_status = METADATA_STATUS_SUFFICIENT
        else:
            metadata_status = METADATA_STATUS_INSUFFICIENT

        ajax_response_data = {'status': 'success', 'element_name': element_name,
                              'metadata_status': metadata_status,
                              'logical_file_type': logical_file.type_name()
                              }

        if element_name.lower() == 'coverage':
            spatial_coverage_dict = get_coverage_data_dict(resource)
            temporal_coverage_dict = get_coverage_data_dict(resource, coverage_type='temporal')
            ajax_response_data['spatial_coverage'] = spatial_coverage_dict
            ajax_response_data['temporal_coverage'] = temporal_coverage_dict

        return JsonResponse(ajax_response_data, status=status.HTTP_200_OK)
    else:
        ajax_response_data = {'status': 'error', 'message': err_msg}
        # need to return http status 200 to show form errors
        return JsonResponse(ajax_response_data, status=status.HTTP_200_OK)
Ejemplo n.º 2
0
def update_aggregation_coverage(request, file_type_id, coverage_type):
    """Updates fileset aggregation level coverage using coverage data from the contained
    aggregations
    :param  file_type_id:   id of the fileset aggregation for which coverage needs to be updated
    :param  coverage_type:  a value of either temporal or spatial
    """
    response_data = {'status': 'error'}
    fs_aggr = FileSetLogicalFile.objects.filter(id=file_type_id).first()
    if fs_aggr is None:
        err_msg = "No matching fileset aggregation was found."
        response_data['message'] = err_msg
        return JsonResponse(response_data, status=status.HTTP_400_BAD_REQUEST)
    resource_id = fs_aggr.resource.short_id
    resource, authorized, _ = authorize(
        request,
        resource_id,
        needed_permission=ACTION_TO_AUTHORIZE.EDIT_RESOURCE,
        raises_exception=False)

    if not authorized:
        response_data['message'] = "Permission denied"
        return JsonResponse(response_data, status=status.HTTP_400_BAD_REQUEST)

    if coverage_type.lower() not in ('temporal', 'spatial'):
        err_msg = "Invalid coverage type specified."
        response_data['message'] = err_msg
        return JsonResponse(response_data, status=status.HTTP_400_BAD_REQUEST)

    if coverage_type.lower() == 'spatial':
        fs_aggr.update_spatial_coverage()
        coverage_element = fs_aggr.metadata.spatial_coverage
    else:
        fs_aggr.update_temporal_coverage()
        coverage_element = fs_aggr.metadata.temporal_coverage

    msg = "Aggregation {} coverage was updated successfully.".format(
        coverage_type.lower())
    response_data['status'] = 'success'
    response_data['message'] = msg
    if coverage_type.lower() == 'spatial':
        response_data['spatial_coverage'] = get_coverage_data_dict(fs_aggr)
    else:
        response_data['temporal_coverage'] = get_coverage_data_dict(
            fs_aggr, 'temporal')
    response_data['element_id'] = coverage_element.id
    response_data['logical_file_id'] = fs_aggr.id
    response_data['logical_file_type'] = fs_aggr.type_name()
    return JsonResponse(response_data, status=status.HTTP_200_OK)
Ejemplo n.º 3
0
def _process_resource_coverage_action(request, resource_id, coverage_type,
                                      action):
    res, authorized, _ = authorize(
        request,
        resource_id,
        needed_permission=ACTION_TO_AUTHORIZE.EDIT_RESOURCE,
        raises_exception=False)

    response_data = {'status': 'error'}
    if not authorized:
        err_msg = "Permission denied"
        response_data['message'] = err_msg
        return JsonResponse(response_data, status=status.HTTP_401_UNAUTHORIZED)

    if res.resource_type != "CompositeResource":
        err_msg = "Coverage can be {}d only for composite resource.".format(
            action)
        response_data['message'] = err_msg
        return JsonResponse(response_data, status=status.HTTP_400_BAD_REQUEST)

    if coverage_type.lower() not in ('temporal', 'spatial'):
        err_msg = "Invalid coverage type specified."
        response_data['message'] = err_msg
        return JsonResponse(response_data, status=status.HTTP_400_BAD_REQUEST)

    if coverage_type.lower() == 'spatial':
        if action == 'delete':
            res.delete_coverage(coverage_type='spatial')
        else:
            res.update_spatial_coverage()
    else:
        if action == 'delete':
            res.delete_coverage(coverage_type='temporal')
        else:
            res.update_temporal_coverage()

    msg = "Resource {0} coverage was {1}d successfully.".format(
        coverage_type.lower(), action)
    response_data['status'] = 'success'
    response_data['message'] = msg
    if coverage_type.lower() == 'spatial':
        spatial_coverage_dict = get_coverage_data_dict(res)
        response_data['spatial_coverage'] = spatial_coverage_dict
    else:
        temporal_coverage_dict = get_coverage_data_dict(res, 'temporal')
        response_data['temporal_coverage'] = temporal_coverage_dict

    return JsonResponse(response_data, status=status.HTTP_200_OK)
Ejemplo n.º 4
0
def remove_aggregation(request, resource_id, hs_file_type, file_type_id, **kwargs):
    """Deletes an instance of a specific file type (aggregation) and all the associated metadata.
    However, it doesn't delete resource files associated with the aggregation.
    """

    response_data = {'status': 'error'}

    res, _, _ = authorize(request, resource_id, needed_permission=ACTION_TO_AUTHORIZE.EDIT_RESOURCE)
    if res.resource_type != "CompositeResource":
        err_msg = "Aggregation type can be deleted only in composite resource."
        response_data['message'] = err_msg
        return JsonResponse(response_data, status=status.HTTP_400_BAD_REQUEST)

    if hs_file_type not in FILE_TYPE_MAP:
        err_msg = "Unsupported aggregation type. Supported aggregation types are: {}"
        err_msg = err_msg.format(FILE_TYPE_MAP.keys())
        response_data['message'] = err_msg
        return JsonResponse(response_data, status=status.HTTP_400_BAD_REQUEST)

    content_type = ContentType.objects.get(app_label="hs_file_types", model=hs_file_type.lower())
    logical_file_type_class = content_type.model_class()
    aggregation = logical_file_type_class.objects.filter(id=file_type_id).first()
    if aggregation is None:
        err_msg = "No matching aggregation was found."
        response_data['message'] = err_msg
        return JsonResponse(response_data, status=status.HTTP_400_BAD_REQUEST)

    aggregation.remove_aggregation()
    msg = "Aggregation was successfully removed."
    response_data['status'] = 'success'
    response_data['message'] = msg
    spatial_coverage_dict = get_coverage_data_dict(res)
    response_data['spatial_coverage'] = spatial_coverage_dict
    return JsonResponse(response_data, status=status.HTTP_200_OK)
Ejemplo n.º 5
0
def set_file_type(request, resource_id, file_id, hs_file_type, **kwargs):
    """Set a file (*file_id*) to a specific file type (*hs_file_type*)
    :param  request: an instance of HttpRequest
    :param  resource_id: id of the resource in which this file type needs to be set
    :param  file_id: id of the file which needs to be set to a file type
    :param  hs_file_type: file type to be set (e.g, NetCDF, GeoRaster, GeoFeature etc)
    :return an instance of JsonResponse type
    """
    res, authorized, _ = authorize(
        request,
        resource_id,
        needed_permission=ACTION_TO_AUTHORIZE.EDIT_RESOURCE,
        raises_exception=False)
    file_type_map = {
        "GeoRaster": GeoRasterLogicalFile,
        "NetCDF": NetCDFLogicalFile,
        'GeoFeature': GeoFeatureLogicalFile,
        'RefTimeseries': RefTimeseriesLogicalFile,
        'TimeSeries': TimeSeriesLogicalFile
    }
    response_data = {'status': 'error'}
    if not authorized:
        err_msg = "Permission denied"
        response_data['message'] = err_msg
        return JsonResponse(response_data, status=status.HTTP_401_UNAUTHORIZED)

    if res.resource_type != "CompositeResource":
        err_msg = "File type can be set only for files in composite resource."
        response_data['message'] = err_msg
        return JsonResponse(response_data, status=status.HTTP_400_BAD_REQUEST)

    if hs_file_type not in file_type_map:
        err_msg = "Unsupported file type. Supported file types are: {}".format(
            file_type_map.keys())
        response_data['message'] = err_msg
        return JsonResponse(response_data, status=status.HTTP_400_BAD_REQUEST)

    try:
        logical_file_type_class = file_type_map[hs_file_type]
        logical_file_type_class.set_file_type(resource=res,
                                              file_id=file_id,
                                              user=request.user)
        resource_modified(res, request.user, overwrite_bag=False)
        msg = "File was successfully set to selected file type. " \
              "Metadata extraction was successful."
        response_data['status'] = 'success'
        response_data['message'] = msg
        spatial_coverage_dict = get_coverage_data_dict(res)
        response_data['spatial_coverage'] = spatial_coverage_dict
        return JsonResponse(response_data, status=status.HTTP_201_CREATED)

    except ValidationError as ex:
        response_data['message'] = ex.message
        return JsonResponse(response_data, status=status.HTTP_400_BAD_REQUEST)
    except Exception as ex:
        response_data['message'] = ex.message
        return JsonResponse(response_data,
                            status=status.HTTP_500_INTERNAL_SERVER_ERROR)
Ejemplo n.º 6
0
def set_file_type(request, resource_id, hs_file_type, file_id=None, **kwargs):
    """Set a file (*file_id*) to a specific file type - aggregation (*hs_file_type*)
    :param  request: an instance of HttpRequest
    :param  resource_id: id of the resource in which this file type needs to be set
    :param  file_id: id of the file which needs to be set to a file type. If file_id is not provided
    then the request must have a file_folder key. In that case the specified folder will be used
    for creating the logical file (aggregation)
    :param  hs_file_type: file type to be set (e.g, SingleFile, NetCDF, GeoRaster, RefTimeseries,
    TimeSeries and GeoFeature)
    :return an instance of JsonResponse type
    """

    response_data = {'status': 'error'}
    folder_path = None
    if file_id is None:
        folder_path = request.POST.get('folder_path', "")
        if not folder_path:
            err_msg = "Must provide id of the file or folder path for setting aggregation type."
            response_data['message'] = err_msg
            return JsonResponse(response_data, status=status.HTTP_400_BAD_REQUEST)

    res, authorized, _ = authorize(request, resource_id,
                                   needed_permission=ACTION_TO_AUTHORIZE.EDIT_RESOURCE,
                                   raises_exception=False)
    response_data = {'status': 'error'}
    if not authorized:
        err_msg = "Permission denied"
        response_data['message'] = err_msg
        return JsonResponse(response_data, status=status.HTTP_401_UNAUTHORIZED)

    if res.resource_type != "CompositeResource":
        err_msg = "Aggregation type can be set only for files in composite resource."
        response_data['message'] = err_msg
        return JsonResponse(response_data, status=status.HTTP_400_BAD_REQUEST)

    try:
        set_logical_file_type(res, request.user, file_id, hs_file_type, folder_path)
        resource_modified(res, request.user, overwrite_bag=False)

        msg = "{} was successfully set to the selected aggregation type."
        if folder_path is None:
            msg = msg.format("Selected file")
        else:
            msg = msg.format("Selected folder")

        response_data['status'] = 'success'
        response_data['message'] = msg
        spatial_coverage_dict = get_coverage_data_dict(res)
        response_data['spatial_coverage'] = spatial_coverage_dict
        return JsonResponse(response_data, status=status.HTTP_201_CREATED)

    except ValidationError as ex:
        response_data['message'] = ex.message
        return JsonResponse(response_data, status=status.HTTP_400_BAD_REQUEST)
    except Exception as ex:
        response_data['message'] = ex.message
        return JsonResponse(response_data, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
Ejemplo n.º 7
0
def update_resource_coverage(request, resource_id, coverage_type, **kwargs):
    """Updates resource coverage based on the coverages of the contained aggregations
    (file types)
    :param  request: an instance of HttpRequest
    :param  resource_id: id of resource for which coverage needs to be updated
    :param  coverage_type: a value of either temporal or spatial
    :return an instance of JsonResponse type
    """

    res, authorized, _ = authorize(request, resource_id,
                                   needed_permission=ACTION_TO_AUTHORIZE.EDIT_RESOURCE,
                                   raises_exception=False)
    response_data = {'status': 'error'}
    if not authorized:
        err_msg = "Permission denied"
        response_data['message'] = err_msg
        return JsonResponse(response_data, status=status.HTTP_401_UNAUTHORIZED)

    if res.resource_type != "CompositeResource":
        err_msg = "Coverage can be updated only for composite resource."
        response_data['message'] = err_msg
        return JsonResponse(response_data, status=status.HTTP_400_BAD_REQUEST)

    if coverage_type.lower() not in ('temporal', 'spatial'):
        err_msg = "Invalid coverage type specified."
        response_data['message'] = err_msg
        return JsonResponse(response_data, status=status.HTTP_400_BAD_REQUEST)

    if coverage_type.lower() == 'spatial':
        res.update_spatial_coverage()
    else:
        res.update_temporal_coverage()

    msg = "Resource {} coverage was updated successfully.".format(coverage_type.lower())
    response_data['status'] = 'success'
    response_data['message'] = msg
    if coverage_type.lower() == 'spatial':
        spatial_coverage_dict = get_coverage_data_dict(res)
        response_data['spatial_coverage'] = spatial_coverage_dict
    else:
        temporal_coverage_dict = get_coverage_data_dict(res, 'temporal')
        response_data['temporal_coverage'] = temporal_coverage_dict

    return JsonResponse(response_data, status=status.HTTP_200_OK)
Ejemplo n.º 8
0
def _process_resource_coverage_action(request, resource_id, coverage_type, action):
    res, authorized, _ = authorize(request, resource_id,
                                   needed_permission=ACTION_TO_AUTHORIZE.EDIT_RESOURCE,
                                   raises_exception=False)

    response_data = {'status': 'error'}
    if not authorized:
        err_msg = "Permission denied"
        response_data['message'] = err_msg
        return JsonResponse(response_data, status=status.HTTP_401_UNAUTHORIZED)

    if res.resource_type != "CompositeResource":
        err_msg = "Coverage can be {}d only for composite resource.".format(action)
        response_data['message'] = err_msg
        return JsonResponse(response_data, status=status.HTTP_400_BAD_REQUEST)

    if coverage_type.lower() not in ('temporal', 'spatial'):
        err_msg = "Invalid coverage type specified."
        response_data['message'] = err_msg
        return JsonResponse(response_data, status=status.HTTP_400_BAD_REQUEST)

    if coverage_type.lower() == 'spatial':
        if action == 'delete':
            res.delete_coverage(coverage_type='spatial')
        else:
            res.update_spatial_coverage()
    else:
        if action == 'delete':
            res.delete_coverage(coverage_type='temporal')
        else:
            res.update_temporal_coverage()

    msg = "Resource {0} coverage was {1}d successfully.".format(coverage_type.lower(), action)
    response_data['status'] = 'success'
    response_data['message'] = msg
    if coverage_type.lower() == 'spatial':
        spatial_coverage_dict = get_coverage_data_dict(res)
        response_data['spatial_coverage'] = spatial_coverage_dict
    else:
        temporal_coverage_dict = get_coverage_data_dict(res, 'temporal')
        response_data['temporal_coverage'] = temporal_coverage_dict

    return JsonResponse(response_data, status=status.HTTP_200_OK)
Ejemplo n.º 9
0
def set_file_type(request, resource_id, file_id, hs_file_type, **kwargs):
    """This view function must be called using ajax call.
    Note: Response status code is always 200 (OK). Client needs check the
    the response 'status' key for success or failure.
    """
    res, authorized, _ = authorize(
        request,
        resource_id,
        needed_permission=ACTION_TO_AUTHORIZE.EDIT_RESOURCE,
        raises_exception=False)
    file_type_map = {
        "GeoRaster": GeoRasterLogicalFile,
        "NetCDF": NetCDFLogicalFile
    }
    response_data = {'status': 'error'}
    if not authorized:
        err_msg = "Permission denied"
        response_data['message'] = err_msg
        return JsonResponse(response_data, status=status.HTTP_200_OK)

    if res.resource_type != "CompositeResource":
        err_msg = "File type can be set only for files in composite resource."
        response_data['message'] = err_msg
        return JsonResponse(response_data, status=status.HTTP_200_OK)

    if hs_file_type not in file_type_map:
        err_msg = "Unsupported file type."
        response_data['message'] = err_msg
        return JsonResponse(response_data, status=status.HTTP_200_OK)

    try:
        logical_file_type_class = file_type_map[hs_file_type]
        logical_file_type_class.set_file_type(resource=res,
                                              file_id=file_id,
                                              user=request.user)
        resource_modified(res, request.user, overwrite_bag=False)
        msg = "File was successfully set to selected file type. " \
              "Metadata extraction was successful."
        response_data['message'] = msg
        response_data['status'] = 'success'
        spatial_coverage_dict = get_coverage_data_dict(res)
        response_data['spatial_coverage'] = spatial_coverage_dict
        return JsonResponse(response_data, status=status.HTTP_200_OK)

    except ValidationError as ex:
        response_data['message'] = ex.message
        return JsonResponse(response_data, status=status.HTTP_200_OK)
def data_store_structure(request):
    """
    Get file hierarchy (collection of subcollections and data objects) for the requested directory
    in hydroshareZone or any federated zone used for CommonsShare resource backend store.
    It is invoked by an AJAX call and returns json object that holds content for files
    and folders under the requested directory/collection/subcollection.
    The AJAX request must be a POST request with input data passed in for res_id and store_path
    where store_path is the relative path under res_id collection/directory
    """
    res_id = request.POST.get('res_id', None)
    if res_id is None:
        logger.error("no resource id in request")
        return HttpResponse('Bad request - resource id is not included',
                            status=status.HTTP_500_INTERNAL_SERVER_ERROR)
    res_id = str(res_id).strip()
    try:
        resource, _, _ = authorize(
            request,
            res_id,
            needed_permission=ACTION_TO_AUTHORIZE.VIEW_RESOURCE)
    except NotFound:
        logger.error("resource {} not found".format(res_id))
        return HttpResponse('Bad request - resource not found',
                            status=status.HTTP_400_BAD_REQUEST)
    except PermissionDenied:
        logger.error("permission denied for resource {}".format(res_id))
        return HttpResponse('Permission denied',
                            status=status.HTTP_401_UNAUTHORIZED)

    store_path = request.POST.get('store_path', None)
    if store_path is None:
        logger.error("store_path not included for resource {}".format(res_id))
        return HttpResponse('Bad request - store_path is not included',
                            status=status.HTTP_400_BAD_REQUEST)
    store_path = str(store_path).strip()
    if not store_path:
        logger.error("store_path empty for resource {}".format(res_id))
        return HttpResponse('Bad request - store_path cannot be empty',
                            status=status.HTTP_400_BAD_REQUEST)

    if not store_path.startswith('data/contents'):
        logger.error(
            "store_path doesn't start with data/contents for resource {}".
            format(res_id))
        return HttpResponse(
            'Bad request - store_path must start with data/contents/',
            status=status.HTTP_400_BAD_REQUEST)

    if store_path.find('/../') >= 0 or store_path.endswith('/..'):
        logger.error(
            "store_path cannot contain .. for resource {}".format(res_id))
        return HttpResponse('Bad request - store_path cannot contain /../',
                            status=status.HTTP_400_BAD_REQUEST)

    istorage = resource.get_irods_storage()
    res_coll = os.path.join(resource.root_path, store_path)
    try:
        store = istorage.listdir(res_coll)
        files = []
        for fname in store[1]:  # files
            fname = fname.decode('utf-8')
            name_with_full_path = os.path.join(res_coll, fname)
            size = istorage.size(name_with_full_path)
            mtype = get_file_mime_type(fname)
            idx = mtype.find('/')
            if idx >= 0:
                mtype = mtype[idx + 1:]
            f_pk = ''
            f_url = ''
            logical_file_type = ''
            logical_file_id = ''
            for f in ResourceFile.objects.filter(object_id=resource.id):
                if name_with_full_path == f.storage_path:
                    f_pk = f.pk
                    f_url = get_resource_file_url(f)
                    if resource.resource_type == "CompositeResource":
                        f_logical = f.get_or_create_logical_file
                        logical_file_type = f.logical_file_type_name
                        logical_file_id = f_logical.id
                    break

            if f_pk:  # file is found in Django
                files.append({
                    'name': fname,
                    'size': size,
                    'type': mtype,
                    'pk': f_pk,
                    'url': f_url,
                    'logical_type': logical_file_type,
                    'logical_file_id': logical_file_id
                })
            else:  # file is not found in Django
                logger.error(
                    "data_store_structure: filename {} in iRODs has no analogue in Django"
                    .format(name_with_full_path))
        # show reference file links if any which don't have physical presence in iRODS
        for f in ResourceFile.objects.filter(object_id=resource.id):
            if not f.resource_file and not f.fed_resource_file and f.reference_file_path:
                files.append({
                    'name': f.reference_file_path,
                    'size': f.reference_file_size,
                    'type': 'Reference',
                    'pk': f.pk,
                    'url': '',
                    'logical_type': '',
                    'logical_file_id': ''
                })
    except SessionException as ex:
        logger.error("session exception querying store_path {} for {}".format(
            store_path, res_id))
        return HttpResponse(ex.stderr,
                            status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    return_object = {
        'files': files,
        'folders': store[0],
        'can_be_public': resource.can_be_public_or_discoverable
    }

    if resource.resource_type == "CompositeResource":
        spatial_coverage_dict = get_coverage_data_dict(resource)
        temporal_coverage_dict = get_coverage_data_dict(
            resource, coverage_type='temporal')
        return_object['spatial_coverage'] = spatial_coverage_dict
        return_object['temporal_coverage'] = temporal_coverage_dict
    return HttpResponse(json.dumps(return_object),
                        content_type="application/json")
Ejemplo n.º 11
0
def data_store_structure(request):
    """
    Get file hierarchy (collection of subcollections and data objects) for the requested directory
    in hydroshareZone or any federated zone used for HydroShare resource backend store.
    It is invoked by an AJAX call and returns json object that holds content for files
    and folders under the requested directory/collection/subcollection.
    The AJAX request must be a POST request with input data passed in for res_id and store_path
    where store_path is the relative path to res_id/data/contents
    """
    res_id = request.POST.get('res_id', None)
    if res_id is None:
        logger.error("no resource id in request")
        return HttpResponse('Bad request - resource id is not included',
                            status=status.HTTP_500_INTERNAL_SERVER_ERROR)
    res_id = str(res_id).strip()
    try:
        resource, _, _ = authorize(
            request,
            res_id,
            needed_permission=ACTION_TO_AUTHORIZE.VIEW_RESOURCE)
    except NotFound:
        logger.error("resource {} not found".format(res_id))
        return HttpResponse('Bad request - resource not found',
                            status=status.HTTP_400_BAD_REQUEST)
    except PermissionDenied:
        logger.error("permission denied for resource {}".format(res_id))
        return HttpResponse('Permission denied',
                            status=status.HTTP_401_UNAUTHORIZED)

    store_path = request.POST.get('store_path', None)

    try:
        store_path = _validate_path(store_path,
                                    'store_path',
                                    check_path_empty=False)
    except ValidationError as ex:
        return HttpResponse(str(ex), status=status.HTTP_400_BAD_REQUEST)

    istorage = resource.get_irods_storage()
    directory_in_irods = resource.get_irods_path(store_path)

    try:
        store = istorage.listdir(directory_in_irods)
    except SessionException as ex:
        logger.error("session exception querying store_path {} for {}".format(
            store_path, res_id))
        return HttpResponse(ex.stderr,
                            status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    files = []
    dirs = []
    aggregations = []
    # folder path relative to 'data/contents/' needed for the UI
    folder_path = store_path[len("data/contents/"):]
    for dname in store[0]:  # directories
        d_pk = dname
        d_store_path = os.path.join(store_path, d_pk)
        d_url = resource.get_url_of_path(d_store_path)
        main_file = ''
        folder_aggregation_type = ''
        folder_aggregation_name = ''
        folder_aggregation_id = ''
        folder_aggregation_type_to_set = ''
        if resource.resource_type == "CompositeResource":
            dir_path = resource.get_irods_path(d_store_path)
            # find if this folder *dir_path* represents (contains) an aggregation object
            aggregation_object = resource.get_folder_aggregation_object(
                dir_path)
            # folder aggregation type is not relevant for single file aggregation types - which
            # are: GenericLogicalFile, and RefTimeseriesLogicalFile
            if aggregation_object is not None:
                folder_aggregation_type = aggregation_object.get_aggregation_class_name(
                )
                folder_aggregation_name = aggregation_object.get_aggregation_display_name(
                )
                folder_aggregation_id = aggregation_object.id
                if not aggregation_object.is_fileset:
                    main_file = aggregation_object.get_main_file.file_name
            else:
                # find if FileSet aggregation type that can be created from this folder
                if resource.can_set_folder_to_fileset(dir_path):
                    folder_aggregation_type_to_set = FileSetLogicalFile.__name__
                else:
                    folder_aggregation_type_to_set = ""
        dirs.append({
            'name': d_pk,
            'url': d_url,
            'main_file': main_file,
            'folder_aggregation_type': folder_aggregation_type,
            'folder_aggregation_name': folder_aggregation_name,
            'folder_aggregation_id': folder_aggregation_id,
            'folder_aggregation_type_to_set': folder_aggregation_type_to_set,
            'folder_short_path': os.path.join(folder_path, d_pk)
        })

    is_federated = resource.is_federated
    for index, fname in enumerate(store[1]):  # files
        f_store_path = os.path.join(store_path, fname)
        file_in_irods = resource.get_irods_path(f_store_path)
        size = store[2][index]
        mtype = get_file_mime_type(fname)
        idx = mtype.find('/')
        if idx >= 0:
            mtype = mtype[idx + 1:]

        if is_federated:
            f = ResourceFile.objects.filter(
                object_id=resource.id,
                fed_resource_file=file_in_irods).first()
        else:
            f = ResourceFile.objects.filter(
                object_id=resource.id, resource_file=file_in_irods).first()

        if not f:
            # skip metadata files
            continue

        f_ref_url = ''
        logical_file_type = ''
        logical_file_id = ''
        aggregation_name = ''
        if f.has_logical_file:
            main_extension = f.logical_file.get_main_file_type()
            if not main_extension:
                # accept any extension
                main_extension = ""
            if main_extension.endswith(f.extension):
                aggregations.append({
                    'logical_file_id':
                    f.logical_file.id,
                    'name':
                    f.logical_file.dataset_name,
                    'logical_type':
                    f.logical_file.get_aggregation_class_name(),
                    'aggregation_name':
                    f.logical_file.get_aggregation_display_name(),
                    'main_file':
                    f.logical_file.get_main_file.file_name,
                    'url':
                    f.logical_file.url
                })
            logical_file_type = f.logical_file_type_name
            logical_file_id = f.logical_file.id
            aggregation_name = f.aggregation_display_name
            if 'url' in f.logical_file.extra_data:
                f_ref_url = f.logical_file.extra_data['url']

        files.append({
            'name': fname,
            'size': size,
            'type': mtype,
            'pk': f.pk,
            'url': f.url,
            'reference_url': f_ref_url,
            'aggregation_name': aggregation_name,
            'logical_type': logical_file_type,
            'logical_file_id': logical_file_id
        })

    return_object = {
        'files': files,
        'folders': dirs,
        'aggregations': aggregations,
        'can_be_public': resource.can_be_public_or_discoverable
    }

    if resource.resource_type == "CompositeResource":
        return_object['spatial_coverage'] = get_coverage_data_dict(resource)
        return_object['temporal_coverage'] = get_coverage_data_dict(
            resource, coverage_type='temporal')
    return HttpResponse(json.dumps(return_object),
                        content_type="application/json")
Ejemplo n.º 12
0
def delete_coverage_element(request, hs_file_type, file_type_id, element_id,
                            **kwargs):
    """This function is to delete coverage metadata for single file aggregation or file set
    aggregation"""

    element_type = 'coverage'
    if hs_file_type not in ('GenericLogicalFile', 'FileSetLogicalFile'):
        err_msg = "Coverage can be deleted only for single file content or file set content."
        ajax_response_data = {'status': 'error', 'message': err_msg}
        return JsonResponse(ajax_response_data, status=status.HTTP_200_OK)

    content_type = ContentType.objects.get(app_label="hs_file_types",
                                           model=hs_file_type.lower())
    logical_file_type_class = content_type.model_class()
    logical_file = logical_file_type_class.objects.filter(
        id=file_type_id).first()
    if logical_file is None:
        err_msg = "No matching aggregation type was found."
        ajax_response_data = {'status': 'error', 'message': err_msg}
        return JsonResponse(ajax_response_data, status=status.HTTP_200_OK)

    resource_id = logical_file.resource.short_id
    resource, authorized, _ = authorize(
        request,
        resource_id,
        needed_permission=ACTION_TO_AUTHORIZE.EDIT_RESOURCE,
        raises_exception=False)

    if not authorized:
        ajax_response_data = {
            'status': 'error',
            'logical_file_type': logical_file.type_name(),
            'element_name': element_type,
            'message': "Permission denied"
        }
        return JsonResponse(ajax_response_data, status=status.HTTP_200_OK)

    coverage_element = logical_file.metadata.coverages.filter(
        id=element_id).first()
    if coverage_element is None:
        ajax_response_data = {
            'status': 'error',
            'logical_file_type': logical_file.type_name(),
            'element_name': element_type,
            'message': "No matching coverage was found"
        }
        return JsonResponse(ajax_response_data, status=status.HTTP_200_OK)
    # delete the coverage element
    logical_file.metadata.delete_element(element_type, element_id)

    if resource.can_be_public_or_discoverable:
        metadata_status = METADATA_STATUS_SUFFICIENT
    else:
        metadata_status = METADATA_STATUS_INSUFFICIENT

    ajax_response_data = {
        'status': 'success',
        'element_name': element_type,
        'metadata_status': metadata_status,
        'logical_file_type': logical_file.type_name(),
        'logical_file_id': logical_file.id
    }

    spatial_coverage_dict = get_coverage_data_dict(resource)
    temporal_coverage_dict = get_coverage_data_dict(resource,
                                                    coverage_type='temporal')
    ajax_response_data['spatial_coverage'] = spatial_coverage_dict
    ajax_response_data['temporal_coverage'] = temporal_coverage_dict

    ajax_response_data['has_logical_spatial_coverage'] = \
        resource.has_logical_spatial_coverage
    ajax_response_data['has_logical_temporal_coverage'] = \
        resource.has_logical_temporal_coverage

    return JsonResponse(ajax_response_data, status=status.HTTP_200_OK)
Ejemplo n.º 13
0
def add_metadata_element(request, hs_file_type, file_type_id, element_name,
                         **kwargs):
    err_msg = "Failed to create metadata element '{}'. {}."
    content_type = ContentType.objects.get(app_label="hs_file_types",
                                           model=hs_file_type.lower())
    logical_file_type_class = content_type.model_class()
    logical_file = logical_file_type_class.objects.filter(
        id=file_type_id).first()

    if logical_file is None:
        err_msg = "No matching aggregation type was found."
        ajax_response_data = {'status': 'error', 'message': err_msg}
        return JsonResponse(ajax_response_data, status=status.HTTP_200_OK)

    resource_id = logical_file.resource.short_id
    resource, authorized, _ = authorize(
        request,
        resource_id,
        needed_permission=ACTION_TO_AUTHORIZE.EDIT_RESOURCE,
        raises_exception=False)

    if not authorized:
        ajax_response_data = {
            'status': 'error',
            'logical_file_type': logical_file.type_name(),
            'element_name': element_name,
            'message': "Permission denied"
        }
        return JsonResponse(ajax_response_data, status=status.HTTP_200_OK)

    validation_response = logical_file.metadata.validate_element_data(
        request, element_name)
    is_add_success = False
    if validation_response['is_valid']:
        element_data_dict = validation_response['element_data_dict']
        try:
            element = logical_file.metadata.create_element(
                element_name, **element_data_dict)
            resource_modified(logical_file.resource,
                              request.user,
                              overwrite_bag=False)
            is_add_success = True
        except ValidationError as ex:
            err_msg = err_msg.format(element_name, ex.message)
        except Error as ex:
            err_msg = err_msg.format(element_name, ex.message)
    else:
        err_msg = err_msg.format(element_name, validation_response['errors'])

    if is_add_success:
        form_action = "/hsapi/_internal/{0}/{1}/{2}/{3}/update-file-metadata/"
        form_action = form_action.format(logical_file.type_name(),
                                         logical_file.id, element_name,
                                         element.id)

        if resource.can_be_public_or_discoverable:
            metadata_status = METADATA_STATUS_SUFFICIENT
        else:
            metadata_status = METADATA_STATUS_INSUFFICIENT

        ajax_response_data = {
            'status': 'success',
            'logical_file_type': logical_file.type_name(),
            'element_name': element_name,
            'form_action': form_action,
            'element_id': element.id,
            'metadata_status': metadata_status
        }

        if logical_file.type_name() == "TimeSeriesLogicalFile":
            ajax_response_data['is_dirty'] = logical_file.metadata.is_dirty
            ajax_response_data[
                'can_update_sqlite'] = logical_file.can_update_sqlite_file
            if element_name.lower() == 'site':
                # get the updated spatial coverage of the resource
                spatial_coverage_dict = get_coverage_data_dict(resource)
                ajax_response_data['spatial_coverage'] = spatial_coverage_dict
        elif element_name.lower() == 'coverage':
            spatial_coverage_dict = get_coverage_data_dict(resource)
            temporal_coverage_dict = get_coverage_data_dict(
                resource, coverage_type='temporal')
            ajax_response_data['spatial_coverage'] = spatial_coverage_dict
            ajax_response_data['temporal_coverage'] = temporal_coverage_dict

        ajax_response_data[
            'has_logical_spatial_coverage'] = resource.has_logical_spatial_coverage
        ajax_response_data[
            'has_logical_temporal_coverage'] = resource.has_logical_temporal_coverage

        return JsonResponse(ajax_response_data, status=status.HTTP_200_OK)
    else:
        ajax_response_data = {'status': 'error', 'message': err_msg}
        # need to return http status 200 to show form errors
        return JsonResponse(ajax_response_data, status=status.HTTP_200_OK)
def data_store_structure(request):
    """
    Get file hierarchy (collection of subcollections and data objects) for the requested directory
    in hydroshareZone or any federated zone used for HydroShare resource backend store.
    It is invoked by an AJAX call and returns json object that holds content for files
    and folders under the requested directory/collection/subcollection.
    The AJAX request must be a POST request with input data passed in for res_id and store_path
    where store_path is the relative path to res_id/data/contents
    """
    res_id = request.POST.get('res_id', None)
    if res_id is None:
        logger.error("no resource id in request")
        return HttpResponse('Bad request - resource id is not included',
                            status=status.HTTP_500_INTERNAL_SERVER_ERROR)
    res_id = str(res_id).strip()
    try:
        resource, _, _ = authorize(request, res_id,
                                   needed_permission=ACTION_TO_AUTHORIZE.VIEW_RESOURCE)
    except NotFound:
        logger.error("resource {} not found".format(res_id))
        return HttpResponse('Bad request - resource not found', status=status.HTTP_400_BAD_REQUEST)
    except PermissionDenied:
        logger.error("permission denied for resource {}".format(res_id))
        return HttpResponse('Permission denied', status=status.HTTP_401_UNAUTHORIZED)

    store_path = request.POST.get('store_path', None)

    try:
        store_path = _validate_path(store_path, 'store_path', check_path_empty=False)
    except ValidationError as ex:
        return HttpResponse(ex.message, status=status.HTTP_400_BAD_REQUEST)

    istorage = resource.get_irods_storage()
    directory_in_irods = resource.get_irods_path(store_path)

    try:
        store = istorage.listdir(directory_in_irods)
    except SessionException as ex:
        logger.error("session exception querying store_path {} for {}".format(store_path, res_id))
        return HttpResponse(ex.stderr, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    files = []
    dirs = []
    # folder path relative to 'data/contents/' needed for the UI
    folder_path = store_path[len("data/contents/"):]
    for dname in store[0]:     # directories
        d_pk = dname.decode('utf-8')
        d_store_path = os.path.join(store_path, d_pk)
        d_url = resource.get_url_of_path(d_store_path)
        main_file = ''
        folder_aggregation_type = ''
        folder_aggregation_name = ''
        folder_aggregation_id = ''
        folder_aggregation_type_to_set = ''
        if resource.resource_type == "CompositeResource":
            dir_path = resource.get_public_path(d_store_path)
            # find if this folder *dir_path* represents (contains) an aggregation object
            aggregation_object = resource.get_folder_aggregation_object(dir_path)
            # folder aggregation type is not relevant for single file aggregation types - which
            # are: GenericLogicalFile, and RefTimeseriesLogicalFile
            if aggregation_object is not None and not \
                    aggregation_object.is_single_file_aggregation:
                folder_aggregation_type = aggregation_object.get_aggregation_class_name()
                folder_aggregation_name = aggregation_object.get_aggregation_display_name()
                folder_aggregation_id = aggregation_object.id
                main_file = ''
                if not aggregation_object.is_fileset:
                    main_file = aggregation_object.get_main_file.file_name
            else:
                # find if any aggregation type that can be created from this folder
                folder_aggregation_type_to_set =  \
                    resource.get_folder_aggregation_type_to_set(dir_path)
                if folder_aggregation_type_to_set is None:
                    folder_aggregation_type_to_set = ""
        dirs.append({'name': d_pk,
                     'url': d_url,
                     'main_file': main_file,
                     'folder_aggregation_type': folder_aggregation_type,
                     'folder_aggregation_name': folder_aggregation_name,
                     'folder_aggregation_id': folder_aggregation_id,
                     'folder_aggregation_type_to_set': folder_aggregation_type_to_set,
                     'folder_short_path': os.path.join(folder_path, d_pk)})

    is_federated = resource.is_federated
    for index, fname in enumerate(store[1]):  # files
        fname = fname.decode('utf-8')
        f_store_path = os.path.join(store_path, fname)
        file_in_irods = resource.get_irods_path(f_store_path)
        size = store[2][index]
        mtype = get_file_mime_type(fname)
        idx = mtype.find('/')
        if idx >= 0:
            mtype = mtype[idx + 1:]

        if is_federated:
            f = ResourceFile.objects.filter(object_id=resource.id,
                                            fed_resource_file=file_in_irods).first()
        else:
            f = ResourceFile.objects.filter(object_id=resource.id,
                                            resource_file=file_in_irods).first()

        if not f:
            # skip metadata files
            continue

        f_ref_url = ''
        logical_file_type = ''
        logical_file_id = ''
        aggregation_name = ''
        is_single_file_aggregation = ''
        if resource.resource_type == "CompositeResource":
            if f.has_logical_file:
                logical_file_type = f.logical_file_type_name
                logical_file_id = f.logical_file.id
                aggregation_name = f.aggregation_display_name
                is_single_file_aggregation = f.logical_file.is_single_file_aggregation
                if 'url' in f.logical_file.extra_data:
                    f_ref_url = f.logical_file.extra_data['url']

        files.append({'name': fname, 'size': size, 'type': mtype, 'pk': f.pk, 'url': f.url,
                      'reference_url': f_ref_url,
                      'aggregation_name': aggregation_name,
                      'logical_type': logical_file_type,
                      'logical_file_id': logical_file_id,
                      'is_single_file_aggregation': is_single_file_aggregation})

    return_object = {'files': files,
                     'folders': dirs,
                     'can_be_public': resource.can_be_public_or_discoverable}

    if resource.resource_type == "CompositeResource":
        return_object['spatial_coverage'] = get_coverage_data_dict(resource)
        return_object['temporal_coverage'] = get_coverage_data_dict(resource,
                                                                    coverage_type='temporal')
    return HttpResponse(
        json.dumps(return_object),
        content_type="application/json"
    )
def data_store_structure(request):
    """
    Get file hierarchy (collection of subcollections and data objects) for the requested directory
    in hydroshareZone or any federated zone used for HydroShare resource backend store.
    It is invoked by an AJAX call and returns json object that holds content for files
    and folders under the requested directory/collection/subcollection.
    The AJAX request must be a POST request with input data passed in for res_id and store_path
    where store_path is the relative path under res_id collection/directory
    """
    res_id = request.POST.get('res_id', None)
    if res_id is None:
        return HttpResponse('Bad request - resource id is not included',
                            status=status.HTTP_500_INTERNAL_SERVER_ERROR)
    res_id = str(res_id).strip()
    try:
        resource, _, _ = authorize(
            request,
            res_id,
            needed_permission=ACTION_TO_AUTHORIZE.VIEW_RESOURCE)
    except NotFound:
        return HttpResponse('Bad request - resource not found',
                            status=status.HTTP_400_BAD_REQUEST)
    except PermissionDenied:
        return HttpResponse('Permission denied',
                            status=status.HTTP_401_UNAUTHORIZED)

    store_path = request.POST.get('store_path', None)
    if store_path is None:
        return HttpResponse('Bad request - store_path is not included',
                            status=status.HTTP_400_BAD_REQUEST)
    store_path = str(store_path).strip()
    if not store_path:
        return HttpResponse('Bad request - store_path cannot be empty',
                            status=status.HTTP_400_BAD_REQUEST)
    # this is federated if warranted, automatically, by choosing an appropriate session.
    istorage = resource.get_irods_storage()
    if resource.resource_federation_path:
        res_coll = os.path.join(resource.resource_federation_path, res_id,
                                store_path)
        rel_path = store_path
    else:
        res_coll = os.path.join(res_id, store_path)
        rel_path = res_coll
    try:
        store = istorage.listdir(res_coll)
        files = []
        for fname in store[1]:
            name_with_full_path = os.path.join(res_coll, fname)
            name_with_rel_path = os.path.join(rel_path, fname)
            size = istorage.size(name_with_full_path)
            mtype = get_file_mime_type(fname)
            idx = mtype.find('/')
            if idx >= 0:
                mtype = mtype[idx + 1:]
            f_pk = ''
            f_url = ''
            logical_file_type = ''
            logical_file_id = ''
            for f in ResourceFile.objects.filter(object_id=resource.id):
                if name_with_rel_path == get_resource_file_name_and_extension(
                        f)[0]:
                    f_pk = f.pk
                    f_url = get_resource_file_url(f)
                    if resource.resource_type == "CompositeResource":
                        logical_file_type = f.logical_file_type_name
                        logical_file_id = f.logical_file.id
                    break

            files.append({
                'name': fname,
                'size': size,
                'type': mtype,
                'pk': f_pk,
                'url': f_url,
                'logical_type': logical_file_type,
                'logical_file_id': logical_file_id
            })
    except SessionException as ex:
        return HttpResponse(ex.stderr,
                            status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    return_object = {
        'files': files,
        'folders': store[0],
        'can_be_public': resource.can_be_public_or_discoverable
    }

    if resource.resource_type == "CompositeResource":
        spatial_coverage_dict = get_coverage_data_dict(resource)
        temporal_coverage_dict = get_coverage_data_dict(
            resource, coverage_type='temporal')
        return_object['spatial_coverage'] = spatial_coverage_dict
        return_object['temporal_coverage'] = temporal_coverage_dict
    return HttpResponse(json.dumps(return_object),
                        content_type="application/json")