python-terminusgps 1.15.1__tar.gz → 1.15.3__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.

Potentially problematic release.


This version of python-terminusgps might be problematic. Click here for more details.

Files changed (37) hide show
  1. {python_terminusgps-1.15.1 → python_terminusgps-1.15.3}/PKG-INFO +1 -1
  2. {python_terminusgps-1.15.1 → python_terminusgps-1.15.3}/pyproject.toml +1 -1
  3. {python_terminusgps-1.15.1 → python_terminusgps-1.15.3}/terminusgps/wialon/items/resource.py +31 -4
  4. python_terminusgps-1.15.3/terminusgps/wialon/utils.py +175 -0
  5. {python_terminusgps-1.15.1 → python_terminusgps-1.15.3}/uv.lock +1 -1
  6. python_terminusgps-1.15.1/terminusgps/wialon/utils.py +0 -113
  7. {python_terminusgps-1.15.1 → python_terminusgps-1.15.3}/.gitignore +0 -0
  8. {python_terminusgps-1.15.1 → python_terminusgps-1.15.3}/COPYING +0 -0
  9. {python_terminusgps-1.15.1 → python_terminusgps-1.15.3}/README.md +0 -0
  10. {python_terminusgps-1.15.1 → python_terminusgps-1.15.3}/terminusgps/__init__.py +0 -0
  11. {python_terminusgps-1.15.1 → python_terminusgps-1.15.3}/terminusgps/authorizenet/__init__.py +0 -0
  12. {python_terminusgps-1.15.1 → python_terminusgps-1.15.3}/terminusgps/authorizenet/auth.py +0 -0
  13. {python_terminusgps-1.15.1 → python_terminusgps-1.15.3}/terminusgps/authorizenet/profiles/__init__.py +0 -0
  14. {python_terminusgps-1.15.1 → python_terminusgps-1.15.3}/terminusgps/authorizenet/profiles/addresses.py +0 -0
  15. {python_terminusgps-1.15.1 → python_terminusgps-1.15.3}/terminusgps/authorizenet/profiles/base.py +0 -0
  16. {python_terminusgps-1.15.1 → python_terminusgps-1.15.3}/terminusgps/authorizenet/profiles/customers.py +0 -0
  17. {python_terminusgps-1.15.1 → python_terminusgps-1.15.3}/terminusgps/authorizenet/profiles/payments.py +0 -0
  18. {python_terminusgps-1.15.1 → python_terminusgps-1.15.3}/terminusgps/authorizenet/subscriptions.py +0 -0
  19. {python_terminusgps-1.15.1 → python_terminusgps-1.15.3}/terminusgps/aws/__init__.py +0 -0
  20. {python_terminusgps-1.15.1 → python_terminusgps-1.15.3}/terminusgps/aws/secrets.py +0 -0
  21. {python_terminusgps-1.15.1 → python_terminusgps-1.15.3}/terminusgps/aws/ses.py +0 -0
  22. {python_terminusgps-1.15.1 → python_terminusgps-1.15.3}/terminusgps/settings.py +0 -0
  23. {python_terminusgps-1.15.1 → python_terminusgps-1.15.3}/terminusgps/twilio/__init__.py +0 -0
  24. {python_terminusgps-1.15.1 → python_terminusgps-1.15.3}/terminusgps/twilio/caller.py +0 -0
  25. {python_terminusgps-1.15.1 → python_terminusgps-1.15.3}/terminusgps/wialon/__init__.py +0 -0
  26. {python_terminusgps-1.15.1 → python_terminusgps-1.15.3}/terminusgps/wialon/constants.py +0 -0
  27. {python_terminusgps-1.15.1 → python_terminusgps-1.15.3}/terminusgps/wialon/errors.py +0 -0
  28. {python_terminusgps-1.15.1 → python_terminusgps-1.15.3}/terminusgps/wialon/flags.py +0 -0
  29. {python_terminusgps-1.15.1 → python_terminusgps-1.15.3}/terminusgps/wialon/items/__init__.py +0 -0
  30. {python_terminusgps-1.15.1 → python_terminusgps-1.15.3}/terminusgps/wialon/items/base.py +0 -0
  31. {python_terminusgps-1.15.1 → python_terminusgps-1.15.3}/terminusgps/wialon/items/notification.py +0 -0
  32. {python_terminusgps-1.15.1 → python_terminusgps-1.15.3}/terminusgps/wialon/items/retranslator.py +0 -0
  33. {python_terminusgps-1.15.1 → python_terminusgps-1.15.3}/terminusgps/wialon/items/route.py +0 -0
  34. {python_terminusgps-1.15.1 → python_terminusgps-1.15.3}/terminusgps/wialon/items/unit.py +0 -0
  35. {python_terminusgps-1.15.1 → python_terminusgps-1.15.3}/terminusgps/wialon/items/unit_group.py +0 -0
  36. {python_terminusgps-1.15.1 → python_terminusgps-1.15.3}/terminusgps/wialon/items/user.py +0 -0
  37. {python_terminusgps-1.15.1 → python_terminusgps-1.15.3}/terminusgps/wialon/session.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-terminusgps
