django-esi 8.0.0a3__tar.gz → 8.0.0b1__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 django-esi might be problematic. Click here for more details.

Files changed (100) hide show
  1. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/PKG-INFO +3 -2
  2. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/__init__.py +2 -2
  3. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/aiopenapi3/plugins.py +100 -3
  4. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/clients.py +15 -6
  5. django_esi-8.0.0b1/esi/helpers.py +62 -0
  6. django_esi-8.0.0b1/esi/locale/cs_CZ/LC_MESSAGES/django.mo +0 -0
  7. django_esi-8.0.0b1/esi/locale/cs_CZ/LC_MESSAGES/django.po +53 -0
  8. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/locale/de/LC_MESSAGES/django.mo +0 -0
  9. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/locale/de/LC_MESSAGES/django.po +10 -9
  10. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/locale/en/LC_MESSAGES/django.mo +0 -0
  11. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/locale/en/LC_MESSAGES/django.po +3 -3
  12. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/locale/es/LC_MESSAGES/django.mo +0 -0
  13. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/locale/es/LC_MESSAGES/django.po +12 -10
  14. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/locale/fr_FR/LC_MESSAGES/django.mo +0 -0
  15. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/locale/fr_FR/LC_MESSAGES/django.po +18 -10
  16. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/locale/it_IT/LC_MESSAGES/django.mo +0 -0
  17. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/locale/it_IT/LC_MESSAGES/django.po +12 -10
  18. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/locale/ja/LC_MESSAGES/django.mo +0 -0
  19. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/locale/ja/LC_MESSAGES/django.po +10 -9
  20. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/locale/ko_KR/LC_MESSAGES/django.mo +0 -0
  21. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/locale/ko_KR/LC_MESSAGES/django.po +10 -9
  22. django_esi-8.0.0b1/esi/locale/nl_NL/LC_MESSAGES/django.mo +0 -0
  23. django_esi-8.0.0b1/esi/locale/nl_NL/LC_MESSAGES/django.po +53 -0
  24. django_esi-8.0.0b1/esi/locale/pl_PL/LC_MESSAGES/django.mo +0 -0
  25. django_esi-8.0.0b1/esi/locale/pl_PL/LC_MESSAGES/django.po +53 -0
  26. django_esi-8.0.0b1/esi/locale/ru/LC_MESSAGES/django.mo +0 -0
  27. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/locale/ru/LC_MESSAGES/django.po +13 -10
  28. django_esi-8.0.0b1/esi/locale/sk/LC_MESSAGES/django.mo +0 -0
  29. django_esi-8.0.0b1/esi/locale/sk/LC_MESSAGES/django.po +55 -0
  30. django_esi-8.0.0b1/esi/locale/uk/LC_MESSAGES/django.mo +0 -0
  31. django_esi-8.0.0b1/esi/locale/uk/LC_MESSAGES/django.po +57 -0
  32. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/locale/zh_Hans/LC_MESSAGES/django.mo +0 -0
  33. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/locale/zh_Hans/LC_MESSAGES/django.po +10 -9
  34. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/management/commands/generate_esi_stubs.py +11 -31
  35. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/models.py +1 -1
  36. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/openapi_clients.py +207 -54
  37. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/stubs.pyi +395 -395
  38. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/tests/__init__.py +3 -3
  39. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/tests/test_clients.py +77 -19
  40. django_esi-8.0.0b1/esi/tests/test_openapi.json +264 -0
  41. django_esi-8.0.0b1/esi/tests/test_openapi.py +415 -0
  42. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/pyproject.toml +2 -1
  43. django_esi-8.0.0a3/esi/helpers.py +0 -25
  44. django_esi-8.0.0a3/esi/locale/ru/LC_MESSAGES/django.mo +0 -0
  45. django_esi-8.0.0a3/esi/tests/test_openapi.py +0 -14
  46. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/LICENSE +0 -0
  47. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/README.md +0 -0
  48. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/admin.py +0 -0
  49. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/app_settings.py +0 -0
  50. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/apps.py +0 -0
  51. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/checks.py +0 -0
  52. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/decorators.py +0 -0
  53. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/errors.py +0 -0
  54. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/exceptions.py +0 -0
  55. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/management/commands/__init__.py +0 -0
  56. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/management/commands/migrate_to_ssov2.py +0 -0
  57. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/managers.py +0 -0
  58. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/managers.pyi +0 -0
  59. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/migrations/0001_initial.py +0 -0
  60. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/migrations/0002_scopes_20161208.py +0 -0
  61. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/migrations/0003_hide_tokens_from_admin_site.py +0 -0
  62. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/migrations/0004_remove_unique_access_token.py +0 -0
  63. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/migrations/0005_remove_token_length_limit.py +0 -0
  64. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/migrations/0006_remove_url_length_limit.py +0 -0
  65. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/migrations/0007_fix_mysql_8_migration.py +0 -0
  66. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/migrations/0008_nullable_refresh_token.py +0 -0
  67. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/migrations/0009_set_old_tokens_to_sso_v1.py +0 -0
  68. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/migrations/0010_set_new_tokens_to_sso_v2.py +0 -0
  69. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/migrations/0011_add_token_indices.py +0 -0
  70. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/migrations/0012_fix_token_type_choices.py +0 -0
  71. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/migrations/0013_squashed_0012_fix_token_type_choices.py +0 -0
  72. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/migrations/__init__.py +0 -0
  73. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/rate_limiting.py +0 -0
  74. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/static/esi/img/EVE_SSO_Login_Buttons_Large_Black.png +0 -0
  75. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/static/esi/img/EVE_SSO_Login_Buttons_Large_White.png +0 -0
  76. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/static/esi/img/EVE_SSO_Login_Buttons_Small_Black.png +0 -0
  77. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/static/esi/img/EVE_SSO_Login_Buttons_Small_White.png +0 -0
  78. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/stubs.py +0 -0
  79. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/tasks.py +0 -0
  80. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/templates/esi/select_token.html +0 -0
  81. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/templatetags/__init__.py +0 -0
  82. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/templatetags/scope_tags.py +0 -0
  83. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/tests/client_authed_pilot.py +0 -0
  84. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/tests/client_public_pilot.py +0 -0
  85. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/tests/factories.py +0 -0
  86. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/tests/factories_2.py +0 -0
  87. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/tests/jwt_factory.py +0 -0
  88. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/tests/test_checks.py +0 -0
  89. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/tests/test_decorators.py +0 -0
  90. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/tests/test_management_command.py +0 -0
  91. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/tests/test_managers.py +0 -0
  92. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/tests/test_models.py +0 -0
  93. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/tests/test_swagger.json +0 -0
  94. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/tests/test_swagger_full.json +0 -0
  95. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/tests/test_tasks.py +0 -0
  96. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/tests/test_templatetags.py +0 -0
  97. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/tests/test_views.py +0 -0
  98. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/tests/threading_pilot.py +0 -0
  99. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/urls.py +0 -0
  100. {django_esi-8.0.0a3 → django_esi-8.0.0b1}/esi/views.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-esi
