taskdog-client 0.18.1__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.
- taskdog_client-0.18.1/PKG-INFO +160 -0
- taskdog_client-0.18.1/README.md +133 -0
- taskdog_client-0.18.1/pyproject.toml +64 -0
- taskdog_client-0.18.1/setup.cfg +4 -0
- taskdog_client-0.18.1/src/taskdog_client/__init__.py +31 -0
- taskdog_client-0.18.1/src/taskdog_client/analytics_client.py +97 -0
- taskdog_client-0.18.1/src/taskdog_client/audit_client.py +120 -0
- taskdog_client-0.18.1/src/taskdog_client/base_client.py +205 -0
- taskdog_client-0.18.1/src/taskdog_client/bulk_client.py +90 -0
- taskdog_client-0.18.1/src/taskdog_client/converters/__init__.py +31 -0
- taskdog_client-0.18.1/src/taskdog_client/converters/datetime_utils.py +160 -0
- taskdog_client-0.18.1/src/taskdog_client/converters/exceptions.py +33 -0
- taskdog_client-0.18.1/src/taskdog_client/converters/gantt_converters.py +158 -0
- taskdog_client-0.18.1/src/taskdog_client/converters/optimization_converters.py +139 -0
- taskdog_client-0.18.1/src/taskdog_client/converters/statistics_converters.py +215 -0
- taskdog_client-0.18.1/src/taskdog_client/converters/tag_converters.py +25 -0
- taskdog_client-0.18.1/src/taskdog_client/converters/task_converters.py +203 -0
- taskdog_client-0.18.1/src/taskdog_client/lifecycle_client.py +148 -0
- taskdog_client-0.18.1/src/taskdog_client/notes_client.py +61 -0
- taskdog_client-0.18.1/src/taskdog_client/py.typed +0 -0
- taskdog_client-0.18.1/src/taskdog_client/query_client.py +211 -0
- taskdog_client-0.18.1/src/taskdog_client/relationship_client.py +102 -0
- taskdog_client-0.18.1/src/taskdog_client/task_client.py +217 -0
- taskdog_client-0.18.1/src/taskdog_client/taskdog_api_client.py +443 -0
- taskdog_client-0.18.1/src/taskdog_client/websocket/__init__.py +8 -0
- taskdog_client-0.18.1/src/taskdog_client/websocket/websocket_client.py +203 -0
- taskdog_client-0.18.1/src/taskdog_client.egg-info/PKG-INFO +160 -0
- taskdog_client-0.18.1/src/taskdog_client.egg-info/SOURCES.txt +40 -0
- taskdog_client-0.18.1/src/taskdog_client.egg-info/dependency_links.txt +1 -0
- taskdog_client-0.18.1/src/taskdog_client.egg-info/requires.txt +10 -0
- taskdog_client-0.18.1/src/taskdog_client.egg-info/top_level.txt +1 -0
- taskdog_client-0.18.1/tests/test_analytics_client.py +83 -0
- taskdog_client-0.18.1/tests/test_audit_client.py +328 -0
- taskdog_client-0.18.1/tests/test_base_client.py +176 -0
- taskdog_client-0.18.1/tests/test_bulk_client.py +171 -0
- taskdog_client-0.18.1/tests/test_converters.py +610 -0
- taskdog_client-0.18.1/tests/test_lifecycle_client.py +53 -0
- taskdog_client-0.18.1/tests/test_notes_client.py +62 -0
- taskdog_client-0.18.1/tests/test_query_client.py +132 -0
- taskdog_client-0.18.1/tests/test_relationship_client.py +92 -0
- taskdog_client-0.18.1/tests/test_task_client.py +152 -0
- taskdog_client-0.18.1/tests/test_taskdog_api_client.py +319 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: taskdog-client
|
|
3
|
+
Version: 0.18.1
|
|
4
|
+
Summary: HTTP API client for Taskdog server
|
|
5
|
+
Author: Kohei Wada
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/Kohei-Wada/taskdog
|
|
8
|
+
Project-URL: Repository, https://github.com/Kohei-Wada/taskdog
|
|
9
|
+
Project-URL: Bug Tracker, https://github.com/Kohei-Wada/taskdog/issues
|
|
10
|
+
Keywords: task,management,api-client
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Requires-Python: >=3.12
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
Requires-Dist: taskdog-core==0.18.1
|
|
19
|
+
Requires-Dist: httpx>=0.27.0
|
|
20
|
+
Requires-Dist: websockets>=14.0
|
|
21
|
+
Provides-Extra: dev
|
|
22
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
23
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
24
|
+
Requires-Dist: pytest-asyncio>=1.0.0; extra == "dev"
|
|
25
|
+
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
26
|
+
Requires-Dist: ruff>=0.7.0; extra == "dev"
|
|
27
|
+
|
|
28
|
+
# taskdog-client
|
|
29
|
+
|
|
30
|
+
HTTP API client library for Taskdog server.
|
|
31
|
+
|
|
32
|
+
## Overview
|
|
33
|
+
|
|
34
|
+
This package provides a type-safe HTTP client for communicating with the Taskdog API server. It handles authentication, error mapping, and response conversion to domain DTOs.
|
|
35
|
+
|
|
36
|
+
**Use cases:**
|
|
37
|
+
|
|
38
|
+
- Building custom CLI tools
|
|
39
|
+
- Integrating Taskdog with other systems
|
|
40
|
+
- Creating automated workflows
|
|
41
|
+
- Testing API endpoints
|
|
42
|
+
|
|
43
|
+
## Installation
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pip install taskdog-client
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
For development:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
pip install -e ".[dev]"
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Client Classes
|
|
56
|
+
|
|
57
|
+
| Client | Purpose |
|
|
58
|
+
|--------|---------|
|
|
59
|
+
| `TaskClient` | Task CRUD operations (create, update, delete, archive) |
|
|
60
|
+
| `LifecycleClient` | Status changes (start, complete, pause, cancel, reopen) |
|
|
61
|
+
| `RelationshipClient` | Dependencies and tags |
|
|
62
|
+
| `QueryClient` | List tasks, get task details |
|
|
63
|
+
| `AnalyticsClient` | Statistics and Gantt data |
|
|
64
|
+
| `NotesClient` | Task notes (markdown) |
|
|
65
|
+
| `AuditClient` | Audit log access |
|
|
66
|
+
| `BaseApiClient` | Base class with common HTTP logic |
|
|
67
|
+
|
|
68
|
+
## Usage Example
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
from taskdog_client import TaskClient, LifecycleClient, QueryClient
|
|
72
|
+
|
|
73
|
+
# Create clients
|
|
74
|
+
base_url = "http://127.0.0.1:8000"
|
|
75
|
+
api_key = "your-api-key" # Optional, for authenticated servers
|
|
76
|
+
|
|
77
|
+
task_client = TaskClient(base_url, api_key)
|
|
78
|
+
lifecycle_client = LifecycleClient(base_url, api_key)
|
|
79
|
+
query_client = QueryClient(base_url, api_key)
|
|
80
|
+
|
|
81
|
+
# Create a task
|
|
82
|
+
task = task_client.create_task(
|
|
83
|
+
name="My Task",
|
|
84
|
+
priority=100,
|
|
85
|
+
estimated_duration=8.0,
|
|
86
|
+
tags=["backend"]
|
|
87
|
+
)
|
|
88
|
+
print(f"Created task: {task.id}")
|
|
89
|
+
|
|
90
|
+
# List tasks
|
|
91
|
+
tasks = query_client.list_tasks(status="pending")
|
|
92
|
+
for t in tasks:
|
|
93
|
+
print(f"- {t.name} (ID: {t.id})")
|
|
94
|
+
|
|
95
|
+
# Start a task
|
|
96
|
+
lifecycle_client.start_task(task.id)
|
|
97
|
+
|
|
98
|
+
# Complete a task
|
|
99
|
+
lifecycle_client.complete_task(task.id)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Error Handling
|
|
103
|
+
|
|
104
|
+
Clients raise exceptions from `taskdog_core.domain.exceptions`:
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
from taskdog_core.domain.exceptions import TaskNotFoundException, TaskValidationError
|
|
108
|
+
|
|
109
|
+
try:
|
|
110
|
+
task_client.get_task(999)
|
|
111
|
+
except TaskNotFoundException:
|
|
112
|
+
print("Task not found")
|
|
113
|
+
except TaskValidationError as e:
|
|
114
|
+
print(f"Validation error: {e}")
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Configuration
|
|
118
|
+
|
|
119
|
+
Clients accept optional configuration:
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
from taskdog_client import TaskClient
|
|
123
|
+
|
|
124
|
+
# Basic usage (no auth)
|
|
125
|
+
client = TaskClient("http://127.0.0.1:8000")
|
|
126
|
+
|
|
127
|
+
# With API key authentication
|
|
128
|
+
client = TaskClient(
|
|
129
|
+
base_url="http://127.0.0.1:8000",
|
|
130
|
+
api_key="your-secret-key"
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
# Custom timeout (in seconds)
|
|
134
|
+
client = TaskClient(
|
|
135
|
+
base_url="http://127.0.0.1:8000",
|
|
136
|
+
timeout=30.0
|
|
137
|
+
)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Dependencies
|
|
141
|
+
|
|
142
|
+
- `taskdog-core`: Domain DTOs and exceptions
|
|
143
|
+
- `httpx`: HTTP client library
|
|
144
|
+
|
|
145
|
+
## Related Packages
|
|
146
|
+
|
|
147
|
+
- [taskdog-core](../taskdog-core/): Domain DTOs used by this package
|
|
148
|
+
- [taskdog-server](../taskdog-server/): API server this client connects to
|
|
149
|
+
- [taskdog-ui](../taskdog-ui/): CLI/TUI that uses this client
|
|
150
|
+
- [taskdog-mcp](../taskdog-mcp/): MCP server that uses this client
|
|
151
|
+
|
|
152
|
+
## Testing
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
pytest tests/
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## License
|
|
159
|
+
|
|
160
|
+
MIT
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# taskdog-client
|
|
2
|
+
|
|
3
|
+
HTTP API client library for Taskdog server.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This package provides a type-safe HTTP client for communicating with the Taskdog API server. It handles authentication, error mapping, and response conversion to domain DTOs.
|
|
8
|
+
|
|
9
|
+
**Use cases:**
|
|
10
|
+
|
|
11
|
+
- Building custom CLI tools
|
|
12
|
+
- Integrating Taskdog with other systems
|
|
13
|
+
- Creating automated workflows
|
|
14
|
+
- Testing API endpoints
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pip install taskdog-client
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
For development:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pip install -e ".[dev]"
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Client Classes
|
|
29
|
+
|
|
30
|
+
| Client | Purpose |
|
|
31
|
+
|--------|---------|
|
|
32
|
+
| `TaskClient` | Task CRUD operations (create, update, delete, archive) |
|
|
33
|
+
| `LifecycleClient` | Status changes (start, complete, pause, cancel, reopen) |
|
|
34
|
+
| `RelationshipClient` | Dependencies and tags |
|
|
35
|
+
| `QueryClient` | List tasks, get task details |
|
|
36
|
+
| `AnalyticsClient` | Statistics and Gantt data |
|
|
37
|
+
| `NotesClient` | Task notes (markdown) |
|
|
38
|
+
| `AuditClient` | Audit log access |
|
|
39
|
+
| `BaseApiClient` | Base class with common HTTP logic |
|
|
40
|
+
|
|
41
|
+
## Usage Example
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
from taskdog_client import TaskClient, LifecycleClient, QueryClient
|
|
45
|
+
|
|
46
|
+
# Create clients
|
|
47
|
+
base_url = "http://127.0.0.1:8000"
|
|
48
|
+
api_key = "your-api-key" # Optional, for authenticated servers
|
|
49
|
+
|
|
50
|
+
task_client = TaskClient(base_url, api_key)
|
|
51
|
+
lifecycle_client = LifecycleClient(base_url, api_key)
|
|
52
|
+
query_client = QueryClient(base_url, api_key)
|
|
53
|
+
|
|
54
|
+
# Create a task
|
|
55
|
+
task = task_client.create_task(
|
|
56
|
+
name="My Task",
|
|
57
|
+
priority=100,
|
|
58
|
+
estimated_duration=8.0,
|
|
59
|
+
tags=["backend"]
|
|
60
|
+
)
|
|
61
|
+
print(f"Created task: {task.id}")
|
|
62
|
+
|
|
63
|
+
# List tasks
|
|
64
|
+
tasks = query_client.list_tasks(status="pending")
|
|
65
|
+
for t in tasks:
|
|
66
|
+
print(f"- {t.name} (ID: {t.id})")
|
|
67
|
+
|
|
68
|
+
# Start a task
|
|
69
|
+
lifecycle_client.start_task(task.id)
|
|
70
|
+
|
|
71
|
+
# Complete a task
|
|
72
|
+
lifecycle_client.complete_task(task.id)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Error Handling
|
|
76
|
+
|
|
77
|
+
Clients raise exceptions from `taskdog_core.domain.exceptions`:
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
from taskdog_core.domain.exceptions import TaskNotFoundException, TaskValidationError
|
|
81
|
+
|
|
82
|
+
try:
|
|
83
|
+
task_client.get_task(999)
|
|
84
|
+
except TaskNotFoundException:
|
|
85
|
+
print("Task not found")
|
|
86
|
+
except TaskValidationError as e:
|
|
87
|
+
print(f"Validation error: {e}")
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Configuration
|
|
91
|
+
|
|
92
|
+
Clients accept optional configuration:
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
from taskdog_client import TaskClient
|
|
96
|
+
|
|
97
|
+
# Basic usage (no auth)
|
|
98
|
+
client = TaskClient("http://127.0.0.1:8000")
|
|
99
|
+
|
|
100
|
+
# With API key authentication
|
|
101
|
+
client = TaskClient(
|
|
102
|
+
base_url="http://127.0.0.1:8000",
|
|
103
|
+
api_key="your-secret-key"
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
# Custom timeout (in seconds)
|
|
107
|
+
client = TaskClient(
|
|
108
|
+
base_url="http://127.0.0.1:8000",
|
|
109
|
+
timeout=30.0
|
|
110
|
+
)
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Dependencies
|
|
114
|
+
|
|
115
|
+
- `taskdog-core`: Domain DTOs and exceptions
|
|
116
|
+
- `httpx`: HTTP client library
|
|
117
|
+
|
|
118
|
+
## Related Packages
|
|
119
|
+
|
|
120
|
+
- [taskdog-core](../taskdog-core/): Domain DTOs used by this package
|
|
121
|
+
- [taskdog-server](../taskdog-server/): API server this client connects to
|
|
122
|
+
- [taskdog-ui](../taskdog-ui/): CLI/TUI that uses this client
|
|
123
|
+
- [taskdog-mcp](../taskdog-mcp/): MCP server that uses this client
|
|
124
|
+
|
|
125
|
+
## Testing
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
pytest tests/
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## License
|
|
132
|
+
|
|
133
|
+
MIT
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "taskdog-client"
|
|
3
|
+
version = "0.18.1"
|
|
4
|
+
description = "HTTP API client for Taskdog server"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.12"
|
|
7
|
+
authors = [
|
|
8
|
+
{ name = "Kohei Wada" }
|
|
9
|
+
]
|
|
10
|
+
license = { text = "MIT" }
|
|
11
|
+
keywords = ["task", "management", "api-client"]
|
|
12
|
+
classifiers = [
|
|
13
|
+
"Development Status :: 4 - Beta",
|
|
14
|
+
"License :: OSI Approved :: MIT License",
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"Programming Language :: Python :: 3.12",
|
|
17
|
+
"Programming Language :: Python :: 3.13",
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
dependencies = [
|
|
21
|
+
"taskdog-core==0.18.1",
|
|
22
|
+
"httpx>=0.27.0",
|
|
23
|
+
"websockets>=14.0",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
[project.optional-dependencies]
|
|
27
|
+
dev = [
|
|
28
|
+
"pytest>=7.0.0",
|
|
29
|
+
"pytest-cov>=4.0.0",
|
|
30
|
+
"pytest-asyncio>=1.0.0",
|
|
31
|
+
"mypy>=1.0.0",
|
|
32
|
+
"ruff>=0.7.0",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
[project.urls]
|
|
36
|
+
Homepage = "https://github.com/Kohei-Wada/taskdog"
|
|
37
|
+
Repository = "https://github.com/Kohei-Wada/taskdog"
|
|
38
|
+
"Bug Tracker" = "https://github.com/Kohei-Wada/taskdog/issues"
|
|
39
|
+
|
|
40
|
+
[build-system]
|
|
41
|
+
requires = ["setuptools>=68.0.0", "wheel"]
|
|
42
|
+
build-backend = "setuptools.build_meta"
|
|
43
|
+
|
|
44
|
+
[tool.setuptools]
|
|
45
|
+
packages = [
|
|
46
|
+
"taskdog_client",
|
|
47
|
+
"taskdog_client.converters",
|
|
48
|
+
"taskdog_client.websocket",
|
|
49
|
+
]
|
|
50
|
+
package-dir = { "" = "src" }
|
|
51
|
+
|
|
52
|
+
[tool.setuptools.package-data]
|
|
53
|
+
taskdog_client = ["py.typed"]
|
|
54
|
+
|
|
55
|
+
[tool.mypy]
|
|
56
|
+
python_version = "3.13"
|
|
57
|
+
strict = true
|
|
58
|
+
warn_unused_ignores = false
|
|
59
|
+
|
|
60
|
+
[tool.pytest.ini_options]
|
|
61
|
+
testpaths = ["tests"]
|
|
62
|
+
python_files = ["test_*.py"]
|
|
63
|
+
python_classes = ["Test*"]
|
|
64
|
+
python_functions = ["test_*"]
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""HTTP and WebSocket client for Taskdog server.
|
|
2
|
+
|
|
3
|
+
This package provides type-safe HTTP and WebSocket clients for communicating with
|
|
4
|
+
the Taskdog API server. It handles authentication, error mapping,
|
|
5
|
+
and response conversion to domain DTOs.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from taskdog_client.analytics_client import AnalyticsClient
|
|
9
|
+
from taskdog_client.audit_client import AuditClient
|
|
10
|
+
from taskdog_client.base_client import BaseApiClient
|
|
11
|
+
from taskdog_client.lifecycle_client import LifecycleClient
|
|
12
|
+
from taskdog_client.notes_client import NotesClient
|
|
13
|
+
from taskdog_client.query_client import QueryClient
|
|
14
|
+
from taskdog_client.relationship_client import RelationshipClient
|
|
15
|
+
from taskdog_client.task_client import TaskClient
|
|
16
|
+
from taskdog_client.taskdog_api_client import TaskdogApiClient
|
|
17
|
+
from taskdog_client.websocket import ConnectionState, WebSocketClient
|
|
18
|
+
|
|
19
|
+
__all__ = [
|
|
20
|
+
"AnalyticsClient",
|
|
21
|
+
"AuditClient",
|
|
22
|
+
"BaseApiClient",
|
|
23
|
+
"ConnectionState",
|
|
24
|
+
"LifecycleClient",
|
|
25
|
+
"NotesClient",
|
|
26
|
+
"QueryClient",
|
|
27
|
+
"RelationshipClient",
|
|
28
|
+
"TaskClient",
|
|
29
|
+
"TaskdogApiClient",
|
|
30
|
+
"WebSocketClient",
|
|
31
|
+
]
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"""Analytics and optimization client."""
|
|
2
|
+
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
|
|
5
|
+
from taskdog_client.base_client import BaseApiClient
|
|
6
|
+
from taskdog_client.converters import (
|
|
7
|
+
convert_to_optimization_output,
|
|
8
|
+
convert_to_statistics_output,
|
|
9
|
+
)
|
|
10
|
+
from taskdog_core.application.dto.optimization_output import OptimizationOutput
|
|
11
|
+
from taskdog_core.application.dto.statistics_output import StatisticsOutput
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class AnalyticsClient:
|
|
15
|
+
"""Client for analytics and schedule optimization.
|
|
16
|
+
|
|
17
|
+
Operations:
|
|
18
|
+
- Calculate statistics
|
|
19
|
+
- Optimize schedules
|
|
20
|
+
- Get algorithm metadata
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
def __init__(self, base_client: BaseApiClient):
|
|
24
|
+
"""Initialize analytics client.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
base_client: Base API client for HTTP operations
|
|
28
|
+
"""
|
|
29
|
+
self._base = base_client
|
|
30
|
+
|
|
31
|
+
def calculate_statistics(self, period: str = "all") -> StatisticsOutput:
|
|
32
|
+
"""Calculate task statistics.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
period: Time period (all, 7d, 30d)
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
StatisticsOutput with statistics data
|
|
39
|
+
|
|
40
|
+
Raises:
|
|
41
|
+
TaskValidationError: If period is invalid
|
|
42
|
+
"""
|
|
43
|
+
data = self._base._request_json("get", f"/api/v1/statistics?period={period}")
|
|
44
|
+
return convert_to_statistics_output(data)
|
|
45
|
+
|
|
46
|
+
def optimize_schedule(
|
|
47
|
+
self,
|
|
48
|
+
algorithm: str,
|
|
49
|
+
start_date: datetime | None,
|
|
50
|
+
max_hours_per_day: float,
|
|
51
|
+
force_override: bool = True,
|
|
52
|
+
task_ids: list[int] | None = None,
|
|
53
|
+
include_all_days: bool = False,
|
|
54
|
+
) -> OptimizationOutput:
|
|
55
|
+
"""Optimize task schedules.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
algorithm: Algorithm name (required)
|
|
59
|
+
start_date: Optimization start date (None = server current time)
|
|
60
|
+
max_hours_per_day: Maximum hours per day (required)
|
|
61
|
+
force_override: Force override existing schedules
|
|
62
|
+
task_ids: Specific task IDs to optimize (None means all schedulable tasks)
|
|
63
|
+
include_all_days: If True, schedule tasks on weekends and holidays too (default: False)
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
OptimizationOutput with optimization results
|
|
67
|
+
|
|
68
|
+
Raises:
|
|
69
|
+
TaskValidationError: If validation fails
|
|
70
|
+
TaskNotFoundException: If any specified task_id does not exist
|
|
71
|
+
NoSchedulableTasksError: If no tasks can be scheduled
|
|
72
|
+
"""
|
|
73
|
+
payload: dict[str, str | float | bool | list[int] | None] = {
|
|
74
|
+
"algorithm": algorithm,
|
|
75
|
+
"start_date": start_date.isoformat() if start_date else None,
|
|
76
|
+
"max_hours_per_day": max_hours_per_day,
|
|
77
|
+
"force_override": force_override,
|
|
78
|
+
"include_all_days": include_all_days,
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
# Only include task_ids if it's not None
|
|
82
|
+
if task_ids is not None:
|
|
83
|
+
payload["task_ids"] = task_ids
|
|
84
|
+
|
|
85
|
+
data = self._base._request_json("post", "/api/v1/optimize", json=payload)
|
|
86
|
+
return convert_to_optimization_output(data)
|
|
87
|
+
|
|
88
|
+
def get_algorithm_metadata(self) -> list[tuple[str, str, str]]:
|
|
89
|
+
"""Get available optimization algorithms.
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
List of (name, display_name, description) tuples
|
|
93
|
+
"""
|
|
94
|
+
data = self._base._request_json("get", "/api/v1/algorithms")
|
|
95
|
+
return [
|
|
96
|
+
(algo["name"], algo["display_name"], algo["description"]) for algo in data
|
|
97
|
+
]
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"""Audit log client."""
|
|
2
|
+
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from taskdog_client.base_client import BaseApiClient
|
|
7
|
+
from taskdog_core.application.dto.audit_log_dto import (
|
|
8
|
+
AuditLogListOutput,
|
|
9
|
+
AuditLogOutput,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class AuditClient:
|
|
14
|
+
"""Client for audit log operations.
|
|
15
|
+
|
|
16
|
+
Operations:
|
|
17
|
+
- List audit logs with filtering
|
|
18
|
+
- Get single audit log by ID
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
def __init__(self, base_client: BaseApiClient):
|
|
22
|
+
"""Initialize audit client.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
base_client: Base API client for HTTP operations
|
|
26
|
+
"""
|
|
27
|
+
self._base = base_client
|
|
28
|
+
|
|
29
|
+
def list_audit_logs(
|
|
30
|
+
self,
|
|
31
|
+
client_filter: str | None = None,
|
|
32
|
+
operation: str | None = None,
|
|
33
|
+
resource_type: str | None = None,
|
|
34
|
+
resource_id: int | None = None,
|
|
35
|
+
success: bool | None = None,
|
|
36
|
+
start_date: datetime | None = None,
|
|
37
|
+
end_date: datetime | None = None,
|
|
38
|
+
limit: int = 100,
|
|
39
|
+
offset: int = 0,
|
|
40
|
+
) -> AuditLogListOutput:
|
|
41
|
+
"""List audit logs with optional filtering.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
client_filter: Filter by client name
|
|
45
|
+
operation: Filter by operation type
|
|
46
|
+
resource_type: Filter by resource type
|
|
47
|
+
resource_id: Filter by resource ID
|
|
48
|
+
success: Filter by success status
|
|
49
|
+
start_date: Filter logs after this datetime
|
|
50
|
+
end_date: Filter logs before this datetime
|
|
51
|
+
limit: Maximum number of logs to return
|
|
52
|
+
offset: Number of logs to skip for pagination
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
AuditLogListOutput with logs and pagination info
|
|
56
|
+
"""
|
|
57
|
+
params: dict[str, str | int] = {"limit": limit, "offset": offset}
|
|
58
|
+
|
|
59
|
+
if client_filter is not None:
|
|
60
|
+
params["client"] = client_filter
|
|
61
|
+
if operation is not None:
|
|
62
|
+
params["operation"] = operation
|
|
63
|
+
if resource_type is not None:
|
|
64
|
+
params["resource_type"] = resource_type
|
|
65
|
+
if resource_id is not None:
|
|
66
|
+
params["resource_id"] = resource_id
|
|
67
|
+
if success is not None:
|
|
68
|
+
params["success"] = str(success).lower()
|
|
69
|
+
if start_date is not None:
|
|
70
|
+
params["start_date"] = start_date.isoformat()
|
|
71
|
+
if end_date is not None:
|
|
72
|
+
params["end_date"] = end_date.isoformat()
|
|
73
|
+
|
|
74
|
+
data = self._base._request_json("get", "/api/v1/audit-logs", params=params)
|
|
75
|
+
return self._convert_to_list_output(data)
|
|
76
|
+
|
|
77
|
+
def get_audit_log(self, log_id: int) -> AuditLogOutput:
|
|
78
|
+
"""Get a single audit log entry by ID.
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
log_id: ID of the audit log entry to retrieve
|
|
82
|
+
|
|
83
|
+
Returns:
|
|
84
|
+
AuditLogOutput with the audit log details
|
|
85
|
+
"""
|
|
86
|
+
data = self._base._request_json("get", f"/api/v1/audit-logs/{log_id}")
|
|
87
|
+
return self._convert_to_output(data)
|
|
88
|
+
|
|
89
|
+
def _convert_to_output(self, data: dict[str, Any]) -> AuditLogOutput:
|
|
90
|
+
"""Convert API response to AuditLogOutput DTO."""
|
|
91
|
+
# Parse timestamp with error handling for malformed data
|
|
92
|
+
try:
|
|
93
|
+
timestamp = datetime.fromisoformat(data["timestamp"])
|
|
94
|
+
except (ValueError, KeyError):
|
|
95
|
+
# Fallback to current time if timestamp is invalid or missing
|
|
96
|
+
timestamp = datetime.now()
|
|
97
|
+
|
|
98
|
+
return AuditLogOutput(
|
|
99
|
+
id=data["id"],
|
|
100
|
+
timestamp=timestamp,
|
|
101
|
+
client_name=data.get("client_name"),
|
|
102
|
+
operation=data["operation"],
|
|
103
|
+
resource_type=data["resource_type"],
|
|
104
|
+
resource_id=data.get("resource_id"),
|
|
105
|
+
resource_name=data.get("resource_name"),
|
|
106
|
+
old_values=data.get("old_values"),
|
|
107
|
+
new_values=data.get("new_values"),
|
|
108
|
+
success=data["success"],
|
|
109
|
+
error_message=data.get("error_message"),
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
def _convert_to_list_output(self, data: dict[str, Any]) -> AuditLogListOutput:
|
|
113
|
+
"""Convert API response to AuditLogListOutput DTO."""
|
|
114
|
+
logs = [self._convert_to_output(log) for log in data["logs"]]
|
|
115
|
+
return AuditLogListOutput(
|
|
116
|
+
logs=logs,
|
|
117
|
+
total_count=data["total_count"],
|
|
118
|
+
limit=data["limit"],
|
|
119
|
+
offset=data["offset"],
|
|
120
|
+
)
|