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", ...]
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
- Documentation: https://github.com/oarepo/oarepo-communities
- PyPI: https://pypi.org/project/oarepo-communities/
- Issues: https://github.com/oarepo/oarepo-communities/issues
- OARepo Project: https://github.com/oarepo
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.0
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_communities-12.1.0.tar.gz | 54.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| oarepo_communities-12.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 154.3 kB
Release files / oarepo_communities-12.1.0.tar.gz
| Download URL | oarepo_communities-12.1.0.tar.gz |
|---|---|
| Size | 54.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b581328ff387f438fb8f4fe57f2571dec2c5c0dd0c192152075d1bb71315d8c5
|
|
BLAKE2b-256 checksum How to use checksums |
3f41b824e81e6a7db735e9d7e152ceaa2947c0ad19b137331393cd5907d6aafb
|
| 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.0-py3-none-any.whl
| Download URL | oarepo_communities-12.1.0-py3-none-any.whl |
|---|---|
| Size | 99.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1f4a4e2d7edd8563aeaed89afe527dfbc4adc66264516fc772491c1ac65b2720
|
|
BLAKE2b-256 checksum How to use checksums |
3ebb7ff031b4d62cfbb13cc8fa8bdd834467806b4d9b1e13896b4c9d19239d9d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|