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)
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)
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)
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)
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)
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)
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)
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)
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")
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")
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)
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")