3
- Version: 8.0.0a3
3
+ Version: 8.0.0b1
4
4
  Summary: Django app for accessing the EVE Swagger Interface (ESI).
5
5
  Keywords: eveonline
6
6
  Author-email: Alliance Auth <adarnof@gmail.com>
@@ -20,6 +20,7 @@ Classifier: Programming Language :: Python :: 3.10
20
20
  Classifier: Programming Language :: Python :: 3.11
21
21
  Classifier: Programming Language :: Python :: 3.12
22
22
  Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Programming Language :: Python :: 3.14
23
24
  Classifier: Topic :: Internet :: WWW/HTTP
24
25
  Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
25
26
  License-File: LICENSE
@@ -27,7 +28,7 @@ Requires-Dist: aiopenapi3
27
28
  Requires-Dist: bravado>=10.6,<12
28
29
  Requires-Dist: celery>=4.0.2
29
30
  Requires-Dist: django>=4.2,<6
30
- Requires-Dist: httpx[http2, brotli, zstd]
31
+ Requires-Dist: httpx[brotli, http2, zstd]
31
32
  Requires-Dist: jsonschema<4
32
33
  Requires-Dist: python-jose>=3.3
33
34
  Requires-Dist: requests>=2.26
@@ -1,6 +1,6 @@
1
1
  """Django app for accessing the EVE Swagger Interface (ESI)."""
2
2
 
3
- __version__ = '8.0.0a3'
3
+ __version__ = "8.0.0-beta.1"
4
4
  __title__ = 'Django-ESI'
5
5
  __url__ = 'https://gitlab.com/allianceauth/django-esi'
6
- __build_date__ = "2025-09-17"
6
+ __build_date__ = "2025-09-18"
@@ -1,4 +1,9 @@
1
- from aiopenapi3.plugin import Document
1
+ import logging
2
+ from typing import Any
3
+ from collections.abc import Generator
4
+ from aiopenapi3.plugin import Document, Init
5
+
6
+ logger = logging.getLogger(__name__)
2
7
 
