def get(self, request, pk, pathname): resource, _, _ = view_utils.authorize( request, pk, needed_permission=ACTION_TO_AUTHORIZE.VIEW_RESOURCE) if not resource.supports_folders and '/' in pathname: return Response("Resource type does not support folders", status.HTTP_403_FORBIDDEN) try: view_utils.irods_path_is_allowed(pathname) except (ValidationError, SuspiciousFileOperation) as ex: return Response(ex.message, status_code=status.HTTP_400_BAD_REQUEST) try: f = hydroshare.get_resource_file(pk, pathname) except ObjectDoesNotExist: err_msg = 'File with file name {file_name} does not exist for resource with ' \ 'resource id {res_id}'.format(file_name=pathname, res_id=pk) raise NotFound(detail=err_msg) # redirects to django_irods/views.download function # use new internal url for rest call # TODO: (Couch) Migrate model (with a "data migration") so that this hack is not needed. redirect_url = f.url.replace('django_irods/download/', 'django_irods/rest_download/') return HttpResponseRedirect(redirect_url)
def test_get_file(self): # test if the added test file is obtained res_file_object = hydroshare.get_resource_file( self.res.short_id, self.file.name).resource_file self.assertEqual(self.file.name, os.path.basename(res_file_object.name), msg='file name did not match')
def get(self, request, pk, pathname): resource, _, _ = view_utils.authorize( request, pk, needed_permission=ACTION_TO_AUTHORIZE.VIEW_RESOURCE) if not resource.supports_folders and '/' in pathname: return Response("Resource type does not support folders", status.HTTP_403_FORBIDDEN) try: view_utils.irods_path_is_allowed(pathname) except (ValidationError, SuspiciousFileOperation) as ex: return Response(ex.message, status_code=status.HTTP_400_BAD_REQUEST) try: f = hydroshare.get_resource_file(pk, pathname).resource_file except ObjectDoesNotExist: err_msg = 'File with file name {file_name} does not exist for resource with ' \ 'resource id {res_id}'.format(file_name=pathname, res_id=pk) raise NotFound(detail=err_msg) # redirects to django_irods/views.download function # use new internal url for rest call # TODO: (Couch) Migrate model (with a "data migration") so that this hack is not needed. redirect_url = f.url.replace('django_irods/download/', 'django_irods/rest_download/') return HttpResponseRedirect(redirect_url)
def get_resource_file(self, pk, filename): authorize(self.request, pk, view=True) try: f = hydroshare.get_resource_file(pk, filename) except ObjectDoesNotExist: raise Http404 return HttpResponseRedirect(f.url, content_type='text/plain')
def ingest_logical_file_metadata(metadata_file, resource, map_files): resource.refresh_from_db() graph = Graph() graph = graph.parse(data=metadata_file.read()) agg_type_name = None for s, _, _ in graph.triples((None, RDFS.isDefinedBy, None)): agg_type_name = s.split("/")[-1] break if not agg_type_name: raise Exception("Could not derive aggregation type from {}".format(metadata_file.name)) subject = None for s, _, _ in graph.triples((None, DC.title, None)): subject = s.split('/resource/', 1)[1].split("#")[0] break if not subject: raise Exception("Could not derive aggregation path from {}".format(metadata_file.name)) logical_file_class = get_logical_file(agg_type_name) lf = get_logical_file_by_map_file_path(resource, logical_file_class, subject) if not lf: # see if the files exist and create it res_file = None if logical_file_class is FileSetLogicalFile: file_path = subject.rsplit('/', 1)[0] file_path = file_path.split('data/contents/', 1)[1] res_file = resource.files.filter(file_folder=file_path).first() if res_file: FileSetLogicalFile.set_file_type(resource, None, folder_path=file_path) elif logical_file_class is GenericLogicalFile: map_name = subject.split('data/contents/', 1)[1] map_name = map_name.split('#', 1)[0] for map_file in map_files: if map_file.name.endswith(map_name): ORE = Namespace("http://www.openarchives.org/ore/terms/") map_graph = Graph().parse(data=map_file.read()) for _, _, o in map_graph.triples((None, ORE.aggregates, None)): if not str(o).endswith("_meta.xml"): file_path = str(o) break if not file_path: raise Exception("Could not determine the generic logical file name") file_path = file_path.split('data/contents/', 1)[1] res_file = get_resource_file(resource.short_id, file_path) if res_file: set_logical_file_type(res=resource, user=None, file_id=res_file.pk, logical_file_type_class=logical_file_class, fail_feedback=True) if res_file: res_file.refresh_from_db() lf = res_file.logical_file else: raise Exception("Could not find aggregation for {}".format(metadata_file.name)) if not lf: raise Exception("Files for aggregation in metadata file {} could not be found".format(metadata_file.name)) with transaction.atomic(): lf.metadata.delete_all_elements() lf.metadata.ingest_metadata(graph) lf.create_aggregation_xml_documents()
def get_resource_file(self, pk, filename): authorize(self.request, pk, view=True) try: f = hydroshare.get_resource_file(pk, filename) except ObjectDoesNotExist: raise Http404 return HttpResponseRedirect(f.resource_file.url, content_type='text/plain')
def test_get_file(self): # test if the added test file is obtained res_file_object = hydroshare.get_resource_file(self.res.short_id, self.file.name).resource_file self.assertEqual( self.file.name, os.path.basename(res_file_object.name), msg='file name did not match' )
def get(self, request, pk, filename): view_utils.authorize(request, pk, view=True, edit=True, full=True) try: f = hydroshare.get_resource_file(pk, filename) except ObjectDoesNotExist: err_msg = "File with file name {file_name} does not exist for resource with resource id " "{res_id}".format( file_name=filename, res_id=pk ) raise NotFound(detail=err_msg) # redirects to django_irods/views.download function return HttpResponseRedirect(f.url)
def test_get_file(self): # test if the added test file is obtained res_file = hydroshare.get_resource_file(self.res.short_id, self.file.name) res_file_object = res_file.resource_file self.assertEqual(self.file.name, os.path.basename(res_file_object.name), msg='file name did not match') # test if the last modified time for the file can be obtained # assert time is not None without iRODS Session Exception being raised self.assertTrue(res_file.modified_time) self.assertTrue(res_file.checksum)
def test_get_file(self): # test if the test file is added to the resource resource_file_objects = ResourceFile.objects.filter(object_id=self.res.pk) self.assertIn( self.file.name, [os.path.basename(rf.resource_file.name) for rf in resource_file_objects], msg='the test file is not added to the resource' ) # test if the added test file is obtained self.assertEqual( self.file.name, os.path.basename(hydroshare.get_resource_file(self.res.short_id, self.file.name).name), msg='the added test file is not obtained from the resource' )
def get_resource_file(self, pk, filename): authorize(self.request, pk, view=True) f = hydroshare.get_resource_file(pk, filename) return HttpResponseRedirect(f.resource_file.url, content_type='text/plain')
def get(self, request, pk, pathname): """ Get a resource file's metadata. ## Parameters * `id` - alphanumeric uuid of the resource, i.e. cde01b3898c94cdab78a2318330cf795 * `pathname` - The pathname of the file to get these ## Returns ``` { "keywords": [ "keyword1", "keyword2" ], "spatial_coverage": { "units": "Decimal degrees", "east": -84.0465, "north": 49.6791, "name": "12232", "projection": "WGS 84 EPSG:4326" }, "extra_metadata": { "extended1": "one" }, "temporal_coverage": { "start": "2018-02-22", "end": "2018-02-24" }, "title": "File Metadata Title", "logical_file": {} } ``` """ try: resource_file = hydroshare.get_resource_file(pk, pathname) logical_file = resource_file.logical_file metadata = resource_file.metadata except ObjectDoesNotExist: # Backwards compatibility for file_id try: resource_file = ResourceFile.objects.get(id=pathname) logical_file = resource_file.logical_file metadata = resource_file.metadata except Exception: # is it a folder? resource = hydroshare.get_resource_by_shortkey(pk) dir_path = pk + os.path.join("/data/contents/", pathname) logical_file = resource.get_folder_aggregation_object(dir_path) metadata = None title = logical_file.dataset_name \ if logical_file else "" keywords = metadata.keywords \ if metadata else [] spatial_coverage = metadata.spatial_coverage.value \ if metadata and metadata.spatial_coverage else {} extra_metadata = metadata.extra_metadata \ if metadata else {} temporal_coverage = metadata.temporal_coverage.value if \ metadata and metadata.temporal_coverage else {} extra_data = logical_file.metadata.dict() \ if logical_file else {} # TODO: How to leverage serializer for this? return Response({ "title": title, "keywords": keywords, "spatial_coverage": spatial_coverage, "extra_metadata": extra_metadata, "temporal_coverage": temporal_coverage, "logical_file": extra_data })
def put(self, request, pk, pathname): """ Update a resource file's metadata Accepts application/json encoding. ## Parameters * `id` - alphanumeric uuid of the resource, i.e. cde01b3898c94cdab78a2318330cf795 * `pathname` - The pathname of the file * `data` - see the "returns" section for formatting ## Returns ``` { "keywords": [ "keyword1", "keyword2" ], "spatial_coverage": { "units": "Decimal degrees", "east": -84.0465, "north": 49.6791, "name": "12232", "projection": "WGS 84 EPSG:4326" }, "extra_metadata": { "extended1": "one" }, "temporal_coverage": { "start": "2018-02-22", "end": "2018-02-24" }, "title": "File Metadata Title" } ``` """ file_serializer = FileMetaDataSerializer(request.data) try: title = file_serializer.data.pop("title", "") try: resource_file = hydroshare.get_resource_file(pk, pathname) except ObjectDoesNotExist: # Backwards compatibility for file_id resource_file = ResourceFile.objects.get(id=pathname) if resource_file is None: raise NotFound("File {} in resource {} does not exist".format( pathname, pk)) resource_file.metadata.logical_file.dataset_name = title resource_file.metadata.logical_file.save() spatial_coverage = file_serializer.data.pop( "spatial_coverage", None) if spatial_coverage is not None: # defaulting to point if not provided for backwards compatibility type = spatial_coverage[ "type"] if "type" in spatial_coverage else "point" if resource_file.metadata.spatial_coverage is not None: cov_id = resource_file.metadata.spatial_coverage.id resource_file.metadata.update_element( 'coverage', cov_id, type=type, value=spatial_coverage) elif resource_file.metadata.spatial_coverage is None: resource_file.metadata.create_element( 'coverage', type=type, value=spatial_coverage) temporal_coverage = file_serializer.data.pop( "temporal_coverage", None) if temporal_coverage is not None: if resource_file.metadata.temporal_coverage is not None: cov_id = resource_file.metadata.temporal_coverage.id resource_file.metadata.update_element( 'coverage', cov_id, type='period', value=temporal_coverage) elif resource_file.metadata.temporal_coverage is None: resource_file.metadata.create_element( 'coverage', type="period", value=temporal_coverage) keywords = file_serializer.data.pop("keywords", None) if keywords is not None: resource_file.metadata.keywords = keywords extra_metadata = file_serializer.data.pop("extra_metadata", None) if extra_metadata is not None: resource_file.metadata.extra_metadata = extra_metadata resource_file.metadata.save() except Exception as e: raise APIException(e) # TODO: How to leverage serializer for this? title = resource_file.metadata.logical_file.dataset_name \ if resource_file.metadata.logical_file else "" keywords = resource_file.metadata.keywords \ if resource_file.metadata else [] spatial_coverage = resource_file.metadata.spatial_coverage.value \ if resource_file.metadata.spatial_coverage else {} extra_metadata = resource_file.metadata.extra_metadata \ if resource_file.metadata else {} temporal_coverage = resource_file.metadata.temporal_coverage.value if \ resource_file.metadata.temporal_coverage else {} return Response({ "title": title, "keywords": keywords, "spatial_coverage": spatial_coverage, "extra_metadata": extra_metadata, "temporal_coverage": temporal_coverage })
def get(self, request, pk, pathname): """ Get a resource file's metadata. ## Parameters * `id` - alphanumeric uuid of the resource, i.e. cde01b3898c94cdab78a2318330cf795 * `pathname` - The pathname of the file to get these ## Returns ``` { "keywords": [ "keyword1", "keyword2" ], "spatial_coverage": { "units": "Decimal degrees", "east": -84.0465, "north": 49.6791, "name": "12232", "projection": "WGS 84 EPSG:4326" }, "extra_metadata": { "extended1": "one" }, "temporal_coverage": { "start": "2018-02-22", "end": "2018-02-24" }, "title": "File Metadata Title" } ``` """ try: resource_file = hydroshare.get_resource_file(pk, pathname) except ObjectDoesNotExist: # Backwards compatibility for file_id resource_file = ResourceFile.objects.get(id=pathname) if resource_file is None: raise NotFound("File {} in resource {} does not exist".format(pathname, pk)) if resource_file.metadata is None or not resource_file.has_logical_file: raise NotFound("File {} in resource {} has no metadata".format(pathname, pk)) title = resource_file.metadata.logical_file.dataset_name \ if resource_file.metadata.logical_file else "" keywords = resource_file.metadata.keywords \ if resource_file.metadata else [] spatial_coverage = resource_file.metadata.spatial_coverage.value \ if resource_file.metadata.spatial_coverage else {} extra_metadata = resource_file.metadata.extra_metadata \ if resource_file.metadata else {} temporal_coverage = resource_file.metadata.temporal_coverage.value if \ resource_file.metadata.temporal_coverage else {} # TODO: How to leverage serializer for this? return Response({ "title": title, "keywords": keywords, "spatial_coverage": spatial_coverage, "extra_metadata": extra_metadata, "temporal_coverage": temporal_coverage })
def put(self, request, pk, pathname): """ Update a resource file's metadata Accepts application/json encoding. ## Parameters * `id` - alphanumeric uuid of the resource, i.e. cde01b3898c94cdab78a2318330cf795 * `pathname` - The pathname of the file * `data` - see the "returns" section for formatting ## Returns ``` { "keywords": [ "keyword1", "keyword2" ], "spatial_coverage": { "units": "Decimal degrees", "east": -84.0465, "north": 49.6791, "name": "12232", "projection": "WGS 84 EPSG:4326" }, "extra_metadata": { "extended1": "one" }, "temporal_coverage": { "start": "2018-02-22", "end": "2018-02-24" }, "title": "File Metadata Title" } ``` """ file_serializer = FileMetaDataSerializer(request.data) try: title = file_serializer.data.pop("title", "") try: resource_file = hydroshare.get_resource_file(pk, pathname) except ObjectDoesNotExist: # Backwards compatibility for file_id resource_file = ResourceFile.objects.get(id=pathname) if resource_file is None: raise NotFound("File {} in resource {} does not exist".format(pathname, pk)) resource_file.metadata.logical_file.dataset_name = title resource_file.metadata.logical_file.save() spatial_coverage = file_serializer.data.pop("spatial_coverage", None) if spatial_coverage is not None: # defaulting to point if not provided for backwards compatibility type = spatial_coverage["type"] if "type" in spatial_coverage else "point" if resource_file.metadata.spatial_coverage is not None: cov_id = resource_file.metadata.spatial_coverage.id resource_file.metadata.update_element('coverage', cov_id, type=type, value=spatial_coverage) elif resource_file.metadata.spatial_coverage is None: resource_file.metadata.create_element('coverage', type=type, value=spatial_coverage) temporal_coverage = file_serializer.data.pop("temporal_coverage", None) if temporal_coverage is not None: if resource_file.metadata.temporal_coverage is not None: cov_id = resource_file.metadata.temporal_coverage.id resource_file.metadata.update_element('coverage', cov_id, type='period', value=temporal_coverage) elif resource_file.metadata.temporal_coverage is None: resource_file.metadata.create_element('coverage', type="period", value=temporal_coverage) keywords = file_serializer.data.pop("keywords", None) if keywords is not None: resource_file.metadata.keywords = keywords extra_metadata = file_serializer.data.pop("extra_metadata", None) if extra_metadata is not None: resource_file.metadata.extra_metadata = extra_metadata resource_file.metadata.save() except Exception as e: raise APIException(e) # TODO: How to leverage serializer for this? title = resource_file.metadata.logical_file.dataset_name \ if resource_file.metadata.logical_file else "" keywords = resource_file.metadata.keywords \ if resource_file.metadata else [] spatial_coverage = resource_file.metadata.spatial_coverage.value \ if resource_file.metadata.spatial_coverage else {} extra_metadata = resource_file.metadata.extra_metadata \ if resource_file.metadata else {} temporal_coverage = resource_file.metadata.temporal_coverage.value if \ resource_file.metadata.temporal_coverage else {} return Response({ "title": title, "keywords": keywords, "spatial_coverage": spatial_coverage, "extra_metadata": extra_metadata, "temporal_coverage": temporal_coverage })
def test_update_resource_file(self): # create a user to be used for creating the resource user_creator = hydroshare.create_account( '*****@*****.**', username='******', first_name='Creator_FirstName', last_name='Creator_LastName', superuser=False, groups=[] ) # create a resource without any owner resource = GenericResource.objects.create( user=user_creator, title='My resource', creator=user_creator, last_changed_by=user_creator, doi='doi1000100010001' ) # resource should not have any files at this point self.assertEqual(resource.files.all().count(), 0, msg="resource file count didn't match") # create a file original_file_name = 'original.txt' original_file = open(original_file_name, 'w') original_file.write("original text") original_file.close() original_file = open(original_file_name, 'r') # add the file to the resource added_files = hydroshare.add_resource_files(resource.short_id, original_file) # resource should have only one file at this point self.assertEqual(len(added_files), 1) self.assertEqual(resource.files.all().count(), 1, msg="resource file count didn't match") self.assertIn( original_file_name, [os.path.basename(f.resource_file.name) for f in resource.files.all()], msg= '%s is not one of the resource files.' % original_file_name ) # create a file that will be used to update the original file -1st update new_file_name = 'update.txt' # file has a different name from the file that we will be updating new_file = open(new_file_name, 'w') new_file_data = 'data in new file' new_file.write(new_file_data) new_file.close() new_file = open(new_file_name, 'r') # this is the api call we are testing rf = hydroshare.update_resource_file(resource.short_id, original_file_name, new_file) # test if the file name matches self.assertEqual(os.path.basename(rf.resource_file.name), new_file_name, msg="resource file name didn't match") # since we are updating a file the number of files in the resource needs to be still 1 self.assertEqual(resource.files.all().count(), 1, msg="resource file count didn't match") # test if the content of the file matches resource_file = hydroshare.get_resource_file(resource.short_id, new_file_name) self.assertEqual(resource_file.read(), new_file_data, msg="resource file content didn't match") # reset the original resource file name for 2nd time resource file update original_file_name = new_file_name # create a file that will be used to update the resource file - 2nd update new_file_name = 'update.txt' # file has the same name as the file that we will be updating new_file = open(new_file_name, 'w') new_file_data = 'data in new file' new_file.write(new_file_data) new_file.close() new_file = open(new_file_name, 'r') # this is the api call we are testing rf = hydroshare.update_resource_file(resource.short_id, original_file_name, new_file) # test if the file name matches self.assertEqual(os.path.basename(rf.resource_file.name), new_file_name, msg="{0} != {1}".format(os.path.basename(rf.resource_file.name), new_file_name)) # exception ObjectDoesNotExist should be raised if resource does not have a file # for the given file name (file_not_in_resource.txt) to update self.assertRaises( ObjectDoesNotExist, lambda: hydroshare.update_resource_file(resource.short_id, 'file_not_in_resource.txt', new_file) )