Skip to main content

OARepo Communities

Community-based workflow and permission extensions for Invenio framework.

Overview

This package extends Invenio with community-centric features:

  • Community-based workflow management with configurable permissions
  • Advanced permission generators for community roles and members
  • Service components for community inclusion and access control
  • Request types for community operations (submission, migration, removal)
  • Custom fields for workflow configuration at community level
  • CLI commands for community and membership management
  • Model presets for integrating communities into record models
  • Integration with OARepo workflows and requests

Installation

pip install oarepo-communities

Requirements

  • Python 3.14
  • Invenio 14.x
  • oarepo-runtime>=2.0.0dev23
  • oarepo-workflows>=2.0.0dev3
  • oarepo-requests>=3.0.0dev1

Key Features

1. Community Workflow Management

Source: oarepo_communities/workflow.py, oarepo_communities/services/custom_fields/workflow.py

Each community can have its own default workflow, allowing different communities to enforce different approval processes and permissions for records.

Workflow Configuration

from oarepo_workflows import Workflow
from oarepo_communities.services.permissions.policy import CommunityDefaultWorkflowPermissions


class MyWorkflowPermissions(CommunityDefaultWorkflowPermissions):
    can_read = [AnyUser()]
    can_create = [DefaultCommunityRole("owner"), DefaultCommunityRole("reader")]


# In invenio.cfg
WORKFLOWS = {
    "default": Workflow(
        code="default",
        label="Default Workflow",
        permission_policy_cls=MyWorkflowPermissions,
    )
}

Community Custom Fields

Communities can specify their default workflow and allowed workflows via custom fields:

# Setting workflow on community creation
from invenio_communities.proxies import current_communities

current_communities.service.create(
    identity,
    {
        "slug": "my-community",
        "metadata": {"title": "My Community"},
        "custom_fields": {"workflow": "default", "allowed_workflows": ["default", "strict_review"]},
    },
)

Automatic Workflow Resolution

from oarepo_communities.proxies import current_oarepo_communities

# Get workflow from community
workflow = current_oarepo_communities.get_community_default_workflow(
    data={"parent": {"communities": {"default": {"id": "community-slug"}}}}
)

2. Permission Generators

Source: oarepo_communities/services/permissions/generators.py

Comprehensive set of permission generators for community-based access control.

Community Role Generators

from oarepo_communities.services.permissions.generators import (
    CommunityRole,
    DefaultCommunityRole,
    CommunityMembers,
    DefaultCommunityMembers,
    TargetCommunityRole,
)

# Allow specific role in any community associated with record
CommunityRole("curator")  # Curators in any primary or secondary community

# Allow specific role only in the default (primary) community
DefaultCommunityRole("owner")  # Only owners of the primary community

# Allow any member of communities associated with record
CommunityMembers()  # Any member of any community

# Allow any member of the default community
DefaultCommunityMembers()  # Any member of primary community

# For request types - target community specified in payload
TargetCommunityRole("owner")  # Owner of the community being joined

Record Owner in Community Generators

These generators combine record ownership with community membership:

from oarepo_communities.services.permissions.generators import (
    RecordOwnerInDefaultRecordCommunity,
    RecordOwnerInRecordCommunity,
)

# Owner only has access if they're a member of the record's primary community
RecordOwnerInDefaultRecordCommunity()

# Owner only has access if they're a member of any of the record's communities
RecordOwnerInRecordCommunity()

Workflow-based Permission Wrapper

from oarepo_communities.services.permissions.generators import CommunityWorkflowPermission

# Automatically resolves workflow from community and applies permissions
CommunityWorkflowPermission("create")  # Uses community's default workflow

Usage Example

from oarepo_communities.services.permissions.policy import (
    CommunityDefaultWorkflowPermissions,
)
from oarepo_communities.services.permissions.generators import (
    DefaultCommunityRole,
    RecordOwnerInDefaultRecordCommunity,
)
from invenio_records_permissions.generators import AnyUser
from oarepo_workflows import IfInState


class MyWorkflowPermissions(CommunityDefaultWorkflowPermissions):
    can_read = [
        RecordOwnerInDefaultRecordCommunity(),
        DefaultCommunityRole("curator"),
        IfInState("published", [AnyUser()]),
    ]

    can_create = [
        DefaultCommunityRole("owner"),
        DefaultCommunityRole("curator"),
    ]

    can_update = [
        IfInState("draft", [RecordOwnerInDefaultRecordCommunity()]),
        IfInState("published", [DefaultCommunityRole("owner")]),
    ]