3
8
 
4
9
  class Trim204ContentType(Document):
@@ -6,6 +11,7 @@ class Trim204ContentType(Document):
6
11
  Removes and content-type from responses on a 204 reponses
7
12
  A 204 never has content...
8
13
  """
14
+
9
15
  def parsed(self, ctx: Document.Context) -> Document.Context:
10
16
  spec = ctx.document
11
17
  # Patch all paths
@@ -19,12 +25,88 @@ class Trim204ContentType(Document):
19
25
  return ctx
20
26
 
21
27
 
28
+ def find_refs_recursively(data: Any, parent: Any = None) -> Generator[Any, None, None]:
29
+ """
30
+ Recursively searches for all instances of "#ref" in a dict+children and returns schemas.
31
+ """
32
+ if isinstance(data, dict):
33
+ for key, value in data.items():
34
+ if key == "$ref":
35
+ if "#/components/schemas/" in value:
36
+ next = value.split("/")[-1]
37
+ yield next
38
+ if parent:
39
+ yield from find_refs_recursively(parent[next], parent)
40
+ yield from find_refs_recursively(value, parent)
41
+ elif isinstance(data, list):
42
+ for item in data:
43
+ yield from find_refs_recursively(item, parent)
44
+
45
+
46
+ class MinifySpec(Document):
47
+ """
48
+ Removes operations and schemas from spec to limit memory spam
49
+ """
50
+
51
+ def __init__(self, tags: list[str], operations: list[str]):
52
+ super().__init__()
53
+ self.keep_tags = set(tags)
54
+ self.keep_ops = operations
55
+
56
+ def parsed(self, ctx: Document.Context) -> Document.Context:
57
+ if self.keep_tags == set() and self.keep_ops == []:
58
+ logger.error("No tag/path filtering supplied to ESI Client. Using all tags. This will bloat memory use!")
59
+ return ctx
60
+ spec = ctx.document
61
+
62
+ remove_paths = set()
63
+ keep_schema = set()
64
+ logger.debug("Filtering Paths/Tags: ")
65
+ for name, path_item in spec.get("paths", {}).items():
66
+ keep = False
67
+ for method_name in ("get", "post", "put", "delete", "patch", "options", "head"):
68
+ method = path_item.get(method_name)
69
+ if not method:
70
+ continue
71
+ if len(self.keep_tags.intersection(method['tags'])) or method["operationId"] in self.keep_ops:
72
+ keep = True
73
+ schemas = find_refs_recursively(
74
+ path_item,
75
+ spec["components"]["schemas"] # find all sub schema's
76
+ )
77
+ for s in schemas:
78
+ keep_schema.add(s)
79
+
80
+ if not keep:
81
+ remove_paths.add(name)
82
+ else:
83
+ logger.debug(f" - {name}")
84
+
85
+ # remove the paths we don't care for
86
+ for name in remove_paths:
87
+ spec["paths"].pop(name)
88
+
89
+ # build new schema from what we need
90
+ logger.debug("Rebuilding Schema: ")
91
+ new_schema = {}
92
+ for name, data in spec["components"]["schemas"].items():
93
+ if name in keep_schema:
94
+ logger.debug(f" - {name}")
95
+ new_schema[name] = data
96
+
97
+ # replace schemas with the new schema
98
+ ctx.document["components"]["schemas"] = new_schema
99
+
100
+ return ctx
101
+
102
+
22
103
  class Add304ContentType(Document):
23
104
  """
24
105
  Adds 304 content-type to responses
25
106
  A 304 never has content. ESI defualt has application/json
26
107
  This is a hack for now
27
108
  """
109
+
28
110
  def parsed(self, ctx: Document.Context) -> Document.Context:
29
111
  spec = ctx.document
30
112
  # Patch all paths
@@ -34,7 +116,7 @@ class Add304ContentType(Document):
34
116
  if not method:
35
117
  continue
36
118
  if "304" not in method['responses']:
37
- method['responses']["304"]={
119
+ method['responses']["304"] = {
38
120
  "description": "Not Modified"
39
121
  }
40
122
  return ctx
@@ -44,6 +126,7 @@ class RemoveSecurityParameter(Document):
44
126
  """
45
127
  Removes the whole OAuth2 securityScheme
46
128
  """
129
+
47
130
  def parsed(self, ctx: Document.Context) -> Document.Context:
48
131
  print("RemoveSecurityParameterPlugin: Removing OAuth2 securityScheme")
49
132
  spec = ctx.document
@@ -64,6 +147,7 @@ class TrimSecurityParameter(Document):
64
147
  Trims out of Spec OAuth2 attributes. CCP have fixed this.
65
148
  Leaving in place in case we need a quick reference again.
66
149
  """
