aa-fleetfinder 2.6.0__py3-none-any.whl → 2.7.0__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.
Potentially problematic release.
This version of aa-fleetfinder might be problematic. Click here for more details.
- {aa_fleetfinder-2.6.0.dist-info → aa_fleetfinder-2.7.0.dist-info}/METADATA +1 -1
- {aa_fleetfinder-2.6.0.dist-info → aa_fleetfinder-2.7.0.dist-info}/RECORD +40 -33
- fleetfinder/__init__.py +1 -1
- fleetfinder/locale/cs_CZ/LC_MESSAGES/django.po +94 -17
- fleetfinder/locale/de/LC_MESSAGES/django.mo +0 -0
- fleetfinder/locale/de/LC_MESSAGES/django.po +108 -20
- fleetfinder/locale/django.pot +96 -18
- fleetfinder/locale/es/LC_MESSAGES/django.po +108 -18
- fleetfinder/locale/fr_FR/LC_MESSAGES/django.po +98 -17
- fleetfinder/locale/it_IT/LC_MESSAGES/django.po +91 -17
- fleetfinder/locale/ja/LC_MESSAGES/django.po +95 -17
- fleetfinder/locale/ko_KR/LC_MESSAGES/django.po +108 -18
- fleetfinder/locale/nl_NL/LC_MESSAGES/django.po +91 -17
- fleetfinder/locale/pl_PL/LC_MESSAGES/django.po +93 -17
- fleetfinder/locale/ru/LC_MESSAGES/django.mo +0 -0
- fleetfinder/locale/ru/LC_MESSAGES/django.po +112 -22
- fleetfinder/locale/sk/LC_MESSAGES/django.po +91 -17
- fleetfinder/locale/uk/LC_MESSAGES/django.mo +0 -0
- fleetfinder/locale/uk/LC_MESSAGES/django.po +112 -22
- fleetfinder/locale/zh_Hans/LC_MESSAGES/django.mo +0 -0
- fleetfinder/locale/zh_Hans/LC_MESSAGES/django.po +112 -22
- fleetfinder/static/fleetfinder/css/fleetfinder.css +21 -0
- fleetfinder/static/fleetfinder/css/fleetfinder.min.css +1 -1
- fleetfinder/static/fleetfinder/css/fleetfinder.min.css.map +1 -1
- fleetfinder/static/fleetfinder/js/fleetfinder.js +23 -0
- fleetfinder/static/fleetfinder/js/fleetfinder.min.js +2 -0
- fleetfinder/static/fleetfinder/js/fleetfinder.min.js.map +1 -0
- fleetfinder/tasks.py +137 -150
- fleetfinder/templates/fleetfinder/bundles/js/fleetfinder-js.html +3 -0
- fleetfinder/templates/fleetfinder/dashboard.html +38 -63
- fleetfinder/templates/fleetfinder/fleet-details.html +124 -33
- fleetfinder/templates/fleetfinder/join-fleet.html +11 -1
- fleetfinder/templates/fleetfinder/modals/kick-fleet-member.html +46 -0
- fleetfinder/templates/fleetfinder/partials/body/form-fleet-details.html +8 -8
- fleetfinder/tests/test_tasks.py +140 -0
- fleetfinder/tests/test_views.py +473 -0
- fleetfinder/urls.py +5 -0
- fleetfinder/views.py +316 -103
- {aa_fleetfinder-2.6.0.dist-info → aa_fleetfinder-2.7.0.dist-info}/WHEEL +0 -0
- {aa_fleetfinder-2.6.0.dist-info → aa_fleetfinder-2.7.0.dist-info}/licenses/LICENSE +0 -0
fleetfinder/views.py
CHANGED
|
@@ -2,25 +2,33 @@
|
|
|
2
2
|
Views
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
+
# Standard Library
|
|
6
|
+
import json
|
|
7
|
+
|
|
5
8
|
# Third Party
|
|
6
9
|
from bravado.exception import HTTPNotFound
|
|
7
10
|
|
|
8
11
|
# Django
|
|
9
12
|
from django.contrib import messages
|
|
10
13
|
from django.contrib.auth.decorators import login_required, permission_required
|
|
14
|
+
from django.core.handlers.wsgi import WSGIRequest
|
|
11
15
|
from django.db.models import Q
|
|
12
16
|
from django.http import JsonResponse
|
|
13
17
|
from django.shortcuts import redirect, render
|
|
14
18
|
from django.urls import reverse
|
|
19
|
+
from django.utils import timezone
|
|
20
|
+
from django.utils.functional import Promise
|
|
15
21
|
from django.utils.safestring import mark_safe
|
|
16
22
|
from django.utils.translation import gettext_lazy as _
|
|
17
23
|
|
|
18
24
|
# Alliance Auth
|
|
19
25
|
from allianceauth.eveonline.evelinks.eveimageserver import character_portrait_url
|
|
20
26
|
from allianceauth.eveonline.models import EveCharacter
|
|
27
|
+
from allianceauth.framework.api.user import get_all_characters_from_user
|
|
21
28
|
from allianceauth.groupmanagement.models import AuthGroup
|
|
22
29
|
from allianceauth.services.hooks import get_extension_logger
|
|
23
30
|
from esi.decorators import token_required
|
|
31
|
+
from esi.models import Token
|
|
24
32
|
|
|
25
33
|
# Alliance Auth (External Libs)
|
|
26
34
|
from app_utils.logging import LoggerAddTag
|
|
@@ -28,11 +36,45 @@ from app_utils.logging import LoggerAddTag
|
|
|
28
36
|
# AA Fleet Finder
|
|
29
37
|
from fleetfinder import __title__
|
|
30
38
|
from fleetfinder.models import Fleet
|
|
31
|
-
from fleetfinder.
|
|
39
|
+
from fleetfinder.providers import esi
|
|
40
|
+
from fleetfinder.tasks import get_fleet_composition, send_fleet_invitation
|
|
32
41
|
|
|
33
42
|
logger = LoggerAddTag(my_logger=get_extension_logger(name=__name__), prefix=__title__)
|
|
34
43
|
|
|
35
44
|
|
|
45
|
+
@login_required()
|
|
46
|
+
@permission_required(perm="fleetfinder.access_fleetfinder")
|
|
47
|
+
def _get_and_validate_fleet(token: Token, character_id: int) -> tuple:
|
|
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: Tuple containing the fleet result, fleet commander, and fleet ID
|
|
56
|
+
:rtype: tuple
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
fleet_result = esi.client.Fleets.get_characters_character_id_fleet(
|
|
60
|
+
character_id=token.character_id, token=token.valid_access_token()
|
|
61
|
+
).result()
|
|
62
|
+
|
|
63
|
+
logger.debug(f"Fleet result: {fleet_result}")
|
|
64
|
+
|
|
65
|
+
fleet_commander = EveCharacter.objects.get(character_id=token.character_id)
|
|
66
|
+
fleet_id = fleet_result.get("fleet_id")
|
|
67
|
+
fleet_boss_id = fleet_result.get("fleet_boss_id")
|
|
68
|
+
|
|
69
|
+
if not fleet_id:
|
|
70
|
+
raise ValueError(f"No fleet found for {fleet_commander.character_name}")
|
|
71
|
+
|
|
72
|
+
if fleet_boss_id != character_id:
|
|
73
|
+
raise ValueError(f"{fleet_commander.character_name} is not the fleet boss")
|
|
74
|
+
|
|
75
|
+
return fleet_result
|
|
76
|
+
|
|
77
|
+
|
|
36
78
|
@login_required()
|
|
37
79
|
@permission_required(perm="fleetfinder.access_fleetfinder")
|
|
38
80
|
def dashboard(request):
|
|
@@ -64,55 +106,100 @@ def ajax_dashboard(request) -> JsonResponse: # pylint: disable=too-many-locals
|
|
|
64
106
|
:return:
|
|
65
107
|
"""
|
|
66
108
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
.
|
|
73
|
-
|
|
109
|
+
def _create_button_style_link(
|
|
110
|
+
url: str, fa_icon_class: str, btn_title: str | Promise, btn_modifier_class: str
|
|
111
|
+
) -> str:
|
|
112
|
+
"""
|
|
113
|
+
Helper function to create a button HTML string
|
|
114
|
+
This function generates an HTML anchor tag styled as a button with an icon.
|
|
115
|
+
|
|
116
|
+
:param url: The URL the button should link to
|
|
117
|
+
:type url: str
|
|
118
|
+
:param fa_icon_class: The Font Awesome class for the icon to be displayed
|
|
119
|
+
:type fa_icon_class: str
|
|
120
|
+
:param btn_title: The title attribute for the button, typically a translation string
|
|
121
|
+
:type btn_title: str | Promise
|
|
122
|
+
:param btn_modifier_class: The Bootstrap modifier class for the button styling
|
|
123
|
+
:type btn_modifier_class: str
|
|
124
|
+
:return: An HTML string representing the button
|
|
125
|
+
:rtype: str
|
|
126
|
+
"""
|
|
127
|
+
|
|
128
|
+
return (
|
|
129
|
+
f'<a href="{url}" class="btn btn-sm {btn_modifier_class} ms-1" '
|
|
130
|
+
f'data-bs-tooltip="aa-fleetfinder" title="{btn_title}">'
|
|
131
|
+
f'<i class="{fa_icon_class}"></i></a>'
|
|
132
|
+
)
|
|
74
133
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
134
|
+
def _get_fleet_commander_information(fleet: Fleet) -> tuple[str, str]:
|
|
135
|
+
"""
|
|
136
|
+
Helper function to get the fleet commander's HTML representation
|
|
137
|
+
This function retrieves the fleet commander's name and portrait URL,
|
|
138
|
+
and returns an HTML string with the portrait image and name.
|
|
139
|
+
|
|
140
|
+
:param fleet: The Fleet object containing the fleet commander's information
|
|
141
|
+
:type fleet: Fleet
|
|
142
|
+
:return: A tuple containing the HTML string for the fleet commander and the name for sorting
|
|
143
|
+
:rtype: tuple[str, str]
|
|
144
|
+
"""
|
|
145
|
+
|
|
146
|
+
commander_name = fleet.fleet_commander.character_name
|
|
147
|
+
portrait_url = character_portrait_url(
|
|
78
148
|
character_id=fleet.fleet_commander.character_id, size=32
|
|
79
149
|
)
|
|
80
|
-
|
|
150
|
+
portrait_img = (
|
|
81
151
|
'<img class="rounded eve-character-portrait" '
|
|
82
|
-
f'src="{
|
|
83
|
-
f'alt="{fleet_commander_name}" loading="lazy">'
|
|
152
|
+
f'src="{portrait_url}" alt="{commander_name}" loading="lazy">'
|
|
84
153
|
)
|
|
85
|
-
fleet_commander_html = fleet_commander_portrait + fleet_commander_name
|
|
86
154
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
155
|
+
return portrait_img + commander_name, commander_name
|
|
156
|
+
|
|
157
|
+
data = []
|
|
158
|
+
groups = request.user.groups.all()
|
|
159
|
+
user_characters = get_all_characters_from_user(user=request.user)
|
|
160
|
+
fleets = (
|
|
161
|
+
Fleet.objects.filter(
|
|
162
|
+
Q(groups__group__in=groups)
|
|
163
|
+
| Q(groups__isnull=True)
|
|
164
|
+
| Q(fleet_commander__in=user_characters)
|
|
94
165
|
)
|
|
166
|
+
.distinct()
|
|
167
|
+
.order_by("name")
|
|
168
|
+
)
|
|
95
169
|
|
|
96
|
-
|
|
97
|
-
button_edit = ""
|
|
170
|
+
can_manage_fleets = request.user.has_perm("fleetfinder.manage_fleets")
|
|
98
171
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
button_details_text = _("View fleet details")
|
|
104
|
-
button_details = (
|
|
105
|
-
f'<a href="{button_details_url}" '
|
|
106
|
-
f'class="btn btn-sm btn-primary">{button_details_text}</a>'
|
|
107
|
-
)
|
|
172
|
+
for fleet in fleets:
|
|
173
|
+
fleet_commander_html, fleet_commander_name = _get_fleet_commander_information(
|
|
174
|
+
fleet
|
|
175
|
+
)
|
|
108
176
|
|
|
109
|
-
|
|
110
|
-
|
|
177
|
+
# Create buttons
|
|
178
|
+
buttons = [
|
|
179
|
+
_create_button_style_link(
|
|
180
|
+
reverse("fleetfinder:join_fleet", args=[fleet.fleet_id]),
|
|
181
|
+
"fa-solid fa-right-to-bracket",
|
|
182
|
+
_("Join fleet"),
|
|
183
|
+
"btn-success",
|
|
111
184
|
)
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
185
|
+
]
|
|
186
|
+
|
|
187
|
+
if can_manage_fleets:
|
|
188
|
+
buttons.extend(
|
|
189
|
+
[
|
|
190
|
+
_create_button_style_link(
|
|
191
|
+
reverse("fleetfinder:fleet_details", args=[fleet.fleet_id]),
|
|
192
|
+
"fa-solid fa-eye",
|
|
193
|
+
_("View fleet details"),
|
|
194
|
+
"btn-info",
|
|
195
|
+
),
|
|
196
|
+
_create_button_style_link(
|
|
197
|
+
reverse("fleetfinder:edit_fleet", args=[fleet.fleet_id]),
|
|
198
|
+
"fa-solid fa-pen-to-square",
|
|
199
|
+
_("Edit fleet advert"),
|
|
200
|
+
"btn-warning",
|
|
201
|
+
),
|
|
202
|
+
]
|
|
116
203
|
)
|
|
117
204
|
|
|
118
205
|
data.append(
|
|
@@ -123,9 +210,7 @@ def ajax_dashboard(request) -> JsonResponse: # pylint: disable=too-many-locals
|
|
|
123
210
|
},
|
|
124
211
|
"fleet_name": fleet.name,
|
|
125
212
|
"created_at": fleet.created_at,
|
|
126
|
-
"
|
|
127
|
-
"details": button_details,
|
|
128
|
-
"edit": button_edit,
|
|
213
|
+
"actions": "".join(buttons),
|
|
129
214
|
}
|
|
130
215
|
)
|
|
131
216
|
|
|
@@ -144,26 +229,30 @@ def create_fleet(request, token):
|
|
|
144
229
|
:return:
|
|
145
230
|
"""
|
|
146
231
|
|
|
147
|
-
|
|
232
|
+
# Validate the token and check if the character is in a fleet and is the fleet boss
|
|
233
|
+
try:
|
|
234
|
+
_get_and_validate_fleet(token, token.character_id)
|
|
235
|
+
except (HTTPNotFound, ValueError) as ex:
|
|
236
|
+
logger.debug(f"Error during fleet creation: {ex}", exc_info=True)
|
|
148
237
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
if "modified_fleet_data" in request.session:
|
|
153
|
-
context["motd"] = request.session["modified_fleet_data"].get("motd", "")
|
|
154
|
-
context["name"] = request.session["modified_fleet_data"].get("name", "")
|
|
155
|
-
context["groups"] = request.session["modified_fleet_data"].get("groups", "")
|
|
156
|
-
context["is_free_move"] = request.session["modified_fleet_data"].get(
|
|
157
|
-
"free_move", ""
|
|
158
|
-
)
|
|
159
|
-
context["character_id"] = token.character_id
|
|
160
|
-
context["auth_groups"] = auth_groups
|
|
161
|
-
|
|
162
|
-
del request.session["modified_fleet_data"]
|
|
238
|
+
if isinstance(ex, HTTPNotFound):
|
|
239
|
+
error_detail = ex.swagger_result["error"]
|
|
163
240
|
else:
|
|
164
|
-
|
|
241
|
+
error_detail = str(ex)
|
|
165
242
|
|
|
166
|
-
|
|
243
|
+
error_message = _(
|
|
244
|
+
f"<h4>Error!</h4><p>There was an error creating the fleet: {error_detail}</p>"
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
messages.error(request, mark_safe(error_message))
|
|
248
|
+
|
|
249
|
+
return redirect("fleetfinder:dashboard")
|
|
250
|
+
|
|
251
|
+
if request.method != "POST":
|
|
252
|
+
return redirect("fleetfinder:dashboard")
|
|
253
|
+
|
|
254
|
+
auth_groups = AuthGroup.objects.filter(internal=False)
|
|
255
|
+
context = {"character_id": token.character_id, "auth_groups": auth_groups}
|
|
167
256
|
|
|
168
257
|
return render(
|
|
169
258
|
request=request,
|
|
@@ -183,7 +272,22 @@ def edit_fleet(request, fleet_id):
|
|
|
183
272
|
:return:
|
|
184
273
|
"""
|
|
185
274
|
|
|
186
|
-
|
|
275
|
+
try:
|
|
276
|
+
fleet = Fleet.objects.get(fleet_id=fleet_id)
|
|
277
|
+
except Fleet.DoesNotExist:
|
|
278
|
+
logger.debug(f"Fleet with ID {fleet_id} does not exist.")
|
|
279
|
+
|
|
280
|
+
messages.error(
|
|
281
|
+
request,
|
|
282
|
+
mark_safe(
|
|
283
|
+
_(
|
|
284
|
+
"<h4>Error!</h4><p>Fleet does not exist or is no longer available.</p>"
|
|
285
|
+
)
|
|
286
|
+
),
|
|
287
|
+
)
|
|
288
|
+
|
|
289
|
+
return redirect("fleetfinder:dashboard")
|
|
290
|
+
|
|
187
291
|
auth_groups = AuthGroup.objects.filter(internal=False)
|
|
188
292
|
|
|
189
293
|
context = {
|
|
@@ -192,6 +296,8 @@ def edit_fleet(request, fleet_id):
|
|
|
192
296
|
"fleet": fleet,
|
|
193
297
|
}
|
|
194
298
|
|
|
299
|
+
logger.debug("Context for fleet edit: %s", context)
|
|
300
|
+
|
|
195
301
|
logger.info(msg=f"Fleet {fleet_id} edit view by {request.user}")
|
|
196
302
|
|
|
197
303
|
return render(
|
|
@@ -252,46 +358,97 @@ def save_fleet(request):
|
|
|
252
358
|
:return:
|
|
253
359
|
"""
|
|
254
360
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
361
|
+
def _edit_or_create_fleet(
|
|
362
|
+
character_id: int,
|
|
363
|
+
free_move: bool,
|
|
364
|
+
name: str,
|
|
365
|
+
groups: list,
|
|
366
|
+
motd: str = None, # pylint: disable=unused-argument
|
|
367
|
+
) -> None:
|
|
368
|
+
"""
|
|
369
|
+
Edit or create a fleet from a fleet in EVE Online
|
|
370
|
+
|
|
371
|
+
:param character_id: The character ID of the fleet commander
|
|
372
|
+
:type character_id: int
|
|
373
|
+
:param free_move: Whether the fleet is free move or not
|
|
374
|
+
:type free_move: bool
|
|
375
|
+
:param name: Name of the fleet
|
|
376
|
+
:type name: str
|
|
377
|
+
:param groups: Groups that are allowed to access the fleet
|
|
378
|
+
:type groups: list[AuthGroup]
|
|
379
|
+
:param motd: Message of the Day for the fleet
|
|
380
|
+
:type motd: str
|
|
381
|
+
:return: None
|
|
382
|
+
:rtype: None
|
|
383
|
+
"""
|
|
384
|
+
|
|
385
|
+
required_scopes = ["esi-fleets.read_fleet.v1", "esi-fleets.write_fleet.v1"]
|
|
386
|
+
token = Token.get_token(character_id=character_id, scopes=required_scopes)
|
|
387
|
+
|
|
388
|
+
fleet_result = _get_and_validate_fleet(token, character_id)
|
|
389
|
+
fleet_commander = EveCharacter.objects.get(character_id=character_id)
|
|
390
|
+
fleet_id = fleet_result.get("fleet_id")
|
|
391
|
+
|
|
392
|
+
fleet, created = Fleet.objects.get_or_create(
|
|
393
|
+
fleet_id=fleet_id,
|
|
394
|
+
defaults={
|
|
395
|
+
"created_at": timezone.now(),
|
|
396
|
+
# "motd": motd,
|
|
397
|
+
"is_free_move": free_move,
|
|
398
|
+
"fleet_commander": fleet_commander,
|
|
399
|
+
"name": name,
|
|
400
|
+
},
|
|
401
|
+
)
|
|
402
|
+
|
|
403
|
+
if not created:
|
|
404
|
+
fleet.is_free_move = free_move
|
|
405
|
+
fleet.name = name
|
|
406
|
+
fleet.save()
|
|
407
|
+
|
|
408
|
+
fleet.groups.set(groups)
|
|
409
|
+
|
|
410
|
+
esi.client.Fleets.put_fleets_fleet_id(
|
|
411
|
+
fleet_id=fleet_id,
|
|
412
|
+
token=token.valid_access_token(),
|
|
413
|
+
# new_settings={"is_free_move": free_move, "motd": motd},
|
|
414
|
+
new_settings={"is_free_move": free_move},
|
|
415
|
+
).result()
|
|
416
|
+
|
|
417
|
+
if request.method != "POST":
|
|
418
|
+
return redirect("fleetfinder:dashboard")
|
|
419
|
+
|
|
420
|
+
# Extract form data
|
|
421
|
+
form_data = {
|
|
422
|
+
"character_id": int(request.POST["character_id"]),
|
|
423
|
+
"free_move": request.POST.get("free_move") == "on",
|
|
424
|
+
# "motd": request.POST.get("motd", ""),
|
|
425
|
+
"name": request.POST.get("name", ""),
|
|
426
|
+
"groups": request.POST.getlist("groups", []),
|
|
427
|
+
}
|
|
278
428
|
|
|
279
|
-
|
|
429
|
+
logger.debug(f"Form data for fleet creation: {form_data}")
|
|
280
430
|
|
|
281
|
-
|
|
282
|
-
|
|
431
|
+
try:
|
|
432
|
+
_edit_or_create_fleet(**form_data)
|
|
433
|
+
except HTTPNotFound as ex:
|
|
434
|
+
logger.debug(f"ESI returned 404 for fleet creation: {ex}", exc_info=True)
|
|
283
435
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
436
|
+
esi_error = ex.swagger_result.get("error", "Unknown error")
|
|
437
|
+
error_message = _(
|
|
438
|
+
f"<h4>Error!</h4><p>ESI returned the following error: {esi_error}</p>"
|
|
439
|
+
)
|
|
440
|
+
|
|
441
|
+
messages.error(request, mark_safe(error_message))
|
|
442
|
+
except ValueError as ex:
|
|
443
|
+
logger.debug(f"Value error during fleet creation: {ex}", exc_info=True)
|
|
291
444
|
|
|
292
|
-
|
|
445
|
+
error_message = _(
|
|
446
|
+
f"<h4>Error!</h4><p>There was an error creating the fleet: {ex}</p>"
|
|
447
|
+
)
|
|
293
448
|
|
|
294
|
-
|
|
449
|
+
messages.error(request, mark_safe(error_message))
|
|
450
|
+
|
|
451
|
+
return redirect("fleetfinder:dashboard")
|
|
295
452
|
|
|
296
453
|
|
|
297
454
|
@login_required()
|
|
@@ -319,8 +476,7 @@ def fleet_details(request, fleet_id):
|
|
|
319
476
|
@login_required()
|
|
320
477
|
@permission_required(perm="fleetfinder.manage_fleets")
|
|
321
478
|
def ajax_fleet_details(
|
|
322
|
-
request, # pylint: disable=unused-argument
|
|
323
|
-
fleet_id,
|
|
479
|
+
request, fleet_id # pylint: disable=unused-argument
|
|
324
480
|
) -> JsonResponse:
|
|
325
481
|
"""
|
|
326
482
|
Ajax :: Fleet Details
|
|
@@ -331,12 +487,69 @@ def ajax_fleet_details(
|
|
|
331
487
|
|
|
332
488
|
fleet = get_fleet_composition(fleet_id)
|
|
333
489
|
|
|
334
|
-
data = {
|
|
490
|
+
data = {
|
|
491
|
+
"fleet_member": list(fleet.fleet),
|
|
492
|
+
"fleet_composition": [
|
|
493
|
+
{"ship_type_name": ship, "number": number}
|
|
494
|
+
for ship, number in fleet.aggregate.items()
|
|
495
|
+
],
|
|
496
|
+
}
|
|
335
497
|
|
|
336
|
-
|
|
337
|
-
data["fleet_member"].append(member)
|
|
498
|
+
return JsonResponse(data=data, safe=False)
|
|
338
499
|
|
|
339
|
-
for ship, number in fleet.aggregate.items():
|
|
340
|
-
data["fleet_composition"].append({"ship_type_name": ship, "number": number})
|
|
341
500
|
|
|
342
|
-
|
|
501
|
+
@login_required()
|
|
502
|
+
@permission_required(perm="fleetfinder.manage_fleets")
|
|
503
|
+
def ajax_fleet_kick_member(request: WSGIRequest, fleet_id: int) -> JsonResponse:
|
|
504
|
+
"""
|
|
505
|
+
Ajax :: Kick member from fleet
|
|
506
|
+
|
|
507
|
+
:param request: WSGIRequest object containing the request data
|
|
508
|
+
:type request: WSGIRequest
|
|
509
|
+
:param fleet_id: The ID of the fleet from which to kick a member
|
|
510
|
+
:type fleet_id: int
|
|
511
|
+
:return: JsonResponse indicating success or failure of the operation
|
|
512
|
+
:rtype: JsonResponse
|
|
513
|
+
"""
|
|
514
|
+
|
|
515
|
+
if request.method != "POST":
|
|
516
|
+
return JsonResponse(
|
|
517
|
+
data={"success": False, "error": _("Method not allowed")}, status=405
|
|
518
|
+
)
|
|
519
|
+
|
|
520
|
+
try:
|
|
521
|
+
fleet = Fleet.objects.get(fleet_id=fleet_id)
|
|
522
|
+
data = json.loads(request.body)
|
|
523
|
+
member_id = data.get("memberId")
|
|
524
|
+
|
|
525
|
+
if not member_id:
|
|
526
|
+
return JsonResponse(
|
|
527
|
+
data={"success": False, "error": _("Member ID required")}, status=400
|
|
528
|
+
)
|
|
529
|
+
|
|
530
|
+
logger.debug(f"Request data for kicking member: {data}")
|
|
531
|
+
|
|
532
|
+
token = Token.get_token(
|
|
533
|
+
character_id=fleet.fleet_commander.character_id,
|
|
534
|
+
scopes=["esi-fleets.write_fleet.v1"],
|
|
535
|
+
)
|
|
536
|
+
|
|
537
|
+
esi.client.Fleets.delete_fleets_fleet_id_members_member_id(
|
|
538
|
+
fleet_id=fleet_id,
|
|
539
|
+
member_id=member_id,
|
|
540
|
+
token=token.valid_access_token(),
|
|
541
|
+
).result()
|
|
542
|
+
|
|
543
|
+
return JsonResponse(data={"success": True}, status=200)
|
|
544
|
+
except Fleet.DoesNotExist:
|
|
545
|
+
return JsonResponse(
|
|
546
|
+
data={"success": False, "error": _("Fleet not found")}, status=404
|
|
547
|
+
)
|
|
548
|
+
except (json.JSONDecodeError, ValueError):
|
|
549
|
+
return JsonResponse(
|
|
550
|
+
data={"success": False, "error": _("Invalid request data")}, status=400
|
|
551
|
+
)
|
|
552
|
+
except HTTPNotFound:
|
|
553
|
+
return JsonResponse(
|
|
554
|
+
data={"success": False, "error": _("Member not found in fleet")}, status=404
|
|
555
|
+
)
|
|
File without changes
|
|
File without changes
|