Skip to content

Commit

Permalink
Merge pull request #112 from scossu/development
Browse files Browse the repository at this point in the history
Switch contributing branch
  • Loading branch information
scossu committed Aug 16, 2019
2 parents 8fb48bb + c4a643e commit cfded38
Show file tree
Hide file tree
Showing 19 changed files with 591 additions and 102 deletions.
44 changes: 31 additions & 13 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,15 +1,33 @@
FROM python:3.7
MAINTAINER Michael B. Klein <michael.klein@northwestern.edu>
RUN mkdir -p /usr/local /data
WORKDIR /usr/local
ADD . lakesuperior
WORKDIR /usr/local/lakesuperior
RUN git submodule update --init
RUN [[ -f lakesuperior/model/base.c ]] || \
pip install -r requirements_dev.txt
FROM python:3.7-alpine
LABEL "maintainer"="Michael B. Klein <michael.klein@northwestern.edu>" \
"maintainer"="Stefano Cossu <scossu@getty.edu>"

RUN apk add --no-cache build-base git
RUN pip3 install cython==0.29.6 cymem

RUN mkdir -p /data
WORKDIR /usr/local/lsup/src
COPY .git ./.git
COPY ext ./ext
COPY bin ./bin
COPY lakesuperior ./lakesuperior
COPY setup.py README.rst ./

