Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

files: add records/files endpoint and change the deposits/files one #1288

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions cap/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -530,15 +530,9 @@ def _(x):
'application/basic+json': ('cap.modules.records.serializers'
':basic_json_v1_search')
},
'files_serializers': {
'application/json': ('cap.modules.deposit.serializers:files_response'),
},
'search_class': 'cap.modules.deposit.search:CAPDepositSearch',
'search_factory_imp': 'cap.modules.search.query:cap_search_factory',
'item_route': '/deposits/<{0}:pid_value>'.format(_PID),
'file_list_route': '/deposits/<{0}:pid_value>/files'.format(_PID),
'file_item_route': '/deposits/<{0}:pid_value>/files/<path:key>'.format(
_PID),
'create_permission_factory_imp': check_oauth2_scope(
lambda record: CreateDepositPermission(record).can(), write_scope.id),
'read_permission_factory_imp': check_oauth2_scope(
Expand Down
8 changes: 6 additions & 2 deletions cap/modules/deposit/ext.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
"""Initialize extension."""

from __future__ import absolute_import, print_function
from cap.modules.schemas.models import Schema

from invenio_search import current_search

from cap.modules.schemas.models import Schema

from .views import create_deposit_files_blueprint


class CAPDeposit(object):
"""CAPDeposit extension."""

def __init__(self, app=None):
"""Extension initialization."""
if app:
Expand All @@ -16,3 +19,4 @@ def __init__(self, app=None):
def init_app(self, app):
"""Flask application initialization."""
app.extensions['cap_deposit'] = self
app.register_blueprint(create_deposit_files_blueprint(app))
7 changes: 1 addition & 6 deletions cap/modules/deposit/serializers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,11 @@

from __future__ import absolute_import, print_function

from invenio_deposit.serializers import json_file_response
from invenio_records_rest.serializers.response import (record_responsify,
search_responsify)

from .json import DepositSerializer
from .schemas.json import DepositSchema, DepositFormSchema
from .schemas.json import DepositFormSchema, DepositSchema

# Serializers
# ===========
Expand All @@ -46,7 +45,3 @@
deposit_form_json_v1_response = record_responsify(deposit_form_json_v1,
'application/json')
deposit_json_v1_search = search_responsify(deposit_json_v1, 'application/json')

# Files-REST serializers
# JSON Files serializers for deposit files
files_response = json_file_response
86 changes: 86 additions & 0 deletions cap/modules/deposit/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# -*- coding: utf-8 -*-
#
# This file is part of CERN Analysis Preservation Framework.
# Copyright (C) 2016 CERN.
#
# CERN Analysis Preservation Framework is free software; you can redistribute
# it and/or modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of the
# License, or (at your option) any later version.
#
# CERN Analysis Preservation Framework is distributed in the hope that it will
# be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with CERN Analysis Preservation Framework; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
# MA 02111-1307, USA.
#
# In applying this license, CERN does not
# waive the privileges and immunities granted to it by virtue of its status
# as an Intergovernmental Organization or submit itself to any jurisdiction.
"""Extra deposit views."""

from __future__ import absolute_import, print_function

from flask import Blueprint, g
from invenio_files_rest.views import bucket_view, object_view
from sqlalchemy.orm.exc import NoResultFound

from .api import CAPDeposit


def create_deposit_files_blueprint(app):
"""Create blueprint from a Flask application.
:params app: A Flask application.
:returns: Configured blueprint.
"""
cap_deposit_files_bp = Blueprint('cap_deposit_files',
__name__,
url_prefix='')

deposit_item_path = app.config['DEPOSIT_REST_ENDPOINTS']['depid'][
'item_route']
cap_deposit_files_bp.add_url_rule('{}/files'.format(deposit_item_path),
view_func=bucket_view)
cap_deposit_files_bp.add_url_rule(
'{}/files/<path:key>'.format(deposit_item_path), view_func=object_view)

@cap_deposit_files_bp.url_value_preprocessor
def resolve_pid_to_bucket_id(endpoint, values):
"""Flask URL preprocessor to resolve pid to Bucket ID.
In the ``cap_deposit_bp`` we are gluing together Records-REST
and Files-REST APIs. Records-REST knows about PIDs but Files-REST does
not, this function will pre-process the URL so the PID is removed from
the URL and resolved to bucket ID which is injected into Files-REST
view calls:
``/api/<record_type>/<pid_value>/files/<key>`` ->
``/files/<bucket>/<key>``.
"""
# Remove the 'pid_value' in order to match the Files-REST bucket view
# signature. Store the value in Flask global request object for later
# usage.
g.pid = values.pop('pid_value')
pid, _ = g.pid.data

try:
deposit = CAPDeposit.get_record(pid.object_uuid)
values['bucket_id'] = str(deposit.files.bucket)
except (AttributeError, NoResultFound):
# Hack, to make invenio_files_rest.views.as_uuid throw a
# ValueError instead of a TypeError if we set the value to None.
values['bucket_id'] = ''

@cap_deposit_files_bp.url_defaults
def restore_pid_to_url(endpoint, values):
"""Put ``pid_value`` back to the URL after matching Files-REST views.
Since we are computing the URL more than one times, we need the
original values of the request to be unchanged so that it can be
reproduced.
"""
# Value here has been saved in above method (resolve_pid_to_bucket_id)
values['pid_value'] = g.pid

return cap_deposit_files_bp
84 changes: 84 additions & 0 deletions cap/modules/records/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# -*- coding: utf-8 -*-
#
# This file is part of CERN Analysis Preservation Framework.
# Copyright (C) 2016 CERN.
#
# CERN Analysis Preservation Framework is free software; you can redistribute
# it and/or modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of the
# License, or (at your option) any later version.
#
# CERN Analysis Preservation Framework is distributed in the hope that it will
# be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with CERN Analysis Preservation Framework; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
# MA 02111-1307, USA.
#
# In applying this license, CERN does not
# waive the privileges and immunities granted to it by virtue of its status
# as an Intergovernmental Organization or submit itself to any jurisdiction.
"""Extra records views."""

from __future__ import absolute_import, print_function

from flask import Blueprint, g
from invenio_files_rest.views import bucket_view, object_view
from sqlalchemy.orm.exc import NoResultFound

from .api import CAPRecord


def create_cap_record_blueprint(app):
"""Create blueprint from a Flask application.
:params app: A Flask application.
:returns: Configured blueprint.
"""
cap_records_bp = Blueprint('cap_records_files', __name__, url_prefix='')

record_item_path = app.config['RECORDS_REST_ENDPOINTS']['recid'][
'item_route']
cap_records_bp.add_url_rule('{}/files'.format(record_item_path),
view_func=bucket_view)
cap_records_bp.add_url_rule('{}/files/<path:key>'.format(record_item_path),
view_func=object_view)

@cap_records_bp.url_value_preprocessor
def resolve_pid_to_bucket_id(endpoint, values):
"""Flask URL preprocessor to resolve pid to Bucket ID.
In the ``cap_records_bp`` we are gluing together Records-REST
and Files-REST APIs. Records-REST knows about PIDs but Files-REST does
not, this function will pre-process the URL so the PID is removed from
the URL and resolved to bucket ID which is injected into Files-REST
view calls:
``/api/<record_type>/<pid_value>/files/<key>`` ->
``/files/<bucket>/<key>``.
"""
# Remove the 'pid_value' in order to match the Files-REST bucket view
# signature. Store the value in Flask global request object for later
# usage.
g.pid = values.pop('pid_value')
pid, _ = g.pid.data

try:
record = CAPRecord.get_record(pid.object_uuid)
values['bucket_id'] = str(record.files.bucket)
except (AttributeError, NoResultFound):
# Hack, to make invenio_files_rest.views.as_uuid throw a
# ValueError instead of a TypeError if we set the value to None.
values['bucket_id'] = ''

@cap_records_bp.url_defaults
def restore_pid_to_url(endpoint, values):
"""Put ``pid_value`` back to the URL after matching Files-REST views.
Since we are computing the URL more than one times, we need the
original values of the request to be unchanged so that it can be
reproduced.
"""
# Value here has been saved in above method (resolve_pid_to_bucket_id)
values['pid_value'] = g.pid

return cap_records_bp
31 changes: 10 additions & 21 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

DATABASE = "postgresql"
ELASTICSEARCH = "elasticsearch5"
INVENIO_VERSION = '3.0.0' # "3.0.0rc2"
INVENIO_VERSION = '3.0.0' # "3.0.0rc2"

tests_require = [
'check-manifest>=0.35',
Expand All @@ -34,19 +34,15 @@
]

extras_require = {
'docs': [
'Sphinx>=1.5.1',
],
'docs': ['Sphinx>=1.5.1', ],
'tests': tests_require,
}

extras_require['all'] = []
for reqs in extras_require.values():
extras_require['all'].extend(reqs)

extras_require['ldap'] = [
'python-ldap>=2.4.39'
]
extras_require['ldap'] = ['python-ldap>=2.4.39']

# Do not include in all requirement
extras_require['xrootd'] = [
Expand Down Expand Up @@ -95,19 +91,17 @@
# "raven" versions needed till we FIX dependecies on installation
'raven[flask]>=5.0.0,<5.5',
'invenio-logging[sentry]>=1.0.0b1',

'uWSGI==2.0.17',
'uwsgi-tools==1.1.1',
'uwsgitop==0.10',
]

packages = find_packages()


# Get the version string. Cannot be done with import!
g = {}
with open(os.path.join('cap', 'version.py'), 'rt') as fp:
exec(fp.read(), g)
exec (fp.read(), g)
version = g['__version__']

setup(
Expand All @@ -119,15 +113,14 @@
license='MIT',
author='CERN',
author_email='[email protected]',
url='https://github.com/cernanalysispreservation/analysispreservation.cern.ch', # noqa
url=
'https://github.com/cernanalysispreservation/analysispreservation.cern.ch', # noqa
packages=packages,
zip_safe=False,
include_package_data=True,
platforms='any',
entry_points={
'console_scripts': [
'cap = cap.cli:cli',
],
'console_scripts': ['cap = cap.cli:cli', ],
'invenio_access.actions': [
'cms_access = '
'cap.modules.experiments.permissions:cms_access_action',
Expand Down Expand Up @@ -162,6 +155,7 @@
'cap_schemas = cap.modules.schemas.views:blueprint',
'cap_auth = cap.modules.auth.views:blueprint',
'cap_repos = cap.modules.repoimporter.views:repos_bp',
'cap_records = cap.modules.records.views:create_cap_record_blueprint', # noqa
'invenio_oauthclient = invenio_oauthclient.views.client:blueprint',
],
'invenio_celery.tasks': [
Expand All @@ -175,7 +169,6 @@
'cap.modules.records.minters:cap_record_minter',
'cap_deposit_minter = '
'cap.modules.deposit.minters:cap_deposit_minter',

],
'invenio_pidstore.fetchers': [
'cap_record_fetcher = '
Expand All @@ -193,12 +186,8 @@
'auth = cap.modules.auth.models',
'git_model = cap.modules.repoimporter.models',
],
'invenio_db.alembic': [
'cap = cap:alembic',
],
'invenio_config.module': [
'cap = cap.config'
]
'invenio_db.alembic': ['cap = cap:alembic', ],
'invenio_config.module': ['cap = cap.config']
},
extras_require=extras_require,
install_requires=install_requires,
Expand Down
Loading