Skip to content
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
21 changes: 18 additions & 3 deletions invenio.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,7 @@ from invenio_app_rdm.config import \
from invenio_app_rdm.config import \
VOCABULARIES_DATASTREAM_WRITERS as DEFAULT_VOCABULARIES_DATASTREAM_WRITERS
from cds_rdm.clc_sync.services.components import ClcSyncComponent
from cds_rdm.components import CDSResourcePublication
from cds_rdm.components import SubjectsValidationComponent
from cds_rdm.components import MintAlternateIdentifierComponent
from cds_rdm.components import CDSResourcePublication, MintAlternateIdentifierComponent, PublicationInclusionComponent, SubjectsValidationComponent
from cds_rdm.pids import validate_optional_doi_transitions
from cds_rdm.views import frontpage_view_function, inspire_link_render
from cds_rdm.reviews.policy import CDSRecordVersionReviewPolicy
Expand Down Expand Up @@ -451,6 +449,22 @@ RDM_COMMUNITY_REQUIRED_TO_PUBLISH = True
RDM_NEW_RECORD_VERSION_REVIEW_POLICY = CDSRecordVersionReviewPolicy
CDS_COMMUNITIES_REQUIRING_NEW_RECORD_VERSION_REVIEW = []

# Public research publication resource types that should be included in the CERN Scientific community.
CDS_CERN_SCIENTIFIC_RESOURCE_TYPES = {
"publication-dissertation",
"publication-book",
"publication-section",
"publication-conferencepaper",
"publication-conferenceproceeding",
"publication-journal",
"publication-article",
"publication-preprint",
"publication-report",
"publication-technicalnote",
"publication-note",
"publication",
}

RDM_SEARCH = {
**deepcopy(RDM_SEARCH),
"query_parser_cls": QueryParser.factory(
Expand Down Expand Up @@ -610,6 +624,7 @@ RDM_RECORDS_SERVICE_COMPONENTS = [
CDSResourcePublication,
ClcSyncComponent,
MintAlternateIdentifierComponent,
PublicationInclusionComponent,
VCSComponent,
]

Expand Down
65 changes: 48 additions & 17 deletions site/cds_rdm/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,7 @@
from invenio_records_resources.services.uow import TaskOp
from marshmallow import ValidationError

from .tasks import sync_alternate_identifiers

# @shared_task()
# def create_community_inclusion_request(record_id):
# """Create a community inclusion request for ."""
# # Create a community-inclusion request
# csc_community_id = current_app.config.get("CDS_CERN_SCIENTIFIC_COMMUNITY_ID")
# data = dict(
# communities=[
# {
# "id": csc_community_id,
# "require_review": True,
# }
# ]
# )

# current_rdm_records.record_communities_service.add(system_identity, record_id, data)
from .tasks import submit_community_inclusion_request, sync_alternate_identifiers


def is_record_public(record):
Expand Down Expand Up @@ -218,3 +202,50 @@ def publish(self, identity, draft=None, record=None):
record_id=str(record.id),
)
)


class PublicationInclusionComponent(ServiceComponent):
"""Auto-submit a community inclusion request to the CERN Scientific Community.

Triggers on publish for public records whose resource type is listed in
`CDS_CERN_SCIENTIFIC_RESOURCE_TYPES`. The request is created asynchronously
after the publish transaction commits.
"""

def _is_eligible(self, draft, record):
"""Return True when the record should be auto-submitted for community inclusion."""
if not is_record_public(draft):
return False

resource_type = draft["metadata"]["resource_type"]["id"]
research_resource_types = current_app.config.get(
"CDS_CERN_SCIENTIFIC_RESOURCE_TYPES", set()
)
if resource_type not in research_resource_types:
return False

csc_community_id = current_app.config.get("CDS_CERN_SCIENTIFIC_COMMUNITY_ID")
if not csc_community_id:
current_app.logger.error(
"CDS_CERN_SCIENTIFIC_COMMUNITY_ID is not configured; "
"skipping auto community inclusion for record %s.",
record.pid.pid_value,
)
return False

if csc_community_id in record.parent.communities.ids:
return False

return True

def publish(self, identity, draft=None, record=None, **kwargs):

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.

do we auto accept it? or it needs to be accepted?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

In the task, there is "require_review": True
It only submits for review

