Skip to content

Commit

Permalink
feat: add support for uptime kuma 1.21.0
Browse files Browse the repository at this point in the history
  • Loading branch information
lucasheld committed Mar 20, 2023
1 parent 550be17 commit 42c040f
Show file tree
Hide file tree
Showing 8 changed files with 329 additions and 12 deletions.
2 changes: 1 addition & 1 deletion run_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ if [ $version ]
then
versions=("$version")
else
versions=(1.20.0 1.19.6 1.18.5 1.17.1)
versions=(1.21.0 1.20.2 1.19.6 1.18.5 1.17.1)
fi

for version in ${versions[*]}
Expand Down
62 changes: 62 additions & 0 deletions tests/test_api_key.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import unittest
from packaging.version import parse as parse_version

from uptime_kuma_api import DockerType, UptimeKumaException
from uptime_kuma_test_case import UptimeKumaTestCase


class TestApiKey(UptimeKumaTestCase):
def setUp(self):
super(TestApiKey, self).setUp()
if parse_version(self.api.version) < parse_version("1.21"):
super(TestApiKey, self).tearDown()
self.skipTest("Unsupported in this Uptime Kuma version")

def test_api_key(self):
# get empty list to make sure that future accesses will also work
self.api.get_api_keys()

expected = {
"name": "name 1",
"expires": "2023-03-30 12:20:00",
"active": True
}

# add api key
r = self.api.add_api_key(**expected)
self.assertEqual(r["msg"], "Added Successfully.")
api_key_id = r["keyID"]

# get api key
api_key = self.api.get_api_key(api_key_id)
self.compare(api_key, expected)

# get api keys
api_keys = self.api.get_api_keys()
api_key = self.find_by_id(api_keys, api_key_id)
self.assertIsNotNone(api_key)
self.compare(api_key, expected)

# disable api key
r = self.api.disable_api_key(api_key_id)
self.assertEqual(r["msg"], "Disabled Successfully.")
api_key = self.api.get_api_key(api_key_id)
expected["active"] = False
self.compare(api_key, expected)

# enable api key
r = self.api.enable_api_key(api_key_id)
self.assertEqual(r["msg"], "Enabled Successfully")
api_key = self.api.get_api_key(api_key_id)
expected["active"] = True
self.compare(api_key, expected)

# delete api key
r = self.api.delete_api_key(api_key_id)
self.assertEqual(r["msg"], "Deleted Successfully.")
with self.assertRaises(UptimeKumaException):
self.api.get_api_key(api_key_id)


if __name__ == '__main__':
unittest.main()
12 changes: 12 additions & 0 deletions tests/test_monitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,18 @@ def test_monitor_auth_method(self):
}
self.do_test_monitor_type(expected_monitor)

if parse_version(self.api.version) >= parse_version("1.21"):
expected_monitor = {
"type": MonitorType.HTTP,
"name": "monitor 1",
"url": "http://127.0.0.1",
"authMethod": AuthMethod.MTLS,
"tlsCert": "cert",
"tlsKey": "key",
"tlsCa": "ca",
}
self.do_test_monitor_type(expected_monitor)