3. Service Components

Source: oarepo_communities/services/components/

Service components that integrate community functionality into record lifecycle.

Community Inclusion Component

Automatically adds records to their specified community on creation:

from oarepo_communities.services.components.include import CommunityInclusionComponent


class MyServiceConfig(RecordServiceConfig):
    components = [
        CommunityInclusionComponent,
        # ... other components
    ]

Community Default Workflow Component

Sets the default workflow from community when creating a record:

from oarepo_communities.services.components.default_workflow import (
    CommunityDefaultWorkflowComponent,
)


class MyServiceConfig(RecordServiceConfig):
    components = [
        CommunityDefaultWorkflowComponent,
        # ... other components
    ]

Community Record Access Component

Enforces access restrictions based on community visibility:

from oarepo_communities.services.components.access import (
    CommunityRecordAccessComponent,
)


class MyServiceConfig(RecordServiceConfig):
    components = [
        CommunityRecordAccessComponent,  # Should be first
        # ... other components
    ]

4. Request Types

Source: oarepo_communities/requests/

Built-in request types for community operations.

Secondary Community Submission

Request to add a record to an additional community:

from oarepo_communities.requests.submission_secondary import (
    SecondaryCommunitySubmissionRequestType,
)

# Submit request
request = requests_service.create(
    identity,
    data={"payload": {"community": "target-community-id"}},
    request_type="secondary_community_submission",
    topic=record,
)

Remove Secondary Community

Request to remove a record from a secondary community:

from oarepo_communities.requests.remove_secondary import (
    RemoveSecondaryCommunityRequestType,
)

# Submit request
request = requests_service.create(
    identity,
    data={"payload": {"community": "community-to-remove"}},
    request_type="remove_secondary_community",
    topic=record,
)

Community Migration

Two-phase process for migrating a record's primary community:

from oarepo_communities.requests.migration import (
    InitiateCommunityMigrationRequestType,
    ConfirmCommunityMigrationRequestType,
)

# Phase 1: Current community owner approves migration
request = requests_service.create(
    identity,
    data={"payload": {"community": "new-primary-community"}},
    request_type="initiate_community_migration",
    topic=record,
)

# Phase 2: Target community owner confirms (auto-created on accept)
# ConfirmCommunityMigrationRequestType is automatically triggered

5. Community Role Service

Source: oarepo_communities/services/community_role/

Pseudo-service for managing community roles as entities in the request system:

from oarepo_communities.proxies import current_oarepo_communities

# Read a community role entity
role = current_oarepo_communities.community_role_service.read(identity, id_="community-id:owner")

# Read multiple community roles
roles = current_oarepo_communities.community_role_service.read_many(
    identity, ids=["community-1:owner", "community-2:curator"]
)

6. CLI Commands

Source: oarepo_communities/cli/

Command-line interface for community management:

# Create a community
invenio communities create my-community "My Community Title" --public

# List all communities
invenio communities list

# Add a member to a community
invenio communities members add my-community user@example.com reader

# Add an owner to a community
invenio communities members add my-community admin@example.com owner

# Remove a member from a community
invenio communities members remove my-community user@example.com

7. Model Presets

Source: oarepo_communities/model/presets/

Integration presets for oarepo-model that add community support to record models:

from oarepo_model.api import model
from oarepo_communities.model.presets import communities_preset

model = model(
    name="my_records",
    version="1.0.0",
    presets=[
        communities_preset,  # Adds community support
        # ... other presets
    ],
)

Key preset features:

  • ParentCommunityMetadata: Adds community relationship to parent records
  • CommunitiesPermissionPolicy: Replaces default permission policy with CommunityWorkflowPermissionPolicy
  • Service Components: Automatically includes community-related components

8. Utilities and Helpers

Source: oarepo_communities/utils.py

Helper functions for working with communities:

from oarepo_communities.utils import (
    get_community_needs_for_identity,
    load_community_user_needs,
    community_id_from_record,
    community_to_dict,
)

# Get all community roles for a user
community_roles = get_community_needs_for_identity(identity)
# Returns: [("community-id-1", "owner"), ("community-id-2", "reader"), ...]

