Skip to content

Commit

Permalink
dap.mds3: fix clearing/deleting
Browse files Browse the repository at this point in the history
  • Loading branch information
RayPlante committed Nov 24, 2023
1 parent f5327e5 commit 858bcc5
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 20 deletions.
59 changes: 40 additions & 19 deletions python/nistoar/midas/dap/service/mds3.py
Original file line number Diff line number Diff line change
Expand Up @@ -485,13 +485,15 @@ def update_data(self, id, newdata, part=None, message="", _prec=None):
"""
return self._update_data(id, newdata, part, replace=False, message="", prec=_prec)

def clear_data(self, id, part=None, _prec=None):
def clear_data(self, id, part=None, message: str=None, _prec=None) -> bool:
"""
remove the stored data content of the record and reset it to its defaults.
:param str id: the identifier for the record whose data should be cleared.
:param stt part: the slash-delimited pointer to an internal data property. If provided,
only that property will be cleared (either removed or set to an initial
default).
:return: True the data was properly cleared; return False if ``part`` was specified but does not
yet exist in the data.
:param ProjectRecord prec: the previously fetched and possibly updated record corresponding to
``id``. If this is not provided, the record will by fetched anew based on
the ``id``.
Expand All @@ -513,44 +515,61 @@ def clear_data(self, id, part=None, _prec=None):
self._store.load_from(nerd)
nerd = self._store.open(id)

provact = None
try:
if part:
what = part
if part == "authors":
if nerd.authors.count == 0:
return False
nerd.authors.empty()
elif part == "references":
if nerd.references.count == 0:
return False
nerd.references.empty()
elif part == FILE_DELIM:
if nerd.files.count == 0:
return False
what = "files"
nerd.files.empty()
elif part == LINK_DELIM:
if nerd.nonfiles.count == 0:
return False
what = "links"
nerd.nonfiles.empty()
elif part == "components":
if nerd.nonfiles.count == 0 and nerd.files.count == 0:
return False
nerd.files.empty()
nerd.nonfiles.empty()
elif part in "title rights disclaimer description".split():
elif part in "title rights disclaimer description landingPage keyword".split():
resmd = nerd.get_res_data()
if part not in resmd:
return False
del resmd[part]
nerd.replace_res_data(resmd)
else:
raise PartNotAccessible(_prec.id, path, "Clearing %s not allowed" % path)
raise PartNotAccessible(_prec.id, part, "Clearing %s not allowed" % part)

provact = Action(Action.PATCH, _prec.id, self.who, "clearing "+what)
if not message:
message = "clearing "+what
provact = Action(Action.PATCH, _prec.id, self.who, message)
part = ("/"+part) if part.startswith("pdr:") else ("."+part)
provact.add_subaction(Action(Action.DELETE, _prec.id+"#data"+part, self.who,
"clearing "+what))
prec.status.act(self.STATUS_ACTION_CLEAR, "cleared "+what)
message))
_prec.status.act(self.STATUS_ACTION_CLEAR, "cleared "+what)

else:
nerd.authors.empty()
nerd.references.empty()
nerd.files.empty()
nerd.nonfiles.empty()
nerd.replace_res_data(self._new_data_for(_prec.id, prec.meta))
nerd.replace_res_data(self._new_data_for(_prec.id, _prec.meta))

provact = Action(Action.PATCH, _prec.id, self.who, "clearing all NERDm data")
prec.status.act(self.STATUS_ACTION_CLEAR, "cleared all NERDm data")
if not message:
message = "clearing all NERDm data"
provact = Action(Action.PATCH, _prec.id, self.who, message)
_prec.status.act(self.STATUS_ACTION_CLEAR, "cleared all NERDm data")

except PartNotAccessible:
# client request error; don't record action
Expand All @@ -559,28 +578,30 @@ def clear_data(self, id, part=None, _prec=None):
except Exception as ex:
self.log.error("Failed to clear requested NERDm data, %s: %s", _prec.id, str(ex))
self.log.warning("Partial update is possible")
provact.message = "Failed to clear requested NERDm data"
self._record_action(provact)
if provact:
provact.message = "Failed to clear requested NERDm data"
self._record_action(provact)

prec.status.act(self.STATUS_ACTION_CLEAR, "Failed to clear NERDm data")
prec.set_state(status.EDIT)
prec.data = self._summarize(nerd)
self._try_save(prec)
_prec.status.act(self.STATUS_ACTION_CLEAR, "Failed to clear NERDm data")
_prec.set_state(status.EDIT)
_prec.data = self._summarize(nerd)
self._try_save(_prec)
raise

prec.data = self._summarize(nerd)
_prec.data = self._summarize(nerd)
if set_state:
prec.status.set_state(status.EDIT)
_prec.status.set_state(status.EDIT)

try:
prec.save()
_prec.save()

except Exception as ex:
self.log.error("Failed to saved DBIO record, %s: %s", prec.id, str(ex))
raise

finally:
self._record_action(provact)
self._record_action(provact)
return True


def _update_data(self, id, newdata, part=None, prec=None, nerd=None, replace=False, message=""):
Expand Down
39 changes: 39 additions & 0 deletions python/tests/nistoar/midas/dap/service/test_mds3.py
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,45 @@ def test_get_sw_desc_for(self):
"accessURL": "https://bitbucket.com/foo/bar"
})

def test_clear_data(self):
self.create_service()
prec = self.svc.create_record("goob")
pdrid = "ark:/88434/%s-%s" % tuple(prec.id.split(":"))
nerd = self.svc.get_nerdm_data(prec.id)
self.assertEqual(set(nerd.keys()),
{"_schema", "@id", "doi", "_extensionSchemas", "@context", "@type"})

