Skip to main content

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 with request_type and topic in payload
  • POST /api/requests/<type>/<topic> - Create a request via URL parameters
  • GET /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) or draft (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_files parameter (yes/no)
  • Only applicable to published records without drafts

Delete Requests

delete_published_record - Request permanent deletion of published record

  • Requires removal_reason and optional note in 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 requests
  • DeletePublishedRecordAcceptAction - Executes record deletion with metadata preservation
  • EditTopicAcceptAction - Creates editable draft from published record
  • NewVersionAcceptAction - 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_to mapping

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:

  1. Retrieves workflow for the record
  2. Looks up request configuration in workflow
  3. Evaluates recipient generators to determine receiver
  4. Returns entity reference or None for 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 topic
  • can_create(identity, data, receiver, topic, creator) - Validate request creation
  • stateful_name(identity, topic, request) - Dynamic name based on request state
  • stateful_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

  1. Creation - Request created via API or service with validation
  2. Submission - Request submitted for approval (optional if auto-approved)
  3. Processing - Receiver accepts or declines request
  4. Completion - Action logic executes, state transitions applied, components run

Component Execution Order

For each action execution:

  1. Action's apply() method executes
  2. Parent class action logic executes
  3. 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.0dev13
  • oarepo-workflows>=2.0.0dev3
  • oarepo[rdm]>=14.0.0
  • oarepo-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

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)

Source distribution for oarepo-requests 9.5.2
File Size Uploaded
oarepo_requests-9.5.2.tar.gz 99.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for oarepo-requests 9.5.2
File Interpreter ABI Platform
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

Release history Release notifications | RSS feed

9.5.3

2 release files

This release

9.5.2 This release

2 release files

9.5.1

2 release files

9.5.0

2 release files

9.4.3

2 release files

9.4.2

2 release files

9.4.1

2 release files

9.4.0

2 release files

9.3.0

2 release files

9.2.1

2 release files

9.2.0

2 release files

9.1.0

2 release files

9.0.0

2 release files

8.1.0

2 release files

8.0.1

2 release files

8.0.0

2 release files

7.0.0

2 release files

5.5.0

2 release files

5.4.0

2 release files

5.3.0

2 release files

5.2.0

2 release files

5.1.0

2 release files

5.0.0

2 release files

4.0.0

2 release files

2.5.8

2 release files

2.5.7

2 release files

2.5.6

2 release files

2.5.5

2 release files

2.5.4

2 release files

2.5.3

2 release files

2.5.2

2 release files

2.5.1

2 release files

2.5.0

2 release files

2.4.24

2 release files

2.4.22

2 release files

2.4.21

2 release files

2.4.20

2 release files

2.4.16

2 release files

2.4.15

2 release files

2.4.14

2 release files

2.4.13

2 release files

2.4.12

2 release files

2.4.11

2 release files

2.4.10

2 release files

2.4.9

2 release files

2.4.8

2 release files

2.4.7

2 release files

2.4.6

2 release files

2.4.5

2 release files

2.4.4

2 release files

2.4.3

2 release files

2.4.2

2 release files

2.4.1

2 release files

2.4.0

2 release files

2.3.19

2 release files

2.3.18

2 release files

2.3.17

2 release files

2.3.16

2 release files

2.3.15

2 release files

2.3.14

2 release files

2.3.13

2 release files

2.3.12

2 release files

2.3.11

2 release files

2.3.10

2 release files

2.3.9

2 release files

2.3.8

2 release files

2.3.7

2 release files

2.3.6

2 release files

2.3.5

2 release files

2.3.4

2 release files

2.3.3

2 release files

2.3.2

2 release files

2.3.1

2 release files

2.3.0

2 release files

2.2.11

2 release files

2.2.10

2 release files

2.2.9

2 release files

2.2.8

2 release files

2.2.7

2 release files

2.2.6

2 release files

2.2.5

2 release files

2.2.4

2 release files

2.2.3

2 release files

2.2.2

2 release files

2.2.1

2 release files

2.2.0

2 release files

2.1.5

2 release files

2.1.4

2 release files

2.1.3

2 release files

2.1.2

2 release files

2.1.1

2 release files

2.1.0

2 release files

2.0.9

2 release files

2.0.8

2 release files

2.0.7

2 release files

2.0.6

2 release files

2.0.5

2 release files

2.0.4

2 release files

2.0.3

2 release files

2.0.2

2 release files

2.0.1

2 release files

2.0.0

2 release files

1.3.2

2 release files

1.3.1

2 release files

1.3.0

2 release files

1.2.2

2 release files

1.2.1

2 release files

1.2.0

2 release files

1.1.19

2 release files

1.1.18

2 release files

1.1.17

2 release files

1.1.16

2 release files

1.1.11

2 release files

1.1.9

2 release files

1.1.8

2 release files

1.1.7

2 release files

1.1.6

2 release files

1.1.5

2 release files

1.1.4

2 release files

1.1.3

2 release files

1.1.2

2 release files

1.1.0

2 release files

1.0.4

2 release files

1.0.3

2 release files

1.0.2

2 release files

1.0.1

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page