3
- Version: 1.15.1
3
+ Version: 1.15.3
4
4
  Summary: Provides abstractions/utilities for working with Wialon API, Authorize.NET API, AWS API, and more.
5
5
  Project-URL: Documentation, https://app.terminusgps.com/docs/apps/python-terminusgps/index.html
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 = "1.15.1"
3
+ version = "1.15.3"
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" } ]
@@ -21,10 +21,34 @@ class WialonResource(WialonBase):
21
21
  return response.get("item", {}).get("id")
22
22
 
23
23
  def delete(self) -> None:
24
- if self.is_account:
25
- self.delete_account()
26
- return
27
- super().delete()
24
+ """
25
+ Deletes all micro-objects assigned to the resource.
26
+
27
+ If the resource is an account, instead deletes all macro-objects and micro-objects assigned to the account.
28
+
29
+ :returns: Nothing.
30
+ :rtype: :py:obj:`None`
31
+
32
+ """
33
+ self.delete_account() if self.is_account else super().delete()
34
+
35
+ @property
36
+ def is_dealer(self) -> bool:
37
+ """
38
+ Whether or not the resource/account has dealer rights.
39
+
40
+ If the resource is **not** an account, this always returns :py:obj:`False`.
41
+
42
+ :type: :py:obj:`bool`
43
+
44
+ """
45
+ if not self.is_account:
46
+ return False # Resources cannot have dealer rights
47
+ return bool(
48
+ self.session.wialon_api.get_account_data(
49
+ **{"itemId": self.id, "type": 1}
50
+ ).get("dealerRights")
51
+ )
28
52
 
29
53
  @property
30
54
  def is_account(self) -> bool:
@@ -60,6 +84,8 @@ class WialonResource(WialonBase):
60
84
  """
61
85
  Sets dealer rights on the account.
62
86
 
87
+ You **probably don't** need to use this method.
88
+
63
89
  :param enabled: :py:obj:`True` to enable dealer rights, :py:obj:`False` to disable dealer rights. Default is :py:obj:`False`.
64
90
  :type enabled: :py:obj:`bool`
65
91
  :raises AssertionError: If the resource is not an account.
@@ -123,6 +149,7 @@ class WialonResource(WialonBase):
123
149
  self.session.wialon_api.account_create_account(
124
150
  **{"itemId": self.id, "plan": billing_plan}
125
151
  )
152
+ self.set_settings_flags()
126
153
 
127
154
  def delete_account(self) -> None:
128
155
  """