150
+
67
151
  def parsed(self, ctx: Document.Context) -> Document.Context:
68
152
  print("TrimSecurityParameter: Trimming out of spec attributes")
69
153
  spec = ctx.document
@@ -81,8 +165,9 @@ class PatchCompatibilityDatePlugin(Document):
81
165
  This is because WE specifically add it in the library to the HTTP requests,
82
166
  but without this, it will be a required parameter during request generation before it hits the HTTP library.
83
167
  """
168
+
84
169
  def parsed(self, ctx: Document.Context) -> Document.Context:
85
- print("PatchCompatibilityDatePlugin: making compatibility date optional")
170
+ logger.debug("PatchCompatibilityDatePlugin: making compatibility date optional")
86
171
  spec = ctx.document
87
172
 
88
173
  def patch_param(param):
@@ -115,3 +200,15 @@ class PatchCompatibilityDatePlugin(Document):
115
200
  param["required"] = False
116
201
 
117
202
  return ctx
203
+
204
+
205
+ class DjangoESIInit(Init):
206
+
207
+ def __init__(self, ua_appname):
208
+ super().__init__()
209
+ self.app_name = ua_appname
210
+
211
+ def initialized(self, ctx: Init.Context) -> Init.Context:
212
+ # Force the app_name into the api client class for etags
213
+ self.api.app_name = self.app_name
214
+ return ctx # noqa
@@ -1,7 +1,7 @@
1
1
  import json
2
2
  import logging
3
3
  import warnings
4
- from datetime import datetime
4
+ import datetime as dt
5
5
  from hashlib import md5
6
6
  from time import sleep
7
7
  from typing import Any
@@ -68,8 +68,10 @@ class CachingHttpFuture(HttpFuture):
68
68
  seconds until "Expires" time
69
69
  """
70
70
  try:
71
- expires_dt = datetime.strptime(str(expires), '%a, %d %b %Y %H:%M:%S %Z')
72
- delta = expires_dt - datetime.utcnow()
71
+ expires_dt = dt.datetime.strptime(str(expires), '%a, %d %b %Y %H:%M:%S %Z')
72
+ if expires_dt.tzinfo is None:
73
+ expires_dt = expires_dt.replace(tzinfo=dt.timezone.utc)
74
+ delta = expires_dt - dt.datetime.now(dt.timezone.utc)
73
75
  return delta.total_seconds()
74
76
  except ValueError:
75
77
  return 0
