eledoctl 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- eledoctl-1.0.0/.gitignore +14 -0
- eledoctl-1.0.0/LICENSE +21 -0
- eledoctl-1.0.0/PKG-INFO +154 -0
- eledoctl-1.0.0/README.md +105 -0
- eledoctl-1.0.0/pyproject.toml +94 -0
- eledoctl-1.0.0/src/eledoctl/__init__.py +1 -0
- eledoctl-1.0.0/src/eledoctl/cli/__init__.py +1 -0
- eledoctl-1.0.0/src/eledoctl/cli/common.py +25 -0
- eledoctl-1.0.0/src/eledoctl/cli/documents.py +195 -0
- eledoctl-1.0.0/src/eledoctl/cli/internal/__init__.py +0 -0
- eledoctl-1.0.0/src/eledoctl/cli/internal/docs.py +37 -0
- eledoctl-1.0.0/src/eledoctl/cli/login.py +72 -0
- eledoctl-1.0.0/src/eledoctl/cli/main.py +30 -0
- eledoctl-1.0.0/src/eledoctl/cli/profile.py +26 -0
- eledoctl-1.0.0/src/eledoctl/cli/templates.py +48 -0
- eledoctl-1.0.0/src/eledoctl/config/__init__.py +1 -0
- eledoctl-1.0.0/src/eledoctl/config/settings.py +108 -0
- eledoctl-1.0.0/src/eledoctl/internal/__init__.py +0 -0
- eledoctl-1.0.0/src/eledoctl/internal/cms/__init__.py +0 -0
- eledoctl-1.0.0/src/eledoctl/internal/docsync/__init__.py +0 -0
- eledoctl-1.0.0/src/eledoctl/internal/docsync/slug.py +21 -0
- eledoctl-1.0.0/src/eledoctl/internal/transform/__init__.py +0 -0
- eledoctl-1.0.0/src/eledoctl/internal/transform/markdown.py +39 -0
- eledoctl-1.0.0/src/pyeledo/__init__.py +29 -0
- eledoctl-1.0.0/src/pyeledo/client.py +151 -0
- eledoctl-1.0.0/src/pyeledo/cms.py +1 -0
- eledoctl-1.0.0/src/pyeledo/exceptions.py +23 -0
- eledoctl-1.0.0/src/pyeledo/generate.py +81 -0
- eledoctl-1.0.0/src/pyeledo/profile.py +22 -0
- eledoctl-1.0.0/src/pyeledo/schema.py +91 -0
- eledoctl-1.0.0/src/pyeledo/templates.py +78 -0
- eledoctl-1.0.0/src/pyeledo/types.py +6 -0
- eledoctl-1.0.0/src/pyeledo/utils.py +95 -0
eledoctl-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Eledo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
eledoctl-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: eledoctl
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Command-line toolkit and async Python API client for Eledo.
|
|
5
|
+
Author: Eledo
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2026 Eledo
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
License-File: LICENSE
|
|
28
|
+
Keywords: api,automation,cli,documents,eledo,pdf,sdk
|
|
29
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
30
|
+
Classifier: Environment :: Console
|
|
31
|
+
Classifier: Intended Audience :: Developers
|
|
32
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
33
|
+
Classifier: Programming Language :: Python :: 3
|
|
34
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
35
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
36
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
37
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
38
|
+
Classifier: Topic :: Office/Business
|
|
39
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
40
|
+
Classifier: Topic :: Utilities
|
|
41
|
+
Classifier: Typing :: Typed
|
|
42
|
+
Requires-Python: >=3.12
|
|
43
|
+
Requires-Dist: click>=8.1
|
|
44
|
+
Requires-Dist: httpx>=0.27
|
|
45
|
+
Requires-Dist: platformdirs>=4.2
|
|
46
|
+
Provides-Extra: repl
|
|
47
|
+
Requires-Dist: prompt-toolkit>=3.0; extra == 'repl'
|
|
48
|
+
Description-Content-Type: text/markdown
|
|
49
|
+
|
|
50
|
+
# eledoctl
|
|
51
|
+
[](https://github.com/eledo-online/eledoctl/actions/workflows/ci.yml)
|
|
52
|
+
[](https://codecov.io/gh/eledo-online/eledoctl)
|
|
53
|
+
[](https://github.com/eledo-online/eledoctl/releases)
|
|
54
|
+
[](https://opensource.org/licenses/MIT)
|
|
55
|
+
[](https://eledo.online/)
|
|
56
|
+

|
|
57
|
+
|
|
58
|
+
`eledoctl` is an open-source command-line toolkit for Eledo.
|
|
59
|
+
|
|
60
|
+
It contains two Python modules:
|
|
61
|
+
|
|
62
|
+
* `pyeledo` — async-native Python API client for Eledo REST APIs
|
|
63
|
+
* `eledoctl` — CLI, REPL, and automation layer built on top of `pyeledo`
|
|
64
|
+
|
|
65
|
+
The project is MIT licensed. Public functionality is exposed through `pyeledo` and `eledoctl`, while internal Eledo tooling is implemented as optional extensions.
|
|
66
|
+
|
|
67
|
+
## Architecture
|
|
68
|
+
|
|
69
|
+
```text
|
|
70
|
+
repo/
|
|
71
|
+
├── src/
|
|
72
|
+
│ ├── pyeledo/ # Async SDK / REST client
|
|
73
|
+
│ └── eledoctl/ # CLI / REPL / orchestration
|
|
74
|
+
└── tests/
|
|
75
|
+
├── pyeledo/
|
|
76
|
+
└── eledoctl/
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
`pyeledo` is async-first and async-only. It never stores credentials. Tokens are passed to the client by the caller.
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
from pyeledo import EledoClient, TemplateScope
|
|
83
|
+
|
|
84
|
+
async with EledoClient(token="...") as client:
|
|
85
|
+
profile = await client.get_profile()
|
|
86
|
+
templates = await client.get_templates(scope=TemplateScope.PRIVATE)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Initial CLI Tree
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
eledoctl profile
|
|
93
|
+
eledoctl templates list
|
|
94
|
+
eledoctl templates schema TEMPLATE_ID
|
|
95
|
+
eledoctl pdf generate TEMPLATE_ID --payload payload.json --output output.pdf
|
|
96
|
+
eledoctl internal docs sync docs
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
For now the CLI passes an empty token unless `--token` is provided. Persistent token storage will be added later in `eledoctl`, not in `pyeledo`.
|
|
100
|
+
|
|
101
|
+
## Installation
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
pip install eledoctl
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Development
|
|
108
|
+
|
|
109
|
+
The project uses modern Python tooling based on `uv`.
|
|
110
|
+
|
|
111
|
+
### Create or update the development environment
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
uv sync --group dev
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Run the test suite
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
uv run pytest
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Run the CLI
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
uv run eledoctl --help
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Format the code
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
uv run ruff format .
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Run linting
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
uv run ruff check .
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Run type checking
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
uv run mypy src
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Full validation
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
uv run ruff format .
|
|
151
|
+
uv run ruff check .
|
|
152
|
+
uv run mypy src
|
|
153
|
+
uv run pytest
|
|
154
|
+
```
|
eledoctl-1.0.0/README.md
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# eledoctl
|
|
2
|
+
[](https://github.com/eledo-online/eledoctl/actions/workflows/ci.yml)
|
|
3
|
+
[](https://codecov.io/gh/eledo-online/eledoctl)
|
|
4
|
+
[](https://github.com/eledo-online/eledoctl/releases)
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
[](https://eledo.online/)
|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
`eledoctl` is an open-source command-line toolkit for Eledo.
|
|
10
|
+
|
|
11
|
+
It contains two Python modules:
|
|
12
|
+
|
|
13
|
+
* `pyeledo` — async-native Python API client for Eledo REST APIs
|
|
14
|
+
* `eledoctl` — CLI, REPL, and automation layer built on top of `pyeledo`
|
|
15
|
+
|
|
16
|
+
The project is MIT licensed. Public functionality is exposed through `pyeledo` and `eledoctl`, while internal Eledo tooling is implemented as optional extensions.
|
|
17
|
+
|
|
18
|
+
## Architecture
|
|
19
|
+
|
|
20
|
+
```text
|
|
21
|
+
repo/
|
|
22
|
+
├── src/
|
|
23
|
+
│ ├── pyeledo/ # Async SDK / REST client
|
|
24
|
+
│ └── eledoctl/ # CLI / REPL / orchestration
|
|
25
|
+
└── tests/
|
|
26
|
+
├── pyeledo/
|
|
27
|
+
└── eledoctl/
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
`pyeledo` is async-first and async-only. It never stores credentials. Tokens are passed to the client by the caller.
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
from pyeledo import EledoClient, TemplateScope
|
|
34
|
+
|
|
35
|
+
async with EledoClient(token="...") as client:
|
|
36
|
+
profile = await client.get_profile()
|
|
37
|
+
templates = await client.get_templates(scope=TemplateScope.PRIVATE)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Initial CLI Tree
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
eledoctl profile
|
|
44
|
+
eledoctl templates list
|
|
45
|
+
eledoctl templates schema TEMPLATE_ID
|
|
46
|
+
eledoctl pdf generate TEMPLATE_ID --payload payload.json --output output.pdf
|
|
47
|
+
eledoctl internal docs sync docs
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
For now the CLI passes an empty token unless `--token` is provided. Persistent token storage will be added later in `eledoctl`, not in `pyeledo`.
|
|
51
|
+
|
|
52
|
+
## Installation
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
pip install eledoctl
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Development
|
|
59
|
+
|
|
60
|
+
The project uses modern Python tooling based on `uv`.
|
|
61
|
+
|
|
62
|
+
### Create or update the development environment
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
uv sync --group dev
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Run the test suite
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
uv run pytest
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Run the CLI
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
uv run eledoctl --help
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Format the code
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
uv run ruff format .
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Run linting
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
uv run ruff check .
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Run type checking
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
uv run mypy src
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Full validation
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
uv run ruff format .
|
|
102
|
+
uv run ruff check .
|
|
103
|
+
uv run mypy src
|
|
104
|
+
uv run pytest
|
|
105
|
+
```
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling>=1.24"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "eledoctl"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "Command-line toolkit and async Python API client for Eledo."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { file = "LICENSE" }
|
|
11
|
+
requires-python = ">=3.12"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "Eledo" }
|
|
14
|
+
]
|
|
15
|
+
keywords = ["eledo", "cli", "sdk", "pdf", "automation", "api", "documents"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 5 - Production/Stable",
|
|
18
|
+
"Environment :: Console",
|
|
19
|
+
"Intended Audience :: Developers",
|
|
20
|
+
"License :: OSI Approved :: MIT License",
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
"Programming Language :: Python :: 3.12",
|
|
23
|
+
"Programming Language :: Python :: 3.13",
|
|
24
|
+
"Programming Language :: Python :: 3.14",
|
|
25
|
+
"Topic :: Office/Business",
|
|
26
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
27
|
+
"Topic :: Utilities",
|
|
28
|
+
"Topic :: Internet :: WWW/HTTP",
|
|
29
|
+
"Typing :: Typed",
|
|
30
|
+
]
|
|
31
|
+
dependencies = [
|
|
32
|
+
"click>=8.1",
|
|
33
|
+
"httpx>=0.27",
|
|
34
|
+
"platformdirs>=4.2",
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
[project.optional-dependencies]
|
|
38
|
+
repl = [
|
|
39
|
+
"prompt-toolkit>=3.0",
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
[dependency-groups]
|
|
43
|
+
dev = [
|
|
44
|
+
"pytest>=8.2",
|
|
45
|
+
"pytest-asyncio>=0.23",
|
|
46
|
+
"pytest-cov>=5.0",
|
|
47
|
+
"ruff>=0.5",
|
|
48
|
+
"mypy>=1.10",
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
[project.scripts]
|
|
52
|
+
eledoctl = "eledoctl.cli.main:main"
|
|
53
|
+
|
|
54
|
+
[tool.hatch.build]
|
|
55
|
+
include = [
|
|
56
|
+
"src/pyeledo/**",
|
|
57
|
+
"src/eledoctl/**",
|
|
58
|
+
"README.md",
|
|
59
|
+
"LICENSE",
|
|
60
|
+
]
|
|
61
|
+
|
|
62
|
+
exclude = [
|
|
63
|
+
".github/**",
|
|
64
|
+
"tests/**",
|
|
65
|
+
"CONTRIBUTING.md",
|
|
66
|
+
"uv.lock",
|
|
67
|
+
]
|
|
68
|
+
|
|
69
|
+
[tool.hatch.build.targets.wheel]
|
|
70
|
+
packages = ["src/pyeledo", "src/eledoctl"]
|
|
71
|
+
|
|
72
|
+
[tool.ruff]
|
|
73
|
+
line-length = 120
|
|
74
|
+
target-version = "py312"
|
|
75
|
+
src = ["src", "tests"]
|
|
76
|
+
|
|
77
|
+
[tool.ruff.lint]
|
|
78
|
+
select = ["E", "F", "I", "UP", "B", "SIM"]
|
|
79
|
+
ignore = []
|
|
80
|
+
|
|
81
|
+
[tool.ruff.format]
|
|
82
|
+
quote-style = "double"
|
|
83
|
+
indent-style = "space"
|
|
84
|
+
|
|
85
|
+
[tool.pytest.ini_options]
|
|
86
|
+
addopts = "--cov=pyeledo --cov=eledoctl --cov-report=term-missing"
|
|
87
|
+
asyncio_mode = "auto"
|
|
88
|
+
testpaths = ["tests"]
|
|
89
|
+
|
|
90
|
+
[tool.mypy]
|
|
91
|
+
python_version = "3.12"
|
|
92
|
+
strict = true
|
|
93
|
+
mypy_path = "src"
|
|
94
|
+
packages = ["pyeledo", "eledoctl"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Command-line toolkit for Eledo."""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""CLI command definitions."""
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""Shared CLI utilities."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
import json
|
|
7
|
+
from collections.abc import Coroutine
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
import click
|
|
11
|
+
|
|
12
|
+
from eledoctl.config.settings import ConnectionSettings, load_connection_settings
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def run[T](coro: Coroutine[Any, Any, T]) -> T:
|
|
16
|
+
"""Run an asynchronous command implementation."""
|
|
17
|
+
return asyncio.run(coro)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def require_connection_settings() -> ConnectionSettings:
|
|
21
|
+
"""Load persisted connection settings or raise a user-facing CLI error."""
|
|
22
|
+
try:
|
|
23
|
+
return load_connection_settings()
|
|
24
|
+
except (OSError, ValueError, json.JSONDecodeError) as exc:
|
|
25
|
+
raise click.ClickException(str(exc)) from exc
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
"""PDF generation CLI commands."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
import click
|
|
9
|
+
|
|
10
|
+
from eledoctl.cli.common import require_connection_settings, run
|
|
11
|
+
from eledoctl.config.settings import ConnectionSettings
|
|
12
|
+
from pyeledo import EledoClient
|
|
13
|
+
from pyeledo.types import JsonObject
|
|
14
|
+
from pyeledo.utils import parse_json_object
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@click.group("documents")
|
|
18
|
+
def documents_group() -> None:
|
|
19
|
+
"""Document generation commands."""
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@documents_group.command("generate")
|
|
23
|
+
@click.argument("template_id")
|
|
24
|
+
@click.option("--template-version", type=int, default=None, help="Optional template version.")
|
|
25
|
+
@click.option(
|
|
26
|
+
"--payload",
|
|
27
|
+
type=str,
|
|
28
|
+
default=None,
|
|
29
|
+
help='Inline JSON containing the Eledo "file" object.',
|
|
30
|
+
)
|
|
31
|
+
@click.option(
|
|
32
|
+
"--payload-file",
|
|
33
|
+
type=click.Path(path_type=Path, exists=True, dir_okay=False),
|
|
34
|
+
default=None,
|
|
35
|
+
help='Read the Eledo "file" object from a JSON file.',
|
|
36
|
+
)
|
|
37
|
+
@click.option(
|
|
38
|
+
"--payload-stdin",
|
|
39
|
+
is_flag=True,
|
|
40
|
+
help='Read the Eledo "file" object from standard input.',
|
|
41
|
+
)
|
|
42
|
+
@click.option(
|
|
43
|
+
"--add-field",
|
|
44
|
+
"fields",
|
|
45
|
+
multiple=True,
|
|
46
|
+
metavar="KEY=VALUE",
|
|
47
|
+
help=("Add a top-level primitive field. May be repeated. Ignored when a JSON payload source is provided."),
|
|
48
|
+
)
|
|
49
|
+
@click.option(
|
|
50
|
+
"--output",
|
|
51
|
+
"output_path",
|
|
52
|
+
type=click.Path(path_type=Path, dir_okay=False),
|
|
53
|
+
default=None,
|
|
54
|
+
help="Document output path. Defaults to filename returned by Eledo.",
|
|
55
|
+
)
|
|
56
|
+
@click.option(
|
|
57
|
+
"--output-dir",
|
|
58
|
+
type=click.Path(path_type=Path, file_okay=False),
|
|
59
|
+
default=None,
|
|
60
|
+
help="Directory for the generated document when --output is not provided.",
|
|
61
|
+
)
|
|
62
|
+
@click.option("--base64-json", is_flag=True, help="Print JSON metadata with base64 PDF content.")
|
|
63
|
+
def generate_pdf(
|
|
64
|
+
template_id: str,
|
|
65
|
+
template_version: int | None,
|
|
66
|
+
payload: str | None,
|
|
67
|
+
payload_file: Path | None,
|
|
68
|
+
payload_stdin: bool,
|
|
69
|
+
fields: tuple[str, ...],
|
|
70
|
+
output_path: Path | None,
|
|
71
|
+
output_dir: Path | None,
|
|
72
|
+
base64_json: bool,
|
|
73
|
+
) -> None:
|
|
74
|
+
"""Generate a PDF document from an Eledo template."""
|
|
75
|
+
settings = require_connection_settings()
|
|
76
|
+
run(
|
|
77
|
+
_generate_pdf(
|
|
78
|
+
template_id=template_id,
|
|
79
|
+
settings=settings,
|
|
80
|
+
template_version=template_version,
|
|
81
|
+
file_data=_resolve_payload(
|
|
82
|
+
payload=payload, payload_file=payload_file, payload_stdin=payload_stdin, fields=fields
|
|
83
|
+
),
|
|
84
|
+
output_path=output_path,
|
|
85
|
+
output_dir=output_dir,
|
|
86
|
+
base64_json=base64_json,
|
|
87
|
+
)
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
async def _generate_pdf(
|
|
92
|
+
*,
|
|
93
|
+
template_id: str,
|
|
94
|
+
settings: ConnectionSettings,
|
|
95
|
+
template_version: int | None,
|
|
96
|
+
file_data: JsonObject | None,
|
|
97
|
+
output_path: Path | None,
|
|
98
|
+
output_dir: Path | None,
|
|
99
|
+
base64_json: bool,
|
|
100
|
+
) -> None:
|
|
101
|
+
async with EledoClient(base_url=settings.base_url, token=settings.token) as client:
|
|
102
|
+
result = await client.generate_pdf(
|
|
103
|
+
template_id=template_id,
|
|
104
|
+
template_version=template_version,
|
|
105
|
+
file_data=file_data,
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
if base64_json:
|
|
109
|
+
click.echo(json.dumps(result.as_json(), indent=2))
|
|
110
|
+
return
|
|
111
|
+
|
|
112
|
+
destination = _resolve_output_path(
|
|
113
|
+
filename=result.filename,
|
|
114
|
+
output_path=output_path,
|
|
115
|
+
output_dir=output_dir,
|
|
116
|
+
)
|
|
117
|
+
destination.write_bytes(result.content)
|
|
118
|
+
click.echo(str(destination))
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def _resolve_payload(
|
|
122
|
+
*,
|
|
123
|
+
payload: str | None,
|
|
124
|
+
payload_file: Path | None,
|
|
125
|
+
payload_stdin: bool,
|
|
126
|
+
fields: tuple[str, ...],
|
|
127
|
+
) -> JsonObject | None:
|
|
128
|
+
"""Read and parse document data from one configured input source."""
|
|
129
|
+
source_count = sum(
|
|
130
|
+
(
|
|
131
|
+
payload is not None,
|
|
132
|
+
payload_file is not None,
|
|
133
|
+
payload_stdin,
|
|
134
|
+
)
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
if source_count > 1:
|
|
138
|
+
raise click.ClickException("Use only one of --payload, --payload-file, or --payload-stdin.")
|
|
139
|
+
|
|
140
|
+
if source_count == 1 and fields:
|
|
141
|
+
click.echo(
|
|
142
|
+
"Warning: --add-field values are ignored because a JSON payload was provided.",
|
|
143
|
+
err=True,
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
if payload is not None:
|
|
147
|
+
return parse_json_object(payload) or None
|
|
148
|
+
|
|
149
|
+
if payload_file is not None:
|
|
150
|
+
return parse_json_object(payload_file.read_text(encoding="utf-8")) or None
|
|
151
|
+
|
|
152
|
+
if payload_stdin:
|
|
153
|
+
return parse_json_object(click.get_text_stream("stdin").read()) or None
|
|
154
|
+
|
|
155
|
+
return _build_field_payload(fields)
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def _build_field_payload(fields: tuple[str, ...]) -> JsonObject | None:
|
|
159
|
+
"""Build a JSON object from repeated KEY=VALUE field arguments."""
|
|
160
|
+
if not fields:
|
|
161
|
+
return None
|
|
162
|
+
|
|
163
|
+
payload: JsonObject = {}
|
|
164
|
+
|
|
165
|
+
for field in fields:
|
|
166
|
+
key, separator, value = field.partition("=")
|
|
167
|
+
|
|
168
|
+
if separator == "":
|
|
169
|
+
raise click.ClickException(f"Invalid field {field!r}. Expected KEY=VALUE.")
|
|
170
|
+
|
|
171
|
+
key = key.strip()
|
|
172
|
+
|
|
173
|
+
if not key:
|
|
174
|
+
raise click.ClickException(f"Invalid field {field!r}. Field name cannot be empty.")
|
|
175
|
+
|
|
176
|
+
payload[key] = value
|
|
177
|
+
|
|
178
|
+
return payload
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def _resolve_output_path(
|
|
182
|
+
*,
|
|
183
|
+
filename: str,
|
|
184
|
+
output_path: Path | None,
|
|
185
|
+
output_dir: Path | None,
|
|
186
|
+
) -> Path:
|
|
187
|
+
"""Resolve the destination path for a generated document."""
|
|
188
|
+
if output_path is not None:
|
|
189
|
+
return output_path
|
|
190
|
+
|
|
191
|
+
if output_dir is not None:
|
|
192
|
+
output_dir.mkdir(parents=True, exist_ok=True)
|
|
193
|
+
return output_dir / filename
|
|
194
|
+
|
|
195
|
+
return Path(filename)
|
|
File without changes
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""Internal documentation synchronization CLI commands."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
import click
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@click.group("internal")
|
|
11
|
+
def internal_group() -> None:
|
|
12
|
+
"""Internal Eledo operational tooling."""
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@internal_group.group("docs")
|
|
16
|
+
def internal_docs_group() -> None:
|
|
17
|
+
"""Internal documentation synchronization tooling."""
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@internal_docs_group.command("sync")
|
|
21
|
+
@click.argument("path", type=click.Path(path_type=Path))
|
|
22
|
+
@click.option(
|
|
23
|
+
"--review-report",
|
|
24
|
+
type=click.Path(path_type=Path, dir_okay=False),
|
|
25
|
+
default=None,
|
|
26
|
+
help="Optional path where manual review report will be written.",
|
|
27
|
+
)
|
|
28
|
+
@click.option("--dry-run", is_flag=True, help="Analyze without uploading changes.")
|
|
29
|
+
def sync_docs(path: Path, review_report: Path | None, dry_run: bool) -> None:
|
|
30
|
+
"""Synchronize Git documentation into Eledo CMS.
|
|
31
|
+
|
|
32
|
+
Implementation will be added after the Eledo CMS CRUD API is available.
|
|
33
|
+
"""
|
|
34
|
+
click.echo("Documentation sync scaffold is ready, but implementation is pending.")
|
|
35
|
+
click.echo(f"path={path}")
|
|
36
|
+
click.echo(f"review_report={review_report}")
|
|
37
|
+
click.echo(f"dry_run={dry_run}")
|