uiprotect 5.2.2__py3-none-any.whl → 5.4.0__py3-none-any.whl
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.
Potentially problematic release.
This version of uiprotect might be problematic. Click here for more details.
- uiprotect/api.py +21 -23
- uiprotect/data/types.py +25 -0
- uiprotect/data/user.py +2 -2
- uiprotect/utils.py +28 -12
- {uiprotect-5.2.2.dist-info → uiprotect-5.4.0.dist-info}/METADATA +1 -1
- {uiprotect-5.2.2.dist-info → uiprotect-5.4.0.dist-info}/RECORD +9 -9
- {uiprotect-5.2.2.dist-info → uiprotect-5.4.0.dist-info}/LICENSE +0 -0
- {uiprotect-5.2.2.dist-info → uiprotect-5.4.0.dist-info}/WHEEL +0 -0
- {uiprotect-5.2.2.dist-info → uiprotect-5.4.0.dist-info}/entry_points.txt +0 -0
uiprotect/api.py
CHANGED
|
@@ -1401,21 +1401,20 @@ class ProtectApiClient(BaseApiClient):
|
|
|
1401
1401
|
|
|
1402
1402
|
Datetime of screenshot is approximate. It may be +/- a few seconds.
|
|
1403
1403
|
"""
|
|
1404
|
-
params = {
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1404
|
+
params: dict[str, Any] = {}
|
|
1405
|
+
if dt is not None:
|
|
1406
|
+
path = "recording-snapshot"
|
|
1407
|
+
params["ts"] = to_js_time(dt)
|
|
1408
|
+
else:
|
|
1409
|
+
path = "snapshot"
|
|
1410
|
+
params["ts"] = int(time.time() * 1000)
|
|
1411
|
+
params["force"] = "true"
|
|
1408
1412
|
|
|
1409
1413
|
if width is not None:
|
|
1410
|
-
params
|
|
1414
|
+
params["w"] = width
|
|
1411
1415
|
|
|
1412
1416
|
if height is not None:
|
|
1413
|
-
params
|
|
1414
|
-
|
|
1415
|
-
path = "snapshot"
|
|
1416
|
-
if dt is not None:
|
|
1417
|
-
path = "recording-snapshot"
|
|
1418
|
-
del params["force"]
|
|
1417
|
+
params["h"] = height
|
|
1419
1418
|
|
|
1420
1419
|
return await self.api_request_raw(
|
|
1421
1420
|
f"cameras/{camera_id}/{path}",
|
|
@@ -1435,22 +1434,21 @@ class ProtectApiClient(BaseApiClient):
|
|
|
1435
1434
|
|
|
1436
1435
|
Datetime of screenshot is approximate. It may be +/- a few seconds.
|
|
1437
1436
|
"""
|
|
1438
|
-
params = {
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1437
|
+
params: dict[str, Any] = {}
|
|
1438
|
+
if dt is not None:
|
|
1439
|
+
path = "recording-snapshot"
|
|
1440
|
+
params["ts"] = to_js_time(dt)
|
|
1441
|
+
params["lens"] = 2
|
|
1442
|
+
else:
|
|
1443
|
+
path = "package-snapshot"
|
|
1444
|
+
params["ts"] = int(time.time() * 1000)
|
|
1445
|
+
params["force"] = "true"
|
|
1442
1446
|
|
|
1443
1447
|
if width is not None:
|
|
1444
|
-
params
|
|
1448
|
+
params["w"] = width
|
|
1445
1449
|
|
|
1446
1450
|
if height is not None:
|
|
1447
|
-
params
|
|
1448
|
-
|
|
1449
|
-
path = "package-snapshot"
|
|
1450
|
-
if dt is not None:
|
|
1451
|
-
path = "recording-snapshot"
|
|
1452
|
-
del params["force"]
|
|
1453
|
-
params.update({"lens": 2})
|
|
1451
|
+
params["h"] = height
|
|
1454
1452
|
|
|
1455
1453
|
return await self.api_request_raw(
|
|
1456
1454
|
f"cameras/{camera_id}/{path}",
|
uiprotect/data/types.py
CHANGED
|
@@ -49,6 +49,11 @@ class ValuesEnumMixin:
|
|
|
49
49
|
_values: list[str] | None = None
|
|
50
50
|
_values_normalized: dict[str, str] | None = None
|
|
51
51
|
|
|
52
|
+
@classmethod
|
|
53
|
+
@cache
|
|
54
|
+
def from_string(cls, value: str) -> Any:
|
|
55
|
+
return cls(value) # type: ignore[call-arg]
|
|
56
|
+
|
|
52
57
|
@classmethod
|
|
53
58
|
@cache
|
|
54
59
|
def values(cls) -> list[str]:
|
|
@@ -111,6 +116,16 @@ class ModelType(str, UnknownValuesEnumMixin, enum.Enum):
|
|
|
111
116
|
"""Return the devices key."""
|
|
112
117
|
return f"{self.value}s"
|
|
113
118
|
|
|
119
|
+
@cached_property
|
|
120
|
+
def name(self) -> str:
|
|
121
|
+
"""Return the name."""
|
|
122
|
+
return self._name_
|
|
123
|
+
|
|
124
|
+
@cached_property
|
|
125
|
+
def value(self) -> str:
|
|
126
|
+
"""Return the value."""
|
|
127
|
+
return self._value_
|
|
128
|
+
|
|
114
129
|
@classmethod
|
|
115
130
|
@cache
|
|
116
131
|
def from_string(cls, value: str) -> ModelType:
|
|
@@ -575,6 +590,16 @@ class PermissionNode(str, UnknownValuesEnumMixin, enum.Enum):
|
|
|
575
590
|
READ_LIVE = "readlive"
|
|
576
591
|
UNKNOWN = "unknown"
|
|
577
592
|
|
|
593
|
+
@cached_property
|
|
594
|
+
def name(self) -> str:
|
|
595
|
+
"""Return the name."""
|
|
596
|
+
return self._name_
|
|
597
|
+
|
|
598
|
+
@cached_property
|
|
599
|
+
def value(self) -> str:
|
|
600
|
+
"""Return the value."""
|
|
601
|
+
return self._value_
|
|
602
|
+
|
|
578
603
|
|
|
579
604
|
@enum.unique
|
|
580
605
|
class HDRMode(str, UnknownValuesEnumMixin, enum.Enum):
|
uiprotect/data/user.py
CHANGED
|
@@ -210,7 +210,7 @@ class User(ProtectModelWithId):
|
|
|
210
210
|
) -> bool:
|
|
211
211
|
"""Checks if a user can do a specific action"""
|
|
212
212
|
check_self = False
|
|
213
|
-
if model
|
|
213
|
+
if model is self.model and obj is not None and obj.id == self.id:
|
|
214
214
|
perm_str = f"{model.value}:{node.value}:$"
|
|
215
215
|
check_self = True
|
|
216
216
|
else:
|
|
@@ -221,7 +221,7 @@ class User(ProtectModelWithId):
|
|
|
221
221
|
return self._perm_cache[perm_str]
|
|
222
222
|
|
|
223
223
|
for perm in self.all_permissions:
|
|
224
|
-
if model
|
|
224
|
+
if model is not perm.model or node not in perm.nodes:
|
|
225
225
|
continue
|
|
226
226
|
if perm.obj_ids is None:
|
|
227
227
|
self._perm_cache[perm_str] = True
|
uiprotect/utils.py
CHANGED
|
@@ -202,6 +202,7 @@ def to_camel_case(name: str) -> str:
|
|
|
202
202
|
|
|
203
203
|
|
|
204
204
|
_EMPTY_UUID = UUID("0" * 32)
|
|
205
|
+
_SHAPE_TYPES = {SHAPE_DICT, SHAPE_LIST, SHAPE_SET}
|
|
205
206
|
|
|
206
207
|
|
|
207
208
|
def convert_unifi_data(value: Any, field: ModelField) -> Any:
|
|
@@ -211,23 +212,20 @@ def convert_unifi_data(value: Any, field: ModelField) -> Any:
|
|
|
211
212
|
if type_ is Any:
|
|
212
213
|
return value
|
|
213
214
|
|
|
214
|
-
shape
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
215
|
+
if (shape := field.shape) in _SHAPE_TYPES:
|
|
216
|
+
if shape == SHAPE_LIST and isinstance(value, list):
|
|
217
|
+
return [convert_unifi_data(v, field) for v in value]
|
|
218
|
+
if shape == SHAPE_SET and isinstance(value, list):
|
|
219
|
+
return {convert_unifi_data(v, field) for v in value}
|
|
220
|
+
if shape == SHAPE_DICT and isinstance(value, dict):
|
|
221
|
+
return {k: convert_unifi_data(v, field) for k, v in value.items()}
|
|
221
222
|
|
|
222
223
|
if value is not None:
|
|
223
224
|
if type_ in IP_TYPES:
|
|
224
|
-
|
|
225
|
-
return ip_address(value)
|
|
226
|
-
except ValueError:
|
|
227
|
-
return value
|
|
225
|
+
return _cached_ip_address(value)
|
|
228
226
|
if type_ is datetime:
|
|
229
227
|
return from_js_time(value)
|
|
230
|
-
if type_ in _CREATE_TYPES
|
|
228
|
+
if type_ in _CREATE_TYPES:
|
|
231
229
|
# cannot do this check too soon because some types cannot be used in isinstance
|
|
232
230
|
if isinstance(value, type_):
|
|
233
231
|
return value
|
|
@@ -236,16 +234,34 @@ def convert_unifi_data(value: Any, field: ModelField) -> Any:
|
|
|
236
234
|
if type_ is UUID and value == _BAD_UUID:
|
|
237
235
|
return _EMPTY_UUID
|
|
238
236
|
return type_(value)
|
|
237
|
+
if _is_enum_type(type_):
|
|
238
|
+
if _is_from_string_enum(type_):
|
|
239
|
+
return type_.from_string(value)
|
|
240
|
+
return type_(value)
|
|
239
241
|
|
|
240
242
|
return value
|
|
241
243
|
|
|
242
244
|
|
|
245
|
+
@lru_cache
|
|
246
|
+
def _cached_ip_address(value: str) -> IPv4Address | IPv6Address | str:
|
|
247
|
+
try:
|
|
248
|
+
return ip_address(value)
|
|
249
|
+
except ValueError:
|
|
250
|
+
return value
|
|
251
|
+
|
|
252
|
+
|
|
243
253
|
@lru_cache
|
|
244
254
|
def _is_enum_type(type_: Any) -> bool:
|
|
245
255
|
"""Checks if type is an Enum."""
|
|
246
256
|
return isclass(type_) and issubclass(type_, Enum)
|
|
247
257
|
|
|
248
258
|
|
|
259
|
+
@lru_cache
|
|
260
|
+
def _is_from_string_enum(type_: Any) -> bool:
|
|
261
|
+
"""Checks if Enum has from_string method."""
|
|
262
|
+
return hasattr(type_, "from_string")
|
|
263
|
+
|
|
264
|
+
|
|
249
265
|
def serialize_unifi_obj(value: Any, levels: int = -1) -> Any:
|
|
250
266
|
"""Serializes UFP data"""
|
|
251
267
|
if unifi_dict := getattr(value, "unifi_dict", None):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
uiprotect/__init__.py,sha256=GDRM9WvWUBbOyBVgltq6Qv8i7LVdWEbG8q5EzYvOFbE,636
|
|
2
2
|
uiprotect/__main__.py,sha256=C_bHCOkv5qj6WMy-6ELoY3Y6HDhLxOa1a30CzmbZhsg,462
|
|
3
|
-
uiprotect/api.py,sha256=
|
|
3
|
+
uiprotect/api.py,sha256=1gtyhk-MRFy6_wGR32Y520XJ2Ucxr1nevuBosod0r7w,67637
|
|
4
4
|
uiprotect/cli/__init__.py,sha256=1MO8rJmjjAsfVx2x01gn5DJo8B64xdPGo6gRVJbWd18,8868
|
|
5
5
|
uiprotect/cli/backup.py,sha256=ZiS7RZnJGKI8TJKLW2cOUzkRM8nyTvE5Ov_jZZGtvSM,36708
|
|
6
6
|
uiprotect/cli/base.py,sha256=k-_qGuNT7br0iV0KE5F4wYXF75iyLLjBEckTqxC71xM,7591
|
|
@@ -19,8 +19,8 @@ uiprotect/data/bootstrap.py,sha256=OSPHu08p7Ys9KqEb8sq_LFufuECtF4lY7OnAYK27ngo,2
|
|
|
19
19
|
uiprotect/data/convert.py,sha256=8h6Il_DhMkPRDPj9F_rA2UZIlTuchS3BQD24peKpk2A,2185
|
|
20
20
|
uiprotect/data/devices.py,sha256=0l8eiTCwacdHCmOc7qNzeUMpHLxvd6FeB7DOqZKycdA,110880
|
|
21
21
|
uiprotect/data/nvr.py,sha256=8M-62AG4q1k71eX-DaFcdO52QWG4zO9X5Voj0Tj9D5A,46598
|
|
22
|
-
uiprotect/data/types.py,sha256=
|
|
23
|
-
uiprotect/data/user.py,sha256=
|
|
22
|
+
uiprotect/data/types.py,sha256=zYQjmFDqxjVzaan-vihOzHaBirWsW_C0Q3Pd9xTH33I,18214
|
|
23
|
+
uiprotect/data/user.py,sha256=1o5gyPHafn4lHARpoSMD_NWbo5IbzGPfiSASwqqDvWs,7002
|
|
24
24
|
uiprotect/data/websocket.py,sha256=5-yM6yr8NrxKJjBPQlGVXXQUTcksF-UavligKYjJQ3k,6770
|
|
25
25
|
uiprotect/exceptions.py,sha256=kgn0cRM6lTtgLza09SDa3ZiX6ue1QqHCOogQ4qu6KTQ,965
|
|
26
26
|
uiprotect/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -28,10 +28,10 @@ uiprotect/release_cache.json,sha256=NamnSFy78hOWY0DPO87J9ELFCAN6NnVquv8gQO75ZG4,
|
|
|
28
28
|
uiprotect/stream.py,sha256=McV3XymKyjn-1uV5jdQHcpaDjqLS4zWyMASQ8ubcyb4,4924
|
|
29
29
|
uiprotect/test_util/__init__.py,sha256=Ky8mTL61nhp5II2mxTKBAsSGvNqK8U_CfKC5AGwToAI,18704
|
|
30
30
|
uiprotect/test_util/anonymize.py,sha256=f-8ijU-_y9r-uAbhIPn0f0I6hzJpAkvJzc8UpWihObI,8478
|
|
31
|
-
uiprotect/utils.py,sha256=
|
|
31
|
+
uiprotect/utils.py,sha256=jIWT7n_reL90oY91svBfQ4naRxo28qHzP5jNOL12mQE,20342
|
|
32
32
|
uiprotect/websocket.py,sha256=D5DZrMzo434ecp8toNxOB5HM193kVwYw42yEcg99yMw,8029
|
|
33
|
-
uiprotect-5.
|
|
34
|
-
uiprotect-5.
|
|
35
|
-
uiprotect-5.
|
|
36
|
-
uiprotect-5.
|
|
37
|
-
uiprotect-5.
|
|
33
|
+
uiprotect-5.4.0.dist-info/LICENSE,sha256=INx18jhdbVXMEiiBANeKEbrbz57ckgzxk5uutmmcxGk,1111
|
|
34
|
+
uiprotect-5.4.0.dist-info/METADATA,sha256=M3IE7App4LAfkDVGjLCYgU0b6uog5u8RGLdsXNFJasg,11009
|
|
35
|
+
uiprotect-5.4.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
36
|
+
uiprotect-5.4.0.dist-info/entry_points.txt,sha256=J78AUTPrTTxgI3s7SVgrmGqDP7piX2wuuEORzhDdVRA,47
|
|
37
|
+
uiprotect-5.4.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|