aa-fleetfinder 2.7.0__py3-none-any.whl → 2.7.1__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.7.0.dist-info → aa_fleetfinder-2.7.1.dist-info}/METADATA +1 -1
- {aa_fleetfinder-2.7.0.dist-info → aa_fleetfinder-2.7.1.dist-info}/RECORD +35 -29
- fleetfinder/__init__.py +1 -1
- fleetfinder/locale/cs_CZ/LC_MESSAGES/django.po +30 -20
- fleetfinder/locale/de/LC_MESSAGES/django.mo +0 -0
- fleetfinder/locale/de/LC_MESSAGES/django.po +35 -33
- fleetfinder/locale/django.pot +31 -21
- fleetfinder/locale/es/LC_MESSAGES/django.po +30 -20
- fleetfinder/locale/fr_FR/LC_MESSAGES/django.po +30 -20
- fleetfinder/locale/it_IT/LC_MESSAGES/django.po +30 -20
- fleetfinder/locale/ja/LC_MESSAGES/django.po +30 -20
- fleetfinder/locale/ko_KR/LC_MESSAGES/django.po +30 -20
- fleetfinder/locale/nl_NL/LC_MESSAGES/django.po +30 -20
- fleetfinder/locale/pl_PL/LC_MESSAGES/django.po +30 -20
- fleetfinder/locale/ru/LC_MESSAGES/django.po +30 -20
- fleetfinder/locale/sk/LC_MESSAGES/django.po +30 -20
- fleetfinder/locale/uk/LC_MESSAGES/django.po +30 -20
- fleetfinder/locale/zh_Hans/LC_MESSAGES/django.po +30 -20
- fleetfinder/static/fleetfinder/js/fleetfinder-dashboard.js +86 -0
- fleetfinder/static/fleetfinder/js/fleetfinder-dashboard.min.js +2 -0
- fleetfinder/static/fleetfinder/js/fleetfinder-dashboard.min.js.map +1 -0
- fleetfinder/static/fleetfinder/js/fleetfinder-fleet-details.js +154 -0
- fleetfinder/static/fleetfinder/js/fleetfinder-fleet-details.min.js +2 -0
- fleetfinder/static/fleetfinder/js/fleetfinder-fleet-details.min.js.map +1 -0
- fleetfinder/static/fleetfinder/js/fleetfinder.min.js +1 -1
- fleetfinder/static/fleetfinder/js/fleetfinder.min.js.map +1 -1
- fleetfinder/tasks.py +13 -5
- fleetfinder/templates/fleetfinder/base.html +11 -0
- fleetfinder/templates/fleetfinder/bundles/js/fleetfinder-js.html +6 -0
- fleetfinder/templates/fleetfinder/dashboard.html +8 -83
- fleetfinder/templates/fleetfinder/fleet-details.html +22 -150
- fleetfinder/tests/test_views.py +63 -0
- fleetfinder/views.py +32 -3
- {aa_fleetfinder-2.7.0.dist-info → aa_fleetfinder-2.7.1.dist-info}/WHEEL +0 -0
- {aa_fleetfinder-2.7.0.dist-info → aa_fleetfinder-2.7.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -8,6 +8,10 @@
|
|
|
8
8
|
{% endblock %}
|
|
9
9
|
|
|
10
10
|
{% block aa_fleetfinder_body %}
|
|
11
|
+
{% include "framework/header/page-header.html" with title=fleet.name subtitle=fleet.fleet_commander.character_name %}
|
|
12
|
+
|
|
13
|
+
<div class="alert alert-warning d-none" id="fleetfinder-fleet-details-warning"></div>
|
|
14
|
+
|
|
11
15
|
<div class="row">
|
|
12
16
|
<div class="col-lg-6 col-lg-push-6">
|
|
13
17
|
<div class="card card-primary">
|
|
@@ -19,7 +23,7 @@
|
|
|
19
23
|
|
|
20
24
|
<div class="card-body">
|
|
21
25
|
<div class="table-responsive">
|
|
22
|
-
<table class="table table-striped table-hover table-vertical-middle w-100" id="
|
|
26
|
+
<table class="table table-striped table-hover table-vertical-middle w-100" id="table-fleet-composition">
|
|
23
27
|
<thead>
|
|
24
28
|
<tr>
|
|
25
29
|
<th>{% translate "Ship class" %}</th>
|
|
@@ -44,7 +48,7 @@
|
|
|
44
48
|
|
|
45
49
|
<div class="card-body">
|
|
46
50
|
<div class="table-responsive">
|
|
47
|
-
<table class="table table-striped table-hover table-vertical-middle w-100" id="
|
|
51
|
+
<table class="table table-striped table-hover table-vertical-middle w-100" id="table-fleet-members">
|
|
48
52
|
<thead>
|
|
49
53
|
<tr>
|
|
50
54
|
<th>{% translate "Name" %}</th>
|
|
@@ -72,159 +76,27 @@
|
|
|
72
76
|
|
|
73
77
|
{% block extra_javascript %}
|
|
74
78
|
{% include "bundles/datatables-js-bs5.html" %}
|
|
75
|
-
{% include "fleetfinder/bundles/js/fleetfinder-js.html" %}
|
|
76
|
-
|
|
77
|
-
{% get_datatables_language_static LANGUAGE_CODE as DT_LANG_PATH %}
|
|
78
79
|
|
|
79
80
|
{% translate "Fleet boss" as l10nFleetBoss %}
|
|
80
81
|
{% translate "Kick member from fleet" as l10nKickMemberFromFleet %}
|
|
81
82
|
{% translate "An unknown error occurred." as l10nUnknownError %}
|
|
82
83
|
|
|
83
84
|
<script>
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
destroy: true
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
const populateDatatables = () => {
|
|
102
|
-
fetchGet({
|
|
103
|
-
url: url.fleetDetails,
|
|
104
|
-
})
|
|
105
|
-
.then((data) => {
|
|
106
|
-
table_fleet_members.DataTable({
|
|
107
|
-
...dataTableConfig,
|
|
108
|
-
data: data.fleet_member,
|
|
109
|
-
columns: [
|
|
110
|
-
{
|
|
111
|
-
render: (data, type, row) => {
|
|
112
|
-
const fwIcon = '<i class="fa-solid fa-star"></i>';
|
|
113
|
-
|
|
114
|
-
return row.is_fleet_boss
|
|
115
|
-
? `${row.character_name} <sup data-bs-tooltip="aa-fleetfinder" title="{{ l10nFleetBoss|escapejs }}"><small>${fwIcon}</small></sup>`
|
|
116
|
-
: row.character_name;
|
|
117
|
-
}
|
|
118
|
-
},
|
|
119
|
-
{data: 'ship_type_name'},
|
|
120
|
-
{data: 'solar_system_name'},
|
|
121
|
-
{
|
|
122
|
-
render: (data, type, row) => {
|
|
123
|
-
const fwIcon = '<i class="fa-solid fa-user-minus"></i>';
|
|
124
|
-
const dataAttributes = Object.entries({
|
|
125
|
-
'data-character-id': row.character_id,
|
|
126
|
-
'data-character-name': row.character_name,
|
|
127
|
-
'data-bs-toggle': 'modal',
|
|
128
|
-
'data-bs-target': '#kick-fleet-member',
|
|
129
|
-
'data-bs-tooltip': 'aa-fleetfinder'
|
|
130
|
-
}).map(([key, value]) => {
|
|
131
|
-
return `${key}="${value}"`;
|
|
132
|
-
}).join(' ');
|
|
133
|
-
|
|
134
|
-
return row.is_fleet_boss
|
|
135
|
-
? ''
|
|
136
|
-
: `<button type="button" class="btn btn-sm btn-danger" ${dataAttributes} title="{{ l10nKickMemberFromFleet|escapejs }}">${fwIcon}</button>`;
|
|
137
|
-
},
|
|
138
|
-
orderable: false,
|
|
139
|
-
searchable: false,
|
|
140
|
-
width: '50px',
|
|
141
|
-
className: 'text-end'
|
|
142
|
-
}
|
|
143
|
-
],
|
|
144
|
-
createdRow: (row, data, rowIndex) => {
|
|
145
|
-
$(row).attr('data-row-id', rowIndex);
|
|
146
|
-
$(row).attr('data-character-id', data.character_id);
|
|
147
|
-
}
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
table_fleet_composition.DataTable({
|
|
151
|
-
...dataTableConfig,
|
|
152
|
-
data: data.fleet_composition,
|
|
153
|
-
columns: [
|
|
154
|
-
{data: 'ship_type_name'},
|
|
155
|
-
{data: 'number', className: 'text-right', width: '100px'}
|
|
156
|
-
],
|
|
157
|
-
order: [[1, 'desc']]
|
|
158
|
-
});
|
|
159
|
-
})
|
|
160
|
-
.then(() => {
|
|
161
|
-
// Initialize tooltips for the kick buttons
|
|
162
|
-
fleetfinderBootstrapTooltip({selector: '#table_fleet_members'});
|
|
163
|
-
})
|
|
164
|
-
.catch((error) => {
|
|
165
|
-
console.error('Error fetching fleet details:', error);
|
|
166
|
-
});
|
|
167
|
-
};
|
|
168
|
-
|
|
169
|
-
populateDatatables();
|
|
170
|
-
|
|
171
|
-
setInterval(populateDatatables, 30000);
|
|
172
|
-
|
|
173
|
-
/* Modals
|
|
174
|
-
------------------------------------------------------------------------- */
|
|
175
|
-
// Handle the kick fleet member modal
|
|
176
|
-
$('#kick-fleet-member')
|
|
177
|
-
.on('show.bs.modal', (event) => {
|
|
178
|
-
const button = $(event.relatedTarget);
|
|
179
|
-
const characterId = button.data('character-id');
|
|
180
|
-
const characterName = button.data('character-name');
|
|
181
|
-
const link = url.kickFleetMember;
|
|
182
|
-
const csrfToken = '{{ csrf_token }}';
|
|
183
|
-
|
|
184
|
-
// Populate the modal content
|
|
185
|
-
$('#kick-fleet-member-character-name').text(characterName);
|
|
186
|
-
|
|
187
|
-
$('#modal-button-confirm-kick-fleet-member')
|
|
188
|
-
// Remove any previous click handlers to avoid multiple bindings
|
|
189
|
-
.off('click.kickMember')
|
|
190
|
-
// Bind the click event for the confirmation button
|
|
191
|
-
.on('click.kickMember', () => {
|
|
192
|
-
fetchPost({
|
|
193
|
-
url: link,
|
|
194
|
-
csrfToken: csrfToken,
|
|
195
|
-
payload: {
|
|
196
|
-
memberId: characterId
|
|
197
|
-
},
|
|
198
|
-
responseIsJson: true
|
|
199
|
-
})
|
|
200
|
-
.then((data) => {
|
|
201
|
-
if (data.success) {
|
|
202
|
-
populateDatatables();
|
|
203
|
-
|
|
204
|
-
$('#kick-fleet-member').modal('hide');
|
|
205
|
-
} else {
|
|
206
|
-
$('#kick-fleet-member .modal-kick-fleet-member-error')
|
|
207
|
-
.removeClass('d-none')
|
|
208
|
-
.find('.modal-kick-fleet-member-error-message')
|
|
209
|
-
.text(data.error || '{{ l10nUnknownError|escapejs }}');
|
|
210
|
-
}
|
|
211
|
-
})
|
|
212
|
-
.catch((error) => {
|
|
213
|
-
console.error('Error kicking fleet member:', error);
|
|
214
|
-
});
|
|
215
|
-
});
|
|
216
|
-
})
|
|
217
|
-
.on('hide.bs.modal', () => {
|
|
218
|
-
// Reset modal content
|
|
219
|
-
$('#kick-fleet-member-character-name').empty();
|
|
220
|
-
$('#kick-fleet-member .modal-kick-fleet-member-error')
|
|
221
|
-
.addClass('d-none')
|
|
222
|
-
.find('.modal-kick-fleet-member-error-message')
|
|
223
|
-
.empty();
|
|
224
|
-
|
|
225
|
-
// Clean up event handler
|
|
226
|
-
$('#modal-button-confirm-kick-fleet-member').off('click.kickMember');
|
|
227
|
-
});
|
|
228
|
-
});
|
|
85
|
+
const aaFleetFinderSettingsOverride = {
|
|
86
|
+
dataTables: {
|
|
87
|
+
url: {
|
|
88
|
+
fleetDetails: '{% url "fleetfinder:ajax_fleet_details" fleet.fleet_id %}',
|
|
89
|
+
kickFleetMember: '{% url "fleetfinder:ajax_fleet_kick_member" fleet.fleet_id %}'
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
l10n: {
|
|
93
|
+
fleetBoss: '{{ l10nFleetBoss|escapejs }}',
|
|
94
|
+
kickMemberFromFleet: '{{ l10nKickMemberFromFleet|escapejs }}',
|
|
95
|
+
unknownError: '{{ l10nUnknownError|escapejs }}'
|
|
96
|
+
},
|
|
97
|
+
csrfToken: '{{ csrf_token }}'
|
|
98
|
+
};
|
|
229
99
|
</script>
|
|
100
|
+
|
|
101
|
+
{% include "fleetfinder/bundles/js/fleetfinder-js.html" with view="fleet-details" %}
|
|
230
102
|
{% endblock %}
|
fleetfinder/tests/test_views.py
CHANGED
|
@@ -402,6 +402,21 @@ class TestFleetDetailsView(FleetfinderTestViews):
|
|
|
402
402
|
|
|
403
403
|
self.assertEqual(response.status_code, HTTPStatus.FOUND)
|
|
404
404
|
|
|
405
|
+
def test_fleet_redirects_to_dashboard_if_not_found(self):
|
|
406
|
+
"""
|
|
407
|
+
Test that the fleet_details view redirects to the dashboard if the fleet does not exist.
|
|
408
|
+
|
|
409
|
+
:return:
|
|
410
|
+
:rtype:
|
|
411
|
+
"""
|
|
412
|
+
|
|
413
|
+
self.client.force_login(self.user_with_manage_perms)
|
|
414
|
+
|
|
415
|
+
response = self.client.get(reverse("fleetfinder:fleet_details", args=[123]))
|
|
416
|
+
|
|
417
|
+
self.assertEqual(response.status_code, HTTPStatus.FOUND)
|
|
418
|
+
self.assertEqual(response.url, reverse("fleetfinder:dashboard"))
|
|
419
|
+
|
|
405
420
|
|
|
406
421
|
class TestAjaxFleetDetailsView(FleetfinderTestViews):
|
|
407
422
|
"""
|
|
@@ -471,3 +486,51 @@ class TestAjaxFleetDetailsView(FleetfinderTestViews):
|
|
|
471
486
|
|
|
472
487
|
self.assertEqual(response.status_code, HTTPStatus.OK)
|
|
473
488
|
self.assertEqual(json.loads(response.content), expected_fleet_composition)
|
|
489
|
+
|
|
490
|
+
@patch("fleetfinder.views.get_fleet_composition")
|
|
491
|
+
def test_returns_error_when_fleet_does_not_exist(self, mock_get_fleet_composition):
|
|
492
|
+
"""
|
|
493
|
+
Test that the ajax_fleet_details view returns an error when the fleet does not exist.
|
|
494
|
+
|
|
495
|
+
:param mock_get_fleet_composition:
|
|
496
|
+
:type mock_get_fleet_composition:
|
|
497
|
+
:return:
|
|
498
|
+
:rtype:
|
|
499
|
+
"""
|
|
500
|
+
|
|
501
|
+
mock_get_fleet_composition.side_effect = Fleet.DoesNotExist
|
|
502
|
+
|
|
503
|
+
self.client.force_login(user=self.user_with_manage_perms)
|
|
504
|
+
|
|
505
|
+
url = reverse("fleetfinder:ajax_fleet_details", args=[123])
|
|
506
|
+
response = self.client.get(url)
|
|
507
|
+
|
|
508
|
+
self.assertEqual(response.status_code, HTTPStatus.OK)
|
|
509
|
+
self.assertJSONEqual(
|
|
510
|
+
response.content,
|
|
511
|
+
{"error": "Fleet with ID 123 does not exist."},
|
|
512
|
+
)
|
|
513
|
+
|
|
514
|
+
@patch("fleetfinder.views.get_fleet_composition")
|
|
515
|
+
def test_returns_error_when_runtime_error_occurs(self, mock_get_fleet_composition):
|
|
516
|
+
"""
|
|
517
|
+
Test that the ajax_fleet_details view returns an error when a runtime error occurs.
|
|
518
|
+
|
|
519
|
+
:param mock_get_fleet_composition:
|
|
520
|
+
:type mock_get_fleet_composition:
|
|
521
|
+
:return:
|
|
522
|
+
:rtype:
|
|
523
|
+
"""
|
|
524
|
+
|
|
525
|
+
mock_get_fleet_composition.side_effect = RuntimeError("Unexpected error")
|
|
526
|
+
|
|
527
|
+
self.client.force_login(user=self.user_with_manage_perms)
|
|
528
|
+
|
|
529
|
+
url = reverse("fleetfinder:ajax_fleet_details", args=[123])
|
|
530
|
+
response = self.client.get(url)
|
|
531
|
+
|
|
532
|
+
self.assertEqual(response.status_code, HTTPStatus.OK)
|
|
533
|
+
self.assertJSONEqual(
|
|
534
|
+
response.content,
|
|
535
|
+
{"error": "Error retrieving fleet composition: Unexpected error"},
|
|
536
|
+
)
|
fleetfinder/views.py
CHANGED
|
@@ -462,9 +462,25 @@ def fleet_details(request, fleet_id):
|
|
|
462
462
|
:return:
|
|
463
463
|
"""
|
|
464
464
|
|
|
465
|
-
|
|
465
|
+
try:
|
|
466
|
+
fleet = Fleet.objects.get(fleet_id=fleet_id)
|
|
467
|
+
except Fleet.DoesNotExist:
|
|
468
|
+
logger.debug(f"Fleet with ID {fleet_id} does not exist.")
|
|
466
469
|
|
|
467
|
-
|
|
470
|
+
messages.error(
|
|
471
|
+
request,
|
|
472
|
+
mark_safe(
|
|
473
|
+
_(
|
|
474
|
+
"<h4>Error!</h4><p>Fleet does not exist or is no longer available.</p>"
|
|
475
|
+
)
|
|
476
|
+
),
|
|
477
|
+
)
|
|
478
|
+
|
|
479
|
+
return redirect("fleetfinder:dashboard")
|
|
480
|
+
|
|
481
|
+
context = {"fleet": fleet}
|
|
482
|
+
|
|
483
|
+
logger.info(msg=f"Fleet {fleet.fleet_id} details view called by {request.user}")
|
|
468
484
|
|
|
469
485
|
return render(
|
|
470
486
|
request=request,
|
|
@@ -485,7 +501,20 @@ def ajax_fleet_details(
|
|
|
485
501
|
:param fleet_id:
|
|
486
502
|
"""
|
|
487
503
|
|
|
488
|
-
|
|
504
|
+
try:
|
|
505
|
+
fleet = get_fleet_composition(fleet_id)
|
|
506
|
+
except Fleet.DoesNotExist:
|
|
507
|
+
logger.debug(f"Fleet with ID {fleet_id} does not exist.")
|
|
508
|
+
|
|
509
|
+
return JsonResponse(
|
|
510
|
+
data={"error": _(f"Fleet with ID {fleet_id} does not exist.")}, safe=False
|
|
511
|
+
)
|
|
512
|
+
except RuntimeError as ex:
|
|
513
|
+
logger.debug(f"Error retrieving fleet composition: {ex}", exc_info=True)
|
|
514
|
+
|
|
515
|
+
return JsonResponse(
|
|
516
|
+
data={"error": _(f"Error retrieving fleet composition: {ex}")}, safe=False
|
|
517
|
+
)
|
|
489
518
|
|
|
490
519
|
data = {
|
|
491
520
|
"fleet_member": list(fleet.fleet),
|
|
File without changes
|
|
File without changes
|