aa-fleetfinder 0.1.0a12__py3-none-any.whl → 3.0.0b2__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.
Files changed (89) hide show
  1. aa_fleetfinder-3.0.0b2.dist-info/METADATA +820 -0
  2. aa_fleetfinder-3.0.0b2.dist-info/RECORD +86 -0
  3. {aa_fleetfinder-0.1.0a12.dist-info → aa_fleetfinder-3.0.0b2.dist-info}/WHEEL +1 -2
  4. fleetfinder/__init__.py +19 -0
  5. fleetfinder/app_settings.py +20 -0
  6. fleetfinder/apps.py +22 -0
  7. fleetfinder/auth_hooks.py +58 -0
  8. fleetfinder/locale/cs_CZ/LC_MESSAGES/django.mo +0 -0
  9. fleetfinder/locale/cs_CZ/LC_MESSAGES/django.po +296 -0
  10. fleetfinder/locale/de/LC_MESSAGES/django.mo +0 -0
  11. fleetfinder/locale/de/LC_MESSAGES/django.po +306 -0
  12. fleetfinder/locale/django.pot +303 -0
  13. fleetfinder/locale/es/LC_MESSAGES/django.mo +0 -0
  14. fleetfinder/locale/es/LC_MESSAGES/django.po +319 -0
  15. fleetfinder/locale/fr_FR/LC_MESSAGES/django.mo +0 -0
  16. fleetfinder/locale/fr_FR/LC_MESSAGES/django.po +314 -0
  17. fleetfinder/locale/it_IT/LC_MESSAGES/django.mo +0 -0
  18. fleetfinder/locale/it_IT/LC_MESSAGES/django.po +294 -0
  19. fleetfinder/locale/ja/LC_MESSAGES/django.mo +0 -0
  20. fleetfinder/locale/ja/LC_MESSAGES/django.po +303 -0
  21. fleetfinder/locale/ko_KR/LC_MESSAGES/django.mo +0 -0
  22. fleetfinder/locale/ko_KR/LC_MESSAGES/django.po +337 -0
  23. fleetfinder/locale/nl_NL/LC_MESSAGES/django.mo +0 -0
  24. fleetfinder/locale/nl_NL/LC_MESSAGES/django.po +294 -0
  25. fleetfinder/locale/pl_PL/LC_MESSAGES/django.mo +0 -0
  26. fleetfinder/locale/pl_PL/LC_MESSAGES/django.po +298 -0
  27. fleetfinder/locale/ru/LC_MESSAGES/django.mo +0 -0
  28. fleetfinder/locale/ru/LC_MESSAGES/django.po +319 -0
  29. fleetfinder/locale/sk/LC_MESSAGES/django.mo +0 -0
  30. fleetfinder/locale/sk/LC_MESSAGES/django.po +294 -0
  31. fleetfinder/locale/uk/LC_MESSAGES/django.mo +0 -0
  32. fleetfinder/locale/uk/LC_MESSAGES/django.po +310 -0
  33. fleetfinder/locale/zh_Hans/LC_MESSAGES/django.mo +0 -0
  34. fleetfinder/locale/zh_Hans/LC_MESSAGES/django.po +319 -0
  35. fleetfinder/migrations/0001_initial.py +72 -0
  36. fleetfinder/migrations/0002_esi_error_handling_and_verbose_names.py +92 -0
  37. fleetfinder/migrations/0003_alter_fleet_fleet_commander_alter_fleet_groups_and_more.py +46 -0
  38. fleetfinder/migrations/__init__.py +0 -0
  39. fleetfinder/models.py +95 -0
  40. fleetfinder/providers.py +32 -0
  41. fleetfinder/static/fleetfinder/css/fleetfinder.css +31 -0
  42. fleetfinder/static/fleetfinder/css/fleetfinder.min.css +2 -0
  43. fleetfinder/static/fleetfinder/css/fleetfinder.min.css.map +1 -0
  44. fleetfinder/static/fleetfinder/js/fleetfinder-dashboard.js +86 -0
  45. fleetfinder/static/fleetfinder/js/fleetfinder-dashboard.min.js +2 -0
  46. fleetfinder/static/fleetfinder/js/fleetfinder-dashboard.min.js.map +1 -0
  47. fleetfinder/static/fleetfinder/js/fleetfinder-fleet-details.js +154 -0
  48. fleetfinder/static/fleetfinder/js/fleetfinder-fleet-details.min.js +2 -0
  49. fleetfinder/static/fleetfinder/js/fleetfinder-fleet-details.min.js.map +1 -0
  50. fleetfinder/static/fleetfinder/js/fleetfinder.js +23 -0
  51. fleetfinder/static/fleetfinder/js/fleetfinder.min.js +2 -0
  52. fleetfinder/static/fleetfinder/js/fleetfinder.min.js.map +1 -0
  53. fleetfinder/static/fleetfinder/libs/slim-select/2.6.0/css/slimselect.css +477 -0
  54. fleetfinder/static/fleetfinder/libs/slim-select/2.6.0/css/slimselect.min.css +2 -0
  55. fleetfinder/static/fleetfinder/libs/slim-select/2.6.0/css/slimselect.min.css.map +1 -0
  56. fleetfinder/static/fleetfinder/libs/slim-select/2.6.0/js/slimselect.min.js +1 -0
  57. fleetfinder/tasks.py +554 -0
  58. fleetfinder/templates/fleetfinder/base.html +43 -0
  59. fleetfinder/templates/fleetfinder/bundles/css/fleetfinder-css.html +3 -0
  60. fleetfinder/templates/fleetfinder/bundles/css/slim-select-css.html +3 -0
  61. fleetfinder/templates/fleetfinder/bundles/js/fleetfinder-js.html +9 -0
  62. fleetfinder/templates/fleetfinder/bundles/js/slim-select-js.html +3 -0
  63. fleetfinder/templates/fleetfinder/create-fleet.html +42 -0
  64. fleetfinder/templates/fleetfinder/dashboard.html +53 -0
  65. fleetfinder/templates/fleetfinder/edit-fleet.html +42 -0
  66. fleetfinder/templates/fleetfinder/fleet-details.html +102 -0
  67. fleetfinder/templates/fleetfinder/join-fleet.html +68 -0
  68. fleetfinder/templates/fleetfinder/modals/kick-fleet-member.html +46 -0
  69. fleetfinder/templates/fleetfinder/partials/body/form-fleet-details.html +50 -0
  70. fleetfinder/templates/fleetfinder/partials/footer/app-translation-footer.html +11 -0
  71. fleetfinder/templates/fleetfinder/partials/header/header-nav-left.html +9 -0
  72. fleetfinder/templates/fleetfinder/partials/header/header-nav-right.html +18 -0
  73. fleetfinder/templatetags/__init__.py +3 -0
  74. fleetfinder/templatetags/fleetfinder.py +33 -0
  75. fleetfinder/tests/__init__.py +41 -0
  76. fleetfinder/tests/test_access.py +74 -0
  77. fleetfinder/tests/test_auth_hooks.py +79 -0
  78. fleetfinder/tests/test_settings.py +38 -0
  79. fleetfinder/tests/test_tasks.py +1116 -0
  80. fleetfinder/tests/test_templatetags.py +65 -0
  81. fleetfinder/tests/test_user_agent.py +88 -0
  82. fleetfinder/tests/test_views.py +1184 -0
  83. fleetfinder/tests/utils.py +58 -0
  84. fleetfinder/urls.py +45 -0
  85. fleetfinder/views.py +631 -0
  86. aa_fleetfinder-0.1.0a12.dist-info/METADATA +0 -50
  87. aa_fleetfinder-0.1.0a12.dist-info/RECORD +0 -5
  88. aa_fleetfinder-0.1.0a12.dist-info/top_level.txt +0 -1
  89. {aa_fleetfinder-0.1.0a12.dist-info → aa_fleetfinder-3.0.0b2.dist-info/licenses}/LICENSE +0 -0