# Load community needs into identity
load_community_user_needs(identity)

# Extract community ID from record
community_id = community_id_from_record(record)

# Convert community to embeddable dict
community_dict = community_to_dict(community)
# Returns: {"slug": "...", "id": "...", "logo": "...", "links": {...}}

9. Notification Support

Source: oarepo_communities/notifications/, oarepo_communities/records/api.py

Community role entity for notifications and email recipients:

from oarepo_communities.records.api import CommunityRoleRecord

# Create a community role record for notifications
role_record = CommunityRoleRecord(community=community, role="curator")

# Get emails of all members with this role
emails = role_record.emails
# Returns: ["curator1@example.com", "curator2@example.com", ...]

Recipients of notifications

Recipients of a notification are generated per entity type from the NOTIFICATION_RECIPIENTS_RESOLVERS configuration. This library provides generators for the community entity types that can be a receiver of a request:

NOTIFICATION_RECIPIENTS_RESOLVERS = {
    # the members holding the role in the community, e.g. {"community_role": "<community-id>:curator"}
    "community_role": lambda key, notification: CommunityRoleEmailRecipient(key),
    # only the members that can act on the request, not all of them
    "community": lambda key, notification: CommunityRecipient(key),
}

Invenio's CommunityMembersRecipient notifies all members of a community when it is not given any roles. As the receiver of a request decides about it, that would leak the request, and every comment on it, to members without any rights on it, e.g. a comment on a community membership request would be sent to every reader of the community. CommunityRecipient therefore notifies only the roles a community receiver is mapped to by the request type, ie. its needs_context["community_roles"]. If the request type does not declare any, the roles configured with can_manage are notified.

10. Entity Resolvers

Source: oarepo_communities/resolvers/communities.py

Entity resolver for community roles in the request system:

# Automatically registered, allows referencing community roles in requests
{"receiver": {"community_role": "community-id:owner"}}

Development

Setup

# Clone repository
git clone https://github.com/oarepo/oarepo-communities.git
cd oarepo-communities

./run.sh venv

Running Tests

./run.sh test

Entry Points

The package registers several Invenio entry points:

[project.entry-points."invenio_base.api_apps"]
oarepo_communities = "oarepo_communities.ext:OARepoCommunities"

[project.entry-points."invenio_base.apps"]
oarepo_communities = "oarepo_communities.ext:OARepoCommunities"

[project.entry-points."invenio_requests.entity_resolvers"]
community_role = "oarepo_communities.resolvers.communities:CommunityRoleResolver"

[project.entry-points."invenio_requests.types"]
confirm-community-migration = "oarepo_communities.requests.migration:ConfirmCommunityMigrationRequestType"
initiate-community-migration = "oarepo_communities.requests.migration:InitiateCommunityMigrationRequestType"
remove-secondary-community = "oarepo_communities.requests.remove_secondary:RemoveSecondaryCommunityRequestType"
secondary-community-submission = "oarepo_communities.requests.submission_secondary:SecondaryCommunitySubmissionRequestType"

[project.entry-points."oarepo_workflows.default_workflow_getters"]
community-default-workflow = "oarepo_communities.workflow:community_default_workflow"

[project.entry-points."invenio_config.module"]
oarepo_communities = "oarepo_communities.initial_config"

Configuration

Key Configuration Options

# Default workflow for communities without explicit workflow
OAREPO_COMMUNITIES_DEFAULT_WORKFLOW = "default"

# Default receiver for workflow-based requests
OAREPO_REQUESTS_DEFAULT_RECEIVER = "oarepo_requests.receiver.default_workflow_receiver_function"

# Allowed request receivers
REQUESTS_ALLOWED_RECEIVERS = ["community_role"]

# Display user communities in UI
DISPLAY_USER_COMMUNITIES = True

# Display new communities section in UI
DISPLAY_NEW_COMMUNITIES = True

# Search across all community records
COMMUNITIES_RECORDS_SEARCH_ALL = False

# Community routes
COMMUNITIES_ROUTES = {
    "my_communities": "/me/communities",
    # ... additional routes
}

License

Copyright (c) 2020-2025 CESNET z.s.p.o.

OARepo Communities 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 Invenio Communities, and is developed as part of the OARepo ecosystem.

