ckanext-tmforum
June 12, 2026 ยท View on GitHub
ckanext-tmforum
CKAN harvester extension for TM Forum APIs.
It harvests product offerings/specifications, enriches them with related service specifications, resolves owner organizations from TMF Party data, and creates/updates datasets in CKAN.
Compatibility
- CKAN: 2.11 (current target)
- Python: 3.10
- Requires
ckanext-harvest
Harvester Info
Harvester type name:
tmforum
This is the value to use when creating a Harvest Source in CKAN.
Harvest Flow
gather_stage
- Reads launched product offerings from TMF Product Catalog (
/productOffering). - Creates harvest objects using product specification id as GUID.
fetch_stage
- Fetches product specification (
/productSpecification/{id}). - Fetches related service specifications from configured service catalog.
- Stores normalized content on harvest object.
import_stage
- Resolves owner party from
relatedPartyusing configuredowner_role. - Resolves/creates owner organization in CKAN.
- Builds CKAN dataset and resources.
- Creates or updates package through harvest base logic.
Configuration
Configuration is read from the Harvest Source JSON config (source.config) for runtime behavior.
Expected keys:
party_url(required)- Base TMF Party endpoint.
service_catalog_url(required)- Base TMF Service Catalog endpoint.
product_inventory_url(required)- Base TMF Product Inventory endpoint.
owner_role(optional)- Default:
owner - Used to select owner party from
relatedParty.
- Default:
marketplace_url(optional)- If set, adds an extra resource access URL:
{marketplace_url}/search/{offer_id}.
- If set, adds an extra resource access URL:
dsp_url(optional)- If set, adds an extra resource access URL pointing to DSP.
The harvest source URL (source.url) is used as TMF Product Catalog base.
Example Harvest Source Config
{
"party_url": "https://tmf.example.com/party",
"service_catalog_url": "https://tmf.example.com/serviceCatalogManagement/v4",
"product_inventory_url": "https://tmf.example.com/productInventoryManagement/v4",
"owner_role": "Seller",
"marketplace_url": "https://marketplace.example.com",
"dsp_url": "https://edc.example.com"
}
Resource Mapping
Per service specification, resources are created with:
name,descriptionaccess_url(TMF product offering URL)conforms_to(TM Forum URIs)- a UI type badge derived from
conforms_toin both the resource list and resource detail page
Known specCharacteristic mappings:
URL->download_urlFormat->formatMedia Type->mimetype
Additional TMForum identifiers are stored on each resource to support CKAN-side entitlement checks:
tmf_offer_idtmf_service_id
Other characteristics are mapped to flattened resource keys:
tmf_char_<normalized_name>- if multiple values:
tmf_char_<normalized_name>_1,..._2, etc.
Duplicate characteristic names are ignored after first occurrence.
Organization Resolution
Owner organization is resolved from party data using DID in this order:
externalReferencewhereexternalReferenceType == "idm_id"and name starts withdidpartyCharacteristicwherename == "did"- fallback to
party_id
Generated CKAN org name format:
vc-org-<sha256(did)[:16]>
Persisted TMForum Metadata
During harvest import, the dataset stores the TMForum endpoint information needed to work with the harvested resources later from the CKAN catalog:
tmf_idtmf_product_catalog_urltmf_party_urltmf_service_catalog_urltmf_product_inventory_url
Installation
git clone https://github.com/SEAMWARE/ckanext-tmforum.git
cd ckanext-tmforum
pip install -e .
pip install -r requirements.txt
Enable plugin:
ckan.plugins = ... harvest tmforum ...
Running Harvest Jobs (ckan-docker)
Examples:
docker compose exec ckan-dev bash -lc "ckan -c /srv/app/ckan.ini harvester sources" docker compose exec ckan-dev bash -lc "ckan -c /srv/app/ckan.ini harvester jobs" docker compose exec ckan-dev bash -lc "ckan -c /srv/app/ckan.ini harvester run-test <source_id_or_name>" docker compose exec ckan-dev bash -lc "ckan -c /srv/app/ckan.ini harvester gather-consumer" docker compose exec ckan-dev bash -lc "ckan -c /srv/app/ckan.ini harvester fetch-consumer"
Tests
Run all tests:
pytest --ckan-ini=test.ini
Run unit tests only:
pytest --ckan-ini=test.ini ckanext/tmforum/tests/unit
Conditional Visualization
The extension can hide CKAN resource previews and visualization widgets while
still showing the protected download_url.
Optional configuration:
ckanext.tmforum.visualization_access_check_enabled- Default:
False
- Default:
When enabled, the helper checks the logged-in user's TMForum organization party
id and then calls _check_visualization_access_for_party_id(). That method is
currently a mock that returns a boolean value and is the place where the real
backend entitlement call should be added later.
With the current mock returning False, the UI renders the locked/no-access
state. This is useful while iterating on the frontend before wiring the real
backend entitlement check.
Releasing
-
Update version in
pyproject.toml -
Build and validate:
python -m build && twine check dist/* -
Upload:
twine upload dist/* -
Commit and tag:
git commit -a -m "Release x.y.z"
git push
git tag x.y.z
git push --tags