OARepo Requests
Extensions to Invenio Requests providing workflow-based request handling for repository records.
Installation
pip install oarepo-requests
Overview
This library extends Invenio Requests to support workflow-based request handling for repository records. It provides:
- Extended request API with additional endpoints
- Pre-built request types for common curation workflows
- Integration with oarepo-workflows for state transitions
- Action components for extensible request processing
- UI serialization support for request entities
Features
Extended Request API
The library extends the standard /api/requests endpoint and adds record-specific request endpoints:
POST /api/requests- Create a request withrequest_typeandtopicin payloadPOST /api/requests/<type>/<topic>- Create a request via URL parametersGET /api/requests/applicable?topic=<reference>- List applicable request types for a topic
Built-in Request Types
Publish Requests
publish_draft - Submit draft for review and publication
- Validates topic is initial version draft
- Supports version field in payload
- Transitions:
submitted→published(accepted) ordraft(declined) - Auto-approval when user has curator permissions
publish_new_version - Publish new version of published record
- For records with existing published versions
- Inherits base publish request behavior
publish_changed_metadata - Publish metadata changes
- For publishing edited metadata of published records
Edit Requests
edit_published_record - Request to edit published record metadata
- Creates draft from published record
- Requires record to have no existing draft
- Auto-creates draft on acceptance
new_version - Request to create new version
- Creates new version draft from published record
- Supports
keep_filesparameter (yes/no) - Only applicable to published records without drafts
Delete Requests
delete_published_record - Request permanent deletion of published record
- Requires
removal_reasonand optionalnotein payload - Executes record deletion on acceptance
- Marked as dangerous operation
Request Actions
All request types support standard workflow actions:
- submit - Submit created request for approval (transitions to
submitted) - accept - Accept submitted request (executes request-specific logic)
- decline - Decline submitted request (typically returns to previous state)
- cancel - Cancel request before acceptance (transitions to
cancelled)
Custom action implementations:
PublishDraftAcceptAction- Publishes draft, validates no unresolved requestsDeletePublishedRecordAcceptAction- Executes record deletion with metadata preservationEditTopicAcceptAction- Creates editable draft from published recordNewVersionAcceptAction- Creates new version draft, optionally copies files
Action Components
The library uses a component architecture for extending action behavior:
class RequestActionComponent:
def submit(self, identity, action, uow, *args, **kwargs): ...
def accept(self, identity, action, uow, *args, **kwargs): ...
def decline(self, identity, action, uow, *args, **kwargs): ...
def cancel(self, identity, action, uow, *args, **kwargs): ...
Built-in components:
WorkflowTransitionComponent - Applies workflow state transitions based on action outcomes
- Reads transitions from workflow request configuration
- Sets record state according to
status_tomapping
AutoAcceptComponent - Auto-accepts requests with auto-approve receivers
- Must be last in component chain
- Executes accept action if receiver has
auto_approve: true
Configure components in invenio.cfg:
REQUESTS_ACTION_COMPONENTS = [
WorkflowTransitionComponent,
AutoAcceptComponent,
]
Workflow Integration
Request types integrate with oarepo-workflows through the receiver function:
OAREPO_REQUESTS_DEFAULT_RECEIVER = "oarepo_requests.receiver:default_workflow_receiver_function"
The receiver function:
- Retrieves workflow for the record
- Looks up request configuration in workflow
- Evaluates recipient generators to determine receiver
- Returns entity reference or
Nonefor auto-approval
Example workflow request configuration:
from oarepo_workflows import WorkflowRequest, WorkflowTransitions, AutoApprove
from oarepo_requests.services.permissions import IfRequestedBy
class MyWorkflowRequests(WorkflowRequestPolicy):
publish_request = WorkflowRequest(
requesters=[IfInState("draft", then_=[RecordOwners(), CommunityRole("curator")])],
recipients=[
IfRequestedBy(
CommunityRole("curator"),
then_=[AutoApprove()],
else_=[CommunityRole("curator")],
)
],
transitions=WorkflowTransitions(submitted="submitted", accepted="published", declined="draft"),
)
Permission Generators
RequestActive - Matches when request action is being executed
- Useful for granting temporary elevated permissions during request processing
- Example: Allow deletion only through request acceptance
class MyWorkflowPermissions(RequestBasedWorkflowPermissions):
can_delete = [..., RequestActive()]
IfRequestedBy - Conditional generator based on request creator
- Evaluates if creator has specified permissions
- Used in workflow recipient configuration
recipients = [
IfRequestedBy(
CommunityRole("curator"),
then_=[AutoApprove()],
else_=[CommunityRole("publisher")],
)
]
IfNoNewVersionDraft - Checks if record has no new version draft
IfNoEditDraft - Checks if record has no edit draft
Request Type Properties
Base properties inherited by all request types:
class OARepoRequestType(RequestType):
dangerous = False # Marks destructive operations
allowed_on_draft = True # Can be created on draft records
allowed_on_published = True # Can be created on published records
editable = None # Whether request can be edited before submission
receiver_can_be_none = False # Whether auto-approval is allowed
payload_schema = {...} # Marshmallow schema for request payload
Request types also implement:
is_applicable_to(identity, topic)- Check if request type can be used for a topiccan_create(identity, data, receiver, topic, creator)- Validate request creationstateful_name(identity, topic, request)- Dynamic name based on request statestateful_description(identity, topic, request)- Dynamic description based on state
UI Support
The library provides UI serialization for requests:
- Expands entity references (creator, receiver, topic)
- Resolves references using configured entity resolvers
- Includes stateful names and descriptions
- Provides form definitions for request creation
Configuration:
REQUESTS_UI_SERIALIZATION_REFERENCED_FIELDS = ["created_by", "receiver", "topic"]
Configuration
Core Settings
# Default receiver function for requests
OAREPO_REQUESTS_DEFAULT_RECEIVER = "oarepo_requests.receiver:default_workflow_receiver_function"
# Allowed receiver entity types
REQUESTS_ALLOWED_RECEIVERS = ["user", "group", "auto_approve"]
# Action components to execute on request actions
REQUESTS_ACTION_COMPONENTS = [
WorkflowTransitionComponent,
AutoAcceptComponent,
]
# Request types that trigger publication
PUBLISH_REQUEST_TYPES = ["publish_draft", "publish_new_version"]
# Workflow events configuration
DEFAULT_WORKFLOW_EVENTS = {
"comment": WorkflowEvent(...),
"log": WorkflowEvent(...),
}
Service Configuration
The library overrides Invenio's default request service and resource:
REQUESTS_SERVICE_CLASS = OARepoRequestsService
REQUESTS_SERVICE_CONFIG_CLASS = OARepoRequestsServiceConfig
REQUESTS_RESOURCE_CLASS = OARepoRequestsResource
REQUESTS_RESOURCE_CONFIG_CLASS = OARepoRequestsResourceConfig
Usage
Creating Requests
Via API:
# Create request with payload
curl -X POST /api/requests \
-H "Content-Type: application/json" \
-d '{
"request_type": "publish_draft",
"topic": {"type": "record", "value": "abc123"},
"payload": {"version": "1.0"}
}'
# Create request via URL
curl -X POST /api/requests/publish_draft/record:abc123 \
-H "Content-Type: application/json" \
-d '{"payload": {"version": "1.0"}}'
Via service:
from invenio_requests.proxies import current_requests_service
result = current_requests_service.create(
identity=identity,
data={"payload": {"version": "1.0"}},
request_type="publish_draft",
topic=record,
)
Executing Actions
from invenio_requests.proxies import current_requests_service
# Submit request
current_requests_service.execute_action(identity, request_id, "submit")
# Accept request
current_requests_service.execute_action(identity, request_id, "accept")
Custom Request Types
from oarepo_requests.types.generic import NonDuplicableOARepoRecordRequestType
from oarepo_requests.actions.generic import OARepoAcceptAction
class MyRequestType(NonDuplicableOARepoRecordRequestType):
type_id = "my_request"
name = _("My Request")
description = _("Description of my request")
payload_schema = {
"my_field": ma.fields.Str(required=True),
}
@classproperty
def available_actions(cls):
return {
**super().available_actions,
"accept": MyAcceptAction,
}
class MyAcceptAction(OARepoAcceptAction):
name = _("Accept")
def apply(self, identity, uow, *args, **kwargs):
# Custom acceptance logic
pass
Register via entry point:
[project.entry-points."invenio_requests.types"]
my_request = "myapp.requests:MyRequestType"
Custom Action Components
from oarepo_requests.actions.components import RequestActionComponent
class MyComponent(RequestActionComponent):
def accept(self, identity, action, uow, *args, **kwargs):
# Custom logic on accept
topic = action.topic
request = action.request
# ... perform operations
Register in invenio.cfg:
REQUESTS_ACTION_COMPONENTS = [
MyComponent,
WorkflowTransitionComponent,
AutoAcceptComponent,
]
Architecture
Request Lifecycle
- Creation - Request created via API or service with validation
- Submission - Request submitted for approval (optional if auto-approved)
- Processing - Receiver accepts or declines request
- Completion - Action logic executes, state transitions applied, components run
Component Execution Order
For each action execution:
- Action's
apply()method executes - Parent class action logic executes
- Each component's action method executes in configured order
Important: Components run after state changes, so they see updated request status.
Dependencies
oarepo-runtime>=2.0.0dev13oarepo-workflows>=2.0.0dev3oarepo[rdm]>=14.0.0oarepo-model>=0.1.0.dev5
Development
# Install with dev dependencies
pip install -e .[dev,tests]
# Run tests
pytest
License
Copyright (c) 2024-2025 CESNET z.s.p.o.
OARepo Requests is free software; you can redistribute it and/or modify it under the terms of the MIT License. See LICENSE file for more details.
Links
- Documentation: https://github.com/oarepo/oarepo-requests
- PyPI: https://pypi.org/project/oarepo-requests/
- Issues: https://github.com/oarepo/oarepo-requests/issues
- OARepo Project: https://github.com/oarepo
Acknowledgments
This project builds upon Invenio Framework and is developed as part of the OARepo ecosystem.
Metadata
Release files for oarepo-requests 9.5.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| oarepo_requests-9.5.2.tar.gz | 99.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| oarepo_requests-9.5.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 277.4 kB
Release files / oarepo_requests-9.5.2.tar.gz
| Download URL | oarepo_requests-9.5.2.tar.gz |
|---|---|
| Size | 99.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a335ce2e5dee4799eab504f71b119928aa30ca52975769f098b8747224de8f41
|
|
BLAKE2b-256 checksum How to use checksums |
f21354145cf6c35a39064ddf48bf889bb07e5a4f5613647af0acaf88f146f06f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / oarepo_requests-9.5.2-py3-none-any.whl
| Download URL | oarepo_requests-9.5.2-py3-none-any.whl |
|---|---|
| Size | 177.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ac96105c0b95d3bb119a4e37e050f7bba8aebbae811e8d65c2b4ad262efdef3d
|
|
BLAKE2b-256 checksum How to use checksums |
179a10f8b63331c5456a5fc52824c6e26083a6b9dc8304016fecb399975d3634
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|