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
|
@@ -19,12 +19,7 @@
|
|
|
19
19
|
<th>{% translate "Fleet commander" %}</th>
|
|
20
20
|
<th>{% translate "Fleet name" %}</th>
|
|
21
21
|
<th>{% translate "Created at" %}</th>
|
|
22
|
-
<th
|
|
23
|
-
|
|
24
|
-
{% if perms.fleetfinder.manage_fleets %}
|
|
25
|
-
<th>{% translate "Details" %}</th>
|
|
26
|
-
<th>{% translate "Edit" %}</th>
|
|
27
|
-
{% endif %}
|
|
22
|
+
<th class="text-end"><!-- {% translate "Join" %} --></th>
|
|
28
23
|
</tr>
|
|
29
24
|
</thead>
|
|
30
25
|
|
|
@@ -43,20 +38,33 @@
|
|
|
43
38
|
{% block extra_javascript %}
|
|
44
39
|
{% include "bundles/datatables-js-bs5.html" %}
|
|
45
40
|
{% include "bundles/moment-js.html" with locale=True %}
|
|
41
|
+
{% include "fleetfinder/bundles/js/fleetfinder-js.html" %}
|
|
46
42
|
|
|
47
43
|
{% get_datatables_language_static LANGUAGE_CODE as DT_LANG_PATH %}
|
|
48
44
|
|
|
49
45
|
<script>
|
|
46
|
+
/* global fetchGet, fleetfinderBootstrapTooltip, DataTable */
|
|
47
|
+
'use strict';
|
|
48
|
+
|
|
50
49
|
$(document).ready(() => {
|
|
51
50
|
const DATETIME_FORMAT = 'YYYY-MM-DD, HH:mm';
|
|
52
51
|
const table_fleet_overview = $('#table_available-fleets');
|
|
52
|
+
let dataTable = null;
|
|
53
53
|
|
|
54
54
|
/**
|
|
55
|
-
* Initialize the datatable
|
|
55
|
+
* Initialize or update the datatable.
|
|
56
|
+
* If the table already exists, it will be updated with new data.
|
|
57
|
+
* If it does not exist, a new DataTable will be created.
|
|
58
|
+
*
|
|
59
|
+
* @param {Object} data - The fleet data to populate the table.
|
|
56
60
|
*/
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
61
|
+
const initializeOrUpdateTable = (data) => {
|
|
62
|
+
if (dataTable) {
|
|
63
|
+
// Update existing table
|
|
64
|
+
dataTable.clear().rows.add(data).draw();
|
|
65
|
+
} else {
|
|
66
|
+
// Initialize new table
|
|
67
|
+
dataTable = table_fleet_overview.DataTable({
|
|
60
68
|
language: {
|
|
61
69
|
url: '{{ DT_LANG_PATH }}'
|
|
62
70
|
},
|
|
@@ -69,15 +77,16 @@
|
|
|
69
77
|
sort: 'sort'
|
|
70
78
|
}
|
|
71
79
|
},
|
|
72
|
-
{
|
|
80
|
+
{
|
|
81
|
+
data: 'fleet_name'
|
|
82
|
+
},
|
|
73
83
|
{
|
|
74
84
|
data: 'created_at',
|
|
75
85
|
},
|
|
76
|
-
{
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
{% endif %}
|
|
86
|
+
{
|
|
87
|
+
data: 'actions',
|
|
88
|
+
className: 'text-end',
|
|
89
|
+
},
|
|
81
90
|
],
|
|
82
91
|
columnDefs: [
|
|
83
92
|
{
|
|
@@ -88,66 +97,32 @@
|
|
|
88
97
|
orderable: false,
|
|
89
98
|
targets: [3]
|
|
90
99
|
},
|
|
91
|
-
{% if perms.fleetfinder.manage_fleets %}
|
|
92
|
-
{
|
|
93
|
-
orderable: false,
|
|
94
|
-
targets: [4, 5]
|
|
95
|
-
},
|
|
96
|
-
{% endif %}
|
|
97
100
|
],
|
|
98
101
|
order: [[0, 'asc']],
|
|
99
102
|
paging: false
|
|
100
103
|
});
|
|
101
|
-
}
|
|
102
|
-
.catch((error) => {
|
|
103
|
-
console.error('Error fetching fleet data:', error);
|
|
104
|
-
});
|
|
104
|
+
}
|
|
105
105
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
const intervalReloadDatatable = 30000; // ms
|
|
110
|
-
let expectedReloadDatatable = Date.now() + intervalReloadDatatable;
|
|
106
|
+
// Initialize Bootstrap tooltips
|
|
107
|
+
fleetfinderBootstrapTooltip({selector: '#table_available-fleets'});
|
|
108
|
+
};
|
|
111
109
|
|
|
112
110
|
/**
|
|
113
|
-
*
|
|
111
|
+
* Fetch and update fleet data
|
|
114
112
|
*/
|
|
115
|
-
const
|
|
116
|
-
const dt = Date.now() - expectedReloadDatatable; // The drift (positive for overshooting)
|
|
117
|
-
|
|
118
|
-
if (dt > intervalReloadDatatable) {
|
|
119
|
-
// Something awful happened. Maybe the browser (tab) was inactive?
|
|
120
|
-
// Possibly special handling to avoid futile "catch up" run
|
|
121
|
-
console.log('Something went wrong, reloading page ...');
|
|
122
|
-
|
|
123
|
-
window.location.replace(
|
|
124
|
-
window.location.pathname + window.location.search + window.location.hash
|
|
125
|
-
);
|
|
126
|
-
}
|
|
127
|
-
|
|
113
|
+
const fetchFleetData = () => {
|
|
128
114
|
fetchGet({url: '{% url "fleetfinder:ajax_dashboard" %}'})
|
|
129
|
-
.then(
|
|
130
|
-
const dataTable = table_fleet_overview.DataTable();
|
|
131
|
-
|
|
132
|
-
dataTable.clear().rows.add(newData).draw();
|
|
133
|
-
})
|
|
115
|
+
.then(initializeOrUpdateTable)
|
|
134
116
|
.catch((error) => {
|
|
135
|
-
console.error('Error fetching
|
|
117
|
+
console.error('Error fetching fleet data:', error);
|
|
136
118
|
});
|
|
137
|
-
|
|
138
|
-
expectedReloadDatatable += intervalReloadDatatable;
|
|
139
|
-
|
|
140
|
-
// Take drift into account
|
|
141
|
-
setTimeout(
|
|
142
|
-
reloadDataTable,
|
|
143
|
-
Math.max(0, intervalReloadDatatable - dt)
|
|
144
|
-
);
|
|
145
119
|
};
|
|
146
120
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
121
|
+
// Initial load
|
|
122
|
+
fetchFleetData();
|
|
123
|
+
|
|
124
|
+
// Refresh every 30 seconds
|
|
125
|
+
setInterval(fetchFleetData, 30000);
|
|
151
126
|
});
|
|
152
127
|
</script>
|
|
153
128
|
{% endblock %}
|
|
@@ -50,6 +50,7 @@
|
|
|
50
50
|
<th>{% translate "Name" %}</th>
|
|
51
51
|
<th>{% translate "Ship class" %}</th>
|
|
52
52
|
<th>{% translate "System" %}</th>
|
|
53
|
+
<th><!-- {% translate "Action" %} --></th>
|
|
53
54
|
</tr>
|
|
54
55
|
</thead>
|
|
55
56
|
|
|
@@ -60,6 +61,8 @@
|
|
|
60
61
|
</div>
|
|
61
62
|
</div>
|
|
62
63
|
</div>
|
|
64
|
+
|
|
65
|
+
{% include "fleetfinder/modals/kick-fleet-member.html" %}
|
|
63
66
|
{% endblock %}
|
|
64
67
|
|
|
65
68
|
{% block extra_css %}
|
|
@@ -69,39 +72,83 @@
|
|
|
69
72
|
|
|
70
73
|
{% block extra_javascript %}
|
|
71
74
|
{% include "bundles/datatables-js-bs5.html" %}
|
|
75
|
+
{% include "fleetfinder/bundles/js/fleetfinder-js.html" %}
|
|
72
76
|
|
|
73
77
|
{% get_datatables_language_static LANGUAGE_CODE as DT_LANG_PATH %}
|
|
74
78
|
|
|
79
|
+
{% translate "Fleet boss" as l10nFleetBoss %}
|
|
80
|
+
{% translate "Kick member from fleet" as l10nKickMemberFromFleet %}
|
|
81
|
+
{% translate "An unknown error occurred." as l10nUnknownError %}
|
|
82
|
+
|
|
75
83
|
<script>
|
|
76
84
|
$(document).ready(() => {
|
|
85
|
+
/* DataTables
|
|
86
|
+
------------------------------------------------------------------------- */
|
|
77
87
|
const table_fleet_members = $('#table_fleet_members');
|
|
78
|
-
const
|
|
88
|
+
const table_fleet_composition = $('#table_fleet_composition');
|
|
89
|
+
const url = {
|
|
90
|
+
kickFleetMember: '{% url "fleetfinder:ajax_fleet_kick_member" fleet_id %}',
|
|
91
|
+
fleetDetails: '{% url "fleetfinder:ajax_fleet_details" fleet_id %}'
|
|
92
|
+
};
|
|
93
|
+
const dataTableConfig = {
|
|
94
|
+
language: {
|
|
95
|
+
url: '{{ DT_LANG_PATH }}'
|
|
96
|
+
},
|
|
97
|
+
paging: false,
|
|
98
|
+
destroy: true
|
|
99
|
+
};
|
|
79
100
|
|
|
80
101
|
const populateDatatables = () => {
|
|
81
102
|
fetchGet({
|
|
82
|
-
url:
|
|
103
|
+
url: url.fleetDetails,
|
|
83
104
|
})
|
|
84
105
|
.then((data) => {
|
|
85
106
|
table_fleet_members.DataTable({
|
|
86
|
-
|
|
87
|
-
url: '{{ DT_LANG_PATH }}'
|
|
88
|
-
},
|
|
89
|
-
destroy: true,
|
|
90
|
-
paging: false,
|
|
107
|
+
...dataTableConfig,
|
|
91
108
|
data: data.fleet_member,
|
|
92
109
|
columns: [
|
|
93
|
-
{
|
|
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
|
+
},
|
|
94
119
|
{data: 'ship_type_name'},
|
|
95
|
-
{data: 'solar_system_name'}
|
|
96
|
-
|
|
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
|
+
}
|
|
97
148
|
});
|
|
98
149
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
url: '{{ DT_LANG_PATH }}'
|
|
102
|
-
},
|
|
103
|
-
destroy: true,
|
|
104
|
-
paging: false,
|
|
150
|
+
table_fleet_composition.DataTable({
|
|
151
|
+
...dataTableConfig,
|
|
105
152
|
data: data.fleet_composition,
|
|
106
153
|
columns: [
|
|
107
154
|
{data: 'ship_type_name'},
|
|
@@ -110,30 +157,74 @@
|
|
|
110
157
|
order: [[1, 'desc']]
|
|
111
158
|
});
|
|
112
159
|
})
|
|
160
|
+
.then(() => {
|
|
161
|
+
// Initialize tooltips for the kick buttons
|
|
162
|
+
fleetfinderBootstrapTooltip({selector: '#table_fleet_members'});
|
|
163
|
+
})
|
|
113
164
|
.catch((error) => {
|
|
114
165
|
console.error('Error fetching fleet details:', error);
|
|
115
166
|
});
|
|
116
167
|
};
|
|
117
168
|
|
|
118
|
-
table_fleet_members.DataTable({
|
|
119
|
-
language: {
|
|
120
|
-
url: '{{ DT_LANG_PATH }}'
|
|
121
|
-
},
|
|
122
|
-
paging: false,
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
tabe_fleet_composition.DataTable({
|
|
126
|
-
language: {
|
|
127
|
-
url: '{{ DT_LANG_PATH }}'
|
|
128
|
-
},
|
|
129
|
-
paging: false,
|
|
130
|
-
});
|
|
131
|
-
|
|
132
169
|
populateDatatables();
|
|
133
170
|
|
|
134
|
-
setInterval(
|
|
135
|
-
|
|
136
|
-
|
|
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
|
+
});
|
|
137
228
|
});
|
|
138
229
|
</script>
|
|
139
230
|
{% endblock %}
|
|
@@ -18,11 +18,21 @@
|
|
|
18
18
|
<div class="card-body container">
|
|
19
19
|
<div class="row">
|
|
20
20
|
<div class="align-self-center">
|
|
21
|
+
<p>
|
|
22
|
+
{% translate "Please ensure you don't have any CSPA charges set on your characters, as this will prevent fleet invites from being sent." %}
|
|
23
|
+
<br>
|
|
24
|
+
{% translate "You can select multiple characters to invite them all at once." %}
|
|
25
|
+
</p>
|
|
26
|
+
|
|
27
|
+
<p>
|
|
28
|
+
{% translate "The selected characters will receive a fleet invite in-game, which they can accept to join the fleet." %}
|
|
29
|
+
</p>
|
|
30
|
+
|
|
21
31
|
<form class="form-signin" role="form" action="" method="POST">
|
|
22
32
|
{% csrf_token %}
|
|
23
33
|
|
|
24
34
|
<div class="mb-3">
|
|
25
|
-
<label for="character_ids">{% translate "
|
|
35
|
+
<label for="character_ids" class="mb-1">{% translate "Please select the characters you want to invite:" %}</label>
|
|
26
36
|
|
|
27
37
|
<select class="multiselect-ui" multiple="multiple" name="character_ids" id="character_ids">
|
|
28
38
|
{% for character in characters %}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{% load bootstrap %}
|
|
2
|
+
{% load i18n %}
|
|
3
|
+
|
|
4
|
+
<!-- kick fleet member modal -->
|
|
5
|
+
<div class="modal fade" id="kick-fleet-member" tabindex="-1" role="dialog" aria-hidden="true">
|
|
6
|
+
<div class="modal-dialog modal-dialog-centered" role="document">
|
|
7
|
+
<div class="modal-content">
|
|
8
|
+
<div class="modal-header">
|
|
9
|
+
<div class="modal-title fs-5">
|
|
10
|
+
{% translate "Kick member from fleet" %}
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="{% translate 'Close' %}"></button>
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
<div class="modal-body">
|
|
17
|
+
<p>
|
|
18
|
+
{% translate "Are you sure you want to kick this member from the fleet?" %}
|
|
19
|
+
</p>
|
|
20
|
+
|
|
21
|
+
<p>
|
|
22
|
+
<strong id="kick-fleet-member-character-name"></strong>
|
|
23
|
+
</p>
|
|
24
|
+
|
|
25
|
+
<p class="aa-callout aa-callout-danger modal-kick-fleet-member-error d-none">
|
|
26
|
+
<i class="fa-solid fa-triangle-exclamation"></i>
|
|
27
|
+
{% translate "Error" %}
|
|
28
|
+
<br>
|
|
29
|
+
<span class="modal-kick-fleet-member-error-message"></span>
|
|
30
|
+
</p>
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
<div class="modal-footer">
|
|
34
|
+
<button id="modal-button-cancel-kick-fleet-member" type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">
|
|
35
|
+
<i class="fa-regular fa-hand"></i>
|
|
36
|
+
{% translate "Cancel" %}
|
|
37
|
+
</button>
|
|
38
|
+
|
|
39
|
+
<button id="modal-button-confirm-kick-fleet-member" type="button" class="btn btn-success btn-sm">
|
|
40
|
+
<i class="fa-solid fa-check"></i>
|
|
41
|
+
{% translate "Confirm" %}
|
|
42
|
+
</button>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
@@ -33,16 +33,16 @@
|
|
|
33
33
|
</p>
|
|
34
34
|
</div>
|
|
35
35
|
|
|
36
|
-
<div class="mb-3"
|
|
37
|
-
<label for="motd" class="control-label">{% translate "Fleet MOTD" %}</label
|
|
38
|
-
|
|
39
|
-
<div
|
|
40
|
-
<textarea class="form-control" name="motd" id="motd" rows="10">{% if motd %}{{ motd }}{% endif %}</textarea
|
|
41
|
-
</div
|
|
42
|
-
</div
|
|
36
|
+
{# <div class="mb-3">#}
|
|
37
|
+
{# <label for="motd" class="control-label">{% translate "Fleet MOTD" %}</label>#}
|
|
38
|
+
{##}
|
|
39
|
+
{# <div>#}
|
|
40
|
+
{# <textarea class="form-control" name="motd" id="motd" rows="10">{% if motd %}{{ motd }}{% endif %}</textarea>#}
|
|
41
|
+
{# </div>#}
|
|
42
|
+
{# </div>#}
|
|
43
43
|
|
|
44
44
|
<div class="mb-3">
|
|
45
|
-
<input type="checkbox" style="margin-right: 5px;" class="form-check-input" name="free_move" id="free_move" {% if is_free_move %}checked{% endif %}>
|
|
45
|
+
<input type="checkbox" style="margin-right: 5px;" class="form-check-input" name="free_move" id="free_move" {% if fleet.is_free_move %}checked{% endif %}>
|
|
46
46
|
<label for="free_move" class="form-check-label">{% translate "Enable free move" %}</label>
|
|
47
47
|
</div>
|
|
48
48
|
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tests for the fleetfinder.tasks module.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
# Standard Library
|
|
6
|
+
from unittest import TestCase
|
|
7
|
+
from unittest.mock import Mock, patch
|
|
8
|
+
|
|
9
|
+
# AA Fleet Finder
|
|
10
|
+
from fleetfinder.tasks import (
|
|
11
|
+
_get_fleet_aggregate,
|
|
12
|
+
check_fleet_adverts,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class TestGetFleetAggregate(TestCase):
|
|
17
|
+
"""
|
|
18
|
+
Tests for the _get_fleet_aggregate function.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
def test_returns_correct_counts_for_valid_fleet_infos(self):
|
|
22
|
+
"""
|
|
23
|
+
Test that _get_fleet_aggregate returns correct counts for valid fleet_infos.
|
|
24
|
+
|
|
25
|
+
:return:
|
|
26
|
+
:rtype:
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
fleet_infos = [
|
|
30
|
+
{"ship_type_name": "Cruiser"},
|
|
31
|
+
{"ship_type_name": "Cruiser"},
|
|
32
|
+
{"ship_type_name": "Battleship"},
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
result = _get_fleet_aggregate(fleet_infos)
|
|
36
|
+
|
|
37
|
+
assert result == {"Cruiser": 2, "Battleship": 1}
|
|
38
|
+
|
|
39
|
+
def test_returns_empty_dict_for_empty_fleet_infos(self):
|
|
40
|
+
"""
|
|
41
|
+
Test that _get_fleet_aggregate returns an empty dictionary for empty fleet_infos.
|
|
42
|
+
|
|
43
|
+
:return:
|
|
44
|
+
:rtype:
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
fleet_infos = []
|
|
48
|
+
|
|
49
|
+
result = _get_fleet_aggregate(fleet_infos)
|
|
50
|
+
|
|
51
|
+
assert result == {}
|
|
52
|
+
|
|
53
|
+
def test_returns_only_valid_ship_type_names(self):
|
|
54
|
+
"""
|
|
55
|
+
Test that _get_fleet_aggregate returns only valid ship type names.
|
|
56
|
+
|
|
57
|
+
:return:
|
|
58
|
+
:rtype:
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
fleet_infos = [
|
|
62
|
+
{"ship_type_name": "Cruiser"},
|
|
63
|
+
{},
|
|
64
|
+
{"ship_type_name": None},
|
|
65
|
+
{"ship_type_name": "Battleship"},
|
|
66
|
+
{"other_key": "Frigate"},
|
|
67
|
+
]
|
|
68
|
+
|
|
69
|
+
result = _get_fleet_aggregate(fleet_infos)
|
|
70
|
+
|
|
71
|
+
assert result == {"Cruiser": 1, "Battleship": 1}
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class TestCheckFleetAdvert(TestCase):
|
|
75
|
+
"""
|
|
76
|
+
Tests for the check_fleet_adverts function.
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
@patch("fleetfinder.models.Fleet.objects.all")
|
|
80
|
+
@patch("fleetfinder.tasks.fetch_esi_status")
|
|
81
|
+
def test_processes_registered_fleets_when_available(
|
|
82
|
+
self, mock_fetch_esi_status, mock_fleet_objects
|
|
83
|
+
):
|
|
84
|
+
"""
|
|
85
|
+
Test that check_fleet_adverts processes registered fleets when ESI is available.
|
|
86
|
+
|
|
87
|
+
:param mock_fetch_esi_status:
|
|
88
|
+
:type mock_fetch_esi_status:
|
|
89
|
+
:param mock_fleet_objects:
|
|
90
|
+
:type mock_fleet_objects:
|
|
91
|
+
:return:
|
|
92
|
+
:rtype:
|
|
93
|
+
"""
|
|
94
|
+
|
|
95
|
+
mock_fetch_esi_status.return_value.is_ok = True
|
|
96
|
+
mock_fleet_objects.return_value.exists.return_value = True
|
|
97
|
+
mock_fleet_objects.return_value.count.return_value = 2
|
|
98
|
+
mock_fleet_objects.return_value.__iter__.return_value = iter([Mock(), Mock()])
|
|
99
|
+
|
|
100
|
+
check_fleet_adverts()
|
|
101
|
+
|
|
102
|
+
mock_fleet_objects.return_value.__iter__.assert_called_once()
|
|
103
|
+
mock_fetch_esi_status.assert_called_once()
|
|
104
|
+
|
|
105
|
+
@patch("fleetfinder.models.Fleet.objects.all")
|
|
106
|
+
@patch("fleetfinder.tasks.fetch_esi_status")
|
|
107
|
+
def test_logs_no_registered_fleets_when_none_exist(
|
|
108
|
+
self, mock_fetch_esi_status, mock_fleet_objects
|
|
109
|
+
):
|
|
110
|
+
"""
|
|
111
|
+
Test that check_fleet_adverts logs a message when no registered fleets exist.
|
|
112
|
+
|
|
113
|
+
:param mock_fetch_esi_status:
|
|
114
|
+
:type mock_fetch_esi_status:
|
|
115
|
+
:param mock_fleet_objects:
|
|
116
|
+
:type mock_fleet_objects:
|
|
117
|
+
:return:
|
|
118
|
+
:rtype:
|
|
119
|
+
"""
|
|
120
|
+
|
|
121
|
+
mock_fetch_esi_status.return_value.is_ok = True
|
|
122
|
+
mock_fleet_objects.return_value.exists.return_value = False
|
|
123
|
+
|
|
124
|
+
check_fleet_adverts()
|
|
125
|
+
|
|
126
|
+
mock_fleet_objects.return_value.exists.assert_called_once()
|
|
127
|
+
mock_fetch_esi_status.assert_not_called()
|
|
128
|
+
|
|
129
|
+
@patch("fleetfinder.models.Fleet.objects.all")
|
|
130
|
+
@patch("fleetfinder.tasks.fetch_esi_status")
|
|
131
|
+
def test_aborts_processing_when_esi_is_unavailable(
|
|
132
|
+
self, mock_fetch_esi_status, mock_fleet_objects
|
|
133
|
+
):
|
|
134
|
+
mock_fetch_esi_status.return_value.is_ok = False
|
|
135
|
+
mock_fleet_objects.return_value.exists.return_value = True
|
|
136
|
+
|
|
137
|
+
check_fleet_adverts()
|
|
138
|
+
|
|
139
|
+
mock_fetch_esi_status.assert_called_once()
|
|
140
|
+
mock_fleet_objects.return_value.__iter__.assert_not_called()
|