Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@

from .config import INVENIO_CAPABILITY_URL, VALIDATE_MESSAGE, WEKO_ROOT_INDEX
from .models import ChangeListIndexes, ResourceListIndexes
from .permissions import can_download_file
from .query import get_items_by_index_tree

import urllib.parse
Expand Down Expand Up @@ -475,6 +476,8 @@ def get_resource_dump_manifest(self, record_id):
record = WekoRecord.get_record_by_pid(record_id)
if record:
for file in record.files:
if not can_download_file(record, file):

@ivis-miyachi ivis-miyachi Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fix no.102

continue
current_app.logger.debug(file.info())
file_info = file.info()
path = 'recid_{}/{}'.format(
Expand Down Expand Up @@ -969,18 +972,24 @@ def get_change_dump_manifest_xml(self, record_id):
else:
prev_record = None
if current_record:
list_file = [file for file in current_record.files]
list_file = [

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fix no.107

(current_record, file) for file in current_record.files
]
current_checksum = [
file.info().get('checksum') for file in current_record.files
]
prev_checksum = []
if prev_record:
list_file.extend([file for file in prev_record.files])
list_file.extend(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fix no.107

[(prev_record, file) for file in prev_record.files]
)
prev_checksum = [
file.info().get('checksum') for file in
prev_record.files
]
for file in list_file:
for record, file in list_file:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fix no.107

if not can_download_file(record, file):
continue
file_info = file.info()
change = None
if file_info.get('checksum') in prev_checksum:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# -*- coding: utf-8 -*-

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fix no.100, 102, 104, 106, 107, 108

#
# This file is part of WEKO3.
# Copyright (C) 2017 National Institute of Informatics.
#
# WEKO3 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.
#
# WEKO3 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 WEKO3; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
# MA 02111-1307, USA.

"""Permissions for ResourceSync Server."""

from functools import wraps

from flask import abort, current_app


def is_public_record(record_id):
"""Check that the record is available to the public.

The record must be published, its publication date must have come and
it must belong to a public index. For a versioned identifier
("<recid>.<version>") the parent record must satisfy the same
conditions.

:param record_id: Identifier of the record.
:return: True if the record can be distributed.
"""
from invenio_oaiserver.response import is_private_index
from weko_deposit.api import WekoRecord
from weko_records_ui.permissions import check_publish_status

record_ids = [str(record_id)]
if '.' in record_ids[0]:
record_ids.append(record_ids[0].split('.')[0])

for _id in record_ids:
try:
record = WekoRecord.get_record_by_pid(_id)
except Exception as ex:
current_app.logger.debug(ex)
return False
if not record or not check_publish_status(record) \
or is_private_index(record):
return False
return True


def can_download_file(record, file):
"""Check that the current user can download the file of the record.

:param record: Record that owns the file.
:param file: File object of the record.
:return: True if the file can be downloaded.
"""
from weko_records_ui.permissions import check_file_download_permission
try:
return bool(check_file_download_permission(record, file.info()))
except Exception as ex:
current_app.logger.debug(ex)
return False


def public_record_required(param='record_id'):
"""Abort with 404 unless the record in the URL is public.

:param param: name of the view argument holding the record identifier.
"""
def decorator(f):
@wraps(f)
def decorated(*args, **kwargs):
record_id = kwargs.get(param)
if record_id is None or not is_public_record(record_id):
abort(404)
return f(*args, **kwargs)
return decorated
return decorator
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,16 @@ def _get_index_search_query(_date_from: str, _date_until: str) -> dict:
"post_filter": {
"bool": {
"must": [
{

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fix no.100, 102, 104, 106, 107, 108

# Deleted items are kept so that the change
# list can report their deletion.
"terms": {
"publish_status": [
PublishStatus.PUBLIC.value,
PublishStatus.DELETE.value
]
}
},
{
"range": {
"publish_date": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from weko_index_tree.models import Index

from .api import ChangeListHandler, ResourceListHandler
from .permissions import public_record_required
from .utils import render_capability_xml, render_well_know_resourcesync

blueprint = Blueprint(
Expand Down Expand Up @@ -60,6 +61,7 @@ def resource_dump(index_id):


@blueprint.route("/resync/<index_id>/<record_id>/file_content.zip")
@public_record_required()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fix no.100

def file_content(index_id, record_id):
"""Download file content."""
resource = ResourceListHandler.get_resource_by_repository_id(index_id)
Expand All @@ -80,6 +82,7 @@ def capability():


@blueprint.route("/resync/<index_id>/<record_id>/resourcedump_manifest.xml")
@public_record_required()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fix no.102

def resource_dump_manifest(index_id, record_id):
"""Render resource dump manifest."""
resource = ResourceListHandler.get_resource_by_repository_id(index_id)
Expand Down Expand Up @@ -138,6 +141,7 @@ def change_dump(index_id, from_date):


@blueprint.route("/resync/<index_id>/<record_id>/changedump_manifest.xml")
@public_record_required()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fix no.107

def change_dump_manifest(index_id, record_id):
"""Render change dump manifest."""
cl = ChangeListHandler.get_change_list_by_repo_id(index_id)
Expand All @@ -149,6 +153,7 @@ def change_dump_manifest(index_id, record_id):


@blueprint.route("/resync/<index_id>/<record_id>/change_dump_content.zip")
@public_record_required()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fix no.108

def change_dump_content(index_id, record_id):
"""Render change dump content."""
cl = ChangeListHandler.get_change_list_by_repo_id(index_id)
Expand Down
84 changes: 78 additions & 6 deletions modules/invenio-resourcesyncserver/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -305,11 +305,42 @@ def as_xml_sample():

with patch("invenio_resourcesyncserver.api.ResourceListHandler._validation", return_value=True):
with patch("weko_deposit.api.WekoRecord.get_record_by_pid", return_value=return_data):
# try and except is for bypassing ResourceDumpManifest.as_xml()
try:
assert test.get_resource_dump_manifest(record_id)
except:
pass
with patch("invenio_resourcesyncserver.api.can_download_file", return_value=True):
# try and except is for bypassing ResourceDumpManifest.as_xml()
try:
assert test.get_resource_dump_manifest(record_id)
except:
pass


def _sample_file(key, checksum):
file = MagicMock()
file.info.return_value = {
"key": key,
"checksum": "sha256:{}".format(checksum),
"size": 10,
}
return file


def test_get_resource_dump_manifest_download_permission_ResourceListHandler(i18n_app):
test = sample_ResourceListHandler()
test.resource_dump_manifest = True
allowed = _sample_file("allowed.txt", "aaaa")
denied = _sample_file("denied.txt", "bbbb")
record = MagicMock()
record.files = [allowed, denied]
record.get.return_value = "1"

with patch("invenio_resourcesyncserver.api.ResourceListHandler._validation", return_value=True):
with patch("weko_deposit.api.WekoRecord.get_record_by_pid", return_value=record):
with patch("invenio_resourcesyncserver.api.can_download_file",
side_effect=lambda r, f: f is allowed) as m:
xml = test.get_resource_dump_manifest("1")
assert "allowed.txt" in xml
assert "denied.txt" not in xml
assert "bbbb" not in xml
assert m.call_count == 2


# def get_record_content_file(self, record_id):
Expand Down Expand Up @@ -545,7 +576,48 @@ def _is_record_in_index(key):
with patch("weko_deposit.api.WekoRecord.get_record_by_pid", return_value=return_data):
with patch("invenio_resourcesyncserver.utils.get_pid", return_value=return_data):
with patch("weko_deposit.api.WekoRecord.get_record", return_value=return_data):
assert test_str.get_change_dump_manifest_xml(record_id)
with patch("invenio_resourcesyncserver.api.can_download_file", return_value=True):
assert test_str.get_change_dump_manifest_xml(record_id)


def test_get_change_dump_manifest_xml_download_permission_ChangeListHandler(i18n_app):
test_str = sample_ChangeListHandler("str")
test_str._validation = lambda: True
test_str._is_record_in_index = lambda key: True

kept = _sample_file("kept.txt", "0000")
created_ok = _sample_file("created_ok.txt", "1111")
created_ng = _sample_file("created_ng.txt", "2222")
deleted_ok = _sample_file("deleted_ok.txt", "3333")
deleted_ng = _sample_file("deleted_ng.txt", "4444")
current_record = MagicMock()
current_record.files = [kept, created_ok, created_ng]
current_record.get.return_value = "8"
prev_record = MagicMock()
prev_record.files = [kept, deleted_ok, deleted_ng]

denied = (created_ng, deleted_ng)
checked = []

def _can_download_file(record, file):
checked.append((record, file))
return file not in denied

with patch("weko_deposit.api.WekoRecord.get_record_by_pid", return_value=current_record):
with patch("invenio_resourcesyncserver.utils.get_pid", return_value=MagicMock()):
with patch("weko_deposit.api.WekoRecord.get_record", return_value=prev_record):
with patch("invenio_resourcesyncserver.api.can_download_file",
side_effect=_can_download_file):
xml = test_str.get_change_dump_manifest_xml("8.2")

assert "created_ok.txt" in xml
assert "deleted_ok.txt" in xml
assert "created_ng.txt" not in xml
assert "deleted_ng.txt" not in xml
assert "kept.txt" not in xml
# each file is checked against the record that owns it
assert (current_record, created_ng) in checked
assert (prev_record, deleted_ng) in checked


# def delete(cls, change_list_id):
Expand Down
Loading
Loading