Skip to content

Commit

Permalink
Merge pull request #114 from /issues/94
Browse files Browse the repository at this point in the history
Issues/94
  • Loading branch information
scossu committed Aug 27, 2019
2 parents cfded38 + a904a8c commit 029db9b
Show file tree
Hide file tree
Showing 6 changed files with 211 additions and 130 deletions.
7 changes: 4 additions & 3 deletions lakesuperior/api/resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from lakesuperior import env, thread_env
from lakesuperior.globals import RES_DELETED, RES_UPDATED
from lakesuperior.model.ldp.ldp_factory import LDP_NR_TYPE, LdpFactory
from lakesuperior.model.ldp.ldpr import Ldpr
from lakesuperior.util.toolbox import rel_uri_to_urn


Expand Down Expand Up @@ -325,13 +326,13 @@ def delete(uid, soft=True, inbound=True):
# to break them.
refint = env.app_globals.rdfly.config['referential_integrity']
inbound = True if refint else inbound
repr_opts = {'incl_inbound' : True} if inbound else {}

rsrc = LdpFactory.from_stored(uid, repr_opts, strict=soft)
if soft:
repr_opts = {'incl_inbound' : True} if inbound else {}
rsrc = LdpFactory.from_stored(uid, repr_opts)
return rsrc.bury(inbound)
else:
return rsrc.forget(inbound)
Ldpr.forget(uid, inbound)


@transaction(True)
Expand Down
103 changes: 50 additions & 53 deletions lakesuperior/endpoints/ldp.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,31 +270,8 @@ def post_resource(parent_uid):
rsp_headers = std_headers.copy()
slug = request.headers.get('Slug')

kwargs = {}
kwargs['handling'], kwargs['disposition'] = set_post_put_params()
stream, mimetype = _bistream_from_req()

if mimetype in rdf_parsable_mimetypes:
# If the content is RDF, localize in-repo URIs.
global_rdf = stream.read()
kwargs['rdf_data'] = g.tbox.localize_payload(global_rdf)
kwargs['rdf_fmt'] = mimetype
else:
kwargs['stream'] = stream
kwargs['mimetype'] = mimetype
# Check digest if requested.
if 'digest' in request.headers:
try:
kwargs['prov_cksum_algo'], kwargs['prov_cksum'] = (
request.headers['digest'].split('=')
)
except ValueError:
return (
f'Cannot parse digest value: {request.headers["digest"]}',
400
)

try:
kwargs = _create_args_from_req(slug)
rsrc = rsrc_api.create(parent_uid, slug, **kwargs)
except IndigestibleError:
return (
Expand All @@ -318,7 +295,7 @@ def post_resource(parent_uid):
rsp_headers.update(_headers_from_metadata(rsrc))
rsp_headers['Location'] = uri

if mimetype and kwargs.get('rdf_fmt') is None:
if kwargs.get('mimetype') and kwargs.get('rdf_fmt') is None:
rsp_headers['Link'] = (
f'<{uri}/fcr:metadata>; rel="describedby"; anchor="{uri}"'
)
Expand All @@ -342,25 +319,13 @@ def put_resource(uid):
if cond_ret:
return cond_ret

kwargs = {}
kwargs['handling'], kwargs['disposition'] = set_post_put_params()
stream, mimetype = _bistream_from_req()

if mimetype in rdf_parsable_mimetypes:
# If the content is RDF, localize in-repo URIs.
global_rdf = stream.read()
kwargs['rdf_data'] = g.tbox.localize_payload(global_rdf)
kwargs['rdf_fmt'] = mimetype
else:
kwargs['stream'] = stream
kwargs['mimetype'] = mimetype
# Check digest if requested.
if 'digest' in request.headers:
kwargs['prov_cksum_algo'], kwargs['prov_cksum'] = \
request.headers['digest'].split('=')

try:
kwargs = _create_args_from_req(uid)
evt, rsrc = rsrc_api.create_or_replace(uid, **kwargs)
except IndigestibleError:
return (
f'Unable to parse digest header: {request.headers["digest"]}'
), 400
except (
InvalidResourceError, ChecksumValidationError,
ResourceExistsError) as e:
Expand All @@ -380,7 +345,7 @@ def put_resource(uid):
if evt == RES_CREATED:
rsp_code = 201
rsp_headers['Location'] = rsp_body = uri
if mimetype and not kwargs.get('rdf_data'):
if kwargs.get('mimetype') and not kwargs.get('rdf_data'):
rsp_headers['Link'] = f'<{uri}/fcr:metadata>; rel="describedby"'
else:
rsp_code = 204
Expand Down Expand Up @@ -410,7 +375,7 @@ def patch_resource(uid, is_metadata=False):
if cond_ret:
return cond_ret

handling, _ = set_post_put_params()
handling, _ = _set_post_put_params()

rsp_headers = {'Content-Type' : 'text/plain; charset=utf-8'}
if request.mimetype != 'application/sparql-update':
Expand Down Expand Up @@ -581,13 +546,30 @@ def _negotiate_content(gr, rdf_mimetype, headers=None, **vw_kwargs):
mimetype=rdf_mimetype)