fleetfinder/views.py ADDED
@@ -0,0 +1,631 @@
1
+ """
2
+ Views
3
+ """
4
+
5
+ # Standard Library
6
+ import json
7
+ from http import HTTPStatus
8
+
9
+ # Django
10
+ from django.contrib import messages
11
+ from django.contrib.auth.decorators import login_required, permission_required
12
+ from django.core.handlers.wsgi import WSGIRequest
13
+ from django.db.models import Q
14
+ from django.http import JsonResponse
15
+ from django.shortcuts import redirect, render
16
+ from django.urls import reverse
17
+ from django.utils import timezone
18
+ from django.utils.functional import Promise
19
+ from django.utils.safestring import mark_safe
20
+ from django.utils.translation import gettext_lazy as _
21
+
22
+ # Alliance Auth
23
+ from allianceauth.eveonline.evelinks.eveimageserver import character_portrait_url
24
+ from allianceauth.eveonline.models import EveCharacter
25
+ from allianceauth.framework.api.user import get_all_characters_from_user
26
+ from allianceauth.groupmanagement.models import AuthGroup
27
+ from allianceauth.services.hooks import get_extension_logger
28
+ from esi.decorators import token_required
29
+ from esi.exceptions import HTTPClientError
30
+ from esi.models import Token
31
+ from esi.openapi_clients import EsiOperation
32
+
33
+ # Alliance Auth (External Libs)
34
+ from app_utils.logging import LoggerAddTag
35
+
36
+ # AA Fleet Finder
37
+ from fleetfinder import __title__
38
+ from fleetfinder.models import Fleet
39
+ from fleetfinder.providers import esi
40
+ from fleetfinder.tasks import get_fleet_composition, send_fleet_invitation
41
+
42
+ logger = LoggerAddTag(my_logger=get_extension_logger(name=__name__), prefix=__title__)
43
+
44
+
45
+ @login_required()
46
+ @permission_required(perm="fleetfinder.access_fleetfinder")
47
+ def _get_and_validate_fleet(token: Token, character_id: int) -> EsiOperation:
48
+ """
49
+ Get fleet information and validate fleet commander permissions
50
+
51
+ :param token: Token object containing the access token
52
+ :type token: Token
53
+ :param character_id: The character ID of the fleet commander
54
+ :type character_id: int
55
+ :return: Fleet information from ESI
56
+ :rtype: GetCharactersCharacterIdFleetOperation
57
+ """
58
+
59
+ try:
60
+ fleet_result = esi.client.Fleets.GetCharactersCharacterIdFleet(
61
+ character_id=token.character_id,
62
+ token=token,
63
+ ).result(force_refresh=True)
64
+ except HTTPClientError as ex:
65
+ logger.debug(f"ESI fleet cannot be retrieved: {str(ex)}", exc_info=True)
66
+
67
+ raise ValueError("Fleet not found") from ex
68
+ except Exception as ex:
69
+ logger.debug(f"Error retrieving fleet from ESI: {str(ex)}", exc_info=True)
70
+
71
+ raise RuntimeError(f"Error retrieving fleet from ESI: {str(ex)}") from ex
72
+
73
+ logger.debug(f"Fleet result: {fleet_result}")
74
+
75
+ fleet_id = fleet_result.fleet_id
76
+ fleet_boss_id = fleet_result.fleet_boss_id
77
+
78
+ if not fleet_id:
79
+ fleet_commander = EveCharacter.objects.get(character_id=token.character_id)
80
+
81
+ raise ValueError(f"No fleet found for {fleet_commander.character_name}")
82
+
83
+ if fleet_boss_id != character_id:
84
+ fleet_commander = EveCharacter.objects.get(character_id=token.character_id)
85
+
86
+ raise ValueError(f"{fleet_commander.character_name} is not the fleet boss")
87
+
88
+ return fleet_result
89
+
90
+
91
+ @login_required()
92
+ @permission_required(perm="fleetfinder.access_fleetfinder")
93
+ def dashboard(request):
94
+ """
95
+ Dashboard view
96
+
97
+ :param request:
98
+ :return:
99
+ """
100
+
101
+ context = {}
102
+
103
+ logger.info(msg=f"Module called by {request.user}")
104
+
105
+ return render(
106
+ request=request,
107
+ template_name="fleetfinder/dashboard.html",
108
+ context=context,
109
+ )
110
+
111
+
112
+ @login_required()
113
+ @permission_required(perm="fleetfinder.access_fleetfinder")
114
+ def ajax_dashboard(request) -> JsonResponse: # pylint: disable=too-many-locals
115
+ """
116
+ Ajax :: Dashboard information
117
+
118
+ :param request:
119
+ :return:
120
+ """
121
+
122
+ def _create_button_style_link(
123
+ url: str, fa_icon_class: str, btn_title: str | Promise, btn_modifier_class: str
124
+ ) -> str:
125
+ """
126
+ Helper function to create a button HTML string
127
+ This function generates an HTML anchor tag styled as a button with an icon.
128
+
129
+ :param url: The URL the button should link to
130
+ :type url: str
131
+ :param fa_icon_class: The Font Awesome class for the icon to be displayed
132
+ :type fa_icon_class: str
133
+ :param btn_title: The title attribute for the button, typically a translation string
134
+ :type btn_title: str | Promise
135
+ :param btn_modifier_class: The Bootstrap modifier class for the button styling
136
+ :type btn_modifier_class: str
137
+ :return: An HTML string representing the button
138
+ :rtype: str
139
+ """
140
+
141
+ return (
142
+ f'<a href="{url}" class="btn btn-sm {btn_modifier_class} ms-1" '
143
+ f'data-bs-tooltip="aa-fleetfinder" title="{btn_title}">'
144
+ f'<i class="{fa_icon_class}"></i></a>'
145
+ )
146
+
147
+ def _get_fleet_commander_information(fleet: Fleet) -> tuple[str, str]:
148
+ """
149
+ Helper function to get the fleet commander's HTML representation
150
+ This function retrieves the fleet commander's name and portrait URL,
151
+ and returns an HTML string with the portrait image and name.
152
+
153
+ :param fleet: The Fleet object containing the fleet commander's information
154
+ :type fleet: Fleet
155
+ :return: A tuple containing the HTML string for the fleet commander and the name for sorting
156
+ :rtype: tuple[str, str]
157
+ """
158
+
159
+ commander_name = fleet.fleet_commander.character_name
160
+ portrait_url = character_portrait_url(
161
+ character_id=fleet.fleet_commander.character_id, size=32
162
+ )
163
+ portrait_img = (
164
+ '<img class="rounded eve-character-portrait" '
165
+ f'src="{portrait_url}" alt="{commander_name}" loading="lazy">'
166
+ )
167
+
168
+ return portrait_img + commander_name, commander_name
169
+
170
+ data = []
171
+ groups = request.user.groups.all()
172
+ user_characters = get_all_characters_from_user(user=request.user)
173
+ fleets = (
174
+ Fleet.objects.filter(
175
+ Q(groups__group__in=groups)
176
+ | Q(groups__isnull=True)
177
+ | Q(fleet_commander__in=user_characters)
178
+ )
179
+ .distinct()
180
+ .order_by("name")
181
+ )
182
+
183
+ can_manage_fleets = request.user.has_perm("fleetfinder.manage_fleets")
184
+
185
+ for fleet in fleets:
186
+ fleet_commander_html, fleet_commander_name = _get_fleet_commander_information(
187
+ fleet
188
+ )
189
+
190
+ # Create buttons
191
+ buttons = [
192
+ _create_button_style_link(
193
+ reverse("fleetfinder:join_fleet", args=[fleet.fleet_id]),
194
+ "fa-solid fa-right-to-bracket",
195
+ _("Join fleet"),
196
+ "btn-success",
197
+ )
198
+ ]
199
+
200
+ if can_manage_fleets:
201
+ buttons.extend(
202
+ [
203
+ _create_button_style_link(
204
+ reverse("fleetfinder:fleet_details", args=[fleet.fleet_id]),
205
+ "fa-solid fa-eye",
206
+ _("View fleet details"),
207
+ "btn-info",
208
+ ),
209
+ _create_button_style_link(
210
+ reverse("fleetfinder:edit_fleet", args=[fleet.fleet_id]),
211
+ "fa-solid fa-pen-to-square",
212
+ _("Edit fleet advert"),
213
+ "btn-warning",
214
+ ),
215
+ ]
216
+ )
217
+
218
+ data.append(
219
+ {
220
+ "fleet_commander": {
221
+ "html": fleet_commander_html,
222
+ "sort": fleet_commander_name,
223
+ },
224
+ "fleet_name": fleet.name,
225
+ "created_at": fleet.created_at,
226
+ "actions": "".join(buttons),
227
+ }
228
+ )
229
+
230
+ return JsonResponse(data=data, safe=False)
231
+
232
+
233
+ @login_required()
234
+ @permission_required(perm="fleetfinder.manage_fleets")
235
+ @token_required(scopes=("esi-fleets.read_fleet.v1", "esi-fleets.write_fleet.v1"))
236
+ def create_fleet(request, token):
237
+ """
238
+ Create fleet view
239
+
240
+ :param request:
241
+ :param token:
242
+ :return:
243
+ """
244
+
245
+ # Validate the token and check if the character is in a fleet and is the fleet boss
246
+ try:
247
+ _get_and_validate_fleet(token, token.character_id)
248
+ except (HTTPClientError, ValueError) as ex:
249
+ error_detail = str(ex)
250
+
251
+ logger.debug(f"Error during fleet creation: {error_detail}", exc_info=True)
252
+
253
+ messages.error(
254
+ request,
255
+ mark_safe(
256
+ _(
257
+ "<h4>Error!</h4><p>There was an error creating the fleet: {error_detail}</p>"
258
+ ).format(error_detail=error_detail)
259
+ ),
260
+ )
261
+
262
+ return redirect("fleetfinder:dashboard")
263
+
264
+ if request.method != "POST":
265
+ return redirect("fleetfinder:dashboard")
266
+
267
+ auth_groups = AuthGroup.objects.filter(internal=False)
268
+ context = {"character_id": token.character_id, "auth_groups": auth_groups}
269
+
270
+ return render(
271
+ request=request,
272
+ template_name="fleetfinder/create-fleet.html",
273
+ context=context,
274
+ )
275
+
276
+
277
+ @login_required()
278
+ @permission_required(perm="fleetfinder.manage_fleets")
279
+ def edit_fleet(request, fleet_id):
280
+ """
281
+ Fleet edit view
282
+
283
+ :param request:
284
+ :param fleet_id:
285
+ :return:
286
+ """
287
+
288
+ try:
289
+ fleet = Fleet.objects.get(fleet_id=fleet_id)
290
+ except Fleet.DoesNotExist:
291
+ logger.debug(f"Fleet with ID {fleet_id} does not exist.")
292
+
293
+ messages.error(
294
+ request,
295
+ mark_safe(
296
+ _(
297
+ "<h4>Error!</h4><p>Fleet does not exist or is no longer available.</p>"
298
+ )
299
+ ),
300
+ )
301
+
302
+ return redirect("fleetfinder:dashboard")
303
+
304
+ auth_groups = AuthGroup.objects.filter(internal=False)
305
+
306
+ context = {
307
+ "character_id": fleet.fleet_commander.character_id,
308
+ "auth_groups": auth_groups,
309
+ "fleet": fleet,
310
+ }
311
+
312
+ logger.debug(f"Context for fleet edit: {context}")
313
+ logger.info(msg=f"Fleet {fleet_id} edit view by {request.user}")
314
+
315
+ return render(
316
+ request=request,
317
+ template_name="fleetfinder/edit-fleet.html",
318
+ context=context,
319
+ )
320
+
321
+
322
+ @login_required()
323
+ @permission_required(perm="fleetfinder.access_fleetfinder")
324
+ def join_fleet(request, fleet_id):
325
+ """
326
+ Join fleet view
327
+
328
+ :param request:
329
+ :param fleet_id:
330
+ :return:
331
+ """
332
+
333
+ context = {}
334
+ groups = request.user.groups.all()
335
+ fleet = Fleet.objects.filter(
336
+ Q(groups__group__in=groups) | Q(groups=None), fleet_id=fleet_id
337
+ ).count()
338
+
339
+ if fleet == 0:
340
+ return redirect(to="fleetfinder:dashboard")
341
+
342
+ if request.method == "POST":
343
+ character_ids = request.POST.getlist(key="character_ids", default=[])
344
+ send_fleet_invitation.delay(character_ids=character_ids, fleet_id=fleet_id)
345
+
346
+ return redirect(to="fleetfinder:dashboard")
347
+
348
+ characters = (
349
+ EveCharacter.objects.filter(character_ownership__user=request.user)
350
+ .select_related()
351
+ .order_by("character_name")
352
+ )
353
+
354
+ context["characters"] = characters
355
+
356
+ return render(
357
+ request=request,
358
+ template_name="fleetfinder/join-fleet.html",
359
+ context=context,
360
+ )
361
+
362
+
363
+ @login_required()
364
+ @permission_required("fleetfinder.manage_fleets")
365
+ def save_fleet(request):
366
+ """
367
+ Save fleet
368
+
369
+ :param request:
370
+ :return:
371
+ """
372
+
373
+ def _edit_or_create_fleet(
374
+ character_id: int,
375
+ free_move: bool,
376
+ name: str,
377
+ groups: list,
378
+ motd: str = None, # pylint: disable=unused-argument
379
+ ) -> None:
380
+ """
381
+ Edit or create a fleet from a fleet in EVE Online
382
+
383
+ :param character_id: The character ID of the fleet commander
384
+ :type character_id: int
385
+ :param free_move: Whether the fleet is free move or not
386
+ :type free_move: bool
387
+ :param name: Name of the fleet
388
+ :type name: str
389
+ :param groups: Groups that are allowed to access the fleet
390
+ :type groups: list[AuthGroup]
391
+ :param motd: Message of the Day for the fleet
392
+ :type motd: str
393
+ :return: None
394
+ :rtype: None
395
+ """
396
+
397
+ required_scopes = ["esi-fleets.read_fleet.v1", "esi-fleets.write_fleet.v1"]
398
+ token = Token.get_token(character_id=character_id, scopes=required_scopes)
399
+
400
+ fleet_result = _get_and_validate_fleet(token, character_id)
401
+ fleet_commander = EveCharacter.objects.get(character_id=character_id)
402
+ fleet_id = fleet_result.fleet_id
403
+
404
+ fleet, created = Fleet.objects.get_or_create(
405
+ fleet_id=fleet_id,
406
+ defaults={
407
+ "created_at": timezone.now(),
408
+ # "motd": motd,
409
+ "is_free_move": free_move,
410
+ "fleet_commander": fleet_commander,
411
+ "name": name,
412
+ },
413
+ )
414
+
415
+ if not created:
416
+ fleet.is_free_move = free_move
417
+ fleet.name = name
418
+ fleet.save()
419
+
420
+ fleet.groups.set(groups)
421
+
422
+ esi.client.Fleets.PutFleetsFleetId(
423
+ fleet_id=fleet_id,
424
+ token=token,
425
+ # body={"is_free_move": free_move, "motd": motd},
426
+ body={"is_free_move": free_move},
427
+ ).result(force_refresh=True)
428
+
429
+ if request.method != "POST":
430
+ return redirect("fleetfinder:dashboard")
431
+
432
+ # Extract form data
433
+ form_data = {
434
+ "character_id": int(request.POST["character_id"]),
435
+ "free_move": request.POST.get("free_move") == "on",
436
+ # "motd": request.POST.get("motd", ""),
437
+ "name": request.POST.get("name", ""),
438
+ "groups": request.POST.getlist("groups", []),
439
+ }
440
+
441
+ logger.debug(f"Form data for fleet creation: {form_data}")
442
+
443
+ try:
444
+ _edit_or_create_fleet(**form_data)
445
+ except HTTPClientError as ex:
446
+ esi_error = str(ex)
447
+
448
+ logger.debug(f"ESI returned 404 for fleet creation: {esi_error}", exc_info=True)
449
+
450
+ messages.error(
451
+ request,
452
+ mark_safe(
453
+ _(
454
+ "<h4>Error!</h4><p>ESI returned the following error: {esi_error}</p>"
455
+ ).format(esi_error=esi_error)
456
+ ),
457
+ )
458
+ except ValueError as ex:
459
+ logger.debug(f"Value error during fleet creation: {ex}", exc_info=True)
460
+
461
+ messages.error(
462
+ request,
463
+ mark_safe(
464
+ _(
465
+ "<h4>Error!</h4><p>There was an error creating the fleet: {ex}</p>"
466
+ ).format(ex=str(ex))
467
+ ),
468
+ )
469
+
470
+ return redirect("fleetfinder:dashboard")
471
+
472
+
473
+ @login_required()
474
+ @permission_required(perm="fleetfinder.manage_fleets")
475
+ def fleet_details(request, fleet_id):
476
+ """
477
+ Fleet details view
478
+
479
+ :param request:
480
+ :param fleet_id:
481
+ :return:
482
+ """
483
+
484
+ try:
485
+ fleet = Fleet.objects.get(fleet_id=fleet_id)
486
+ except Fleet.DoesNotExist:
487
+ logger.debug(f"Fleet with ID {fleet_id} does not exist.")
488
+
489
+ messages.error(
490
+ request,
491
+ mark_safe(
492
+ _(
493
+ "<h4>Error!</h4><p>Fleet does not exist or is no longer available.</p>"
494
+ )
495
+ ),
496
+ )
497
+
498
+ return redirect("fleetfinder:dashboard")
499
+
500
+ context = {"fleet": fleet}
501
+
502
+ logger.info(msg=f"Fleet {fleet.fleet_id} details view called by {request.user}")
503
+
504
+ return render(
505
+ request=request,
506
+ template_name="fleetfinder/fleet-details.html",
507
+ context=context,
508
+ )
509
+
510
+
511
+ @login_required()
512
+ @permission_required(perm="fleetfinder.manage_fleets")
513
+ def ajax_fleet_details(
514
+ request, fleet_id # pylint: disable=unused-argument
515
+ ) -> JsonResponse:
516
+ """
517
+ Ajax :: Fleet Details
518
+
519
+ :param request:
520
+ :param fleet_id:
521
+ """
522
+
523
+ try:
524
+ fleet = get_fleet_composition(fleet_id)
525
+ except Fleet.DoesNotExist:
526
+ logger.debug(f"Fleet with ID {fleet_id} does not exist.")
527
+
528
+ return JsonResponse(
529
+ data={
530
+ "error": _("Fleet with ID {fleet_id} does not exist.").format(
531
+ fleet_id=fleet_id
532
+ )
533
+ },
534
+ safe=False,
535
+ )
536
+ except RuntimeError as ex:
537
+ logger.debug(f"Error retrieving fleet composition: {str(ex)}", exc_info=True)
538
+
539
+ return JsonResponse(
540
+ data={
541
+ "error": _("Error retrieving fleet composition: {ex}").format(
542
+ ex=str(ex)
543
+ )
544
+ },
545
+ safe=False,
546
+ )
547
+
548
+ data = {
549
+ "fleet_member": list(fleet.fleet),
550
+ "fleet_composition": [
551
+ {"ship_type_name": ship, "number": number}
552
+ for ship, number in fleet.aggregate.items()
553
+ ],
554
+ }
555
+
556
+ return JsonResponse(data=data, safe=False)
557
+
558
+
559
+ @login_required()
560
+ @permission_required(perm="fleetfinder.manage_fleets")
561
+ def ajax_fleet_kick_member( # pylint: disable=too-many-return-statements
562
+ request: WSGIRequest, fleet_id: int
563
+ ) -> JsonResponse:
564
+ """
565
+ Ajax :: Kick member from fleet
566
+
567
+ :param request: WSGIRequest object containing the request data
568
+ :type request: WSGIRequest
569
+ :param fleet_id: The ID of the fleet from which to kick a member
570
+ :type fleet_id: int
571
+ :return: JsonResponse indicating success or failure of the operation
572
+ :rtype: JsonResponse
573
+ """
574
+
575
+ if request.method != "POST":
576
+ return JsonResponse(
577
+ data={"success": False, "error": _("Method not allowed")},
578
+ status=HTTPStatus.METHOD_NOT_ALLOWED,
579
+ )
580
+
581
+ try:
582
+ fleet = Fleet.objects.get(fleet_id=fleet_id)
583
+ data = json.loads(request.body)
584
+ member_id = data.get("memberId")
585
+
586
+ if not member_id:
587
+ return JsonResponse(
588
+ data={"success": False, "error": _("Member ID required")},
589
+ status=HTTPStatus.BAD_REQUEST,
590
+ )
591
+
592
+ logger.debug(f"Request data for kicking member: {data}")
593
+
594
+ token = Token.get_token(
595
+ character_id=fleet.fleet_commander.character_id,
596
+ scopes=["esi-fleets.write_fleet.v1"],
597
+ )
598
+
599
+ esi.client.Fleets.DeleteFleetsFleetIdMembersMemberId(
600
+ fleet_id=fleet_id,
601
+ member_id=member_id,
602
+ token=token,
603
+ ).result(force_refresh=True)
604
+
605
+ return JsonResponse(data={"success": True}, status=HTTPStatus.OK)
606
+ except Fleet.DoesNotExist:
607
+ return JsonResponse(
608
+ data={"success": False, "error": _("Fleet not found")},
609
+ status=HTTPStatus.NOT_FOUND,
610
+ )
611
+ except (json.JSONDecodeError, ValueError):
612
+ return JsonResponse(
613
+ data={"success": False, "error": _("Invalid request data")},
614
+ status=HTTPStatus.BAD_REQUEST,
615
+ )
616
+ except HTTPClientError as ex:
617
+ if ex.status_code == HTTPStatus.NOT_FOUND:
618
+ return JsonResponse(
619
+ data={"success": False, "error": _("Member not found in fleet")},
620
+ status=HTTPStatus.NOT_FOUND,
621
+ )
622
+
623
+ logger.debug(f"ESI error while kicking member: {str(ex)}", exc_info=True)
624
+
625
+ return JsonResponse(
626
+ data={
627
+ "success": False,
628
+ "error": _("An ESI error occurred: {ex}").format(ex=str(ex)),
629
+ },
630
+ status=ex.status_code,
631
+ )
@@ -1,50 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: aa-fleetfinder
3
- Version: 0.1.0a12
4
- Summary: Fleet finder plugin for Alliance Auth
5
- Home-page: https://github.com/ppfeufer/aa-fleetfinder
6
- Author: Peter Pfeufer
7
- Author-email: development@ppfeufer.de
8
- Maintainer: Peter Pfeufer
9
- Maintainer-email: development@ppfeufer.de
10
- License: GPL-3.0
11
- Project-URL: Issue / Bug Reports, https://github.com/ppfeufer/aa-fleetfinder/issues
12
- Project-URL: Changelog, https://github.com/ppfeufer/aa-fleetfinder/blob/master/CHANGELOG.md
13
- Keywords: allianceauth,eveonline,fleetfinder
14
- Platform: UNKNOWN
15
- Classifier: Environment :: Web Environment
16
- Classifier: Framework :: Django
17
- Classifier: Framework :: Django :: 3.2
18
- Classifier: Intended Audience :: Developers
19
- Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
20
- Classifier: Operating System :: OS Independent
21
- Classifier: Programming Language :: Python
22
- Classifier: Programming Language :: Python :: 3
23
- Classifier: Programming Language :: Python :: 3.7
24
- Classifier: Programming Language :: Python :: 3.8
25
- Classifier: Programming Language :: Python :: 3.9
26
- Classifier: Programming Language :: Python :: 3.10
27
- Classifier: Programming Language :: Python :: 3.11
28
- Classifier: Topic :: Internet :: WWW/HTTP
29
- Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
30
- Requires-Python: ~=3.7
31
- Description-Content-Type: text/markdown
32
- License-File: LICENSE
33
- Requires-Dist: allianceauth (>=2.9.4)
34
-
35
- # AA Fleet Finder
36
-
37
- [![Version](https://img.shields.io/pypi/v/aa-fleetfinder?label=release)](https://pypi.org/project/aa-fleetfinder/)
38
- [![License](https://img.shields.io/github/license/ppfeufer/aa-fleetfinder)](https://github.com/ppfeufer/aa-fleetfinder/blob/master/LICENSE)
39
- [![Python](https://img.shields.io/pypi/pyversions/aa-fleetfinder)](https://pypi.org/project/aa-fleetfinder/)
40
- [![Django](https://img.shields.io/pypi/djversions/aa-fleetfinder?label=django)](https://pypi.org/project/aa-fleetfinder/)
41
- ![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)
42
- [![Code Style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](http://black.readthedocs.io/en/latest/)
43
- [![Discord](https://img.shields.io/discord/790364535294132234?label=discord)](https://discord.gg/zmh52wnfvM)
44
- [![Checks](https://github.com/ppfeufer/aa-fleetfinder/actions/workflows/automated-checks.yml/badge.svg)](https://github.com/ppfeufer/aa-fleetfinder/actions/workflows/automated-checks.yml)
45
- [![codecov](https://codecov.io/gh/ppfeufer/aa-fleetfinder/branch/master/graph/badge.svg?token=GFOR9GWRNQ)](https://codecov.io/gh/ppfeufer/aa-fleetfinder)
46
- [![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg)](https://github.com/ppfeufer/aa-fleetfinder/blob/master/CODE_OF_CONDUCT.md)
47
-
48
- ## Not yet publicly available
49
-
50
-
@@ -1,5 +0,0 @@
1
- aa_fleetfinder-0.1.0a12.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
2
- aa_fleetfinder-0.1.0a12.dist-info/METADATA,sha256=dG25cZdfhPeZ1dd7Neioz2XCTQpmFWmoLx6Bj4mLjSc,2787
3
- aa_fleetfinder-0.1.0a12.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
4
- aa_fleetfinder-0.1.0a12.dist-info/top_level.txt,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
5
- aa_fleetfinder-0.1.0a12.dist-info/RECORD,,