initial commit
This commit is contained in:
35
.gitea/ISSUE_TEMPLATE/bug_report.md
Normal file
35
.gitea/ISSUE_TEMPLATE/bug_report.md
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
---
|
||||||
|
name: "Bug"
|
||||||
|
about: "Report a reproducible defect, regression, or incorrect behavior"
|
||||||
|
title: "[Bug] "
|
||||||
|
labels:
|
||||||
|
- type/bug
|
||||||
|
- status/triage
|
||||||
|
- module/dist-lists
|
||||||
|
---
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
- Repository:
|
||||||
|
- Area/module:
|
||||||
|
- Affected version or commit:
|
||||||
|
|
||||||
|
## Behavior
|
||||||
|
|
||||||
|
Expected:
|
||||||
|
|
||||||
|
Actual:
|
||||||
|
|
||||||
|
## Reproduction
|
||||||
|
|
||||||
|
1.
|
||||||
|
2.
|
||||||
|
3.
|
||||||
|
|
||||||
|
## Evidence
|
||||||
|
|
||||||
|
Logs, screenshots, traces, or failing test output:
|
||||||
|
|
||||||
|
## Verification Target
|
||||||
|
|
||||||
|
Command or workflow that should pass when fixed:
|
||||||
1
.gitea/ISSUE_TEMPLATE/config.yaml
Normal file
1
.gitea/ISSUE_TEMPLATE/config.yaml
Normal file
@@ -0,0 +1 @@
|
|||||||
|
blank_issues_enabled: false
|
||||||
27
.gitea/ISSUE_TEMPLATE/docs_workflow.md
Normal file
27
.gitea/ISSUE_TEMPLATE/docs_workflow.md
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
---
|
||||||
|
name: "Docs / workflow"
|
||||||
|
about: "Request documentation, process, or developer workflow changes"
|
||||||
|
title: "[Docs] "
|
||||||
|
labels:
|
||||||
|
- type/docs
|
||||||
|
- status/triage
|
||||||
|
- module/dist-lists
|
||||||
|
- area/docs
|
||||||
|
---
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
- Repository:
|
||||||
|
- Document or workflow:
|
||||||
|
|
||||||
|
## Current State
|
||||||
|
|
||||||
|
What is missing, unclear, duplicated, or stale?
|
||||||
|
|
||||||
|
## Desired State
|
||||||
|
|
||||||
|
What should the docs or workflow make clear?
|
||||||
|
|
||||||
|
## Verification Target
|
||||||
|
|
||||||
|
How should this be checked?
|
||||||
32
.gitea/ISSUE_TEMPLATE/feature_request.md
Normal file
32
.gitea/ISSUE_TEMPLATE/feature_request.md
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
---
|
||||||
|
name: "Feature"
|
||||||
|
about: "Propose new user-visible behavior or platform capability"
|
||||||
|
title: "[Feature] "
|
||||||
|
labels:
|
||||||
|
- type/feature
|
||||||
|
- status/triage
|
||||||
|
- module/dist-lists
|
||||||
|
---
|
||||||
|
|
||||||
|
## Problem
|
||||||
|
|
||||||
|
What user, operator, or developer problem should this solve?
|
||||||
|
|
||||||
|
## Proposed Capability
|
||||||
|
|
||||||
|
What should exist when this is done?
|
||||||
|
|
||||||
|
## Ownership
|
||||||
|
|
||||||
|
- Owning repository:
|
||||||
|
- Related module repositories:
|
||||||
|
- Extension point or integration boundary:
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
- [ ]
|
||||||
|
- [ ]
|
||||||
|
|
||||||
|
## Verification Target
|
||||||
|
|
||||||
|
Command, scenario, or UI flow that should prove completion:
|
||||||
28
.gitea/ISSUE_TEMPLATE/task.md
Normal file
28
.gitea/ISSUE_TEMPLATE/task.md
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
---
|
||||||
|
name: "Task"
|
||||||
|
about: "Track implementation, maintenance, or migration work"
|
||||||
|
title: "[Task] "
|
||||||
|
labels:
|
||||||
|
- type/task
|
||||||
|
- status/triage
|
||||||
|
- module/dist-lists
|
||||||
|
---
|
||||||
|
|
||||||
|
## Objective
|
||||||
|
|
||||||
|
What needs to be completed?
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
- Owning repository:
|
||||||
|
- In-scope:
|
||||||
|
- Out-of-scope:
|
||||||
|
|
||||||
|
## Checklist
|
||||||
|
|
||||||
|
- [ ]
|
||||||
|
- [ ]
|
||||||
|
|
||||||
|
## Verification Target
|
||||||
|
|
||||||
|
Command or manual check:
|
||||||
25
.gitea/ISSUE_TEMPLATE/tech_debt.md
Normal file
25
.gitea/ISSUE_TEMPLATE/tech_debt.md
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
---
|
||||||
|
name: "Tech debt"
|
||||||
|
about: "Track cleanup, refactoring, risk reduction, or deferred engineering work"
|
||||||
|
title: "[Debt] "
|
||||||
|
labels:
|
||||||
|
- type/debt
|
||||||
|
- status/triage
|
||||||
|
- module/dist-lists
|
||||||
|
---
|
||||||
|
|
||||||
|
## Current Cost
|
||||||
|
|
||||||
|
What does this make harder, riskier, slower, or more fragile?
|
||||||
|
|
||||||
|
## Desired Shape
|
||||||
|
|
||||||
|
What should the code, tests, or architecture look like afterwards?
|
||||||
|
|
||||||
|
## Constraints
|
||||||
|
|
||||||
|
What behavior, compatibility, or module boundary must be preserved?
|
||||||
|
|
||||||
|
## Verification Target
|
||||||
|
|
||||||
|
Focused checks that should pass:
|
||||||
15
.gitea/PULL_REQUEST_TEMPLATE.md
Normal file
15
.gitea/PULL_REQUEST_TEMPLATE.md
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
## Issue
|
||||||
|
|
||||||
|
Closes #
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
-
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
-
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
Follow-up issues:
|
||||||
13
.gitignore
vendored
Normal file
13
.gitignore
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
.venv/
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*.egg-info/
|
||||||
|
.pytest_cache/
|
||||||
|
.ruff_cache/
|
||||||
|
dist/
|
||||||
|
build/
|
||||||
|
node_modules/
|
||||||
|
coverage/
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
69
README.md
Normal file
69
README.md
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
# GovOPlaN Distribution Lists
|
||||||
|
|
||||||
|
<!-- govoplan-repository-type:start -->
|
||||||
|
**Repository type:** module (domain).
|
||||||
|
<!-- govoplan-repository-type:end -->
|
||||||
|
|
||||||
|
`govoplan-dist-lists` will own reusable operational distribution lists
|
||||||
|
(`Verteiler`) for GovOPlaN. Distribution lists are broader than address lists:
|
||||||
|
they can resolve contacts, raw addresses, identities, users, groups,
|
||||||
|
organization units, functions, roles, and later nested lists into immutable
|
||||||
|
recipient snapshots for campaigns, postbox messages, notifications, scheduling,
|
||||||
|
polls, consultations, approvals, workflow, and case operations.
|
||||||
|
|
||||||
|
The module is intentionally initialized as a documentation and manifest seed
|
||||||
|
first. Classical address lists remain in `govoplan-addresses`; this module will
|
||||||
|
take over the mixed operational recipient model once the address-owned list
|
||||||
|
primitive is stable.
|
||||||
|
|
||||||
|
## Boundary
|
||||||
|
|
||||||
|
Distribution Lists owns:
|
||||||
|
|
||||||
|
- reusable mixed recipient definitions
|
||||||
|
- German-administration `Verteiler` semantics
|
||||||
|
- expansion of mixed entries into concrete delivery/recipient targets
|
||||||
|
- snapshot DTOs with source revision and provenance
|
||||||
|
- stale-source detection for expanded entries
|
||||||
|
- eligibility and policy explanations for disabled recipient entries
|
||||||
|
- audit evidence for who was resolved at execution time
|
||||||
|
|
||||||
|
Distribution Lists does not own:
|
||||||
|
|
||||||
|
- contacts, vCard/CardDAV address books, or address-only lists; those belong in
|
||||||
|
`govoplan-addresses`
|
||||||
|
- mail transport, queues, or mailbox access; those belong in `govoplan-mail`
|
||||||
|
- campaign versions, message rendering, or delivery evidence; those belong in
|
||||||
|
`govoplan-campaign`
|
||||||
|
- workflow/Umlauf execution state, ordering, deadlines, escalation, or task
|
||||||
|
state; those belong in `govoplan-workflow` and `govoplan-tasks`
|
||||||
|
- global identity, organization, tenancy, access, or policy engines
|
||||||
|
|
||||||
|
## Key Distinction
|
||||||
|
|
||||||
|
```text
|
||||||
|
AddressBook -> contacts and contact points
|
||||||
|
AddressList -> address-domain grouping of contacts/contact methods
|
||||||
|
DistributionList -> operational Verteiler with mixed recipient entry types
|
||||||
|
Umlauf -> workflow execution over recipients, actors, tasks, and deadlines
|
||||||
|
CampaignVersion/PostboxMessage/etc. -> immutable snapshot of expanded recipients
|
||||||
|
```
|
||||||
|
|
||||||
|
## Development Install
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /mnt/DATA/git/govoplan
|
||||||
|
./.venv/bin/python -m pip install -e ../govoplan-dist-lists
|
||||||
|
```
|
||||||
|
|
||||||
|
Focused manifest verification:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /mnt/DATA/git/govoplan-dist-lists
|
||||||
|
PYTHONPATH=src:/mnt/DATA/git/govoplan-core/src /mnt/DATA/git/govoplan/.venv/bin/python -m unittest discover -s tests
|
||||||
|
```
|
||||||
|
|
||||||
|
## Design Documents
|
||||||
|
|
||||||
|
- [Distribution lists architecture](docs/DISTRIBUTION_LISTS_ARCHITECTURE.md)
|
||||||
|
- [Implementation plan](docs/IMPLEMENTATION_PLAN.md)
|
||||||
98
docs/DISTRIBUTION_LISTS_ARCHITECTURE.md
Normal file
98
docs/DISTRIBUTION_LISTS_ARCHITECTURE.md
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
# GovOPlaN Distribution Lists Architecture
|
||||||
|
|
||||||
|
## Decision
|
||||||
|
|
||||||
|
`govoplan-dist-lists` owns reusable operational distribution lists
|
||||||
|
(`Verteiler`). This module is deliberately separate from `govoplan-addresses`:
|
||||||
|
address lists are plain address-domain groupings, while distribution lists are
|
||||||
|
cross-module recipient definitions that may resolve through address books,
|
||||||
|
identity, organizations, groups, functions, roles, raw addresses, and other
|
||||||
|
future provider capabilities.
|
||||||
|
|
||||||
|
## Vocabulary
|
||||||
|
|
||||||
|
- **Address book:** stores contacts and contact points such as email and postal
|
||||||
|
addresses.
|
||||||
|
- **Address list:** an address-owned list of contacts/contact methods from
|
||||||
|
address books.
|
||||||
|
- **Distribution list / Verteiler:** a reusable operational recipient
|
||||||
|
definition with mixed entry types.
|
||||||
|
- **Umlauf:** an execution workflow over recipients or actors with order,
|
||||||
|
state, deadlines, decisions, and escalation. Distribution lists define who;
|
||||||
|
workflow/tasks define what happens.
|
||||||
|
- **Snapshot:** immutable expansion evidence stored by the consuming module at
|
||||||
|
send, publish, decision, notification, or execution time.
|
||||||
|
|
||||||
|
## Ownership
|
||||||
|
|
||||||
|
Distribution Lists owns:
|
||||||
|
|
||||||
|
- distribution-list definitions
|
||||||
|
- mixed recipient entries
|
||||||
|
- provider-neutral recipient entry DTOs
|
||||||
|
- expansion plans and expansion results
|
||||||
|
- immutable expansion snapshots and stale-source warnings
|
||||||
|
- nested-list handling, cycle detection, and expansion limits
|
||||||
|
- source provenance and traceability
|
||||||
|
- policy/read-only explanation payloads for unavailable entries
|
||||||
|
|
||||||
|
It does not own:
|
||||||
|
|
||||||
|
- contact storage or vCard/CardDAV sync
|
||||||
|
- identity or organization master data
|
||||||
|
- delivery transports
|
||||||
|
- campaign versioning
|
||||||
|
- workflow task execution
|
||||||
|
|
||||||
|
## Entry Types
|
||||||
|
|
||||||
|
Initial supported entry types should be provider-neutral:
|
||||||
|
|
||||||
|
- `address_contact`
|
||||||
|
- `address_email`
|
||||||
|
- `raw_email`
|
||||||
|
- `raw_postal_address`
|
||||||
|
- `identity_principal`
|
||||||
|
- `organization_unit`
|
||||||
|
- `group`
|
||||||
|
- `function`
|
||||||
|
- `role`
|
||||||
|
- `distribution_list`
|
||||||
|
|
||||||
|
Each entry should carry a stable source reference, display label, optional
|
||||||
|
delivery-channel hints, provenance, and a policy/readiness state.
|
||||||
|
|
||||||
|
## Capability Direction
|
||||||
|
|
||||||
|
The first capabilities should be:
|
||||||
|
|
||||||
|
- `distLists.source`: list visible distribution lists as reusable recipient
|
||||||
|
sources.
|
||||||
|
- `distLists.expand`: expand a distribution list into immutable recipient rows.
|
||||||
|
- `distLists.writer`: explain whether a caller can create or change a list.
|
||||||
|
|
||||||
|
Consumers must resolve those capabilities through core and must not import
|
||||||
|
distribution-list ORM or service internals.
|
||||||
|
|
||||||
|
## Consumers
|
||||||
|
|
||||||
|
Likely consumers:
|
||||||
|
|
||||||
|
- Campaign: campaign recipient sources and send snapshots.
|
||||||
|
- Mail: ad-hoc recipient picking and reusable send groups.
|
||||||
|
- Postbox: recipient routing and publish snapshots.
|
||||||
|
- Notifications: notification target groups.
|
||||||
|
- Scheduling: invitation target groups.
|
||||||
|
- Poll/Evaluation/Consultation: invited participants and response audiences.
|
||||||
|
- Workflow/Tasks: Umlauf participant lists and escalation targets.
|
||||||
|
- Cases/Permits: case routing and responsible-function targeting.
|
||||||
|
|
||||||
|
## Relationship To Address Lists
|
||||||
|
|
||||||
|
`govoplan-addresses` should implement classical address lists first. A
|
||||||
|
distribution list may later include an address list as an entry, but the
|
||||||
|
address module remains the owner of contact records and address-only grouping.
|
||||||
|
|
||||||
|
The distribution-list module owns mixed operational routing. This prevents
|
||||||
|
campaign-specific recipient logic from becoming the platform's de facto
|
||||||
|
Verteiler implementation.
|
||||||
75
docs/IMPLEMENTATION_PLAN.md
Normal file
75
docs/IMPLEMENTATION_PLAN.md
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
# GovOPlaN Distribution Lists Implementation Plan
|
||||||
|
|
||||||
|
## Milestone 0: Module Seed
|
||||||
|
|
||||||
|
Goal: establish repository identity, module boundary, and installable manifest.
|
||||||
|
|
||||||
|
Tasks:
|
||||||
|
|
||||||
|
- [x] initialize repository type and package metadata
|
||||||
|
- [x] document boundary between address lists, distribution lists, and Umlauf
|
||||||
|
- [x] add a no-op module manifest with durable documentation topics
|
||||||
|
- [ ] create Gitea issues for the implementation milestones
|
||||||
|
|
||||||
|
## Milestone 1: Contract And DTOs
|
||||||
|
|
||||||
|
Goal: define mixed recipient entries without implementing every provider.
|
||||||
|
|
||||||
|
Tasks:
|
||||||
|
|
||||||
|
- define distribution-list, entry, expansion-plan, and expansion-result DTOs
|
||||||
|
- define source reference format for address, identity, organization, group,
|
||||||
|
function, role, raw, and nested-list entries
|
||||||
|
- define policy/read-only explanation payloads
|
||||||
|
- define snapshot evidence shape
|
||||||
|
- add cycle detection and expansion-limit semantics
|
||||||
|
|
||||||
|
## Milestone 2: Local Distribution Lists
|
||||||
|
|
||||||
|
Goal: implement local, manually maintained distribution lists.
|
||||||
|
|
||||||
|
Tasks:
|
||||||
|
|
||||||
|
- add database tables and migrations
|
||||||
|
- add CRUD routes and permissions
|
||||||
|
- add local raw email/postal entries
|
||||||
|
- add references to address contacts and address lists via capabilities
|
||||||
|
- expose `distLists.source` and `distLists.expand`
|
||||||
|
- add tests for expansion and snapshots
|
||||||
|
|
||||||
|
## Milestone 3: Provider Integrations
|
||||||
|
|
||||||
|
Goal: allow distribution lists to resolve through installed modules.
|
||||||
|
|
||||||
|
Tasks:
|
||||||
|
|
||||||
|
- integrate with `addresses.lookup` and address-list source capability
|
||||||
|
- integrate with identity/principal resolution
|
||||||
|
- integrate with organizations/groups/functions once those modules expose
|
||||||
|
provider capabilities
|
||||||
|
- preserve module independence when optional providers are absent
|
||||||
|
|
||||||
|
## Milestone 4: UI
|
||||||
|
|
||||||
|
Goal: make distribution lists practical for administrators and operators.
|
||||||
|
|
||||||
|
Tasks:
|
||||||
|
|
||||||
|
- add list management UI
|
||||||
|
- add mixed entry editor with provider-specific search
|
||||||
|
- show disabled/read-only entries with hover explanations
|
||||||
|
- show expansion preview and stale-source warnings
|
||||||
|
- expose picker components to campaign, mail, postbox, notifications,
|
||||||
|
scheduling, poll, and workflow consumers
|
||||||
|
|
||||||
|
## Milestone 5: Umlauf Integration
|
||||||
|
|
||||||
|
Goal: support administrative circulation workflows without confusing list
|
||||||
|
definition with execution.
|
||||||
|
|
||||||
|
Tasks:
|
||||||
|
|
||||||
|
- let workflow/tasks consume distribution-list expansion snapshots
|
||||||
|
- support ordered participant sequences where workflow owns state
|
||||||
|
- add escalation and substitution hooks through workflow, not distribution lists
|
||||||
|
- preserve immutable recipient evidence for every execution
|
||||||
23
pyproject.toml
Normal file
23
pyproject.toml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
[build-system]
|
||||||
|
requires = ["setuptools>=69", "wheel"]
|
||||||
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
|
[project]
|
||||||
|
name = "govoplan-dist-lists"
|
||||||
|
version = "0.1.8"
|
||||||
|
description = "GovOPlaN operational distribution lists and Verteiler module seed."
|
||||||
|
readme = "README.md"
|
||||||
|
requires-python = ">=3.12"
|
||||||
|
authors = [{ name = "GovOPlaN" }]
|
||||||
|
dependencies = [
|
||||||
|
"govoplan-core>=0.1.8",
|
||||||
|
]
|
||||||
|
|
||||||
|
[tool.setuptools.packages.find]
|
||||||
|
where = ["src"]
|
||||||
|
|
||||||
|
[tool.setuptools.package-data]
|
||||||
|
govoplan_dist_lists = ["py.typed"]
|
||||||
|
|
||||||
|
[project.entry-points."govoplan.modules"]
|
||||||
|
dist_lists = "govoplan_dist_lists.backend.manifest:get_manifest"
|
||||||
5
src/govoplan_dist_lists/__init__.py
Normal file
5
src/govoplan_dist_lists/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
"""GovOPlaN distribution lists module."""
|
||||||
|
|
||||||
|
__all__ = ["__version__"]
|
||||||
|
|
||||||
|
__version__ = "0.1.8"
|
||||||
1
src/govoplan_dist_lists/backend/__init__.py
Normal file
1
src/govoplan_dist_lists/backend/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
"""Backend integration for the distribution lists module."""
|
||||||
95
src/govoplan_dist_lists/backend/manifest.py
Normal file
95
src/govoplan_dist_lists/backend/manifest.py
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from govoplan_core.core.access import CAPABILITY_AUTH_PERMISSION_EVALUATOR, CAPABILITY_AUTH_PRINCIPAL_RESOLVER
|
||||||
|
from govoplan_core.core.modules import DocumentationTopic, ModuleInterfaceProvider, ModuleManifest, PermissionDefinition, RoleTemplate
|
||||||
|
|
||||||
|
MODULE_ID = "dist_lists"
|
||||||
|
MODULE_NAME = "Distribution Lists"
|
||||||
|
MODULE_VERSION = "0.1.8"
|
||||||
|
|
||||||
|
READ_SCOPE = "dist_lists:list:read"
|
||||||
|
WRITE_SCOPE = "dist_lists:list:write"
|
||||||
|
ADMIN_SCOPE = "dist_lists:list:admin"
|
||||||
|
|
||||||
|
|
||||||
|
def _permission(scope: str, label: str, description: str) -> PermissionDefinition:
|
||||||
|
module_id, resource, action = scope.split(":", 2)
|
||||||
|
return PermissionDefinition(
|
||||||
|
scope=scope,
|
||||||
|
label=label,
|
||||||
|
description=description,
|
||||||
|
category=MODULE_NAME,
|
||||||
|
level="tenant",
|
||||||
|
module_id=module_id,
|
||||||
|
resource=resource,
|
||||||
|
action=action,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
PERMISSIONS = (
|
||||||
|
_permission(READ_SCOPE, "View distribution lists", "Read operational distribution lists and expansion previews."),
|
||||||
|
_permission(WRITE_SCOPE, "Manage distribution lists", "Create and edit operational distribution lists."),
|
||||||
|
_permission(ADMIN_SCOPE, "Administer distribution lists", "Configure distribution-list policies and provider integrations."),
|
||||||
|
)
|
||||||
|
|
||||||
|
ROLE_TEMPLATES = (
|
||||||
|
RoleTemplate(
|
||||||
|
slug="distribution_list_manager",
|
||||||
|
name="Distribution list manager",
|
||||||
|
description="Create, manage, preview, and reuse operational distribution lists.",
|
||||||
|
permissions=(READ_SCOPE, WRITE_SCOPE),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
DOCUMENTATION = (
|
||||||
|
DocumentationTopic(
|
||||||
|
id="dist-lists.boundary",
|
||||||
|
title="Distribution list boundary",
|
||||||
|
summary="Distribution lists model operational Verteiler separately from address-book lists and workflow Umlauf execution.",
|
||||||
|
body=(
|
||||||
|
"Distribution Lists owns reusable mixed recipient definitions and expansion snapshots. "
|
||||||
|
"Address lists remain in the addresses module and represent address-domain groupings only. "
|
||||||
|
"Workflow and Tasks own Umlauf execution state, ordering, deadlines, escalation, and completion."
|
||||||
|
),
|
||||||
|
layer="available",
|
||||||
|
documentation_types=("admin", "user"),
|
||||||
|
audience=("operator", "module_admin", "product_owner"),
|
||||||
|
related_modules=("addresses", "campaigns", "mail", "postbox", "notifications", "scheduling", "poll", "workflow", "tasks"),
|
||||||
|
metadata={"seed": True},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
manifest = ModuleManifest(
|
||||||
|
id=MODULE_ID,
|
||||||
|
name=MODULE_NAME,
|
||||||
|
version=MODULE_VERSION,
|
||||||
|
dependencies=(),
|
||||||
|
optional_dependencies=(
|
||||||
|
"addresses",
|
||||||
|
"access",
|
||||||
|
"identity",
|
||||||
|
"organizations",
|
||||||
|
"campaigns",
|
||||||
|
"mail",
|
||||||
|
"postbox",
|
||||||
|
"notifications",
|
||||||
|
"scheduling",
|
||||||
|
"poll",
|
||||||
|
"workflow",
|
||||||
|
"tasks",
|
||||||
|
),
|
||||||
|
optional_capabilities=(CAPABILITY_AUTH_PRINCIPAL_RESOLVER, CAPABILITY_AUTH_PERMISSION_EVALUATOR),
|
||||||
|
provides_interfaces=(
|
||||||
|
ModuleInterfaceProvider(name="distLists.source", version=MODULE_VERSION),
|
||||||
|
ModuleInterfaceProvider(name="distLists.expand", version=MODULE_VERSION),
|
||||||
|
ModuleInterfaceProvider(name="distLists.writer", version=MODULE_VERSION),
|
||||||
|
),
|
||||||
|
permissions=PERMISSIONS,
|
||||||
|
role_templates=ROLE_TEMPLATES,
|
||||||
|
documentation=DOCUMENTATION,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_manifest() -> ModuleManifest:
|
||||||
|
return manifest
|
||||||
1
src/govoplan_dist_lists/py.typed
Normal file
1
src/govoplan_dist_lists/py.typed
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
25
tests/test_manifest.py
Normal file
25
tests/test_manifest.py
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from govoplan_core.core.modules import ModuleManifest
|
||||||
|
from govoplan_dist_lists.backend.manifest import get_manifest
|
||||||
|
|
||||||
|
|
||||||
|
class DistributionListsManifestTests(unittest.TestCase):
|
||||||
|
def test_manifest_contract(self) -> None:
|
||||||
|
manifest = get_manifest()
|
||||||
|
|
||||||
|
self.assertIsInstance(manifest, ModuleManifest)
|
||||||
|
self.assertEqual(manifest.id, "dist_lists")
|
||||||
|
self.assertFalse(manifest.dependencies)
|
||||||
|
self.assertIn("addresses", manifest.optional_dependencies)
|
||||||
|
self.assertIn("auth.principalResolver", manifest.optional_capabilities)
|
||||||
|
self.assertIn("distLists.expand", {interface.name for interface in manifest.provides_interfaces})
|
||||||
|
self.assertIn("dist_lists:list:read", {permission.scope for permission in manifest.permissions})
|
||||||
|
self.assertIsNone(manifest.route_factory)
|
||||||
|
self.assertIsNone(manifest.migration_spec)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
Reference in New Issue
Block a user