RUN git submodule update --init ext
RUN pip install -e .
RUN cp ./docker/etc/* ./lakesuperior/etc.defaults/
CMD ./docker/docker_entrypoint
COPY ./docker/etc ./lakesuperior/etc.defaults

# Clean up build-required packages & dirs.
RUN apk del build-base git
RUN rm -rf .git

RUN [ -f /data/ldprs_store/data.mdb ] || \
echo yes | lsup-admin bootstrap

VOLUME /data

EXPOSE 8000
HEALTHCHECK --interval=30s --timeout=5s \
CMD curl -X OPTIONS -f http://localhost:8000/ || exit 1

ENTRYPOINT ["gunicorn", "-c", "python:lakesuperior.wsgi", \
"lakesuperior.server:fcrepo"]
#ENTRYPOINT ["./bin/fcrepo"]
2 changes: 1 addition & 1 deletion bin/fcrepo
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#!/bin/bash
#!/bin/sh

gunicorn -c python:lakesuperior.wsgi lakesuperior.server:fcrepo
5 changes: 3 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
version: '2'
version: '3'

volumes:
lakesuperior:

services:
lakesuperior:
image: scossu/lakesuperior:stable
build:
context: .
volumes:
- lakesuperior:/data
ports:
Expand Down
10 changes: 0 additions & 10 deletions docker/docker_entrypoint

This file was deleted.

4 changes: 2 additions & 2 deletions docker/etc/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
# One of ``prod``, ``test`` or ``dev``.
# ``prod`` is normal running mode. 'test' is used for running test suites.
# ``dev`` is similar to normal mode but with reload and debug enabled.
app_mode: 'dev'
app_mode: 'prod'

###
# Base data directory.
Expand All @@ -23,7 +23,7 @@ app_mode: 'dev'
# the individual subdirectories can be mounted on different file systems.
#
# If unset, it will default to <lakesuperior package root>/data.
data_dir:
data_dir: /data

###
# Configuration for binary path and fixity check generation. The hash is a
Expand Down
9 changes: 4 additions & 5 deletions docs/contributing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,10 @@ displaying and linking correctly.

Likewise, please add mindful testing to new fatures or bug fixes.

Development is done on the ``development`` branch. If you have any suggested
addition to the code, please fork the repo, create a new branch for your topic
and open a pull request against development. In case you find a critical bug,
a hotfix can be proposed against master if agreed in the related issue
discussion.
Development is done on the ``master`` branch. If you have an addition to the
code that you have previously discussed by opening an issue, please fork the
repo, create a new branch for your topic and open a pull request against
master.

Last but not least, read carefully the `Code of Conduct
<https://github.com/scossu/lakesuperior/blob/master/code_of_conduct.md>`__.
2 changes: 1 addition & 1 deletion lakesuperior/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@


version = '1.0 alpha'
release = '1.0.0a21'
release = '1.0.0a22'

basedir = path.dirname(path.realpath(__file__))
"""
Expand Down
24 changes: 20 additions & 4 deletions lakesuperior/api/resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@
from rdflib.namespace import XSD

from lakesuperior.config_parser import config
from lakesuperior.dictionaries.namespaces import ns_collection as nsc
from lakesuperior.exceptions import (
InvalidResourceError, ResourceNotExistsError, TombstoneError)
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.util.toolbox import rel_uri_to_urn


logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -230,26 +232,30 @@ def create_or_replace(uid, **kwargs):
:rtype: tuple(str, lakesuperior.model.ldp.ldpr.Ldpr)
:return: A tuple of:
1. Event type (str): whether the resource was created or updated.
2. Resource (lakesuperior.model.ldp.ldpr.Ldpr): The new or updated resource.
2. Resource (lakesuperior.model.ldp.ldpr.Ldpr): The new or updated
resource.
"""
rsrc = LdpFactory.from_provided(uid, **kwargs)
return rsrc.create_or_replace(), rsrc


@transaction(True)
def update(uid, update_str, is_metadata=False):
def update(uid, update_str, is_metadata=False, handling='strict'):
"""
Update a resource with a SPARQL-Update string.
:param string uid: Resource UID.
:param string update_str: SPARQL-Update statements.
:param bool is_metadata: Whether the resource metadata are being updated.
:param str handling: How to handle server-managed triples. ``strict``
(the default) rejects the update with an exception if server-managed
triples are being changed. ``lenient`` modifies the update graph so
offending triples are removed and the update can be applied.
:raise InvalidResourceError: If ``is_metadata`` is False and the resource
being updated is a LDP-NR.
"""
# FCREPO is lenient here and Hyrax requires it.
rsrc = LdpFactory.from_stored(uid, handling='lenient')
rsrc = LdpFactory.from_stored(uid, handling=handling)
if LDP_NR_TYPE in rsrc.ldp_types and not is_metadata:
raise InvalidResourceError(
'Cannot use this method to update an LDP-NR content.')
Expand All @@ -274,6 +280,16 @@ def update_delta(uid, remove_trp, add_trp):
add, as 3-tuples of RDFLib terms.
"""
rsrc = LdpFactory.from_stored(uid)

# FIXME Wrong place to put this, should be at the LDP level.
remove_trp = {
(rel_uri_to_urn(s, uid), p, rel_uri_to_urn(o, uid))
for s, p, o in remove_trp
}
add_trp = {
(rel_uri_to_urn(s, uid), p, rel_uri_to_urn(o, uid))
for s, p, o in add_trp
}
remove_trp = rsrc.check_mgd_terms(remove_trp)
add_trp = rsrc.check_mgd_terms(add_trp)

Expand Down
29 changes: 24 additions & 5 deletions lakesuperior/endpoints/ldp.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@
from lakesuperior.exceptions import (
ChecksumValidationError, ResourceNotExistsError, TombstoneError,
ServerManagedTermError, InvalidResourceError, SingleSubjectError,
ResourceExistsError, IncompatibleLdpTypeError)
ResourceExistsError, IncompatibleLdpTypeError,
IndigestibleError)
from lakesuperior.globals import RES_CREATED
from lakesuperior.model.ldp.ldp_factory import LdpFactory
from lakesuperior.model.ldp.ldp_nr import LdpNr
Expand Down Expand Up @@ -283,18 +284,33 @@ def post_resource(parent_uid):
kwargs['mimetype'] = mimetype
# Check digest if requested.
if 'digest' in request.headers:
kwargs['prov_cksum_algo'], kwargs['prov_cksum'] = \
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:
rsrc = rsrc_api.create(parent_uid, slug, **kwargs)
except IndigestibleError:
return (
f'Unable to parse digest header: {request.headers["digest"]}'
), 400
except ResourceNotExistsError as e:
return str(e), 404
except (InvalidResourceError, ChecksumValidationError) as e:
return str(e), 409
except TombstoneError as e:
return _tombstone_response(e, uid)
except ServerManagedTermError as e:
rsp_headers['Link'] = (
f'<{uri}>; rel="{nsc["ldp"].constrainedBy}"; '
f'{g.webroot}/info/ldp_constraints"'
)
return str(e), 412

uri = g.tbox.uid_to_uri(rsrc.uid)
Expand All @@ -303,8 +319,9 @@ def post_resource(parent_uid):
rsp_headers['Location'] = uri

if mimetype and kwargs.get('rdf_fmt') is None:
rsp_headers['Link'] = (f'<{uri}/fcr:metadata>; rel="describedby"; '
f'anchor="{uri}"')
rsp_headers['Link'] = (
f'<{uri}/fcr:metadata>; rel="describedby"; anchor="{uri}"'
)

return uri, 201, rsp_headers

Expand Down Expand Up @@ -393,6 +410,8 @@ def patch_resource(uid, is_metadata=False):
if cond_ret:
return cond_ret

handling, _ = set_post_put_params()

rsp_headers = {'Content-Type' : 'text/plain; charset=utf-8'}
if request.mimetype != 'application/sparql-update':
return 'Provided content type is not a valid parsable format: {}'\
Expand All @@ -401,7 +420,7 @@ def patch_resource(uid, is_metadata=False):
update_str = request.get_data().decode('utf-8')
local_update_str = g.tbox.localize_ext_str(update_str, nsc['fcres'][uid])
try:
rsrc = rsrc_api.update(uid, local_update_str, is_metadata)
rsrc = rsrc_api.update(uid, local_update_str, is_metadata, handling)
except (ServerManagedTermError, SingleSubjectError) as e:
return str(e), 412
except InvalidResourceError as e:
Expand Down
17 changes: 10 additions & 7 deletions lakesuperior/endpoints/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

from os import path

from flask import Blueprint, render_template
from flask import Blueprint, jsonify, render_template

from lakesuperior import release
from lakesuperior.dictionaries import srv_mgd_terms as smt

logger = logging.getLogger(__name__)

Expand All @@ -21,9 +22,11 @@ def index():
return render_template('index.html', release=release)


@main.route('/debug', methods=['GET'])
def debug():
"""Debug page."""
raise RuntimeError()


@main.route('/info/ldp_constraints', methods=['GET'])
def ldp_constraints():
""" LDP term constraints. """
return jsonify({
'srv_mgd_subjects': [*smt.srv_mgd_subjects],
'srv_mgd_predicates': [*smt.srv_mgd_predicates],
'srv_mgd_types': [*smt.srv_mgd_types],
})
8 changes: 1 addition & 7 deletions lakesuperior/etc.defaults/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ uuid:
#
# ``blake2b`` is a strong, fast cryptographic alternative to SHA2/3:
# https://blake2.net/
algo: sha1
algo: blake2b

###
# Data store configuration.
Expand Down Expand Up @@ -77,12 +77,6 @@ store:
# Changes to this parameter require a full migration.
referential_integrity: lenient

###
# Split newly minted URIs into pairtrees.
#
# This mimics Fedora4 behavior which segments an identifier on POST.
legacy_ptree_split: False

###
# The path used to persist LDP-NR (bitstreams).
#
Expand Down
10 changes: 8 additions & 2 deletions lakesuperior/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,17 @@ def __init__(self, uid, prov_cksum, calc_cksum, msg=None):


def __str__(self):
return self.msg or (f'Validation failed for resource {self.uid}. '
f'Provided checksum: {self.prov_cksum}; '
return self.msg or (f'validation failed for resource {self.uid}. '
f'provided checksum: {self.prov_cksum}; '
f'calculated checksum: {self.calc_cksum}')


class IndigestibleError(ResourceError):
"""
Raised when an unsupported digest algorithm is requested.
"""
pass


class ResourceNotExistsError(ResourceError):
'''
Expand Down

0 comments on commit cfded38

Please sign in to comment.