Release files for oarepo-communities 12.1.3

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-communities 12.1.3
File Size Uploaded
oarepo_communities-12.1.3.tar.gz 77.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for oarepo-communities 12.1.3
File Interpreter ABI Platform
oarepo_communities-12.1.3-py3-none-any.whl Python 3 none any Details

Total release size: 213.0 kB

Release files / oarepo_communities-12.1.3.tar.gz

Download URL oarepo_communities-12.1.3.tar.gz
Size 77.0 kB
Tags Source
SHA-256 checksum
How to use checksums
c4a05fd916bf89d3310f2a4863b23b91fbef8d1ff8f0ff3e10914de38f0177cc
BLAKE2b-256 checksum
How to use checksums
add4bb7f782a2c62a324cc6934ebef7d91b1f2085b1812769cc60d6ef9e9a495
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / oarepo_communities-12.1.3-py3-none-any.whl

Download URL oarepo_communities-12.1.3-py3-none-any.whl
Size 136.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7e57995e04523ca151777f4017cabeb51a6cf0008106fded86447795a0f1c259
BLAKE2b-256 checksum
How to use checksums
69ec15a0e698a4396be3877e910d003a7ce04bcef55158a291957264edd1d2d6
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

12.1.4

2 release files

This release

12.1.3 This release

2 release files

12.1.2

2 release files

12.1.1

2 release files

12.1.0

2 release files

12.0.0

2 release files

11.8.0

2 release files

11.7.0

2 release files

11.5.0

2 release files

11.4.2

2 release files

11.4.1

2 release files

11.3.0

2 release files

11.2.0

2 release files

11.1.0

2 release files

11.0.0

2 release files

10.2.0

2 release files

10.1.0

2 release files

9.0.2

2 release files

9.0.1

2 release files

9.0.0

2 release files

8.1.4

2 release files

8.1.3

2 release files

8.1.2

2 release files

8.1.1

2 release files

8.1.0

2 release files

8.0.0

2 release files

7.0.1

2 release files

7.0.0

2 release files

5.4.5

2 release files

5.4.4

2 release files

5.4.3

2 release files

5.4.2

2 release files

5.4.1

2 release files

5.4.0

2 release files

5.3.5

2 release files

5.3.4

2 release files

5.3.3

2 release files

5.3.2

2 release files

5.3.0

2 release files

5.2.1

2 release files

5.2.0

2 release files

5.1.14

2 release files

5.1.13

2 release files

5.1.9

2 release files

5.1.8

2 release files

5.1.7

2 release files

5.1.6

2 release files

5.1.5

2 release files

5.1.4

2 release files

5.1.3

2 release files

5.1.2

2 release files

5.1.1

2 release files

5.1.0

2 release files

5.0.24

2 release files

5.0.23

2 release files

5.0.22

2 release files

5.0.21

2 release files

5.0.20

2 release files

5.0.19

2 release files

5.0.18

2 release files

5.0.17

2 release files

5.0.16

2 release files

5.0.15

2 release files

5.0.14

2 release files

5.0.13

2 release files

5.0.12

2 release files

5.0.11

2 release files

5.0.10

2 release files

5.0.9

2 release files

5.0.8

2 release files

5.0.7

2 release files

5.0.6

2 release files

5.0.5

2 release files

5.0.4

2 release files

5.0.3

2 release files

5.0.2

2 release files

5.0.0

2 release files

4.0.13

2 release files

4.0.12

2 release files

4.0.11

2 release files

4.0.10

2 release files

4.0.9

2 release files

4.0.8

2 release files

4.0.7

2 release files

4.0.6

2 release files

4.0.5

2 release files

4.0.4

2 release files

4.0.3

2 release files

4.0.2

2 release files

3.0.5

2 release files

3.0.3

2 release files

3.0.2

2 release files

3.0.0

2 release files

2.3.1

2 release files

2.3.0

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.1

2 release files

2.1.0

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.4.2

2 release files

1.4.1

2 release files

1.4.0

2 release files

1.3.4

2 release files

1.3.3

2 release files

1.3.2

2 release files

1.3.1

2 release files

1.3.0

2 release files

1.2.5

2 release files

1.2.4

2 release files

1.2.3

2 release files

1.2.2

2 release files

1.2.1

2 release files

1.2.0

2 release files

1.1.0

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