nerd = self.svc.update_data(prec.id,
{"landingPage": "https://example.com",
"contactPoint": { "fn": "Gurn Cranston", "hasEmail": "mailto:[email protected]"}})
self.assertEqual(set(nerd.keys()),
{"_schema", "@id", "doi", "_extensionSchemas", "@context", "@type",
"contactPoint", "landingPage"})
self.assertEqual(set(nerd["contactPoint"].keys()), {"@type", "fn", "hasEmail"})

with self.assertRaises(PartNotAccessible):
self.assertIs(self.svc.clear_data(prec.id, "goober"), False)
with self.assertRaises(PartNotAccessible):
self.assertIs(self.svc.clear_data(prec.id, "contactPoint/hasEmail"), True)
nerd = self.svc.get_nerdm_data(prec.id)
self.assertEqual(set(nerd.keys()),
{"_schema", "@id", "doi", "_extensionSchemas", "@context", "@type",
"contactPoint", "landingPage"})
self.assertEqual(set(nerd["contactPoint"].keys()), {"@type", "fn", "hasEmail"})

self.assertIs(self.svc.clear_data(prec.id, "landingPage"), True)
nerd = self.svc.get_nerdm_data(prec.id)
self.assertEqual(set(nerd.keys()),
{"_schema", "@id", "doi", "_extensionSchemas", "@context", "@type",
"contactPoint"})
self.assertIs(self.svc.clear_data(prec.id, "references"), False)

self.assertIs(self.svc.clear_data(prec.id), True)
nerd = self.svc.get_nerdm_data(prec.id)
self.assertEqual(set(nerd.keys()),
{"_schema", "@id", "doi", "_extensionSchemas", "@context", "@type"})


def test_update(self):
rec = read_nerd(pdr2210)
self.create_service()
Expand Down
89 changes: 88 additions & 1 deletion python/tests/nistoar/midas/dap/service/test_mds3_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ def test_put_patch(self):
self.assertNotIn("downloadURL", resp)

self.resp = []
path = id + '/data/components[file_1]'
path = id + '/data/components/file_1'
req = {
'REQUEST_METHOD': 'GET',
'PATH_INFO': self.rootpath + path
Expand Down Expand Up @@ -443,6 +443,93 @@ def test_put_patch(self):
self.assertIn('description', resp)
self.assertEqual(resp['rights'], "What ever.")

def test_delete(self):
testnerd = read_nerd(pdr2210)
res = deepcopy(testnerd)
del res['references']
del res['components']
del res['@id']
del res['_schema']
del res['_extensionSchemas']

path = ""
req = {
'REQUEST_METHOD': 'POST',
'PATH_INFO': self.rootpath + path
}
req['wsgi.input'] = StringIO(json.dumps({"data": { "contactPoint": res['contactPoint'],
"keyword": [ "testing" ],
"landingPage": "https://example.com/" },
"meta": { "creatorisContact": "false" },
"name": "OptSortSph" }))
hdlr = self.app.create_handler(req, self.start, path, nistr)
self.assertTrue(isinstance(hdlr, prj.ProjectSelectionHandler))
self.assertNotEqual(hdlr.cfg, {})
self.assertEqual(hdlr._path, "")
body = hdlr.handle()

self.assertIn("201 ", self.resp[0])
resp = self.body2dict(body)
self.assertEqual(resp['name'], "OptSortSph")
self.assertEqual(resp['id'], "mds3:0001")
self.assertEqual(resp['data']['@id'], 'ark:/88434/mds3-0001')
self.assertEqual(resp['data']['doi'], 'doi:10.88888/mds3-0001')
recid = resp['id']

self.resp = []
path = recid + '/data'
req = {
'REQUEST_METHOD': 'GET',
'PATH_INFO': self.rootpath + path
}
hdlr = self.app.create_handler(req, self.start, path, nistr)
self.assertTrue(isinstance(hdlr, prj.ProjectDataHandler))
self.assertEqual(hdlr._path, "")
body = hdlr.handle()
self.assertIn("200 ", self.resp[0])
resp = self.body2dict(body)
self.assertEqual(resp['@id'], 'ark:/88434/mds3-0001')
self.assertEqual(resp['doi'], 'doi:10.88888/mds3-0001')
self.assertEqual(resp['contactPoint'],
{"fn": "Zachary Levine", "@type": "vcard:Contact",
"hasEmail": "mailto:[email protected]" })
self.assertEqual(resp['@type'],
[ "nrdp:PublicDataResource", "dcat:Resource" ])
self.assertEqual(resp['landingPage'], "https://example.com/")
self.assertEqual(resp['keyword'], ["testing"])

self.resp = []
path = recid + '/data/landingPage'
req = {
'REQUEST_METHOD': 'DELETE',
'PATH_INFO': self.rootpath + path
}
hdlr = self.app.create_handler(req, self.start, path, nistr)
self.assertTrue(isinstance(hdlr, prj.ProjectDataHandler))
self.assertEqual(hdlr._path, "landingPage")
body = hdlr.handle()
self.assertIn("201 ", self.resp[0])
resp = self.body2dict(body)
self.assertIs(resp, True)


self.resp = []
path = recid + '/data'
req = {
'REQUEST_METHOD': 'GET',
'PATH_INFO': self.rootpath + path
}
hdlr = self.app.create_handler(req, self.start, path, nistr)
self.assertTrue(isinstance(hdlr, prj.ProjectDataHandler))
self.assertEqual(hdlr._path, "")
body = hdlr.handle()
self.assertIn("200 ", self.resp[0])
resp = self.body2dict(body)
self.assertNotIn("landingPage", resp)







Expand Down

0 comments on commit 858bcc5

Please sign in to comment.