def _bistream_from_req():
def _create_args_from_req(uid):
"""
Find how a binary file and its MIMEtype were uploaded in the request.
Set API creation method arguments from request parameters.
The ``kwargs`` variable returned has two keys: either ``rdf_data`` and
``rdf_fmt`` for LDP-RS or ``stream`` and ``mimetype`` for LDP-NR.
:rtype: dict
"""
#logger.debug('Content type: {}'.format(request.mimetype))
#logger.debug('files: {}'.format(request.files))
#logger.debug('stream: {}'.format(request.stream))
#pdb.set_trace()

kwargs = {}
kwargs['handling'], kwargs['disposition'] = _set_post_put_params()

link_hdr = request.headers.get('Link')
if link_hdr:
force_ldpnr = (
nsc['ldp']['NonRDFSource'] in link_hdr
and 'rel="type"' in link_hdr)
else:
force_ldpnr = False

if request.mimetype == 'multipart/form-data':
# This seems the "right" way to upload a binary file, with a
Expand All @@ -606,13 +588,28 @@ def _bistream_from_req():
# @FIXME Must decide what to do with this.
mimetype = request.mimetype

if mimetype == '' or mimetype == 'application/x-www-form-urlencoded':
if getattr(stream, 'limit', 0) == 0:
stream = mimetype = None
else:
mimetype = 'application/octet-stream'
if mimetype == 'application/x-www-form-urlencoded':
mimetype = None

if mimetype in rdf_parsable_mimetypes and not force_ldpnr:
# If the content is RDF, localize in-repo URIs.
global_rdf = stream.read()
kwargs['rdf_data'] = g.tbox.localize_payload(global_rdf)
kwargs['rdf_fmt'] = mimetype
else:
# Unspecified mimetype or force_ldpnr creates a LDP-NR.
kwargs['stream'] = stream or BytesIO(b'')
kwargs['mimetype'] = mimetype or 'application/octet-stream'
# Check digest if requested.
if 'digest' in request.headers:
try:
kwargs['prov_cksum_algo'], kwargs['prov_cksum'] = (
request.headers['digest'].split('=')
)
except ValueError:
raise IndigestibleError(uid)

return stream, mimetype
return kwargs


def _tombstone_response(e, uid):
Expand All @@ -622,7 +619,7 @@ def _tombstone_response(e, uid):
return str(e), 410, headers


def set_post_put_params():
def _set_post_put_params():
"""
Sets handling and content disposition for POST and PUT by parsing headers.
"""
Expand Down
5 changes: 3 additions & 2 deletions lakesuperior/model/ldp/ldp_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,14 @@ def from_stored(uid, ver_label=None, repr_opts={}, strict=True, **kwargs):

if LDP_NR_TYPE in rdf_types:
logger.info('Resource is a LDP-NR.')
rsrc = LdpNr(uid, repr_opts, **kwargs)
cls = LdpNr
elif LDP_RS_TYPE in rdf_types:
logger.info('Resource is a LDP-RS.')
rsrc = LdpRs(uid, repr_opts, **kwargs)
cls = LdpRs
else:
raise ResourceNotExistsError(uid)

rsrc = cls(uid, repr_opts, **kwargs)
# Sneak in the already extracted metadata to save a query.
rsrc._metadata = rsrc_meta

Expand Down
17 changes: 9 additions & 8 deletions lakesuperior/model/ldp/ldpr.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,13 +155,13 @@ def __init__(self, uid, repr_opts={}, provided_imr=None, **kwargs):
Instantiate an in-memory LDP resource.
:param str uid: uid of the resource. If None (must be explicitly
set) it refers to the root node. It can also be the full URI or URN,
in which case it will be converted.
set) it refers to the root node. It can also be the full URI or
URN, in which case it will be converted.
:param dict repr_opts: Options used to retrieve the IMR. See
`parse_rfc7240` for format details.
`parse_rfc7240` for format details.
:param str provided_imr: RDF data provided by the client in
operations such as `PUT` or `POST`, serialized as a string. This sets
the `provided_imr` property.
operations such as `PUT` or `POST`, serialized as a string. This
sets the `provided_imr` property.
"""
self.uid = (
rdfly.uri_to_uid(uid) if isinstance(uid, URIRef) else uid)
Expand Down Expand Up @@ -488,13 +488,14 @@ def bury(self, inbound, tstone_pointer=None):
return RES_DELETED


def forget(self, inbound=True):
@staticmethod
def forget(uid, inbound=True):
"""
Remove all traces of a resource and versions.
"""
logger.info('Forgetting resource {}'.format(self.uid))
logger.info('Forgetting resource {}'.format(uid))

rdfly.forget_rsrc(self.uid, inbound)
rdfly.forget_rsrc(uid, inbound)

return RES_DELETED

Expand Down
2 changes: 1 addition & 1 deletion lakesuperior/store/ldp_nr/default_layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ def persist(
os.unlink(tmp_fname)
raise
if size == 0:
logger.warn('Zero-length file received.')
logger.warning('Zero-length file received.')

# If the file exists already, don't bother rewriting it.
dst = __class__.local_path(
Expand Down

0 comments on commit 029db9b

Please sign in to comment.