python-terminusgps 47.0.0__tar.gz → 47.1.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.
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/PKG-INFO +1 -1
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/pyproject.toml +1 -1
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/terminusgps/default_settings.py +1 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/terminusgps/wialon/session.py +2 -2
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/terminusgps/wialon/utils.py +23 -10
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/uv.lock +1 -1
- python_terminusgps-47.0.0/terminusgps/wialon/validators.py +0 -114
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/.github/workflows/sphinx.yml +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/.gitignore +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/.python-version +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/COPYING +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/README.md +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/docs/Makefile +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/docs/make.bat +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/docs/requirements.txt +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/docs/source/authorizenet/api.rst +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/docs/source/authorizenet/constants.rst +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/docs/source/authorizenet/index.rst +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/docs/source/authorizenet/service.rst +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/docs/source/conf.py +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/docs/source/index.rst +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/docs/source/mixins.rst +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/docs/source/validators.rst +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/docs/source/wialon/constants.rst +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/docs/source/wialon/exceptions.rst +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/docs/source/wialon/index.rst +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/docs/source/wialon/items.rst +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/docs/source/wialon/session.rst +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/docs/source/wialon/usage.rst +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/terminusgps/__init__.py +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/terminusgps/authorizenet/__init__.py +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/terminusgps/authorizenet/api/__init__.py +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/terminusgps/authorizenet/api/address_profiles.py +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/terminusgps/authorizenet/api/customer_profiles.py +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/terminusgps/authorizenet/api/payment_profiles.py +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/terminusgps/authorizenet/api/subscriptions.py +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/terminusgps/authorizenet/api/transactions.py +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/terminusgps/authorizenet/constants.py +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/terminusgps/authorizenet/service.py +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/terminusgps/mixins.py +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/terminusgps/validators.py +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/terminusgps/wialon/__init__.py +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/terminusgps/wialon/constants.py +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/terminusgps/wialon/flags.py +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/terminusgps/wialon/items/__init__.py +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/terminusgps/wialon/items/account.py +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/terminusgps/wialon/items/base.py +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/terminusgps/wialon/items/factory.py +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/terminusgps/wialon/items/resource.py +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/terminusgps/wialon/items/retranslator.py +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/terminusgps/wialon/items/route.py +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/terminusgps/wialon/items/unit.py +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/terminusgps/wialon/items/unit_group.py +0 -0
- {python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/terminusgps/wialon/items/user.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-terminusgps
|
|
3
|
-
Version: 47.
|
|
3
|
+
Version: 47.1.0
|
|
4
4
|
Summary: Provides abstractions/utilities for working with Wialon API, Authorize.NET API, AWS API, and more.
|
|
5
5
|
Project-URL: Documentation, https://terminusgps.github.io/python-terminusgps
|
|
6
6
|
Project-URL: Repository, https://github.com/terminusgps/python-terminusgps
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "python-terminusgps"
|
|
3
|
-
version = "47.
|
|
3
|
+
version = "47.1.0"
|
|
4
4
|
description = "Provides abstractions/utilities for working with Wialon API, Authorize.NET API, AWS API, and more."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [ {name = "Blake Nall", email = "blake@terminusgps.com" } ]
|
|
@@ -16,3 +16,4 @@ MERCHANT_AUTH_VALIDATION_MODE = ValidationMode.TEST
|
|
|
16
16
|
MERCHANT_AUTH_LOGIN_ID = os.getenv("MERCHANT_AUTH_LOGIN_ID")
|
|
17
17
|
MERCHANT_AUTH_TRANSACTION_KEY = os.getenv("MERCHANT_AUTH_TRANSACTION_KEY")
|
|
18
18
|
WIALON_TOKEN = os.getenv("WIALON_TOKEN")
|
|
19
|
+
WIALON_USERNAME = os.getenv("WIALON_USERNAME")
|
|
@@ -57,7 +57,7 @@ class WialonSession:
|
|
|
57
57
|
:type token: str | None
|
|
58
58
|
:param auth_hash: A Wialon API authentication hash. Default is environment variable ``"WIALON_TOKEN"``.
|
|
59
59
|
:type auth_hash: str | None
|
|
60
|
-
:param username: A Wialon user id to operate as during the session. Default is
|
|
60
|
+
:param username: A Wialon user id to operate as during the session. Default is environment variable ``"WIALON_USERNAME"``.
|
|
61
61
|
:type username: str | None
|
|
62
62
|
:param check_service: A Wialon service name to check before calling the Wialon API. Default is :py:obj:`None`.
|
|
63
63
|
:type check_service: str | None
|
|
@@ -69,7 +69,7 @@ class WialonSession:
|
|
|
69
69
|
self._wialon_api = Wialon(scheme=scheme, host=host, port=port, sid=sid)
|
|
70
70
|
|
|
71
71
|
self._token = token if token else os.getenv("WIALON_TOKEN")
|
|
72
|
-
self._username = username
|
|
72
|
+
self._username = username if username else os.getenv("WIALON_USERNAME")
|
|
73
73
|
self._auth_hash = auth_hash
|
|
74
74
|
self._check_service = check_service
|
|
75
75
|
|
|
@@ -64,9 +64,9 @@ def get_user_by_name(name: str, session: WialonSession) -> WialonUser:
|
|
|
64
64
|
raise ValueError(f"Multiple users returned for '{name}'.")
|
|
65
65
|
elif num_items <= 0:
|
|
66
66
|
raise ValueError(f"Couldn't find a Wialon user named '{name}'.")
|
|
67
|
-
|
|
68
67
|
factory = WialonObjectFactory(session)
|
|
69
|
-
|
|
68
|
+
user_id = response.get("items")[0].get("id")
|
|
69
|
+
return factory.get("user", id=int(user_id))
|
|
70
70
|
|
|
71
71
|
|
|
72
72
|
def get_carrier_names(session: WialonSession) -> list[str]:
|
|
@@ -89,7 +89,8 @@ def get_carrier_names(session: WialonSession) -> list[str]:
|
|
|
89
89
|
"propType": "propitemname",
|
|
90
90
|
},
|
|
91
91
|
"force": 0,
|
|
92
|
-
"flags": flags.DataFlag.UNIT_BASE
|
|
92
|
+
"flags": flags.DataFlag.UNIT_BASE
|
|
93
|
+
| flags.DataFlag.UNIT_ADMIN_FIELDS,
|
|
93
94
|
"from": 0,
|
|
94
95
|
"to": 0,
|
|
95
96
|
}
|
|
@@ -103,7 +104,9 @@ def get_carrier_names(session: WialonSession) -> list[str]:
|
|
|
103
104
|
return sorted(list(frozenset(carrier_names)))
|
|
104
105
|
|
|
105
106
|
|
|
106
|
-
def get_units_by_carrier(
|
|
107
|
+
def get_units_by_carrier(
|
|
108
|
+
carrier_name: str, session: WialonSession
|
|
109
|
+
) -> list[WialonUnit]:
|
|
107
110
|
"""
|
|
108
111
|
Returns a list of all units by telecommunications carrier company name.
|
|
109
112
|
|
|
@@ -125,14 +128,17 @@ def get_units_by_carrier(carrier_name: str, session: WialonSession) -> list[Wial
|
|
|
125
128
|
"propType": "propitemname",
|
|
126
129
|
},
|
|
127
130
|
"force": 0,
|
|
128
|
-
"flags": flags.DataFlag.UNIT_BASE
|
|
131
|
+
"flags": flags.DataFlag.UNIT_BASE
|
|
132
|
+
| flags.DataFlag.UNIT_ADMIN_FIELDS,
|
|
129
133
|
"from": 0,
|
|
130
134
|
"to": 0,
|
|
131
135
|
}
|
|
132
136
|
)
|
|
133
137
|
num_items: int = int(response.get("totalItemsCount"))
|
|
134
138
|
if num_items <= 0:
|
|
135
|
-
raise ValueError(
|
|
139
|
+
raise ValueError(
|
|
140
|
+
f"Couldn't find any units by carrier '{carrier_name}'."
|
|
141
|
+
)
|
|
136
142
|
|
|
137
143
|
factory = WialonObjectFactory(session)
|
|
138
144
|
unit_ids = [int(unit.get("id")) for unit in response.get("items")]
|
|
@@ -161,7 +167,8 @@ def get_unit_by_iccid(iccid: str, session: WialonSession) -> WialonUnit:
|
|
|
161
167
|
"propType": "propitemname",
|
|
162
168
|
},
|
|
163
169
|
"force": 0,
|
|
164
|
-
"flags": flags.DataFlag.UNIT_BASE
|
|
170
|
+
"flags": flags.DataFlag.UNIT_BASE
|
|
171
|
+
| flags.DataFlag.UNIT_ADMIN_FIELDS,
|
|
165
172
|
"from": 0,
|
|
166
173
|
"to": 0,
|
|
167
174
|
}
|
|
@@ -177,7 +184,9 @@ def get_unit_by_iccid(iccid: str, session: WialonSession) -> WialonUnit:
|
|
|
177
184
|
return factory.get("avl_unit", id=int(response.get("items")[0].get("id")))
|
|
178
185
|
|
|
179
186
|
|
|
180
|
-
def get_unit_by_imei(
|
|
187
|
+
def get_unit_by_imei(
|
|
188
|
+
imei: int | str, session: WialonSession
|
|
189
|
+
) -> WialonUnit | None:
|
|
181
190
|
"""
|
|
182
191
|
Takes a Wialon unit's IMEI # and returns its unit id.
|
|
183
192
|
|
|
@@ -218,7 +227,9 @@ def get_unit_by_imei(imei: int | str, session: WialonSession) -> WialonUnit | No
|
|
|
218
227
|
return factory.get("avl_unit", id=int(response.get("items")[0].get("id")))
|
|
219
228
|
|
|
220
229
|
|
|
221
|
-
def get_vin_info(
|
|
230
|
+
def get_vin_info(
|
|
231
|
+
vin_number: str, session: WialonSession
|
|
232
|
+
) -> dict[str, typing.Any]:
|
|
222
233
|
"""
|
|
223
234
|
Retrieves vehicle data from a VIN number.
|
|
224
235
|
|
|
@@ -279,7 +290,9 @@ def generate_wialon_password(length: int = 32) -> str:
|
|
|
279
290
|
s3 = list("!@#$%^*()[]-_+")
|
|
280
291
|
|
|
281
292
|
while True:
|
|
282
|
-
password = "".join(
|
|
293
|
+
password = "".join(
|
|
294
|
+
[secrets.choice(s0 + s1 + s2 + s3) for _ in range(length)]
|
|
295
|
+
)
|
|
283
296
|
if (
|
|
284
297
|
any(c.islower() for c in password)
|
|
285
298
|
and any(c.isupper() for c in password)
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
import string
|
|
2
|
-
|
|
3
|
-
from django.conf import settings
|
|
4
|
-
from django.core.exceptions import ImproperlyConfigured, ValidationError
|
|
5
|
-
from django.utils.translation import gettext_lazy as _
|
|
6
|
-
|
|
7
|
-
from .session import WialonSession
|
|
8
|
-
|
|
9
|
-
if settings.configured and not hasattr(settings, "WIALON_TOKEN"):
|
|
10
|
-
raise ImproperlyConfigured("'WIALON_TOKEN' setting is required.")
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class WialonValidatorBase:
|
|
14
|
-
def __init__(self) -> None:
|
|
15
|
-
self.session = WialonSession()
|
|
16
|
-
self.session.login(self.session.token)
|
|
17
|
-
|
|
18
|
-
def __call__(self, value: str) -> None:
|
|
19
|
-
raise NotImplementedError("Subclasses must implement this method.")
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class WialonVinNumberValidator(WialonValidatorBase):
|
|
23
|
-
def __call__(self, value: str) -> None:
|
|
24
|
-
response = self.session.wialon_api.unit_get_vin_info(vin=value)
|
|
25
|
-
if "error" in response["vin_lookup_result"].keys():
|
|
26
|
-
raise ValidationError(
|
|
27
|
-
_("Failed to get info for VIN # '%(value)s': '%(message)s'"),
|
|
28
|
-
code="invalid",
|
|
29
|
-
params={
|
|
30
|
-
"value": value,
|
|
31
|
-
"message": response["vin_lookup_result"].get("message", ""),
|
|
32
|
-
},
|
|
33
|
-
)
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
class WialonImeiNumberValidator(WialonValidatorBase):
|
|
37
|
-
def __call__(self, value: str) -> None:
|
|
38
|
-
response = self.session.wialon_api.core_search_items(
|
|
39
|
-
**{
|
|
40
|
-
"spec": {
|
|
41
|
-
"itemsType": "avl_unit",
|
|
42
|
-
"propName": "sys_id,sys_unique_id",
|
|
43
|
-
"propValueMask": f"*,*{value}*",
|
|
44
|
-
"sortType": "sys_id,sys_unique_id",
|
|
45
|
-
},
|
|
46
|
-
"force": 0,
|
|
47
|
-
"flags": 1,
|
|
48
|
-
"from": 0,
|
|
49
|
-
"to": 0,
|
|
50
|
-
}
|
|
51
|
-
)
|
|
52
|
-
if response is None or not response.get("items"):
|
|
53
|
-
raise ValidationError(
|
|
54
|
-
_("IMEI # '%(value)s' wasn't found in Wialon."),
|
|
55
|
-
code="invalid",
|
|
56
|
-
params={"value": value},
|
|
57
|
-
)
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
def validate_imei_number(value: str) -> None:
|
|
61
|
-
"""Raises :py:exec:`ValidationError` if the value is an invalid IMEI number."""
|
|
62
|
-
WialonImeiNumberValidator()(value)
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
def validate_vin_number(value: str) -> None:
|
|
66
|
-
"""Raises :py:exec:`ValidationError` if the value is an invalid VIN number."""
|
|
67
|
-
if len(value) != 17:
|
|
68
|
-
raise ValidationError(
|
|
69
|
-
_("Whoops! VIN # must be exactly 17 characters in length, got %(length)s."),
|
|
70
|
-
code="invalid",
|
|
71
|
-
params={"length": len(value)},
|
|
72
|
-
)
|
|
73
|
-
WialonVinNumberValidator()(value)
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
def validate_wialon_password(value: str) -> None:
|
|
77
|
-
"""Raises :py:exec:`ValidationError` if the value represents an invalid Wialon password."""
|
|
78
|
-
special_symbols_0: list[str] = ["!", "@", "#", "$", "%", "^", "*"]
|
|
79
|
-
special_symbols_1: list[str] = ["(", ")", "[", "]", "-", "_", "+"]
|
|
80
|
-
forbidden_symbols: list[str] = [",", ":", "&", "<", ">", "'"]
|
|
81
|
-
|
|
82
|
-
if len(value) < 4:
|
|
83
|
-
raise ValidationError(
|
|
84
|
-
_("Password cannot be less than 4 characters in length, got %(len)s."),
|
|
85
|
-
code="invalid",
|
|
86
|
-
params={"len": len(value)},
|
|
87
|
-
)
|
|
88
|
-
if len(value) > 64:
|
|
89
|
-
raise ValidationError(
|
|
90
|
-
_("Password cannot be greater than 64 characters in length, got %(len)s."),
|
|
91
|
-
code="invalid",
|
|
92
|
-
params={"len": len(value)},
|
|
93
|
-
)
|
|
94
|
-
if not any([char for char in value if char in string.ascii_uppercase]):
|
|
95
|
-
raise ValidationError(
|
|
96
|
-
_("Password must contain at least one uppercase letter."), code="invalid"
|
|
97
|
-
)
|
|
98
|
-
if not any([char for char in value if char in string.ascii_lowercase]):
|
|
99
|
-
raise ValidationError(
|
|
100
|
-
_("Password must contain at least one lowercase letter."), code="invalid"
|
|
101
|
-
)
|
|
102
|
-
if not any(
|
|
103
|
-
[char for char in value if char in special_symbols_0 + special_symbols_1]
|
|
104
|
-
):
|
|
105
|
-
raise ValidationError(
|
|
106
|
-
_("Password must contain at least one special symbol."), code="invalid"
|
|
107
|
-
)
|
|
108
|
-
for char in value:
|
|
109
|
-
if char in forbidden_symbols:
|
|
110
|
-
raise ValidationError(
|
|
111
|
-
_("Password cannot contain forbidden character '%(char)s'."),
|
|
112
|
-
code="invalid",
|
|
113
|
-
params={"char": char},
|
|
114
|
-
)
|
|
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
|
{python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/docs/source/authorizenet/constants.rst
RENAMED
|
File without changes
|
|
File without changes
|
{python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/docs/source/authorizenet/service.rst
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
|
{python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/terminusgps/authorizenet/__init__.py
RENAMED
|
File without changes
|
{python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/terminusgps/authorizenet/api/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/terminusgps/authorizenet/api/transactions.py
RENAMED
|
File without changes
|
{python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/terminusgps/authorizenet/constants.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/terminusgps/wialon/items/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/terminusgps/wialon/items/resource.py
RENAMED
|
File without changes
|
{python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/terminusgps/wialon/items/retranslator.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_terminusgps-47.0.0 → python_terminusgps-47.1.0}/terminusgps/wialon/items/unit_group.py
RENAMED
|
File without changes
|
|
File without changes
|