@@ -0,0 +1,175 @@
1
+ import secrets
2
+ import string
3
+ import warnings
4
+ from typing import Type
5
+
6
+ from terminusgps.wialon import items, flags
7
+ from terminusgps.wialon.items.base import WialonBase
8
+ from terminusgps.wialon.session import WialonSession
9
+
10
+
11
+ def get_hw_type_id(name: str, session: WialonSession) -> int | None:
12
+ """
13
+ Takes a Wialon hardware type name and returns its id, if it exists.
14
+
15
+ :param name: The name of a Wialon hardware type.
16
+ :type name: :py:obj:`str`
17
+ :param session: A valid Wialon API session.
18
+ :type session: :py:obj:`~terminusgps.wialon.session.WialonSession`
19
+ :raises WialonError: If something goes wrong with Wialon.
20
+ :returns: A Wialon hardware type id, if it was found.
21
+ :rtype: :py:obj:`int` | :py:obj:`None`
22
+
23
+ """
24
+ response = session.wialon_api.core_get_hw_types(
25
+ **{
26
+ "filterType": "id",
27
+ "filterValue": "name,id",
28
+ "includeType": "true",
29
+ "ignoreRename": "true",
30
+ }
31
+ )
32
+ hw_types = {item.get("name"): item.get("id") for item in response}
33
+ return int(hw_types.get(name)) if name in hw_types.keys() else None
34
+
35
+
36
+ def get_id_from_iccid(iccid: str, session: WialonSession) -> str | None:
37
+ """
38
+ Takes a Wialon unit's IMEI # and returns its unit id, if it exists.
39
+
40
+ :param iccid: A unique id.
41
+ :type iccid: :py:obj:`str`
42
+ :param session: A valid Wialon API session.
43
+ :type session: :py:obj:`~terminusgps.wialon.session.WialonSession`
44
+ :raises WialonError: If something goes wrong with Wialon.
45
+ :returns: A Wialon object id, if it was found.
46
+ :rtype: :py:obj:`str` | :py:obj:`None`
47
+
48
+ """
49
+ response = session.wialon_api.core_search_items(
50
+ **{
51
+ "spec": {
52
+ "itemsType": "avl_unit",
53
+ "propName": "rel_admin_field_value",
54
+ "propValueMask": str(iccid),
55
+ "sortType": "admin_fields",
56
+ "propType": "adminfield",
57
+ "or_logic": 0,
58
+ },
59
+ "force": 0,
60
+ "flags": flags.DATAFLAG_UNIT_BASE,
61
+ "from": 0,
62
+ "to": 0,
63
+ }
64
+ )
65
+
66
+ if response.get("totalItemsCount", 0) == 1:
67
+ return response["items"][0].get("id")
68
+
69
+
70
+ def get_wialon_cls(items_type: str) -> Type[WialonBase]:
71
+ """
72
+ Returns a Wialon object class based on items_type.
73
+
74
+ :param items_type: A Wialon object type.
75
+ :type items_type: :py:obj:`str`
76
+ :returns: A subclass of :py:obj:`~terminusgps.wialon.items.base.WialonBase`.
77
+ :rtype: :py:obj:`~terminusgps.wialon.items.base.WialonBase`
78
+
79
+ """
80
+ match items_type:
81
+ case "user":
82
+ wialon_cls = items.WialonUser
83
+ case "avl_unit":
84
+ wialon_cls = items.WialonUnit
85
+ case "avl_unit_group":
86
+ wialon_cls = items.WialonUnitGroup
87
+ case "avl_resource":
88
+ wialon_cls = items.WialonResource
89
+ case _:
90
+ raise ValueError(f"Invalid items_type '{items_type}'")
91
+ return wialon_cls
92
+
93
+
94
+ def is_unique(value: str, session: WialonSession, items_type: str = "avl_unit") -> bool:
95
+ """
96
+ Determines if the value is unique among Wialon objects of type 'items_type'.
97
+
98
+ :param value: A value whose uniqueness is unknown.
99
+ :type value: :py:obj:`str`
100
+ :param session: A valid Wialon API session.
101
+ :type session: :py:obj:`~terminusgps.wialon.session.WialonSession`
102
+ :param items_type: The type of Wialon objects to validate the value against. Default is ``"avl_unit"``.
103
+ :type items_type: :py:obj:`str`
104
+ :returns: Whether or not the value is unique among 'items_type'.
105
+ :rtype: :py:obj:`bool`
106
+
107
+
108
+ """
109
+ result = session.wialon_api.core_check_unique(
110
+ **{"type": items_type, "value": value.strip()}
111
+ ).get("result")
112
+ return not bool(result)
113
+
114
+
115
+ def gen_wialon_password(length: int = 32) -> str:
116
+ """
117
+ DEPRECATED: Use :py:func:`~terminusgps.wialon.utils.generate_wialon_password` instead.
118
+
119
+ Generates a Wialon compliant password of random characters.
120
+
121
+ Password length can be between ``8`` and ``64`` characters.
122
+
123
+ :param length: Length of the generated password. Default is ``32``.
124
+ :type length: :py:obj:`int`
125
+ :raises ValueError: If the provided length is invalid.
126
+ :returns: A Wialon compliant password.
127
+ :rtype: :py:obj:`str`
128
+
129
+ """
130
+ warnings.warn(
131
+ "gen_wialon_password is deprecated and will be removed in a future version. Use generate_wialon_password instead.",
132
+ DeprecationWarning,
133
+ stacklevel=2,
134
+ )
135
+ return generate_wialon_password(length)
136
+
137
+
138
+ def generate_wialon_password(length: int = 32) -> str:
139
+ """
140
+ Generates a Wialon compliant password of random characters.
141
+
142
+ Password length can be between ``8`` and ``64`` characters.
143
+
144
+ :param length: Length of the generated password. Default is ``32``.
145
+ :type length: :py:obj:`int`
146
+ :raises ValueError: If the provided length is invalid.
147
+ :returns: A Wialon compliant password.
148
+ :rtype: :py:obj:`str`
149
+
150
+ """
151
+ min_length, max_length = 8, 64
152
+ if length > max_length:
153
+ raise ValueError(
154
+ f"Password cannot be greater than {max_length} characters in length. Got {length}."
155
+ )
156
+ elif length < min_length:
157
+ raise ValueError(
158
+ f"Password cannot be less than {min_length} characters in length. Got {length}."
159
+ )
160
+
161
+ s0 = list(string.ascii_uppercase)
162
+ s1 = list(string.ascii_lowercase)
163
+ s2 = list(string.digits)
164
+ s3 = list("!@#$%^*()[]-_+")
165
+
166
+ while True:
167
+ password = "".join([secrets.choice(s0 + s1 + s2 + s3) for _ in range(length)])
168
+ if (
169
+ any(c.islower() for c in password)
170
+ and any(c.isupper() for c in password)
171
+ and sum(c.isdigit() for c in password) >= 3
172
+ and any(c in s3 for c in password)
173
+ ):
174
+ break
175
+ return password
@@ -504,7 +504,7 @@ wheels = [
504
504
 
505
505
  [[package]]
506
506
  name = "python-terminusgps"
507
- version = "1.15.1"
507
+ version = "1.15.3"
508
508
  source = { editable = "." }
509
509
  dependencies = [
510
510
  { name = "argparse" },
@@ -1,113 +0,0 @@
1
- import secrets
2
- import string
3
-
4
- from typing import Any
5
- from .session import WialonSession
6
- from .flags import DATAFLAG_UNIT_BASE
7
-
8
- from terminusgps.wialon.items import (
9
- WialonUser,
10
- WialonUnit,
11
- WialonUnitGroup,
12
- WialonResource,
13
- )
14
-
15
-
16
- def get_hw_type_id(name: str, session: WialonSession) -> int | None:
17
- response = session.wialon_api.core_get_hw_types(
18
- **{
19
- "filterType": "id",
20
- "filterValue": "name,id",
21
- "includeType": "true",
22
- "ignoreRename": "true",
23
- }
24
- )
25
- hw_types = {item.get("name"): item.get("id") for item in response}
26
- return int(hw_types.get(name)) if name in hw_types.keys() else None
27
-
28
-
29
- def get_wialon_cls(items_type: str) -> Any:
30
- """Returns a Wialon object class based on items_type."""
31
- match items_type:
32
- case "user":
33
- wialon_cls = WialonUser
34
- case "avl_unit":
35
- wialon_cls = WialonUnit
36
- case "avl_unit_group":
37
- wialon_cls = WialonUnitGroup
38
- case "avl_resource":
39
- wialon_cls = WialonResource
40
- case _:
41
- raise ValueError(f"Invalid items_type '{items_type}'")
42
- return wialon_cls
43
-
44
-
45
- def is_unique(value: str, session: WialonSession, items_type: str = "avl_unit") -> bool:
46
- """Determines if the value is unique among Wialon objects of type 'items_type'."""
47
- result = session.wialon_api.core_check_unique(
48
- **{"type": items_type, "value": value.strip()}
49
- ).get("result")
50
- return not bool(result)
51
-
52
-
53
- def gen_wialon_password(length: int = 32) -> str:
54
- """Generates a Wialon compliant password."""
55
- min_length, max_length = 4, 64
56
- if length > max_length:
57
- raise ValueError(
58
- f"Password cannot be greater than {max_length} characters in length. Got {length}."
59
- )
60
- elif length < min_length:
61
- raise ValueError(
62
- f"Password cannot be less than {min_length} characters in length. Got {length}."
63
- )
64
-
65
- s0 = list(string.ascii_uppercase)
66
- s1 = list(string.ascii_lowercase)
67
- s2 = list(string.digits)
68
- s3 = list("!@#$%^*()[]-_+")
69
-
70
- while True:
71
- password = "".join([secrets.choice(s0 + s1 + s2 + s3) for _ in range(length)])
72
- if (
73
- any(c.islower() for c in password)
74
- and any(c.isupper() for c in password)
75
- and sum(c.isdigit() for c in password) >= 3
76
- and any(c in s3 for c in password)
77
- ):
78
- break
79
- return password
80
-
81
-
82
- def get_id_from_iccid(iccid: str, session: WialonSession) -> str | None:
83
- """Takes a Wialon unit's IMEI # and returns its unit id, if it exists."""
84
- response = session.wialon_api.core_search_items(
85
- **{
86
- "spec": {
87
- "itemsType": "avl_unit",
88
- "propName": "rel_admin_field_value",
89
- "propValueMask": str(iccid),
90
- "sortType": "admin_fields",
91
- "propType": "adminfield",
92
- "or_logic": 0,
93
- },
94
- "force": 0,
95
- "flags": DATAFLAG_UNIT_BASE,
96
- "from": 0,
97
- "to": 0,
98
- }
99
- )
100
-
101
- if response.get("totalItemsCount", 0) == 1:
102
- return response["items"][0].get("id")
103
-
104
-
105
- def main() -> None:
106
- with WialonSession() as session:
107
- wialon_id = get_id_from_iccid("89015809000307608963", session)
108
- print(f"{wialon_id = }")
109
- return
110
-
111
-
112
- if __name__ == "__main__":
113
- main()