@@ -482,19 +484,26 @@ def esi_client_factory(
482
484
 
483
485
  client = RequestsClientPlus()
484
486
 
487
+ from esi.helpers import pascal_case_string
488
+ sanitized_appname = pascal_case_string(__title__)
489
+
485
490
  if app_info_text:
486
491
  # app_info_text (email@example) Django-ESI/1.2.3 (+https://gitlab.com/allianceauth/django-esi)
487
492
  # Deprecated
488
- user_agent = f"{app_info_text} ({app_settings.ESI_USER_CONTACT_EMAIL}) {__title__}/{__version__} (+{__url__})"
493
+ user_agent = f"{app_info_text} ({app_settings.ESI_USER_CONTACT_EMAIL}) {sanitized_appname}/{__version__} (+{__url__})"
489
494
  elif ua_appname is None or ua_version is None:
490
495
  # Django-ESI/1.2.3 () (email@example; +https://gitlab.com/allianceauth/django-esi)
491
496
  # Deprecated
492
- user_agent = f"{__title__}/{__version__} ({app_settings.ESI_USER_CONTACT_EMAIL}; +{__url__})"
497
+ user_agent = f"{sanitized_appname}/{__version__} ({app_settings.ESI_USER_CONTACT_EMAIL}; +{__url__})"
493
498
  else:
494
499
  # AppName/1.2.3 (email@example.com) Django-ESI/1.2.3 (+https://gitlab.com/allianceauth/django-esi)
495
500
  # or AppName/1.2.3 (email@example.com; +https://gitlab.com/) Django-ESI/1.2.3 (+https://gitlab.com/allianceauth/django-esi) (+https://gitlab.com/allianceauth/django-esi)
496
501
  # Preferred
497
- user_agent = f"{ua_appname}/{ua_version} ({app_settings.ESI_USER_CONTACT_EMAIL}{f'; +{ua_url})' if ua_url else ')'} {__title__}/{__version__} (+{__url__})"
502
+
503
+ # Enforce PascalCase for `ua_appname` and strip whitespace
504
+ sanitized_ua_appname = pascal_case_string(ua_appname)
505
+
506
+ user_agent = f"{sanitized_ua_appname}/{ua_version} ({app_settings.ESI_USER_CONTACT_EMAIL}{f'; +{ua_url})' if ua_url else ')'} {sanitized_appname}/{__version__} (+{__url__})"
498
507
 
499
508
  client.user_agent = user_agent
500
509
 
@@ -0,0 +1,62 @@
1
+ from esi.models import Token
2
+ from string import capwords
3
+
4
+
5
+ def get_token(character_id: int, scopes: list) -> Token:
6
+ """Helper method to get a valid token for a specific character with specific scopes.
7
+
8
+ Args:
9
+ character_id: Character to filter on.
10
+ scopes: array of ESI scope strings to search for.
11
+
12
+ Returns:
13
+ Matching Token
14
+ """
15
+ qs = (
16
+ Token.objects
17
+ .filter(character_id=character_id)
18
+ .require_scopes(scopes)
19
+ .require_valid()
20
+ )
21
+ token = qs.first()
22
+ if token is None:
23
+ raise Token.DoesNotExist(
24
+ f"No valid token found for character_id={character_id} with required scopes."
25
+ )
26
+ return token
27
+
28
+ def pascal_case_string(string: str) -> str:
29
+ """
30
+ Convert a string to PascalCase by capitalizing the first letter of each word and removing spaces,
31
+ but only if the string contains spaces or hyphens.
32
+
33
+ This function checks if the input string contains spaces or hyphens. If so, it replaces hyphens with spaces,
34
+ capitalizes the first letter of each word, removes the spaces, and returns the resulting PascalCase string.
35
+ If the input string does not contain spaces or hyphens, it is returned unchanged.
36
+
37
+ Behaviour:
38
+ Any string containing spaces or hyphens will be converted to PascalCase.
39
+ Strings without spaces or hyphens will be returned unchanged.
40
+ This gives you the opportunity to use already formatted strings as needed.
41
+
42
+ Examples:
43
+ - "app name" -> "AppName"
44
+ - "app-name" -> "AppName"
45
+ - "appname" -> "appname"
46
+ - "AppName" -> "AppName"
47
+ - "appName" -> "appName"
48
+ - "app_name" -> "app_name"
49
+
50
+ :param string: The input string to be converted to PascalCase.
51
+ :type string: str
52
+ :return: The PascalCase formatted string, or the original string if no spaces or hyphens are present.
53
+ :rtype: str
54
+ """
55
+
56
+ # Check if the string contains spaces or hyphens
57
+ if any(c in string for c in (" ", "-")):
58
+ # Replace hyphens with spaces, capitalize each word, and remove spaces
59
+ return capwords(string.replace("-", " ")).replace(" ", "")
60
+
61
+ # Return the original string if no spaces or hyphens are present
62
+ return string
@@ -0,0 +1,53 @@
1
+ # SOME DESCRIPTIVE TITLE.
2
+ # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
3
+ # This file is distributed under the same license as the PACKAGE package.
4
+ # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
5
+ #
6
+ #, fuzzy
7
+ msgid ""
8
+ msgstr ""
9
+ "Project-Id-Version: Django ESI 8.0.0-beta.1\n"
10
+ "Report-Msgid-Bugs-To: https://gitlab.com/allianceauth/django-esi/-/issues\n"
11
+ "POT-Creation-Date: 2025-10-17 15:19+1000\n"
12
+ "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13
+ "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14
+ "Language-Team: LANGUAGE <LL@li.org>\n"
15
+ "Language: \n"
16
+ "MIME-Version: 1.0\n"
17
+ "Content-Type: text/plain; charset=UTF-8\n"
18
+ "Content-Transfer-Encoding: 8bit\n"
19
+
20
+ #: esi/models.py:66
21
+ msgid "Character"
22
+ msgstr ""
23
+
24
+ #: esi/models.py:67
25
+ msgid "Corporation"
26
+ msgstr ""
27
+
28
+ #: esi/templates/esi/select_token.html:13
29
+ msgid "ESI Token Selection"
30
+ msgstr ""
31
+
32
+ #: esi/templates/esi/select_token.html:44
33
+ msgid "Select Character"
34
+ msgstr ""
35
+
36
+ #: esi/templates/esi/select_token.html:48
37
+ msgid "Scopes Requested"
38
+ msgstr ""
39
+
40
+ #: esi/templates/esi/select_token.html:61
41
+ #: esi/templates/esi/select_token.html:98
42
+ msgid "New Character"
43
+ msgstr ""
44
+
45
+ #: esi/templates/esi/select_token.html:71
46
+ #: esi/templates/esi/select_token.html:107
47
+ msgid "Add Token"
48
+ msgstr ""
49
+
50
+ #: esi/templates/esi/select_token.html:88
51
+ #: esi/templates/esi/select_token.html:89
52
+ msgid "Select"
53
+ msgstr ""
@@ -2,30 +2,31 @@
2
2
  # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
3
3
  # This file is distributed under the same license as the PACKAGE package.
4
4
  # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
5
- #
5
+ #
6
6
  # Translators:
7
7
  # Peter Pfeufer, 2023
8
- #
8
+ #
9
9
  #, fuzzy
10
10
  msgid ""
11
11
  msgstr ""
12
- "Project-Id-Version: PACKAGE VERSION\n"
13
- "Report-Msgid-Bugs-To: \n"
14
- "POT-Creation-Date: 2023-10-08 23:42+1000\n"
12
+ "Project-Id-Version: Django ESI 8.0.0-beta.1\n"
13
+ "Report-Msgid-Bugs-To: https://gitlab.com/allianceauth/django-esi/-/issues\n"
14
+ "POT-Creation-Date: 2025-10-17 15:19+1000\n"
15
15
  "PO-Revision-Date: 2023-10-25 11:04+0000\n"
16
16
  "Last-Translator: Peter Pfeufer, 2023\n"
17
- "Language-Team: German (https://app.transifex.com/alliance-auth/teams/107430/de/)\n"
17
+ "Language-Team: German (https://app.transifex.com/alliance-auth/teams/107430/"
18
+ "de/)\n"
19
+ "Language: de\n"
18
20
  "MIME-Version: 1.0\n"
19
21
  "Content-Type: text/plain; charset=UTF-8\n"
20
22
  "Content-Transfer-Encoding: 8bit\n"
21
- "Language: de\n"
22
23
  "Plural-Forms: nplurals=2; plural=(n != 1);\n"
23
24
 
24
- #: esi/models.py:72
25
+ #: esi/models.py:66
25
26
  msgid "Character"
26
27
  msgstr "Charakter"
27
28
 
28
- #: esi/models.py:73
29
+ #: esi/models.py:67
29
30
  msgid "Corporation"
30
31
  msgstr "Corporation"
31
32
 
@@ -6,9 +6,9 @@
6
6
  #, fuzzy
7
7
  msgid ""
8
8
  msgstr ""
9
- "Project-Id-Version: PACKAGE VERSION\n"
10
- "Report-Msgid-Bugs-To: \n"
11
- "POT-Creation-Date: 2025-09-04 13:41+1000\n"
9
+ "Project-Id-Version: Django ESI 8.0.0-beta.1\n"
10
+ "Report-Msgid-Bugs-To: https://gitlab.com/allianceauth/django-esi/-/issues\n"
11
+ "POT-Creation-Date: 2025-10-17 15:19+1000\n"
12
12
  "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13
13
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14
14
  "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -2,30 +2,32 @@
2
2
  # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
3
3
  # This file is distributed under the same license as the PACKAGE package.
4
4
  # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
5
- #
5
+ #
6
6
  # Translators:
7
7
  # trenus, 2023
8
- #
8
+ #
9
9
  #, fuzzy
10
10
  msgid ""
11
11
  msgstr ""
12
- "Project-Id-Version: PACKAGE VERSION\n"
13
- "Report-Msgid-Bugs-To: \n"
14
- "POT-Creation-Date: 2023-10-08 23:42+1000\n"
12
+ "Project-Id-Version: Django ESI 8.0.0-beta.1\n"
13
+ "Report-Msgid-Bugs-To: https://gitlab.com/allianceauth/django-esi/-/issues\n"
14
+ "POT-Creation-Date: 2025-10-17 15:19+1000\n"
15
15
  "PO-Revision-Date: 2023-10-25 11:04+0000\n"
16
16
  "Last-Translator: trenus, 2023\n"
17
- "Language-Team: Spanish (https://app.transifex.com/alliance-auth/teams/107430/es/)\n"
17
+ "Language-Team: Spanish (https://app.transifex.com/alliance-auth/teams/107430/"
18
+ "es/)\n"
19
+ "Language: es\n"
18
20
  "MIME-Version: 1.0\n"
19
21
  "Content-Type: text/plain; charset=UTF-8\n"
20
22
  "Content-Transfer-Encoding: 8bit\n"
21
- "Language: es\n"
22
- "Plural-Forms: nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n"
23
+ "Plural-Forms: nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? "
24
+ "1 : 2;\n"
23
25
 
24
- #: esi/models.py:72
26
+ #: esi/models.py:66
25
27
  msgid "Character"
26
28
  msgstr ""
27
29
 
28
- #: esi/models.py:73
30
+ #: esi/models.py:67
29
31
  msgid "Corporation"
30
32
  msgstr ""
31
33
 
@@ -2,30 +2,32 @@
2
2
  # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
3
3
  # This file is distributed under the same license as the PACKAGE package.
4
4
  # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
5
- #
5
+ #
6
6
  # Translators:
7
7
  # rockclodbuster, 2023
8
- #
8
+ #
9
9
  #, fuzzy
10
10
  msgid ""
11
11
  msgstr ""
12
- "Project-Id-Version: PACKAGE VERSION\n"
13
- "Report-Msgid-Bugs-To: \n"
14
- "POT-Creation-Date: 2023-10-08 02:26+1000\n"
12
+ "Project-Id-Version: Django ESI 8.0.0-beta.1\n"
13
+ "Report-Msgid-Bugs-To: https://gitlab.com/allianceauth/django-esi/-/issues\n"
14
+ "POT-Creation-Date: 2025-10-17 15:19+1000\n"
15
15
  "PO-Revision-Date: 2020-12-28 06:44+0000\n"
16
16
  "Last-Translator: rockclodbuster, 2023\n"
17
- "Language-Team: French (France) (https://app.transifex.com/alliance-auth/teams/107430/fr_FR/)\n"
17
+ "Language-Team: French (France) (https://app.transifex.com/alliance-auth/"
18
+ "teams/107430/fr_FR/)\n"
19
+ "Language: fr_FR\n"
18
20
  "MIME-Version: 1.0\n"
19
21
  "Content-Type: text/plain; charset=UTF-8\n"
20
22
  "Content-Transfer-Encoding: 8bit\n"
21
- "Language: fr_FR\n"
22
- "Plural-Forms: nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n"
23
+ "Plural-Forms: nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % "
24
+ "1000000 == 0 ? 1 : 2;\n"
23
25
 
24
- #: esi/models.py:72
26
+ #: esi/models.py:66
25
27
  msgid "Character"
26
28
  msgstr ""
27
29
 
28
- #: esi/models.py:73
30
+ #: esi/models.py:67
29
31
  msgid "Corporation"
30
32
  msgstr ""
31
33
 
@@ -46,6 +48,12 @@ msgstr ""
46
48
  msgid "New Character"
47
49
  msgstr "Nouveau personnage"
48
50
 
51
+ #: esi/templates/esi/select_token.html:71
52
+ #: esi/templates/esi/select_token.html:107
53
+ msgid "Add Token"
54
+ msgstr ""
55
+
56
+ #: esi/templates/esi/select_token.html:88
49
57
  #: esi/templates/esi/select_token.html:89
50
58
  msgid "Select"
51
59
  msgstr "Sélectionnez"
@@ -2,30 +2,32 @@
2
2
  # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
3
3
  # This file is distributed under the same license as the PACKAGE package.
4
4
  # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
5
- #
5
+ #
6
6
  # Translators:
7
7
  # Thomas Turini, 2024
8
- #
8
+ #
9
9
  #, fuzzy
10
10
  msgid ""
11
11
  msgstr ""
12
- "Project-Id-Version: PACKAGE VERSION\n"
13
- "Report-Msgid-Bugs-To: \n"
14
- "POT-Creation-Date: 2023-10-08 23:42+1000\n"
12
+ "Project-Id-Version: Django ESI 8.0.0-beta.1\n"
13
+ "Report-Msgid-Bugs-To: https://gitlab.com/allianceauth/django-esi/-/issues\n"
14
+ "POT-Creation-Date: 2025-10-17 15:19+1000\n"
15
15
  "PO-Revision-Date: 2023-10-25 11:04+0000\n"
16
16
  "Last-Translator: Thomas Turini, 2024\n"
17
- "Language-Team: Italian (Italy) (https://app.transifex.com/alliance-auth/teams/107430/it_IT/)\n"
17
+ "Language-Team: Italian (Italy) (https://app.transifex.com/alliance-auth/"
18
+ "teams/107430/it_IT/)\n"
19
+ "Language: it_IT\n"
18
20
  "MIME-Version: 1.0\n"
19
21
  "Content-Type: text/plain; charset=UTF-8\n"
20
22
  "Content-Transfer-Encoding: 8bit\n"
21
- "Language: it_IT\n"
22
- "Plural-Forms: nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n"
23
+ "Plural-Forms: nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? "
24
+ "1 : 2;\n"
23
25
 
24
- #: esi/models.py:72
26
+ #: esi/models.py:66
25
27
  msgid "Character"
26
28
  msgstr "Personaggio"
27
29
 
28
- #: esi/models.py:73
30
+ #: esi/models.py:67
29
31
  msgid "Corporation"
30
32
  msgstr "Corporazione"
31
33
 
@@ -2,30 +2,31 @@
2
2
  # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
3
3
  # This file is distributed under the same license as the PACKAGE package.
4
4
  # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
5
- #
5
+ #
6
6
  # Translators:
7
7
  # kotaneko, 2023
8
- #
8
+ #
9
9
  #, fuzzy
10
10
  msgid ""
11
11
  msgstr ""
12
- "Project-Id-Version: PACKAGE VERSION\n"
13
- "Report-Msgid-Bugs-To: \n"
14
- "POT-Creation-Date: 2023-10-08 23:42+1000\n"
12
+ "Project-Id-Version: Django ESI 8.0.0-beta.1\n"
13
+ "Report-Msgid-Bugs-To: https://gitlab.com/allianceauth/django-esi/-/issues\n"
14
+ "POT-Creation-Date: 2025-10-17 15:19+1000\n"
15
15
  "PO-Revision-Date: 2023-10-25 11:04+0000\n"
16
16
  "Last-Translator: kotaneko, 2023\n"
17
- "Language-Team: Japanese (https://app.transifex.com/alliance-auth/teams/107430/ja/)\n"
17
+ "Language-Team: Japanese (https://app.transifex.com/alliance-auth/"
18
+ "teams/107430/ja/)\n"
19
+ "Language: ja\n"
18
20
  "MIME-Version: 1.0\n"
19
21
  "Content-Type: text/plain; charset=UTF-8\n"
20
22
  "Content-Transfer-Encoding: 8bit\n"
21
- "Language: ja\n"
22
23
  "Plural-Forms: nplurals=1; plural=0;\n"
23
24
 
24
- #: esi/models.py:72
25
+ #: esi/models.py:66
25
26
  msgid "Character"
26
27
  msgstr ""
27
28
 
28
- #: esi/models.py:73
29
+ #: esi/models.py:67
29
30
  msgid "Corporation"
30
31
  msgstr ""
31
32
 
@@ -2,30 +2,31 @@
2
2
  # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
3
3
  # This file is distributed under the same license as the PACKAGE package.
4
4
  # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
5
- #
5
+ #
6
6
  # Translators:
7
7
  # Seowon Jung <seowon@hawaii.edu>, 2023
8
- #
8
+ #
9
9
  #, fuzzy
10
10
  msgid ""
11
11
  msgstr ""
12
- "Project-Id-Version: PACKAGE VERSION\n"
13
- "Report-Msgid-Bugs-To: \n"
14
- "POT-Creation-Date: 2023-10-08 23:42+1000\n"
12
+ "Project-Id-Version: Django ESI 8.0.0-beta.1\n"
13
+ "Report-Msgid-Bugs-To: https://gitlab.com/allianceauth/django-esi/-/issues\n"
14
+ "POT-Creation-Date: 2025-10-17 15:19+1000\n"
15
15
  "PO-Revision-Date: 2023-10-25 11:04+0000\n"
16
16
  "Last-Translator: Seowon Jung <seowon@hawaii.edu>, 2023\n"
17
- "Language-Team: Korean (Korea) (https://app.transifex.com/alliance-auth/teams/107430/ko_KR/)\n"
17
+ "Language-Team: Korean (Korea) (https://app.transifex.com/alliance-auth/"
18
+ "teams/107430/ko_KR/)\n"
19
+ "Language: ko_KR\n"
18
20
  "MIME-Version: 1.0\n"
19
21
  "Content-Type: text/plain; charset=UTF-8\n"
20
22
  "Content-Transfer-Encoding: 8bit\n"
21
- "Language: ko_KR\n"
22
23
  "Plural-Forms: nplurals=1; plural=0;\n"
23
24
 
24
- #: esi/models.py:72
25
+ #: esi/models.py:66
25
26
  msgid "Character"
26
27
  msgstr ""
27
28
 
28
- #: esi/models.py:73
29
+ #: esi/models.py:67
29
30
  msgid "Corporation"
30
31
  msgstr ""
31
32