"""Schedule community inclusion request after the record is published."""
if not self._is_eligible(draft, record):
return

self.uow.register(
TaskOp(
submit_community_inclusion_request,
record_id=record.pid.pid_value,
)
)
49 changes: 49 additions & 0 deletions site/cds_rdm/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from invenio_cern_sync.users.sync import sync as users_sync
from invenio_db import db
from invenio_pidstore.models import PersistentIdentifier, PIDStatus
from invenio_rdm_records.proxies import current_record_communities_service
from invenio_rdm_records.records.api import RDMRecord
from invenio_records_resources.proxies import current_service_registry
from invenio_records_resources.services.uow import UnitOfWork
Expand Down Expand Up @@ -312,3 +313,51 @@ def sync_alternate_identifiers(parent_id, record_id):
)
db.session.add(report_number_pid)
db.session.commit()


@shared_task(ignore_result=True)
def submit_community_inclusion_request(record_id):
"""Create and submit a community inclusion request to the CERN Scientific Community after a public record satisfies the criteria."""
csc_community_id = current_app.config.get("CDS_CERN_SCIENTIFIC_COMMUNITY_ID")

data = {
"communities": [
{
"id": csc_community_id,
"require_review": True,
"comment": {
"payload": {
"content": "<p>This record was automatically submitted to the CERN Research Community by the system because it satisfies the criteria for inclusion (resource type identified as research related).</p>",
"format": "html",
}
},
}
]
}

try:
with UnitOfWork() as uow:
processed, errors = current_record_communities_service.add(

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.

doesn't it automatically add the community to the record without requiring the review? We discussed that initially we should go through approval, we might switch to automatic approval later on

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

If that happens, later on we can remove the require_review flag from the data being passed to this service method.

system_identity, record_id, data, uow=uow
)
uow.commit()

if errors:
for error in errors:
current_app.logger.info(
"Community inclusion not created for record %s to community %s: %s",
record_id,
error.get("community_id"),
error.get("message"),
)
else:
current_app.logger.info(
"Community inclusion request %s submitted for record %s to community %s.",
processed[0].get("request_id"),
record_id,
processed[0].get("community_id"),
)
except Exception as e:
current_app.logger.exception(
f"Failed to submit community inclusion request for record {record_id}: {e}"
)
50 changes: 50 additions & 0 deletions site/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
RDM_RECORDS_RELATED_IDENTIFIERS_SCHEMES,
always_valid,
)
from invenio_rdm_records.proxies import current_rdm_records_service
from invenio_rdm_records.records.api import RDMRecord
from invenio_rdm_records.resources.serializers import DataCite43JSONSerializer
from invenio_rdm_records.services.pids import providers
from invenio_records_resources.proxies import current_service_registry
Expand Down Expand Up @@ -95,6 +97,7 @@ def mock_datacite_client():
"""Mock DataCite client."""
return FakeDataCiteClient


@pytest.fixture(scope="module")
def mock_crossref_client():
"""Mock DataCite client."""
Expand Down Expand Up @@ -1606,3 +1609,50 @@ def name_full_data():
],
"affiliations": [{"name": "CustomORG"}],
}


@pytest.fixture(scope="function")
def community(community_service, minimal_community):
"""Scientific community where Thesis should be submitted."""
minimal_community["slug"] = "TEST-COMMUNITY"
minimal_community["metadata"] = {"title": "TEST-COMMUNITY"}
c = community_service.create(system_identity, minimal_community)
Community.index.refresh()
return c._record


@pytest.fixture()
def record_community(db, uploader, minimal_restricted_record, community):
"""Creates a record that belongs to a community."""

class Record:
"""Test record class."""

def create_record(
self,
uploader=uploader,
record_dict=minimal_restricted_record,
community=community,
):
"""Creates new record that belongs to the same community."""
# create draft
draft = current_rdm_records_service.create(uploader.identity, record_dict)
record = draft._record
if community:
# add the record to the community
record.parent.communities.add(community, default=False)
record.parent.commit()
db.session.commit()

# publish and get record
result_item = current_rdm_records_service.publish(
uploader.identity, draft.id
)
record = result_item._record
current_rdm_records_service.indexer.index(
record, arguments={"refresh": True}
)

return record

return Record()
Loading
Loading