topdesk-mcp 0.2.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.
- topdesk_mcp-0.2.0/.github/copilot-instructions.md +7 -0
- topdesk_mcp-0.2.0/.github/workflows/pypi.yml +26 -0
- topdesk_mcp-0.2.0/.github/workflows/pytest.yml +25 -0
- topdesk_mcp-0.2.0/.gitignore +5 -0
- topdesk_mcp-0.2.0/.vscode/launch.json +14 -0
- topdesk_mcp-0.2.0/.vscode/mcp.json +13 -0
- topdesk_mcp-0.2.0/.vscode/settings.json +7 -0
- topdesk_mcp-0.2.0/.vscode/tasks.json +16 -0
- topdesk_mcp-0.2.0/LICENSE +21 -0
- topdesk_mcp-0.2.0/PKG-INFO +102 -0
- topdesk_mcp-0.2.0/README.md +89 -0
- topdesk_mcp-0.2.0/pyproject.toml +56 -0
- topdesk_mcp-0.2.0/topdesk_mcp/__init__.py +2 -0
- topdesk_mcp-0.2.0/topdesk_mcp/_incident.py +256 -0
- topdesk_mcp-0.2.0/topdesk_mcp/_operator.py +101 -0
- topdesk_mcp-0.2.0/topdesk_mcp/_person.py +61 -0
- topdesk_mcp-0.2.0/topdesk_mcp/_topdesk_sdk.py +184 -0
- topdesk_mcp-0.2.0/topdesk_mcp/_utils.py +228 -0
- topdesk_mcp-0.2.0/topdesk_mcp/main.py +309 -0
- topdesk_mcp-0.2.0/topdesk_mcp/resources/fiql_query_howto.md +40 -0
- topdesk_mcp-0.2.0/topdesk_mcp/resources/object_schemas.yaml +2393 -0
- topdesk_mcp-0.2.0/topdesk_mcp/tests/__init__.py +2 -0
- topdesk_mcp-0.2.0/topdesk_mcp/tests/test_python_sdk.py +289 -0
- topdesk_mcp-0.2.0/uv.lock +708 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<!-- Use this file to provide workspace-specific custom instructions to Copilot. For more details, visit https://code.visualstudio.com/docs/copilot/copilot-customization#_use-a-githubcopilotinstructionsmd-file -->
|
|
2
|
+
|
|
3
|
+
This is an MCP Server project. You can find more info and examples at https://modelcontextprotocol.io/llms-full.txt
|
|
4
|
+
|
|
5
|
+
This MCP server exposes the Topdesk API using the TOPdeskPy SDK: https://github.com/TwinkelToe/TOPdeskPy
|
|
6
|
+
|
|
7
|
+
Reference the SDK documentation and MCP protocol documentation when generating code for this project.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
on:
|
|
2
|
+
release:
|
|
3
|
+
types: [created]
|
|
4
|
+
|
|
5
|
+
jobs:
|
|
6
|
+
deploy:
|
|
7
|
+
runs-on: ubuntu-latest
|
|
8
|
+
permissions:
|
|
9
|
+
id-token: write
|
|
10
|
+
steps:
|
|
11
|
+
- uses: actions/checkout@v4
|
|
12
|
+
- name: Set up Python
|
|
13
|
+
uses: actions/setup-python@v5
|
|
14
|
+
with:
|
|
15
|
+
python-version: '3.12'
|
|
16
|
+
cache: pip
|
|
17
|
+
cache-dependency-path: '**/pyproject.toml'
|
|
18
|
+
- name: Build
|
|
19
|
+
run: |
|
|
20
|
+
pip install uv
|
|
21
|
+
uv venv
|
|
22
|
+
uv pip install setuptools wheel build
|
|
23
|
+
uv build
|
|
24
|
+
|
|
25
|
+
- name: Publish
|
|
26
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
name: Run Pytest
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
branches: [ master ]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
test:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
steps:
|
|
11
|
+
- name: Checkout code
|
|
12
|
+
uses: actions/checkout@v4
|
|
13
|
+
|
|
14
|
+
- name: Set up Python
|
|
15
|
+
uses: actions/setup-python@v5
|
|
16
|
+
with:
|
|
17
|
+
python-version: '3.12'
|
|
18
|
+
|
|
19
|
+
- name: Run pytest
|
|
20
|
+
run: |
|
|
21
|
+
pip install uv
|
|
22
|
+
uv venv
|
|
23
|
+
uv pip install -e .
|
|
24
|
+
uv pip install -e ".[dev]"
|
|
25
|
+
uv run pytest
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
// Use IntelliSense to learn about possible attributes.
|
|
3
|
+
// Hover to view descriptions of existing attributes.
|
|
4
|
+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
|
5
|
+
"version": "0.2.0",
|
|
6
|
+
"configurations": [
|
|
7
|
+
{
|
|
8
|
+
"name": "Python Debugger: Module",
|
|
9
|
+
"type": "debugpy",
|
|
10
|
+
"request": "launch",
|
|
11
|
+
"module": "topdesk_mcp.main"
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 David Sanftenberg
|
|
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.
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: topdesk-mcp
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: MCP server for TOPdesk API using FastMCP and TOPdeskPy SDK
|
|
5
|
+
License-File: LICENSE
|
|
6
|
+
Requires-Python: >=3.11
|
|
7
|
+
Requires-Dist: fastmcp
|
|
8
|
+
Requires-Dist: requests
|
|
9
|
+
Provides-Extra: dev
|
|
10
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
|
|
11
|
+
Requires-Dist: pytest>=7.0.0; extra == 'dev'
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
|
|
14
|
+
# topdesk-mcp
|
|
15
|
+
|
|
16
|
+
This project is a Model Context Protocol (MCP) server implemented in Python. It exposes the Topdesk API via the TOPdeskPy SDK.
|
|
17
|
+
|
|
18
|
+
## Project Purpose
|
|
19
|
+
- Acts as an MCP server to bridge MCP clients with the Topdesk API.
|
|
20
|
+
- Uses the [TOPdeskPy SDK](https://github.com/TwinkelToe/TOPdeskPy) (with some modifications) for all Topdesk API interactions.
|
|
21
|
+
|
|
22
|
+
## MCP Config JSON
|
|
23
|
+
```
|
|
24
|
+
{
|
|
25
|
+
"servers": {
|
|
26
|
+
"topdesk-mcp": {
|
|
27
|
+
"type": "stdio",
|
|
28
|
+
"command": "uvx",
|
|
29
|
+
"args": [
|
|
30
|
+
"--from",
|
|
31
|
+
"git+https://github.com/dbsanfte/topdesk-mcp@master",
|
|
32
|
+
"topdesk-mcp"
|
|
33
|
+
],
|
|
34
|
+
"env": {
|
|
35
|
+
"TOPDESK_URL": "<your topdesk URL>",
|
|
36
|
+
"TOPDESK_USERNAME": "<your topdesk username>",
|
|
37
|
+
"TOPDESK_PASSWORD": "<your topdesk api key>"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Environment Variables
|
|
45
|
+
* `TOPDESK_URL`: The base URL of your Topdesk instance. e.g. `https://yourcompany.topdesk.net`
|
|
46
|
+
* `TOPDESK_USERNAME`: The username you generated the API token against.
|
|
47
|
+
* `TOPDESK_PASSWORD`: Your API token
|
|
48
|
+
* `TOPDESK_MCP_TRANSPORT`: (Optional) The transport to use: 'stdio', 'streamable-http', 'sse'. Defaults to 'stdio'.
|
|
49
|
+
* `TOPDESK_MCP_HOST`: (Optional) The host to listen on (for 'streamable-http' and 'sse'). Defaults to '0.0.0.0'.
|
|
50
|
+
* `TOPDESK_MCP_PORT`: (Optional) The port to listen on (for 'streamable-http' and 'sse'). Defaults to '3030'.
|
|
51
|
+
|
|
52
|
+
## Setup for Local Development
|
|
53
|
+
1. Ensure Python 3.11+ is installed.
|
|
54
|
+
2. Create and activate a virtual environment:
|
|
55
|
+
|
|
56
|
+
**PowerShell:**
|
|
57
|
+
```powershell
|
|
58
|
+
python -m venv .venv
|
|
59
|
+
.venv\Scripts\Activate.ps1
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**Bash:**
|
|
63
|
+
```bash
|
|
64
|
+
python3 -m venv .venv
|
|
65
|
+
source .venv/bin/activate
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
3. Install dependencies:
|
|
69
|
+
```
|
|
70
|
+
pip install uv
|
|
71
|
+
uv pip install -r requirements.txt
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
4. Run:
|
|
75
|
+
```
|
|
76
|
+
python -m topdesk_mcp.main
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Notes:
|
|
80
|
+
* The server skeleton was generated using the official MCP server template.
|
|
81
|
+
* Contributions are welcome.
|
|
82
|
+
|
|
83
|
+
## Package Structure
|
|
84
|
+
```
|
|
85
|
+
topdesk_mcp/ # Directory for the MCP server package
|
|
86
|
+
__init__.py # Marks as a Python package
|
|
87
|
+
main.py # Entry point for the MCP server
|
|
88
|
+
|
|
89
|
+
_topdesk_sdk.py # TOPdeskPy SDK
|
|
90
|
+
_incident.py # Incidents API
|
|
91
|
+
_operator.py # Operator API
|
|
92
|
+
_person.py # Person API
|
|
93
|
+
_utils.py # Helper methods for Requests
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## References
|
|
97
|
+
- [MCP Protocol Documentation](https://modelcontextprotocol.io/llms-full.txt)
|
|
98
|
+
- [TOPdeskPy SDK](https://github.com/TwinkelToe/TOPdeskPy)
|
|
99
|
+
- [FastMCP](https://github.com/jlowin/fastmcp)
|
|
100
|
+
|
|
101
|
+
## License
|
|
102
|
+
MIT license.
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# topdesk-mcp
|
|
2
|
+
|
|
3
|
+
This project is a Model Context Protocol (MCP) server implemented in Python. It exposes the Topdesk API via the TOPdeskPy SDK.
|
|
4
|
+
|
|
5
|
+
## Project Purpose
|
|
6
|
+
- Acts as an MCP server to bridge MCP clients with the Topdesk API.
|
|
7
|
+
- Uses the [TOPdeskPy SDK](https://github.com/TwinkelToe/TOPdeskPy) (with some modifications) for all Topdesk API interactions.
|
|
8
|
+
|
|
9
|
+
## MCP Config JSON
|
|
10
|
+
```
|
|
11
|
+
{
|
|
12
|
+
"servers": {
|
|
13
|
+
"topdesk-mcp": {
|
|
14
|
+
"type": "stdio",
|
|
15
|
+
"command": "uvx",
|
|
16
|
+
"args": [
|
|
17
|
+
"--from",
|
|
18
|
+
"git+https://github.com/dbsanfte/topdesk-mcp@master",
|
|
19
|
+
"topdesk-mcp"
|
|
20
|
+
],
|
|
21
|
+
"env": {
|
|
22
|
+
"TOPDESK_URL": "<your topdesk URL>",
|
|
23
|
+
"TOPDESK_USERNAME": "<your topdesk username>",
|
|
24
|
+
"TOPDESK_PASSWORD": "<your topdesk api key>"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Environment Variables
|
|
32
|
+
* `TOPDESK_URL`: The base URL of your Topdesk instance. e.g. `https://yourcompany.topdesk.net`
|
|
33
|
+
* `TOPDESK_USERNAME`: The username you generated the API token against.
|
|
34
|
+
* `TOPDESK_PASSWORD`: Your API token
|
|
35
|
+
* `TOPDESK_MCP_TRANSPORT`: (Optional) The transport to use: 'stdio', 'streamable-http', 'sse'. Defaults to 'stdio'.
|
|
36
|
+
* `TOPDESK_MCP_HOST`: (Optional) The host to listen on (for 'streamable-http' and 'sse'). Defaults to '0.0.0.0'.
|
|
37
|
+
* `TOPDESK_MCP_PORT`: (Optional) The port to listen on (for 'streamable-http' and 'sse'). Defaults to '3030'.
|
|
38
|
+
|
|
39
|
+
## Setup for Local Development
|
|
40
|
+
1. Ensure Python 3.11+ is installed.
|
|
41
|
+
2. Create and activate a virtual environment:
|
|
42
|
+
|
|
43
|
+
**PowerShell:**
|
|
44
|
+
```powershell
|
|
45
|
+
python -m venv .venv
|
|
46
|
+
.venv\Scripts\Activate.ps1
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**Bash:**
|
|
50
|
+
```bash
|
|
51
|
+
python3 -m venv .venv
|
|
52
|
+
source .venv/bin/activate
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
3. Install dependencies:
|
|
56
|
+
```
|
|
57
|
+
pip install uv
|
|
58
|
+
uv pip install -r requirements.txt
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
4. Run:
|
|
62
|
+
```
|
|
63
|
+
python -m topdesk_mcp.main
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Notes:
|
|
67
|
+
* The server skeleton was generated using the official MCP server template.
|
|
68
|
+
* Contributions are welcome.
|
|
69
|
+
|
|
70
|
+
## Package Structure
|
|
71
|
+
```
|
|
72
|
+
topdesk_mcp/ # Directory for the MCP server package
|
|
73
|
+
__init__.py # Marks as a Python package
|
|
74
|
+
main.py # Entry point for the MCP server
|
|
75
|
+
|
|
76
|
+
_topdesk_sdk.py # TOPdeskPy SDK
|
|
77
|
+
_incident.py # Incidents API
|
|
78
|
+
_operator.py # Operator API
|
|
79
|
+
_person.py # Person API
|
|
80
|
+
_utils.py # Helper methods for Requests
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## References
|
|
84
|
+
- [MCP Protocol Documentation](https://modelcontextprotocol.io/llms-full.txt)
|
|
85
|
+
- [TOPdeskPy SDK](https://github.com/TwinkelToe/TOPdeskPy)
|
|
86
|
+
- [FastMCP](https://github.com/jlowin/fastmcp)
|
|
87
|
+
|
|
88
|
+
## License
|
|
89
|
+
MIT license.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "topdesk-mcp"
|
|
3
|
+
version = "0.2.0"
|
|
4
|
+
description = "MCP server for TOPdesk API using FastMCP and TOPdeskPy SDK"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.11"
|
|
7
|
+
dependencies = [
|
|
8
|
+
"fastmcp",
|
|
9
|
+
"requests"
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
[build-system]
|
|
13
|
+
requires = ["hatchling"]
|
|
14
|
+
build-backend = "hatchling.build"
|
|
15
|
+
|
|
16
|
+
[tool.uv]
|
|
17
|
+
trusted-hosts = [
|
|
18
|
+
"pypi.org",
|
|
19
|
+
"files.pythonhosted.org"
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
[project.scripts]
|
|
23
|
+
topdesk-mcp = "topdesk_mcp.main:main"
|
|
24
|
+
|
|
25
|
+
[tool.pytest.ini_options]
|
|
26
|
+
testpaths = ["tests"]
|
|
27
|
+
python_files = "test_*.py"
|
|
28
|
+
python_classes = "Test*"
|
|
29
|
+
python_functions = "test_*"
|
|
30
|
+
filterwarnings = [
|
|
31
|
+
"ignore::DeprecationWarning",
|
|
32
|
+
"ignore::PendingDeprecationWarning",
|
|
33
|
+
]
|
|
34
|
+
markers = [
|
|
35
|
+
"integration: marks tests as integration tests",
|
|
36
|
+
"unit: marks tests as unit tests",
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
[project.optional-dependencies]
|
|
40
|
+
dev = [
|
|
41
|
+
"pytest>=7.0.0",
|
|
42
|
+
"pytest-cov>=4.0.0",
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
[tool.coverage.run]
|
|
46
|
+
source = ["topdesk_mcp"]
|
|
47
|
+
omit = ["tests/*", "**/__init__.py"]
|
|
48
|
+
|
|
49
|
+
[tool.coverage.report]
|
|
50
|
+
exclude_lines = [
|
|
51
|
+
"pragma: no cover",
|
|
52
|
+
"def __repr__",
|
|
53
|
+
"raise NotImplementedError",
|
|
54
|
+
"if __name__ == .__main__.:",
|
|
55
|
+
"pass",
|
|
56
|
+
]
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
from topdesk_mcp import _utils
|
|
2
|
+
import re
|
|
3
|
+
import logging
|
|
4
|
+
|
|
5
|
+
class incident:
|
|
6
|
+
|
|
7
|
+
def __init__(self, topdesk_url, credpair):
|
|
8
|
+
self._topdesk_url = topdesk_url
|
|
9
|
+
self._credpair = credpair
|
|
10
|
+
self.utils = _utils.utils(self._topdesk_url, self._credpair)
|
|
11
|
+
self.action = self._action(self._topdesk_url, self._credpair)
|
|
12
|
+
self.request = self._request(self._topdesk_url, self._credpair)
|
|
13
|
+
self.timespent = self._timespent(self._topdesk_url, self._credpair)
|
|
14
|
+
self._logger = logging.getLogger(__name__)
|
|
15
|
+
self._logger.debug("Incident class initialized with URL: %s", self._topdesk_url)
|
|
16
|
+
self._logger.debug("Incident class initialized with credentials: %s", self._credpair)
|
|
17
|
+
|
|
18
|
+
def get(self, incident):
|
|
19
|
+
if self.utils.is_valid_uuid(incident):
|
|
20
|
+
return self.utils.handle_topdesk_response(self.utils.request_topdesk("/tas/api/incidents/id/{}".format(incident)))
|
|
21
|
+
else:
|
|
22
|
+
return self.utils.handle_topdesk_response(self.utils.request_topdesk("/tas/api/incidents/number/{}".format(incident)))
|
|
23
|
+
|
|
24
|
+
def deescalate(self, incident, reason_id=None):
|
|
25
|
+
if reason_id:
|
|
26
|
+
param = {'id': reason_id}
|
|
27
|
+
if self.utils.is_valid_uuid(incident):
|
|
28
|
+
return self.utils.handle_topdesk_response(self.utils.put_to_topdesk("/tas/api/incidents/id/{}/deescalate".format(incident), param))
|
|
29
|
+
else:
|
|
30
|
+
return self.utils.handle_topdesk_response(self.utils.put_to_topdesk("/tas/api/incidents/number/{}/deescalate".format(incident), param))
|
|
31
|
+
|
|
32
|
+
def escalate(self, incident, reason_id=None):
|
|
33
|
+
if reason_id:
|
|
34
|
+
param = {'id': reason_id}
|
|
35
|
+
if self.utils.is_valid_uuid(incident):
|
|
36
|
+
return self.utils.handle_topdesk_response(self.utils.put_to_topdesk("/tas/api/incidents/id/{}/escalate".format(incident), param))
|
|
37
|
+
else:
|
|
38
|
+
return self.utils.handle_topdesk_response(self.utils.put_to_topdesk("/tas/api/incidents/number/{}/escalate".format(incident), param))
|
|
39
|
+
|
|
40
|
+
def get_progress_trail(self, incident, inlineimages=False, non_api_attachments_url=False, page_size=100):
|
|
41
|
+
ext_uri= { 'inlineimages': inlineimages, 'non_api_attachments_url': non_api_attachments_url }
|
|
42
|
+
if self.utils.is_valid_uuid(incident):
|
|
43
|
+
return self.utils.handle_topdesk_response(self.utils.request_topdesk("/tas/api/incidents/id/{}/progresstrail".format(incident), page_size=page_size, extended_uri=ext_uri))
|
|
44
|
+
else:
|
|
45
|
+
return self.utils.handle_topdesk_response(self.utils.request_topdesk("/tas/api/incidents/number/{}/progresstrail".format(incident), page_size=page_size, extended_uri=ext_uri))
|
|
46
|
+
|
|
47
|
+
def patch(self, incident, **kwargs):
|
|
48
|
+
if self.utils.is_valid_uuid(incident):
|
|
49
|
+
return self.utils.handle_topdesk_response(self.utils.patch_to_topdesk("/tas/api/incidents/id/{}".format(incident), self.utils.add_id_jsonbody(**kwargs)))
|
|
50
|
+
else:
|
|
51
|
+
return self.utils.handle_topdesk_response(self.utils.patch_to_topdesk("/tas/api/incidents/number/{}".format(incident), self.utils.add_id_jsonbody(**kwargs)))
|
|
52
|
+
|
|
53
|
+
class _action:
|
|
54
|
+
|
|
55
|
+
def __init__(self, topdesk_url, credpair):
|
|
56
|
+
self._topdesk_url = topdesk_url
|
|
57
|
+
self._credpair = credpair
|
|
58
|
+
self.utils = _utils.utils(self._topdesk_url, self._credpair)
|
|
59
|
+
self._logger = logging.getLogger(__name__)
|
|
60
|
+
self._logger.debug("TOPdesk API action object initialised.")
|
|
61
|
+
|
|
62
|
+
def get_list(self, incident, inlineimages=False, non_api_attachments_url=False, page_size=100):
|
|
63
|
+
ext_uri= { 'inlineimages': inlineimages, 'non_api_attachments_url': non_api_attachments_url }
|
|
64
|
+
if self.utils.is_valid_uuid(incident):
|
|
65
|
+
return self.utils.handle_topdesk_response(self.utils.request_topdesk("/tas/api/incidents/id/{}/actions".format(incident), page_size=page_size, extended_uri=ext_uri))
|
|
66
|
+
else:
|
|
67
|
+
return self.utils.handle_topdesk_response(self.utils.request_topdesk("/tas/api/incidents/number/{}/actions".format(incident), page_size=page_size, extended_uri=ext_uri))
|
|
68
|
+
|
|
69
|
+
def get(self, incident, actions_id, inlineimages=False, non_api_attachments_url=False):
|
|
70
|
+
ext_uri= { 'inlineimages': inlineimages, 'non_api_attachments_url': non_api_attachments_url }
|
|
71
|
+
if self.utils.is_valid_uuid(incident):
|
|
72
|
+
return self.utils.handle_topdesk_response(self.utils.request_topdesk("/tas/api/incidents/id/{}/actions/{}".format(incident, actions_id), page_size=10, extended_uri=ext_uri))
|
|
73
|
+
else:
|
|
74
|
+
return self.utils.handle_topdesk_response(self.utils.request_topdesk("/tas/api/incidents/number/{}/actions/{}".format(incident, actions_id), page_size=10, extended_uri=ext_uri))
|
|
75
|
+
|
|
76
|
+
def delete(self, incident, actions_id):
|
|
77
|
+
if self.utils.is_valid_uuid(incident):
|
|
78
|
+
return self.utils.handle_topdesk_response(self.utils.delete_from_topdesk("/tas/api/incidents/id/{}/actions/{}".format(incident, actions_id), None))
|
|
79
|
+
else:
|
|
80
|
+
return self.utils.handle_topdesk_response(self.utils.delete_from_topdesk("/tas/api/incidents/number/{}/actions/{}".format(incident, actions_id), None))
|
|
81
|
+
|
|
82
|
+
class _request:
|
|
83
|
+
|
|
84
|
+
def __init__(self, topdesk_url, credpair):
|
|
85
|
+
self._topdesk_url = topdesk_url
|
|
86
|
+
self._credpair = credpair
|
|
87
|
+
self.utils = _utils.utils(self._topdesk_url, self._credpair)
|
|
88
|
+
self._logger = logging.getLogger(__name__)
|
|
89
|
+
self._logger.debug("TOPdesk API request object initialised.")
|
|
90
|
+
|
|
91
|
+
def get_list(self, incident, inlineimages=False, non_api_attachments_url=False, page_size=100):
|
|
92
|
+
ext_uri= { 'inlineimages': inlineimages, 'non_api_attachments_url': non_api_attachments_url }
|
|
93
|
+
if self.utils.is_valid_uuid(incident):
|
|
94
|
+
return self.utils.handle_topdesk_response(self.utils.request_topdesk("/tas/api/incidents/id/{}/requests".format(incident), page_size=page_size, extended_uri=ext_uri))
|
|
95
|
+
else:
|
|
96
|
+
return self.utils.handle_topdesk_response(self.utils.request_topdesk("/tas/api/incidents/number/{}/requests".format(incident), page_size=page_size, extended_uri=ext_uri))
|
|
97
|
+
|
|
98
|
+
def get(self, incident, request_id, inlineimages=False, non_api_attachments_url=False):
|
|
99
|
+
ext_uri= { 'inlineimages': inlineimages, 'non_api_attachments_url': non_api_attachments_url }
|
|
100
|
+
if self.utils.is_valid_uuid(incident):
|
|
101
|
+
return self.utils.handle_topdesk_response(self.utils.request_topdesk("/tas/api/incidents/id/{}/actions/{}".format(incident, request_id), page_size=10, extended_uri=ext_uri))
|
|
102
|
+
else:
|
|
103
|
+
return self.utils.handle_topdesk_response(self.utils.request_topdesk("/tas/api/incidents/number/{}/actions/{}".format(incident, request_id), page_size=10, extended_uri=ext_uri))
|
|
104
|
+
|
|
105
|
+
def delete(self, incident, request_id):
|
|
106
|
+
if self.utils.is_valid_uuid(incident):
|
|
107
|
+
return self.utils.handle_topdesk_response(self.utils.delete_from_topdesk("/tas/api/incidents/id/{}/actions/{}".format(incident, request_id), None))
|
|
108
|
+
else:
|
|
109
|
+
return self.utils.handle_topdesk_response(self.utils.delete_from_topdesk("/tas/api/incidents/number/{}/actions/{}".format(incident, request_id), None))
|
|
110
|
+
|
|
111
|
+
class _timespent:
|
|
112
|
+
|
|
113
|
+
def __init__(self, topdesk_url, credpair):
|
|
114
|
+
self._topdesk_url = topdesk_url
|
|
115
|
+
self._credpair = credpair
|
|
116
|
+
self.utils = _utils.utils(self._topdesk_url, self._credpair)
|
|
117
|
+
self._logger = logging.getLogger(__name__)
|
|
118
|
+
self._logger.debug("TOPdesk API timespent object initialised.")
|
|
119
|
+
|
|
120
|
+
def get(self, incident):
|
|
121
|
+
if self.utils.is_valid_uuid(incident):
|
|
122
|
+
return self.utils.handle_topdesk_response(self.utils.request_topdesk("/tas/api/incidents/id/{}/timespent".format(incident)))
|
|
123
|
+
else:
|
|
124
|
+
return self.utils.handle_topdesk_response(self.utils.request_topdesk("/tas/api/incidents/number/{}/timespent".format(incident)))
|
|
125
|
+
|
|
126
|
+
def register(self, incident, timespent, **kwargs):
|
|
127
|
+
param = {}
|
|
128
|
+
if kwargs:
|
|
129
|
+
param = kwargs
|
|
130
|
+
param['timespent'] = timespent
|
|
131
|
+
if self.utils.is_valid_uuid(incident):
|
|
132
|
+
return self.utils.handle_topdesk_response(self.utils.post_to_topdesk("/tas/api/incidents/id/{}/timespent".format(incident), param))
|
|
133
|
+
else:
|
|
134
|
+
return self.utils.handle_topdesk_response(self.utils.post_to_topdesk("/tas/api/incidents/number/{}/timespent".format(incident), param))
|
|
135
|
+
|
|
136
|
+
def durations(self):
|
|
137
|
+
return self.utils.handle_topdesk_response(self.utils.request_topdesk("/tas/api/incidents/durations"))
|
|
138
|
+
|
|
139
|
+
def statuses(self):
|
|
140
|
+
return self.utils.handle_topdesk_response(self.utils.request_topdesk("/tas/api/incidents/statuses"))
|
|
141
|
+
|
|
142
|
+
def deescalation_reasons(self):
|
|
143
|
+
return self.utils.handle_topdesk_response(self.utils.request_topdesk("/tas/api/incidents/deescalation-reasons"))
|
|
144
|
+
|
|
145
|
+
def escalation_reasons(self):
|
|
146
|
+
return self.utils.handle_topdesk_response(self.utils.request_topdesk("/tas/api/incidents/escalation-reasons"))
|
|
147
|
+
|
|
148
|
+
def service_windows(self):
|
|
149
|
+
return self.utils.handle_topdesk_response(self.utils.request_topdesk("/tas/api/incidents/slas/services"))
|
|
150
|
+
|
|
151
|
+
def call_types(self):
|
|
152
|
+
return self.utils.handle_topdesk_response(self.utils.request_topdesk("/tas/api/incidents/call_types"))
|
|
153
|
+
|
|
154
|
+
def closure_codes(self):
|
|
155
|
+
return self.utils.handle_topdesk_response(self.utils.request_topdesk("/tas/api/incidents/closure_codes"))
|
|
156
|
+
|
|
157
|
+
def entry_types(self):
|
|
158
|
+
return self.utils.handle_topdesk_response(self.utils.request_topdesk("/tas/api/incidents/entry_types"))
|
|
159
|
+
|
|
160
|
+
def categorys(self):
|
|
161
|
+
return self.utils.handle_topdesk_response(self.utils.request_topdesk("/tas/api/incidents/categories"))
|
|
162
|
+
|
|
163
|
+
def subcategorys(self):
|
|
164
|
+
return self.utils.handle_topdesk_response(self.utils.request_topdesk("/tas/api/incidents/subcategories"))
|
|
165
|
+
|
|
166
|
+
def impacts(self):
|
|
167
|
+
return self.utils.handle_topdesk_response(self.utils.request_topdesk("/tas/api/incidents/impacts"))
|
|
168
|
+
|
|
169
|
+
def priorities(self):
|
|
170
|
+
return self.utils.handle_topdesk_response(self.utils.request_topdesk("/tas/api/incidents/priorities"))
|
|
171
|
+
|
|
172
|
+
def urgencies(self):
|
|
173
|
+
return self.utils.handle_topdesk_response(self.utils.request_topdesk("/tas/api/incidents/urgencies"))
|
|
174
|
+
|
|
175
|
+
def get_id_impact(self, query):
|
|
176
|
+
result = self.impacts()
|
|
177
|
+
canidates = list()
|
|
178
|
+
for impact in result:
|
|
179
|
+
if re.match(rf"(.+)?{query}(.+)?", impact['name'], re.IGNORECASE):
|
|
180
|
+
canidates.append(impact['id'])
|
|
181
|
+
|
|
182
|
+
return self.utils.resolve_lookup_candidates(canidates)
|
|
183
|
+
|
|
184
|
+
def get_id_priority(self, query):
|
|
185
|
+
result = self.priorities()
|
|
186
|
+
canidates = list()
|
|
187
|
+
for priority in result:
|
|
188
|
+
if re.match(rf"(.+)?{query}(.+)?", priority['name'], re.IGNORECASE):
|
|
189
|
+
canidates.append(priority['id'])
|
|
190
|
+
|
|
191
|
+
return self.utils.resolve_lookup_candidates(canidates)
|
|
192
|
+
|
|
193
|
+
def get_id_urgency(self, query):
|
|
194
|
+
result = self.urgencies()
|
|
195
|
+
canidates = list()
|
|
196
|
+
for urgency in result:
|
|
197
|
+
if re.match(rf"(.+)?{query}(.+)?", urgency['name'], re.IGNORECASE):
|
|
198
|
+
canidates.append(urgency['id'])
|
|
199
|
+
|
|
200
|
+
return self.utils.resolve_lookup_candidates(canidates)
|
|
201
|
+
|
|
202
|
+
def get_id_entryType(self, query):
|
|
203
|
+
result = self.entry_types()
|
|
204
|
+
canidates = list()
|
|
205
|
+
for entryType in result:
|
|
206
|
+
if re.match(rf"(.+)?{query}(.+)?", entryType['name'], re.IGNORECASE):
|
|
207
|
+
canidates.append(entryType['id'])
|
|
208
|
+
|
|
209
|
+
return self.utils.resolve_lookup_candidates(canidates)
|
|
210
|
+
|
|
211
|
+
def get_id_callType(self, query):
|
|
212
|
+
result = self.call_types()
|
|
213
|
+
canidates = list()
|
|
214
|
+
for callType in result:
|
|
215
|
+
if re.match(rf"(.+)?{query}(.+)?", callType['name'], re.IGNORECASE):
|
|
216
|
+
canidates.append(callType['id'])
|
|
217
|
+
|
|
218
|
+
return self.utils.resolve_lookup_candidates(canidates)
|
|
219
|
+
|
|
220
|
+
def get_id_duration(self, query):
|
|
221
|
+
result = self.durations()
|
|
222
|
+
canidates = list()
|
|
223
|
+
for callType in result:
|
|
224
|
+
if re.match(rf"(.+)?{query}(.+)?", callType['name'], re.IGNORECASE):
|
|
225
|
+
canidates.append(callType['id'])
|
|
226
|
+
|
|
227
|
+
return self.utils.resolve_lookup_candidates(canidates)
|
|
228
|
+
|
|
229
|
+
def create(self, caller, **kwargs):
|
|
230
|
+
# Caller can be: email, uuid or unregisted user. We'll try it in that order.
|
|
231
|
+
create_body = kwargs
|
|
232
|
+
create_body['caller'] = caller
|
|
233
|
+
return self.utils.handle_topdesk_response(self.utils.post_to_topdesk("/tas/api/incidents/", self.utils.add_id_jsonbody(**create_body)))
|
|
234
|
+
|
|
235
|
+
def update(self, incident, **kwargs):
|
|
236
|
+
if self.utils.is_valid_uuid(incident):
|
|
237
|
+
return self.utils.handle_topdesk_response(self.utils.put_to_topdesk("/tas/api/incidents/id/{}".format(incident), self.utils.add_id_jsonbody(**kwargs)))
|
|
238
|
+
else:
|
|
239
|
+
return self.utils.handle_topdesk_response(self.utils.put_to_topdesk("/tas/api/incidents/number/{}".format(incident), self.utils.add_id_jsonbody(**kwargs)))
|
|
240
|
+
|
|
241
|
+
def archive(self, incident, reason_id=None):
|
|
242
|
+
if reason_id:
|
|
243
|
+
param = {'id': reason_id}
|
|
244
|
+
if self.utils.is_valid_uuid(incident):
|
|
245
|
+
return self.utils.handle_topdesk_response(self.utils.put_to_topdesk("/tas/api/incidents/id/{}/archive".format(incident), param))
|
|
246
|
+
else:
|
|
247
|
+
return self.utils.handle_topdesk_response(self.utils.put_to_topdesk("/tas/api/incidents/number/{}/archive".format(incident), param))
|
|
248
|
+
|
|
249
|
+
def unarchive(self, incident):
|
|
250
|
+
if self.utils.is_valid_uuid(incident):
|
|
251
|
+
return self.utils.handle_topdesk_response(self.utils.put_to_topdesk("/tas/api/incidents/id/{}/unarchive".format(incident), None))
|
|
252
|
+
else:
|
|
253
|
+
return self.utils.handle_topdesk_response(self.utils.put_to_topdesk("/tas/api/incidents/number/{}/unarchive".format(incident), None))
|
|
254
|
+
|
|
255
|
+
def get_list(self, archived=False, page_size=100, query=None, **kwargs):
|
|
256
|
+
return self.utils.handle_topdesk_response(self.utils.request_topdesk("/tas/api/incidents/", archived, page_size=page_size, query=query, extended_uri=kwargs))
|