def test_monitor_type_port(self):
expected_monitor = {
"type": MonitorType.PORT,
Expand Down
210 changes: 205 additions & 5 deletions uptime_kuma_api/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,8 @@ def __init__(
Event.CERT_INFO: None,
Event.DOCKER_HOST_LIST: None,
Event.AUTO_LOGIN: None,
Event.MAINTENANCE_LIST: None
Event.MAINTENANCE_LIST: None,
Event.API_KEY_LIST: None
}

self.sio.on(Event.CONNECT, self._event_connect)
Expand All @@ -444,6 +445,7 @@ def __init__(
self.sio.on(Event.AUTO_LOGIN, self._event_auto_login)
self.sio.on(Event.INIT_SERVER_TIMEZONE, self._event_init_server_timezone)
self.sio.on(Event.MAINTENANCE_LIST, self._event_maintenance_list)
self.sio.on(Event.API_KEY_LIST, self._event_api_key_list)

self.connect()

Expand Down Expand Up @@ -566,6 +568,9 @@ def _event_init_server_timezone(self) -> None:
def _event_maintenance_list(self, data) -> None:
self._event_data[Event.MAINTENANCE_LIST] = data

def _event_api_key_list(self, data) -> None:
self._event_data[Event.API_KEY_LIST] = data

# connection

def connect(self) -> None:
Expand Down Expand Up @@ -601,12 +606,14 @@ def _build_monitor_data(
self,
type: MonitorType,
name: str,
description: str = None,
interval: int = 60,
retryInterval: int = 60,
resendInterval: int = 0,
maxretries: int = 0,
upsideDown: bool = False,
notificationIDList: list = None,
httpBodyEncoding: str = "json",

# HTTP, KEYWORD
url: str = None,
Expand All @@ -619,6 +626,9 @@ def _build_monitor_data(
body: str = None,
headers: str = None,
authMethod: AuthMethod = AuthMethod.NONE,
tlsCert: str = None,
tlsKey: str = None,
tlsCa: str = None,
basic_auth_user: str = None,
basic_auth_pass: str = None,
authDomain: str = None,
Expand Down Expand Up @@ -690,6 +700,12 @@ def _build_monitor_data(
"resendInterval": resendInterval
})

if parse_version(self.version) >= parse_version("1.21"):
data.update({
"description": description,
"httpBodyEncoding": httpBodyEncoding
})

if type in [MonitorType.KEYWORD, MonitorType.GRPC_KEYWORD]:
data.update({
"keyword": keyword,
Expand Down Expand Up @@ -721,6 +737,13 @@ def _build_monitor_data(
"authWorkstation": authWorkstation,
})

if authMethod == AuthMethod.MTLS:
data.update({
"tlsCert": tlsCert,
"tlsKey": tlsKey,
"tlsCa": tlsCa,
})

# GRPC_KEYWORD
if type == MonitorType.GRPC_KEYWORD:
data.update({
Expand Down Expand Up @@ -878,6 +901,9 @@ def get_monitors(self) -> list:
}
]
"""

# TODO: replace with getMonitorList?

r = list(self._get_event_data(Event.MONITOR_LIST).values())
for monitor in r:
_convert_monitor_return(monitor)
Expand Down Expand Up @@ -1095,7 +1121,10 @@ def get_game_list(self) -> list:
]
"""
r = self._call('getGameList')
if not r: # workaround, gamelist is not available on first call. TODO: remove when fixed
# Workaround, gamelist is not available on first call.
# Fixed in https://github.com/louislam/uptime-kuma/commit/7b8ed01f272fc4c6b69ff6299185e936a5e63735
# Exists in 1.20.0 - 1.21.0
if not r:
r = self._call('getGameList')
return r["gameList"]

Expand Down Expand Up @@ -2781,12 +2810,14 @@ def delete_docker_host(self, id_: int) -> dict:
with self.wait_for_event(Event.DOCKER_HOST_LIST):
return self._call('deleteDockerHost', id_)

# maintenance

def get_maintenances(self) -> list:
"""
Get all maintenances.
:return: All maintenances.
:rtype: dict
:rtype: list
:raises UptimeKumaException: If the server returns an error.
Example::
Expand Down Expand Up @@ -3176,7 +3207,7 @@ def get_monitor_maintenance(self, id_: int) -> list:
:param int id_: Id of the maintenance to get the monitors from.
:return: All monitors of the maintenance.
:rtype: dict
:rtype: list
:raises UptimeKumaException: If the server returns an error.
Example::
Expand Down Expand Up @@ -3234,7 +3265,7 @@ def get_status_page_maintenance(self, id_: int) -> list:
:param int id_: Id of the maintenance to get the status pages from.
:return: All status pages of the maintenance.
:rtype: dict
:rtype: list
:raises UptimeKumaException: If the server returns an error.
Example::
Expand Down Expand Up @@ -3281,3 +3312,172 @@ def add_status_page_maintenance(
}
"""
return self._call('addMaintenanceStatusPage', (id_, status_pages))

# api key

def get_api_keys(self) -> list:
"""
Get all api keys.
:return: All api keys.
:rtype: list
:raises UptimeKumaException: If the server returns an error.
Example::
>>> api.get_api_key_list()
[
{
"id": 1,
"name": "test",
"userID": 1,
"createdDate": "2023-03-20 11:15:05",
"active": False,
"expires": null,
"status": "inactive"
},
{
"id": 2,
"name": "test2",
"userID": 1,
"createdDate": "2023-03-20 11:20:29",
"active": True,
"expires": "2023-03-30 12:20:00",
"status": "active"
}
]
"""

# TODO: replace with getAPIKeyList?

r = self._get_event_data(Event.API_KEY_LIST)
int_to_bool(r, ["active"])
return r

def get_api_key(self, id_: int) -> dict:
"""
Get an api key.
:param int id_: Id of the api key to get.
:return: The api key.
:rtype: dict
:raises UptimeKumaException: If the api key does not exist.
Example::
>>> api.get_api_key(1)
{
"id": 1,
"name": "test",
"userID": 1,
"createdDate": "2023-03-20 11:15:05",
"active": False,
"expires": null,
"status": "inactive"
}
"""
api_keys = self.get_api_keys()
for api_key in api_keys:
if api_key["id"] == id_:
return api_key
raise UptimeKumaException("notification does not exist")

def add_api_key(self, name: str, expires: str, active: bool) -> dict:
"""
Adds a new api key.
:param str name: Name of the api key.
:param str expires: Expiration date of the api key. Set to ``None`` to disable expiration.
:param bool active: True to activate api key.
:return: The server response.
:rtype: dict
:raises UptimeKumaException: If the server returns an error.
Example::
>>> api.add_api_key(
... name="test",
... expires="2023-03-30 12:20:00",
... active=True
... )
{
"msg": "Added Successfully.",
"key": "uk1_9XPRjV7ilGj9CvWRKYiBPq9GLtQs74UzTxKfCxWY",
"keyID": 1
}
>>> api.add_api_key(
... name="test2",
... expires=None,
... active=True
... )
{
"msg": "Added Successfully.",
"key": "uk2_jsB9H1Zmt9eEjycNFMTKgse1B0Vfvb944H4_aRqW",
"keyID": 2
}
"""
data = {
"name": name,
"expires": expires,
"active": 1 if active else 0
}
with self.wait_for_event(Event.API_KEY_LIST):
return self._call('addAPIKey', data)

def enable_api_key(self, id_: int) -> dict:
"""
Enable an api key.
:param int id_: Id of the api key to enable.
:return: The server response.
:rtype: dict
:raises UptimeKumaException: If the server returns an error.
Example::
>>> api.enable_api_key(1)
{
"msg": "Enabled Successfully"
}
"""
with self.wait_for_event(Event.API_KEY_LIST):
return self._call('enableAPIKey', id_)

def disable_api_key(self, id_: int) -> dict:
"""
Disable an api key.
:param int id_: Id of the api key to disable.
:return: The server response.
:rtype: dict
:raises UptimeKumaException: If the server returns an error.
Example::
>>> api.disable_api_key(1)
{
"msg": "Disabled Successfully."
}
"""
with self.wait_for_event(Event.API_KEY_LIST):
return self._call('disableAPIKey', id_)

def delete_api_key(self, id_: int) -> dict:
"""
Enable an api key.
:param int id_: Id of the api key to delete.
:return: The server response.
:rtype: dict
:raises UptimeKumaException: If the server returns an error.
Example::
>>> api.delete_api_key(1)
{
"msg": "Deleted Successfully."
}
"""
with self.wait_for_event(Event.API_KEY_LIST):
return self._call('deleteAPIKey', id_)
Loading

0 comments on commit 42c040f

Please sign in to comment.