pyGuardPoint 2.1.1__tar.gz → 2.1.2__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.
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/PKG-INFO +1 -1
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/CustomWebsocketTransport.py +15 -3
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/_guardpoint_cardholders.py +10 -22
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/_guardpoint_cards.py +5 -2
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/_guardpoint_departments.py +4 -1
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/_guardpoint_readers.py +4 -1
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/_odata_filter.py +13 -6
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/_str_match_algo.py +11 -2
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/gp_asyncio/guardpoint_connection_asyncio.py +4 -2
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/guardpoint_connection.py +2 -1
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/guardpoint_dataclasses.py +16 -11
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/guardpoint_utils.py +17 -7
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint.egg-info/PKG-INFO +1 -1
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/setup.py +1 -1
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/LICENSE.txt +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/README.rst +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/CustomWebsocketTransportOld.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/__init__.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/_guardpoint_accessgroups.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/_guardpoint_alarmstates.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/_guardpoint_alarmzones.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/_guardpoint_areas.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/_guardpoint_cardholdertypes.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/_guardpoint_controllers.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/_guardpoint_customizedfields.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/_guardpoint_diagnostic.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/_guardpoint_events.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/_guardpoint_genericinformation.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/_guardpoint_inputs.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/_guardpoint_manualevents.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/_guardpoint_ouputs.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/_guardpoint_personaldetails.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/_guardpoint_scheduledmags.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/_guardpoint_securitygroups.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/_guardpoint_sites.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/_guardpoint_weeklyprograms.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/gp_asyncio/__init__.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/gp_asyncio/_async_guardpoint_accessgroups.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/gp_asyncio/_async_guardpoint_alarmstates.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/gp_asyncio/_async_guardpoint_alarmzones.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/gp_asyncio/_async_guardpoint_areas.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/gp_asyncio/_async_guardpoint_cardholders.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/gp_asyncio/_async_guardpoint_cardholdertypes.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/gp_asyncio/_async_guardpoint_cards.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/gp_asyncio/_async_guardpoint_controllers.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/gp_asyncio/_async_guardpoint_customizedfields.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/gp_asyncio/_async_guardpoint_departments.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/gp_asyncio/_async_guardpoint_diagnostic.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/gp_asyncio/_async_guardpoint_events.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/gp_asyncio/_async_guardpoint_genericinformation.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/gp_asyncio/_async_guardpoint_manualevents.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/gp_asyncio/_async_guardpoint_ouputs.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/gp_asyncio/_async_guardpoint_personaldetails.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/gp_asyncio/_async_guardpoint_readers.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/gp_asyncio/_async_guardpoint_scheduledmags.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/gp_asyncio/_async_guardpoint_securitygroups.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/gp_asyncio/_async_guardpoint_sites.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/gp_asyncio/_async_guardpoint_weeklyprograms.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/guardpoint.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/guardpoint_asyncio.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/guardpoint_error.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/guardpoint_threaded.py +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint.egg-info/SOURCES.txt +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint.egg-info/dependency_links.txt +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint.egg-info/not-zip-safe +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint.egg-info/requires.txt +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint.egg-info/top_level.txt +0 -0
- {pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/setup.cfg +0 -0
|
@@ -8,10 +8,22 @@ from typing import TYPE_CHECKING
|
|
|
8
8
|
from aiohttp import ClientSession, TCPConnector
|
|
9
9
|
from aiohttp import ClientTimeout
|
|
10
10
|
from aiohttp import ServerConnectionError
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
|
|
12
|
+
# Handle websockets version compatibility
|
|
13
|
+
try:
|
|
14
|
+
from websockets.asyncio.client import ClientConnection, connect
|
|
15
|
+
except ImportError:
|
|
16
|
+
# websockets<13.0 compatibility
|
|
17
|
+
from websockets.client import WebSocketClientProtocol as ClientConnection
|
|
18
|
+
from websockets.client import connect
|
|
19
|
+
|
|
13
20
|
from websockets.exceptions import ConnectionClosed
|
|
14
|
-
|
|
21
|
+
|
|
22
|
+
try:
|
|
23
|
+
from websockets.protocol import State
|
|
24
|
+
except ImportError:
|
|
25
|
+
# websockets<13.0 compatibility
|
|
26
|
+
State = None
|
|
15
27
|
|
|
16
28
|
import pysignalr.exceptions as exceptions
|
|
17
29
|
from pysignalr.messages import CompletionMessage
|
|
@@ -298,9 +298,6 @@ class CardholdersAPI:
|
|
|
298
298
|
return None
|
|
299
299
|
else:
|
|
300
300
|
return None
|
|
301
|
-
# Part of the Cards_API
|
|
302
|
-
# (Broken API Call)
|
|
303
|
-
#return self.get_cardholder_by_card_code(card_code)
|
|
304
301
|
else:
|
|
305
302
|
return self._get_card_holder(uid)
|
|
306
303
|
|
|
@@ -355,12 +352,6 @@ class CardholdersAPI:
|
|
|
355
352
|
"securityGroup," \
|
|
356
353
|
"insideArea"
|
|
357
354
|
|
|
358
|
-
# Do not apply site filter, when looking for individuals
|
|
359
|
-
#if self.site_uid is not None:
|
|
360
|
-
# match_args = {'ownerSiteUID': self.site_uid}
|
|
361
|
-
# filter_str = _compose_filter(exact_match=match_args)
|
|
362
|
-
# url_query_params += ("&" + filter_str)
|
|
363
|
-
|
|
364
355
|
code, json_body = self.gp_json_query("GET", url=(url + url_query_params))
|
|
365
356
|
|
|
366
357
|
if code == 404: # Not Found
|
|
@@ -428,14 +419,14 @@ class CardholdersAPI:
|
|
|
428
419
|
return []
|
|
429
420
|
if limit > 50 and count is False:
|
|
430
421
|
i_offset = offset
|
|
431
|
-
|
|
422
|
+
current_offset = 0
|
|
432
423
|
batch_limit = 50
|
|
433
424
|
card_holders = []
|
|
434
|
-
while len(card_holders)
|
|
435
|
-
if
|
|
436
|
-
batch_limit = limit -
|
|
425
|
+
while len(card_holders) < limit:
|
|
426
|
+
if current_offset + batch_limit > limit:
|
|
427
|
+
batch_limit = limit - current_offset
|
|
437
428
|
if batch_limit > 0:
|
|
438
|
-
batch = self._split_get_card_holders_query(offset=
|
|
429
|
+
batch = self._split_get_card_holders_query(offset=current_offset + i_offset, limit=batch_limit,
|
|
439
430
|
search_terms=search_terms,
|
|
440
431
|
areas=areas,
|
|
441
432
|
filter_expired=filter_expired,
|
|
@@ -447,11 +438,11 @@ class CardholdersAPI:
|
|
|
447
438
|
**cardholder_kwargs)
|
|
448
439
|
if isinstance(batch, list):
|
|
449
440
|
card_holders.extend(batch)
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
441
|
+
if len(batch) < batch_limit:
|
|
442
|
+
break
|
|
443
|
+
else:
|
|
444
|
+
break
|
|
445
|
+
current_offset = len(card_holders)
|
|
455
446
|
else:
|
|
456
447
|
break
|
|
457
448
|
|
|
@@ -571,9 +562,6 @@ class CardholdersAPI:
|
|
|
571
562
|
url_query_params += "$top=" + str(limit) + "&$skip=" + str(offset)
|
|
572
563
|
|
|
573
564
|
code, json_body = self.gp_json_query("GET", url=(url + url_query_params))
|
|
574
|
-
# Check response body is formatted correctly
|
|
575
|
-
# if json_body:
|
|
576
|
-
# GuardPointResponse.check_odata_body_structure(json_body)
|
|
577
565
|
|
|
578
566
|
if code != 200:
|
|
579
567
|
error_msg = GuardPointResponse.extract_error_msg(json_body)
|
|
@@ -72,7 +72,7 @@ class CardsAPI:
|
|
|
72
72
|
if code == 401:
|
|
73
73
|
raise GuardPointUnauthorized(f"Unauthorized - ({error_msg})")
|
|
74
74
|
elif code == 404: # Not Found
|
|
75
|
-
raise GuardPointError(f"
|
|
75
|
+
raise GuardPointError(f"Cards Not Found")
|
|
76
76
|
else:
|
|
77
77
|
raise GuardPointError(f"{error_msg}")
|
|
78
78
|
|
|
@@ -244,7 +244,10 @@ class CardsAPI:
|
|
|
244
244
|
if 'value' not in json_body:
|
|
245
245
|
raise GuardPointError("Badly formatted response.")
|
|
246
246
|
|
|
247
|
-
|
|
247
|
+
value = json_body['value']
|
|
248
|
+
if isinstance(value, list):
|
|
249
|
+
return Card(value[0]) if value else None
|
|
250
|
+
return Card(value)
|
|
248
251
|
|
|
249
252
|
def get_cardholder_by_card_code(self, card_code):
|
|
250
253
|
"""
|
|
@@ -33,7 +33,10 @@ class DepartmentsAPI:
|
|
|
33
33
|
if 'value' not in json_body:
|
|
34
34
|
raise GuardPointError("Badly formatted response.")
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
value = json_body['value']
|
|
37
|
+
if isinstance(value, list):
|
|
38
|
+
return Department(value[0]) if value else None
|
|
39
|
+
return Department(value)
|
|
37
40
|
|
|
38
41
|
def get_departments(self):
|
|
39
42
|
url = "/odata/API_Departments"
|
|
@@ -141,5 +141,8 @@ class ReadersAPI:
|
|
|
141
141
|
if 'value' not in json_body:
|
|
142
142
|
raise GuardPointError("Badly formatted response.")
|
|
143
143
|
|
|
144
|
-
|
|
144
|
+
value = json_body['value']
|
|
145
|
+
if isinstance(value, list):
|
|
146
|
+
return Reader(value[0]) if value else None
|
|
147
|
+
return Reader(value)
|
|
145
148
|
|
|
@@ -93,29 +93,36 @@ def _compose_filter(search_words=None,
|
|
|
93
93
|
if isinstance(v, str):
|
|
94
94
|
v = v.replace("'", "''")
|
|
95
95
|
if validators.uuid(v):
|
|
96
|
-
filter_phrases.append(f"({k}%20eq%20{
|
|
96
|
+
filter_phrases.append(f"({k}%20eq%20{v})")
|
|
97
97
|
else:
|
|
98
98
|
filter_phrases.append(f"({k}%20eq%20'{quote(v)}')")
|
|
99
99
|
if isinstance(v, (bool, int)):
|
|
100
|
-
filter_phrases.append(f"({k}%20eq%20{
|
|
100
|
+
filter_phrases.append(f"({k}%20eq%20{v})")
|
|
101
101
|
if k == "cardholderPersonalDetail" and v.__class__.__name__ == "CardholderPersonalDetail":
|
|
102
102
|
details = v.dict(changed_only=True)
|
|
103
103
|
for dk, dv in details.items():
|
|
104
104
|
if isinstance(dv, str):
|
|
105
105
|
dv = dv.replace("'", "''")
|
|
106
|
-
|
|
106
|
+
filter_phrases.append(f"(CardholderPersonalDetail/{dk}%20eq%20'{quote(dv)}')")
|
|
107
|
+
elif isinstance(dv, (bool, int)):
|
|
108
|
+
filter_phrases.append(f"(CardholderPersonalDetail/{dk}%20eq%20{dv})")
|
|
109
|
+
elif isinstance(dv, type(None)):
|
|
110
|
+
filter_phrases.append(f"(CardholderPersonalDetail/{dk}%20eq%20null)")
|
|
111
|
+
else:
|
|
112
|
+
dv_str = str(dv).replace("'", "''")
|
|
113
|
+
filter_phrases.append(f"(CardholderPersonalDetail/{dk}%20eq%20'{quote(dv_str)}')")
|
|
107
114
|
if k == "cardholderCustomizedField" and v.__class__.__name__ == "CardholderCustomizedField":
|
|
108
115
|
details = v.dict(changed_only=True)
|
|
109
116
|
for dk, dv in details.items():
|
|
110
117
|
if isinstance(dv, type(None)):
|
|
111
|
-
filter_phrases.append(f"(CardholderCustomizedField/{dk}%20eq%
|
|
118
|
+
filter_phrases.append(f"(CardholderCustomizedField/{dk}%20eq%20null)")
|
|
112
119
|
elif isinstance(dv, (bool, int)):
|
|
113
120
|
filter_phrases.append(f"(CardholderCustomizedField/{dk}%20eq%20{str(dv).lower()})")
|
|
114
121
|
elif isinstance(dv, str):
|
|
115
122
|
dv = dv.replace("'", "''")
|
|
116
123
|
filter_phrases.append(f"(CardholderCustomizedField/{dk}%20eq%20'{quote(dv)}')")
|
|
117
124
|
else:
|
|
118
|
-
filter_phrases.append(f"(CardholderCustomizedField/{dk}%20eq%20'{
|
|
125
|
+
filter_phrases.append(f"(CardholderCustomizedField/{dk}%20eq%20'{str(dv)}')")
|
|
119
126
|
|
|
120
127
|
if earliest_last_pass:
|
|
121
128
|
if isinstance(earliest_last_pass, datetime):
|
|
@@ -136,7 +143,7 @@ def _compose_filter(search_words=None,
|
|
|
136
143
|
if areas:
|
|
137
144
|
if isinstance(areas, Area):
|
|
138
145
|
filter_phrases.append(f"(insideAreaUID%20eq%20{areas.uid})")
|
|
139
|
-
|
|
146
|
+
elif isinstance(areas, list):
|
|
140
147
|
if len(areas) > 0:
|
|
141
148
|
area_phrases = []
|
|
142
149
|
for area in areas:
|
|
@@ -12,11 +12,20 @@ def fuzzy_match(search_words: str, cardholders: list, threshold: int = 75):
|
|
|
12
12
|
|
|
13
13
|
match_ratios = process.extract(search_words, cardholder_patterns, scorer=fuzz.WRatio, limit=20)
|
|
14
14
|
|
|
15
|
+
pattern_to_indices = {}
|
|
16
|
+
for idx, pattern in enumerate(cardholder_patterns):
|
|
17
|
+
if pattern not in pattern_to_indices:
|
|
18
|
+
pattern_to_indices[pattern] = []
|
|
19
|
+
pattern_to_indices[pattern].append(idx)
|
|
20
|
+
|
|
15
21
|
sorted_cardholders = []
|
|
22
|
+
seen = set()
|
|
16
23
|
for match in match_ratios:
|
|
17
24
|
if match[1] >= threshold:
|
|
18
|
-
pos
|
|
19
|
-
|
|
25
|
+
for pos in pattern_to_indices.get(match[0], []):
|
|
26
|
+
if pos not in seen:
|
|
27
|
+
sorted_cardholders.append(cardholders[pos])
|
|
28
|
+
seen.add(pos)
|
|
20
29
|
|
|
21
30
|
return sorted_cardholders
|
|
22
31
|
|
{pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/gp_asyncio/guardpoint_connection_asyncio.py
RENAMED
|
@@ -59,9 +59,10 @@ class GuardPointConnection:
|
|
|
59
59
|
if self.session:
|
|
60
60
|
await self.session.close()
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
def reopen(self):
|
|
63
63
|
conn = aiohttp.TCPConnector(ssl_context=self.ssl_context)
|
|
64
64
|
self.session = aiohttp.ClientSession(connector=conn)
|
|
65
|
+
|
|
65
66
|
def open(self, url_components, auth, user, pwd, key, token=None,
|
|
66
67
|
cert_file=None, key_file=None, key_pwd="", ca_file=None, p12_file=None, p12_pwd="", timeout=5):
|
|
67
68
|
self.ssl_context = None
|
|
@@ -116,7 +117,8 @@ class GuardPointConnection:
|
|
|
116
117
|
|
|
117
118
|
if cert_file and key_file:
|
|
118
119
|
# Loading of client certificate
|
|
119
|
-
|
|
120
|
+
pwd_bytes = key_pwd.encode() if isinstance(key_pwd, str) else key_pwd
|
|
121
|
+
self.ssl_context.load_cert_chain(certfile=cert_file, keyfile=key_file, password=pwd_bytes if pwd_bytes else None)
|
|
120
122
|
|
|
121
123
|
if ca_file:
|
|
122
124
|
# Loading of CA certificate.
|
|
@@ -108,7 +108,8 @@ class GuardPointConnection:
|
|
|
108
108
|
|
|
109
109
|
if cert_file and key_file:
|
|
110
110
|
# Loading of client certificate
|
|
111
|
-
|
|
111
|
+
pwd_bytes = p12_pwd.encode() if isinstance(p12_pwd, str) else p12_pwd
|
|
112
|
+
self.ssl_context.load_cert_chain(certfile=cert_file, keyfile=key_file, password=pwd_bytes if pwd_bytes else None)
|
|
112
113
|
|
|
113
114
|
if ca_file:
|
|
114
115
|
# Loading of CA certificate.
|
|
@@ -33,7 +33,7 @@ class Observable:
|
|
|
33
33
|
|
|
34
34
|
def add_observer(self, name):
|
|
35
35
|
with self._observer_lock:
|
|
36
|
-
self.observed[name].append(lambda
|
|
36
|
+
self.observed[name].append(lambda attr_name: self.changed_attributes.add(attr_name))
|
|
37
37
|
|
|
38
38
|
|
|
39
39
|
def sanitise_args(obj: Observable, args, kwargs):
|
|
@@ -56,12 +56,12 @@ def sanitise_args(obj: Observable, args, kwargs):
|
|
|
56
56
|
|
|
57
57
|
|
|
58
58
|
class SortAlgorithm(Enum):
|
|
59
|
-
SERVER_DEFAULT = 0
|
|
59
|
+
SERVER_DEFAULT = 0
|
|
60
60
|
FUZZY_MATCH = 1
|
|
61
61
|
|
|
62
62
|
|
|
63
63
|
class CardholderOrderBy(Enum):
|
|
64
|
-
fromDateValid_DESC = 0
|
|
64
|
+
fromDateValid_DESC = 0
|
|
65
65
|
lastPassDate_DESC = 1
|
|
66
66
|
|
|
67
67
|
|
|
@@ -99,6 +99,7 @@ class CustomizedField:
|
|
|
99
99
|
cf_dict[k] = None
|
|
100
100
|
else:
|
|
101
101
|
cf_dict[k] = str(v)
|
|
102
|
+
return cf_dict
|
|
102
103
|
|
|
103
104
|
@dataclass
|
|
104
105
|
class WeeklyProgram:
|
|
@@ -124,6 +125,7 @@ class WeeklyProgram:
|
|
|
124
125
|
me_dict[k] = None
|
|
125
126
|
else:
|
|
126
127
|
me_dict[k] = str(v)
|
|
128
|
+
return me_dict
|
|
127
129
|
|
|
128
130
|
|
|
129
131
|
@dataclass
|
|
@@ -150,6 +152,7 @@ class ManualEvent:
|
|
|
150
152
|
me_dict[k] = None
|
|
151
153
|
else:
|
|
152
154
|
me_dict[k] = str(v)
|
|
155
|
+
return me_dict
|
|
153
156
|
|
|
154
157
|
|
|
155
158
|
@dataclass
|
|
@@ -158,12 +161,12 @@ class Input:
|
|
|
158
161
|
logicalStatus: str = ""
|
|
159
162
|
isUnderAlarm: bool = False
|
|
160
163
|
uid: str = ""
|
|
161
|
-
number: int = 0
|
|
164
|
+
number: int = 0
|
|
162
165
|
name: str = ""
|
|
163
166
|
descriprion: any = None
|
|
164
167
|
weeklyProgramUID: any = None
|
|
165
168
|
delayType: str = ""
|
|
166
|
-
delayTime: int = 0
|
|
169
|
+
delayTime: int = 0
|
|
167
170
|
inputType: str = ""
|
|
168
171
|
statusType: str = ""
|
|
169
172
|
controllerUID: str = ""
|
|
@@ -172,12 +175,12 @@ class Input:
|
|
|
172
175
|
lastEventType: any = None
|
|
173
176
|
latestAction: any = None
|
|
174
177
|
inputGroupUID: any = None
|
|
175
|
-
alarmPriority: int = 0
|
|
178
|
+
alarmPriority: int = 0
|
|
176
179
|
isArm: bool = False
|
|
177
180
|
isBypassed: bool = False
|
|
178
181
|
instructions: any = None
|
|
179
182
|
isGalaxy: bool = False
|
|
180
|
-
omitted: int = 0
|
|
183
|
+
omitted: int = 0
|
|
181
184
|
apiKey: any = None
|
|
182
185
|
|
|
183
186
|
def __init__(self, *args, **kwargs):
|
|
@@ -197,6 +200,7 @@ class Input:
|
|
|
197
200
|
input_dict[k] = None
|
|
198
201
|
else:
|
|
199
202
|
input_dict[k] = str(v)
|
|
203
|
+
return input_dict
|
|
200
204
|
|
|
201
205
|
|
|
202
206
|
@dataclass
|
|
@@ -233,6 +237,7 @@ class AlarmState:
|
|
|
233
237
|
alarm_state_dict[k] = None
|
|
234
238
|
else:
|
|
235
239
|
alarm_state_dict[k] = str(v)
|
|
240
|
+
return alarm_state_dict
|
|
236
241
|
|
|
237
242
|
|
|
238
243
|
@dataclass
|
|
@@ -544,7 +549,7 @@ class AccessEvent:
|
|
|
544
549
|
accessDeniedCode: str = ""
|
|
545
550
|
cardCode: str = ""
|
|
546
551
|
cardholderFirstName: any = None
|
|
547
|
-
cardholderIdNumber:
|
|
552
|
+
cardholderIdNumber: any = None
|
|
548
553
|
cardholderLastName: any = None
|
|
549
554
|
cardholderTypeName: any = None
|
|
550
555
|
cardholderTypeUID: any = None
|
|
@@ -868,7 +873,7 @@ class ScheduledMag(Observable):
|
|
|
868
873
|
@dataclass
|
|
869
874
|
class CardholderCustomizedField(Observable):
|
|
870
875
|
uid: str = ""
|
|
871
|
-
cF_BoolField_1: bool = False
|
|
876
|
+
cF_BoolField_1: bool = False
|
|
872
877
|
cF_BoolField_2: bool = False
|
|
873
878
|
cF_BoolField_3: bool = False
|
|
874
879
|
cF_BoolField_4: bool = False
|
|
@@ -1183,8 +1188,8 @@ class Cardholder(Observable):
|
|
|
1183
1188
|
|
|
1184
1189
|
for property_name in cardholder_dict:
|
|
1185
1190
|
if isinstance(cardholder_dict[property_name], list):
|
|
1186
|
-
if property_name == "accessGroupUIDs":
|
|
1187
|
-
setattr(self, property_name,
|
|
1191
|
+
if property_name == "accessGroupUIDs" or property_name == "liftAccessGroupUIDs":
|
|
1192
|
+
setattr(self, property_name, cardholder_dict[property_name])
|
|
1188
1193
|
elif property_name == "cards":
|
|
1189
1194
|
setattr(self, property_name, [])
|
|
1190
1195
|
for card_entry in cardholder_dict[property_name]:
|
|
@@ -6,19 +6,29 @@ from .guardpoint_error import GuardPointError
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
def url_parser(url):
|
|
9
|
+
if not url or not isinstance(url, str):
|
|
10
|
+
raise GuardPointError("Invalid URL: must be a non-empty string")
|
|
11
|
+
|
|
9
12
|
parts = urlparse(url)
|
|
10
|
-
|
|
11
|
-
|
|
13
|
+
|
|
14
|
+
if not parts.netloc:
|
|
15
|
+
raise GuardPointError("Invalid URL: missing host")
|
|
16
|
+
|
|
17
|
+
directories = parts.path.strip('/').split('/') if parts.path else ['']
|
|
18
|
+
queries = parts.query.strip('&').split('&') if parts.query else []
|
|
12
19
|
host = parts.netloc.strip(':').split(':')[0]
|
|
13
20
|
|
|
21
|
+
if not host:
|
|
22
|
+
raise GuardPointError("Invalid URL: empty host")
|
|
23
|
+
|
|
14
24
|
elements = {
|
|
15
|
-
'scheme': parts.scheme,
|
|
25
|
+
'scheme': parts.scheme or '',
|
|
16
26
|
'host': host,
|
|
17
|
-
'path': parts.path,
|
|
18
|
-
'params': parts.params,
|
|
19
|
-
'query': parts.query,
|
|
27
|
+
'path': parts.path or '',
|
|
28
|
+
'params': parts.params or '',
|
|
29
|
+
'query': parts.query or '',
|
|
20
30
|
'port': parts.port,
|
|
21
|
-
'fragment': parts.fragment,
|
|
31
|
+
'fragment': parts.fragment or '',
|
|
22
32
|
'directories': directories,
|
|
23
33
|
'queries': queries,
|
|
24
34
|
}
|
|
@@ -5,7 +5,7 @@ long_description = open('README.rst').read()
|
|
|
5
5
|
setup(name="pyGuardPoint",
|
|
6
6
|
python_requires='>3.9.0',
|
|
7
7
|
packages=find_packages(),
|
|
8
|
-
version="2.1.
|
|
8
|
+
version="2.1.2",
|
|
9
9
|
author="John Owen",
|
|
10
10
|
description="Python wrapper for GuardPoint 10 Access Control System",
|
|
11
11
|
long_description_content_type='text/markdown',
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/gp_asyncio/_async_guardpoint_accessgroups.py
RENAMED
|
File without changes
|
{pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/gp_asyncio/_async_guardpoint_alarmstates.py
RENAMED
|
File without changes
|
{pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/gp_asyncio/_async_guardpoint_alarmzones.py
RENAMED
|
File without changes
|
{pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/gp_asyncio/_async_guardpoint_areas.py
RENAMED
|
File without changes
|
{pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/gp_asyncio/_async_guardpoint_cardholders.py
RENAMED
|
File without changes
|
|
File without changes
|
{pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/gp_asyncio/_async_guardpoint_cards.py
RENAMED
|
File without changes
|
{pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/gp_asyncio/_async_guardpoint_controllers.py
RENAMED
|
File without changes
|
|
File without changes
|
{pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/gp_asyncio/_async_guardpoint_departments.py
RENAMED
|
File without changes
|
{pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/gp_asyncio/_async_guardpoint_diagnostic.py
RENAMED
|
File without changes
|
{pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/gp_asyncio/_async_guardpoint_events.py
RENAMED
|
File without changes
|
|
File without changes
|
{pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/gp_asyncio/_async_guardpoint_manualevents.py
RENAMED
|
File without changes
|
{pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/gp_asyncio/_async_guardpoint_ouputs.py
RENAMED
|
File without changes
|
|
File without changes
|
{pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/gp_asyncio/_async_guardpoint_readers.py
RENAMED
|
File without changes
|
{pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/gp_asyncio/_async_guardpoint_scheduledmags.py
RENAMED
|
File without changes
|
|
File without changes
|
{pyguardpoint-2.1.1 → pyguardpoint-2.1.2}/pyGuardPoint/gp_asyncio/_async_guardpoint_sites.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|