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
|
@@ -4,21 +4,21 @@
|
|
|
4
4
|
# Dehao Wu <wudehao2000@163.com>, 2024.
|
|
5
5
|
# Faer Yili <yilifaer@gmail.com>, 2024.
|
|
6
6
|
# SAM_FPS <sam_fps@163.com>, 2024.
|
|
7
|
-
# Peter Pfeufer <info@ppfeufer.de>, 2024.
|
|
7
|
+
# Peter Pfeufer <info@ppfeufer.de>, 2024, 2025.
|
|
8
8
|
msgid ""
|
|
9
9
|
msgstr ""
|
|
10
10
|
"Project-Id-Version: AA Fleet Finder 2.2.1\n"
|
|
11
11
|
"Report-Msgid-Bugs-To: https://github.com/ppfeufer/aa-fleetfinder/issues\n"
|
|
12
|
-
"POT-Creation-Date: 2025-08-
|
|
13
|
-
"PO-Revision-Date:
|
|
12
|
+
"POT-Creation-Date: 2025-08-21 15:11+0200\n"
|
|
13
|
+
"PO-Revision-Date: 2025-08-21 13:16+0000\n"
|
|
14
14
|
"Last-Translator: Peter Pfeufer <info@ppfeufer.de>\n"
|
|
15
|
-
"Language-Team: Chinese (Simplified) <https://weblate.ppfeufer.de/projects/alliance-auth-apps/aa-fleetfinder/zh_Hans/>\n"
|
|
15
|
+
"Language-Team: Chinese (Simplified Han script) <https://weblate.ppfeufer.de/projects/alliance-auth-apps/aa-fleetfinder/zh_Hans/>\n"
|
|
16
16
|
"Language: zh_Hans\n"
|
|
17
17
|
"MIME-Version: 1.0\n"
|
|
18
18
|
"Content-Type: text/plain; charset=UTF-8\n"
|
|
19
19
|
"Content-Transfer-Encoding: 8bit\n"
|
|
20
20
|
"Plural-Forms: nplurals=1; plural=0;\n"
|
|
21
|
-
"X-Generator: Weblate 5.
|
|
21
|
+
"X-Generator: Weblate 5.13\n"
|
|
22
22
|
|
|
23
23
|
#: fleetfinder/__init__.py:9 fleetfinder/models.py:24
|
|
24
24
|
#: fleetfinder/templates/fleetfinder/base.html:6
|
|
@@ -70,7 +70,6 @@ msgid "Creation date and time"
|
|
|
70
70
|
msgstr "创建日期和时间"
|
|
71
71
|
|
|
72
72
|
#: fleetfinder/models.py:62
|
|
73
|
-
#: fleetfinder/templates/fleetfinder/partials/body/form-fleet-details.html:37
|
|
74
73
|
msgid "Fleet MOTD"
|
|
75
74
|
msgstr "舰队置顶信息"
|
|
76
75
|
|
|
@@ -117,14 +116,6 @@ msgstr "创建于"
|
|
|
117
116
|
msgid "Join"
|
|
118
117
|
msgstr "加入"
|
|
119
118
|
|
|
120
|
-
#: fleetfinder/templates/fleetfinder/dashboard.html:25
|
|
121
|
-
msgid "Details"
|
|
122
|
-
msgstr "细节"
|
|
123
|
-
|
|
124
|
-
#: fleetfinder/templates/fleetfinder/dashboard.html:26
|
|
125
|
-
msgid "Edit"
|
|
126
|
-
msgstr "编辑"
|
|
127
|
-
|
|
128
119
|
#: fleetfinder/templates/fleetfinder/edit-fleet.html:6
|
|
129
120
|
#: fleetfinder/templates/fleetfinder/edit-fleet.html:14
|
|
130
121
|
msgid "Edit fleet"
|
|
@@ -159,7 +150,26 @@ msgstr "名字"
|
|
|
159
150
|
msgid "System"
|
|
160
151
|
msgstr "星系"
|
|
161
152
|
|
|
162
|
-
#: fleetfinder/templates/fleetfinder/
|
|
153
|
+
#: fleetfinder/templates/fleetfinder/fleet-details.html:53
|
|
154
|
+
msgid "Action"
|
|
155
|
+
msgstr "行动"
|
|
156
|
+
|
|
157
|
+
#: fleetfinder/templates/fleetfinder/fleet-details.html:79
|
|
158
|
+
#, fuzzy
|
|
159
|
+
#| msgid "Fleet members"
|
|
160
|
+
msgid "Fleet boss"
|
|
161
|
+
msgstr "舰队成员"
|
|
162
|
+
|
|
163
|
+
#: fleetfinder/templates/fleetfinder/fleet-details.html:80
|
|
164
|
+
#: fleetfinder/templates/fleetfinder/modals/kick-fleet-member.html:10
|
|
165
|
+
msgid "Kick member from fleet"
|
|
166
|
+
msgstr ""
|
|
167
|
+
|
|
168
|
+
#: fleetfinder/templates/fleetfinder/fleet-details.html:81
|
|
169
|
+
msgid "An unknown error occurred."
|
|
170
|
+
msgstr ""
|
|
171
|
+
|
|
172
|
+
#: fleetfinder/templates/fleetfinder/join-fleet.html:6 fleetfinder/views.py:182
|
|
163
173
|
msgid "Join fleet"
|
|
164
174
|
msgstr "加入舰队"
|
|
165
175
|
|
|
@@ -167,14 +177,50 @@ msgstr "加入舰队"
|
|
|
167
177
|
msgid "Fleet invitation"
|
|
168
178
|
msgstr "舰队邀请"
|
|
169
179
|
|
|
170
|
-
#: fleetfinder/templates/fleetfinder/join-fleet.html:
|
|
171
|
-
msgid "
|
|
180
|
+
#: fleetfinder/templates/fleetfinder/join-fleet.html:22
|
|
181
|
+
msgid "Please ensure you don't have any CSPA charges set on your characters, as this will prevent fleet invites from being sent."
|
|
182
|
+
msgstr ""
|
|
183
|
+
|
|
184
|
+
#: fleetfinder/templates/fleetfinder/join-fleet.html:24
|
|
185
|
+
#, fuzzy
|
|
186
|
+
#| msgid "Select the characters to invite"
|
|
187
|
+
msgid "You can select multiple characters to invite them all at once."
|
|
172
188
|
msgstr "选择要邀请的角色"
|
|
173
189
|
|
|
190
|
+
#: fleetfinder/templates/fleetfinder/join-fleet.html:28
|
|
191
|
+
msgid "The selected characters will receive a fleet invite in-game, which they can accept to join the fleet."
|
|
192
|
+
msgstr ""
|
|
193
|
+
|
|
174
194
|
#: fleetfinder/templates/fleetfinder/join-fleet.html:35
|
|
195
|
+
#, fuzzy
|
|
196
|
+
#| msgid "Select the characters to invite"
|
|
197
|
+
msgid "Please select the characters you want to invite:"
|
|
198
|
+
msgstr "选择要邀请的角色"
|
|
199
|
+
|
|
200
|
+
#: fleetfinder/templates/fleetfinder/join-fleet.html:45
|
|
175
201
|
msgid "Send fleet invites"
|
|
176
202
|
msgstr "发送舰队邀请"
|
|
177
203
|
|
|
204
|
+
#: fleetfinder/templates/fleetfinder/modals/kick-fleet-member.html:13
|
|
205
|
+
msgid "Close"
|
|
206
|
+
msgstr ""
|
|
207
|
+
|
|
208
|
+
#: fleetfinder/templates/fleetfinder/modals/kick-fleet-member.html:18
|
|
209
|
+
msgid "Are you sure you want to kick this member from the fleet?"
|
|
210
|
+
msgstr ""
|
|
211
|
+
|
|
212
|
+
#: fleetfinder/templates/fleetfinder/modals/kick-fleet-member.html:27
|
|
213
|
+
msgid "Error"
|
|
214
|
+
msgstr ""
|
|
215
|
+
|
|
216
|
+
#: fleetfinder/templates/fleetfinder/modals/kick-fleet-member.html:36
|
|
217
|
+
msgid "Cancel"
|
|
218
|
+
msgstr "取消"
|
|
219
|
+
|
|
220
|
+
#: fleetfinder/templates/fleetfinder/modals/kick-fleet-member.html:41
|
|
221
|
+
msgid "Confirm"
|
|
222
|
+
msgstr "确认"
|
|
223
|
+
|
|
178
224
|
#: fleetfinder/templates/fleetfinder/partials/body/form-fleet-details.html:15
|
|
179
225
|
msgid "Select groups"
|
|
180
226
|
msgstr "选择群组"
|
|
@@ -199,18 +245,62 @@ msgstr "加入我们的翻译团队吧!"
|
|
|
199
245
|
msgid "Available fleets"
|
|
200
246
|
msgstr "可用的舰队"
|
|
201
247
|
|
|
202
|
-
#: fleetfinder/views.py:
|
|
248
|
+
#: fleetfinder/views.py:193
|
|
203
249
|
msgid "View fleet details"
|
|
204
250
|
msgstr "查看船队详情"
|
|
205
251
|
|
|
206
|
-
#: fleetfinder/views.py:
|
|
252
|
+
#: fleetfinder/views.py:199
|
|
207
253
|
msgid "Edit fleet advert"
|
|
208
254
|
msgstr "编辑舰队宣传信息"
|
|
209
255
|
|
|
210
|
-
#: fleetfinder/views.py:
|
|
211
|
-
#, python-brace-format
|
|
212
|
-
msgid "<h4>Error!</h4><p>ESI returned the following error: {esi_error_message}</p>"
|
|
256
|
+
#: fleetfinder/views.py:244
|
|
257
|
+
#, fuzzy, python-brace-format
|
|
258
|
+
#| msgid "<h4>Error!</h4><p>ESI returned the following error: {esi_error_message}</p>"
|
|
259
|
+
msgid "<h4>Error!</h4><p>There was an error creating the fleet: {error_detail}</p>"
|
|
260
|
+
msgstr "<h4>错误!</h4><p>ESI返回如下错误:{esi_error_message}</p>"
|
|
261
|
+
|
|
262
|
+
#: fleetfinder/views.py:284
|
|
263
|
+
msgid "<h4>Error!</h4><p>Fleet does not exist or is no longer available.</p>"
|
|
264
|
+
msgstr ""
|
|
265
|
+
|
|
266
|
+
#: fleetfinder/views.py:438
|
|
267
|
+
#, fuzzy, python-brace-format
|
|
268
|
+
#| msgid "<h4>Error!</h4><p>ESI returned the following error: {esi_error_message}</p>"
|
|
269
|
+
msgid "<h4>Error!</h4><p>ESI returned the following error: {esi_error}</p>"
|
|
213
270
|
msgstr "<h4>错误!</h4><p>ESI返回如下错误:{esi_error_message}</p>"
|
|
214
271
|
|
|
272
|
+
#: fleetfinder/views.py:446
|
|
273
|
+
#, python-brace-format
|
|
274
|
+
msgid "<h4>Error!</h4><p>There was an error creating the fleet: {ex}</p>"
|
|
275
|
+
msgstr ""
|
|
276
|
+
|
|
277
|
+
#: fleetfinder/views.py:517
|
|
278
|
+
msgid "Method not allowed"
|
|
279
|
+
msgstr ""
|
|
280
|
+
|
|
281
|
+
#: fleetfinder/views.py:527
|
|
282
|
+
msgid "Member ID required"
|
|
283
|
+
msgstr ""
|
|
284
|
+
|
|
285
|
+
#: fleetfinder/views.py:546
|
|
286
|
+
#, fuzzy
|
|
287
|
+
#| msgid "Fleet invitation"
|
|
288
|
+
msgid "Fleet not found"
|
|
289
|
+
msgstr "舰队邀请"
|
|
290
|
+
|
|
291
|
+
#: fleetfinder/views.py:550
|
|
292
|
+
msgid "Invalid request data"
|
|
293
|
+
msgstr ""
|
|
294
|
+
|
|
295
|
+
#: fleetfinder/views.py:554
|
|
296
|
+
msgid "Member not found in fleet"
|
|
297
|
+
msgstr ""
|
|
298
|
+
|
|
299
|
+
#~ msgid "Details"
|
|
300
|
+
#~ msgstr "细节"
|
|
301
|
+
|
|
302
|
+
#~ msgid "Edit"
|
|
303
|
+
#~ msgstr "编辑"
|
|
304
|
+
|
|
215
305
|
#~ msgid "Toggle navigation"
|
|
216
306
|
#~ msgstr "切换导航"
|
|
@@ -7,4 +7,25 @@
|
|
|
7
7
|
.aa-fleetfinder .table-vertical-middle td {
|
|
8
8
|
vertical-align: middle;
|
|
9
9
|
}
|
|
10
|
+
|
|
11
|
+
/* Slim Select
|
|
12
|
+
--------------------------------------------------------------------------------- */
|
|
13
|
+
|
|
14
|
+
.aa-fleetfinder .ss-main {
|
|
15
|
+
appearance: none;
|
|
16
|
+
background-clip: padding-box;
|
|
17
|
+
border: var(--bs-border-width) solid var(--bs-border-color);
|
|
18
|
+
border-radius: var(--bs-border-radius);
|
|
19
|
+
color: var(--bs-body-color);
|
|
20
|
+
font-size: 1rem;
|
|
21
|
+
font-weight: 400;
|
|
22
|
+
line-height: 1.5;
|
|
23
|
+
min-height: calc(1.5em + .75rem + 2px);
|
|
24
|
+
padding: .375rem .75rem;
|
|
25
|
+
transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out;
|
|
26
|
+
width: 100%;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/* END Slim Select
|
|
30
|
+
--------------------------------------------------------------------------------- */
|
|
10
31
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
@media all{.aa-fleetfinder .eve-character-portrait,.aa-fleetfinder .eve-type-icon{margin-right:.5rem}.aa-fleetfinder .table-vertical-middle td{vertical-align:middle}}
|
|
1
|
+
@media all{.aa-fleetfinder .eve-character-portrait,.aa-fleetfinder .eve-type-icon{margin-right:.5rem}.aa-fleetfinder .table-vertical-middle td{vertical-align:middle}.aa-fleetfinder .ss-main{appearance:none;background-clip:padding-box;border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius);color:var(--bs-body-color);font-size:1rem;font-weight:400;line-height:1.5;min-height:calc(1.5em + .75rem + 2px);padding:.375rem .75rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out;width:100%}}
|
|
2
2
|
/*# sourceMappingURL=fleetfinder.min.css.map */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["fleetfinder.css"],"names":[],"mappings":"AAAA,A,WACI,uC,CACA,8B,CACI,kB,CAGJ,yC,CACI,
|
|
1
|
+
{"version":3,"sources":["fleetfinder.css"],"names":[],"mappings":"AAAA,A,WACI,uC,CACA,8B,CACI,kB,CAGJ,yC,CACI,qB,CAMJ,wB,CACI,e,CACA,2B,CACA,0D,CACA,qC,CACA,0B,CACA,c,CACA,e,CACA,e,CACA,qC,CACA,sB,CACA,oE,CACA,Y","file":"fleetfinder.css","sourcesContent":["@media all {\n .aa-fleetfinder .eve-character-portrait,\n .aa-fleetfinder .eve-type-icon {\n margin-right: 0.5rem;\n }\n\n .aa-fleetfinder .table-vertical-middle td {\n vertical-align: middle;\n }\n\n /* Slim Select\n --------------------------------------------------------------------------------- */\n\n .aa-fleetfinder .ss-main {\n appearance: none;\n background-clip: padding-box;\n border: var(--bs-border-width) solid var(--bs-border-color);\n border-radius: var(--bs-border-radius);\n color: var(--bs-body-color);\n font-size: 1rem;\n font-weight: 400;\n line-height: 1.5;\n min-height: calc(1.5em + .75rem + 2px);\n padding: .375rem .75rem;\n transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out;\n width: 100%;\n }\n\n /* END Slim Select\n --------------------------------------------------------------------------------- */\n}\n"]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/* global bootstrap */
|
|
2
|
+
|
|
3
|
+
/* jshint -W097 */
|
|
4
|
+
'use strict';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Bootstrap tooltip
|
|
8
|
+
*
|
|
9
|
+
* @param {string} [selector=body] Selector for the tooltip elements, defaults to 'body'
|
|
10
|
+
* to apply to all elements with the data-bs-tooltip attribute.
|
|
11
|
+
* Example: 'body', '.my-tooltip-class', '#my-tooltip-id'
|
|
12
|
+
* If you want to apply it to a specific element, use that element's selector.
|
|
13
|
+
* If you want to apply it to all elements with the data-bs-tooltip attribute,
|
|
14
|
+
* use 'body' or leave it empty.
|
|
15
|
+
* @param {string} [namespace=aa-fleetfinderl] Namespace for the tooltip
|
|
16
|
+
* @returns {void}
|
|
17
|
+
*/
|
|
18
|
+
const fleetfinderBootstrapTooltip = ({selector = 'body', namespace = 'aa-fleetfinder'}) => { // eslint-disable-line no-unused-vars
|
|
19
|
+
document.querySelectorAll(`${selector} [data-bs-tooltip="${namespace}"]`)
|
|
20
|
+
.forEach((tooltipTriggerEl) => {
|
|
21
|
+
return new bootstrap.Tooltip(tooltipTriggerEl);
|
|
22
|
+
});
|
|
23
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["fleetfinder.js"],"names":["fleetfinderBootstrapTooltip","selector","namespace","document","querySelectorAll","forEach","bootstrap","Tooltip","tooltipTriggerEl"],"mappings":"AAiBA,MAAMA,4BAA8B,CAAA,CAAEC,SAAAA,EAAW,OAAQC,UAAAA,EAAY,gBAAiB,KAClFC,SAASC,oBAAoBH,uBAA8BC,KAAa,EACnEG,QAAQ,GACE,IAAIC,UAAUC,QAAQC,CAAgB,CAChD,CACT"}
|
fleetfinder/tasks.py
CHANGED
|
@@ -14,7 +14,6 @@ from celery import shared_task
|
|
|
14
14
|
from django.utils import timezone
|
|
15
15
|
|
|
16
16
|
# Alliance Auth
|
|
17
|
-
from allianceauth.eveonline.models import EveCharacter
|
|
18
17
|
from allianceauth.services.hooks import get_extension_logger
|
|
19
18
|
from allianceauth.services.tasks import QueueOnce
|
|
20
19
|
from esi.models import Token
|
|
@@ -148,10 +147,13 @@ def _get_fleet_aggregate(fleet_infos):
|
|
|
148
147
|
for member in fleet_infos:
|
|
149
148
|
type_ = member.get("ship_type_name")
|
|
150
149
|
|
|
151
|
-
if type_
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
150
|
+
if type_ and isinstance(type_, str) and type_.strip():
|
|
151
|
+
type_ = type_.strip() # Normalize ship type name
|
|
152
|
+
|
|
153
|
+
if type_ in counts:
|
|
154
|
+
counts[type_] += 1
|
|
155
|
+
else:
|
|
156
|
+
counts[type_] = 1
|
|
155
157
|
|
|
156
158
|
return counts
|
|
157
159
|
|
|
@@ -187,110 +189,56 @@ def _check_for_esi_fleet(fleet: Fleet):
|
|
|
187
189
|
return False
|
|
188
190
|
|
|
189
191
|
|
|
190
|
-
def _process_fleet(fleet: Fleet):
|
|
192
|
+
def _process_fleet(fleet: Fleet) -> None:
|
|
191
193
|
"""
|
|
192
194
|
Processing a fleet
|
|
193
195
|
|
|
194
|
-
:param fleet:
|
|
195
|
-
:type fleet:
|
|
196
|
-
:return:
|
|
197
|
-
:rtype:
|
|
196
|
+
:param fleet: Fleet object to process
|
|
197
|
+
:type fleet: Fleet
|
|
198
|
+
:return: None
|
|
199
|
+
:rtype: None
|
|
198
200
|
"""
|
|
199
201
|
|
|
200
|
-
fleet_id = fleet.fleet_id
|
|
201
|
-
fleet_name = fleet.name
|
|
202
|
-
fleet_commander = fleet.fleet_commander
|
|
203
|
-
|
|
204
202
|
logger.info(
|
|
205
|
-
f'Processing information for fleet "{
|
|
206
|
-
f"of {fleet_commander} (ESI ID: {fleet_id})"
|
|
203
|
+
f'Processing information for fleet "{fleet.name}" '
|
|
204
|
+
f"of {fleet.fleet_commander} (ESI ID: {fleet.fleet_id})"
|
|
207
205
|
)
|
|
208
206
|
|
|
209
207
|
# Check if there is a fleet
|
|
210
208
|
esi_fleet = _check_for_esi_fleet(fleet=fleet)
|
|
211
|
-
if esi_fleet and fleet.fleet_id == esi_fleet["fleet"]["fleet_id"]:
|
|
212
|
-
try:
|
|
213
|
-
fleet_from_esi = esi.client.Fleets.get_characters_character_id_fleet(
|
|
214
|
-
character_id=fleet.fleet_commander.character_id,
|
|
215
|
-
token=esi_fleet["token"].valid_access_token(),
|
|
216
|
-
).result()
|
|
217
|
-
except HTTPNotFound:
|
|
218
|
-
_esi_fleet_error_handling(
|
|
219
|
-
fleet=fleet, error_key=Fleet.EsiError.NOT_IN_FLEET
|
|
220
|
-
)
|
|
221
|
-
except Exception: # pylint: disable=broad-exception-caught
|
|
222
|
-
_esi_fleet_error_handling(fleet=fleet, error_key=Fleet.EsiError.NO_FLEET)
|
|
223
|
-
|
|
224
|
-
# We have a valid fleet result from ESI
|
|
225
|
-
else:
|
|
226
|
-
if fleet_id == fleet_from_esi["fleet_id"]:
|
|
227
|
-
# Check if we deal with the fleet boss here
|
|
228
|
-
try:
|
|
229
|
-
_ = esi.client.Fleets.get_fleets_fleet_id_members(
|
|
230
|
-
fleet_id=fleet_from_esi["fleet_id"],
|
|
231
|
-
token=esi_fleet["token"].valid_access_token(),
|
|
232
|
-
).result()
|
|
233
|
-
except Exception: # pylint: disable=broad-exception-caught
|
|
234
|
-
_esi_fleet_error_handling(
|
|
235
|
-
fleet=fleet, error_key=Fleet.EsiError.NOT_FLEETBOSS
|
|
236
|
-
)
|
|
237
|
-
else:
|
|
238
|
-
_esi_fleet_error_handling(
|
|
239
|
-
fleet=fleet, error_key=Fleet.EsiError.FC_CHANGED_FLEET
|
|
240
|
-
)
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
@shared_task
|
|
244
|
-
def open_fleet(character_id, motd, free_move, name, groups):
|
|
245
|
-
"""
|
|
246
|
-
Open a fleet
|
|
247
|
-
|
|
248
|
-
:param character_id:
|
|
249
|
-
:param motd:
|
|
250
|
-
:param free_move:
|
|
251
|
-
:param name:
|
|
252
|
-
:param groups:
|
|
253
|
-
:return:
|
|
254
|
-
"""
|
|
255
|
-
|
|
256
|
-
required_scopes = ["esi-fleets.read_fleet.v1", "esi-fleets.write_fleet.v1"]
|
|
257
|
-
token = Token.get_token(character_id=character_id, scopes=required_scopes)
|
|
258
|
-
|
|
259
|
-
fleet_result = esi.client.Fleets.get_characters_character_id_fleet(
|
|
260
|
-
character_id=token.character_id, token=token.valid_access_token()
|
|
261
|
-
).result()
|
|
262
|
-
fleet_id = fleet_result.pop("fleet_id")
|
|
263
|
-
fleet_role = fleet_result.pop("role")
|
|
264
209
|
|
|
265
|
-
if
|
|
210
|
+
if not esi_fleet:
|
|
266
211
|
return
|
|
267
212
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
is_free_move=free_move,
|
|
275
|
-
fleet_commander=fleet_commander,
|
|
276
|
-
name=name,
|
|
277
|
-
)
|
|
278
|
-
fleet.save()
|
|
279
|
-
fleet.groups.set(groups)
|
|
213
|
+
# Fleet IDs don't match, FC changed fleets
|
|
214
|
+
if fleet.fleet_id != esi_fleet["fleet"]["fleet_id"]:
|
|
215
|
+
_esi_fleet_error_handling(
|
|
216
|
+
fleet=fleet, error_key=Fleet.EsiError.FC_CHANGED_FLEET
|
|
217
|
+
)
|
|
218
|
+
return
|
|
280
219
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
220
|
+
# Check if we deal with the fleet boss here
|
|
221
|
+
try:
|
|
222
|
+
_ = esi.client.Fleets.get_fleets_fleet_id_members(
|
|
223
|
+
fleet_id=fleet.fleet_id,
|
|
224
|
+
token=esi_fleet["token"].valid_access_token(),
|
|
225
|
+
).result()
|
|
226
|
+
except Exception: # pylint: disable=broad-exception-caught
|
|
227
|
+
_esi_fleet_error_handling(fleet=fleet, error_key=Fleet.EsiError.NOT_FLEETBOSS)
|
|
285
228
|
|
|
286
229
|
|
|
287
230
|
@shared_task
|
|
288
|
-
def send_fleet_invitation(
|
|
231
|
+
def send_fleet_invitation(fleet_id: int, character_ids: list) -> None:
|
|
289
232
|
"""
|
|
290
|
-
Send
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
:param fleet_id:
|
|
233
|
+
Send fleet invitations to characters through ESI
|
|
234
|
+
This task sends fleet invitations to a list of character IDs using the ESI API.
|
|
235
|
+
|
|
236
|
+
:param fleet_id: The ID of the fleet to which invitations are sent
|
|
237
|
+
:type fleet_id: int
|
|
238
|
+
:param character_ids: List of character IDs to invite to the fleet
|
|
239
|
+
:type character_ids: list[int]
|
|
240
|
+
:return: None
|
|
241
|
+
:rtype: None
|
|
294
242
|
"""
|
|
295
243
|
|
|
296
244
|
required_scopes = ["esi-fleets.write_fleet.v1"]
|
|
@@ -298,95 +246,134 @@ def send_fleet_invitation(character_ids, fleet_id):
|
|
|
298
246
|
fleet_commander_token = Token.get_token(
|
|
299
247
|
character_id=fleet.fleet_commander.character_id, scopes=required_scopes
|
|
300
248
|
)
|
|
301
|
-
_processes = []
|
|
302
249
|
|
|
303
250
|
with ThreadPoolExecutor(max_workers=50) as ex:
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
fleet_id=fleet_id,
|
|
311
|
-
)
|
|
251
|
+
futures = [
|
|
252
|
+
ex.submit(
|
|
253
|
+
_send_invitation,
|
|
254
|
+
character_id=character_id,
|
|
255
|
+
fleet_commander_token=fleet_commander_token,
|
|
256
|
+
fleet_id=fleet_id,
|
|
312
257
|
)
|
|
258
|
+
for character_id in character_ids
|
|
259
|
+
]
|
|
313
260
|
|
|
314
|
-
|
|
315
|
-
|
|
261
|
+
for future in as_completed(futures):
|
|
262
|
+
future.result() # This will raise any exceptions that occurred
|
|
316
263
|
|
|
317
264
|
|
|
318
265
|
@shared_task(**{**TASK_DEFAULT_KWARGS}, **{"base": QueueOnce})
|
|
319
|
-
def check_fleet_adverts():
|
|
266
|
+
def check_fleet_adverts() -> None:
|
|
320
267
|
"""
|
|
321
|
-
|
|
268
|
+
Check all registered fleets and process them
|
|
269
|
+
|
|
270
|
+
:return: None
|
|
271
|
+
:rtype: None
|
|
322
272
|
"""
|
|
323
273
|
|
|
324
274
|
fleets = Fleet.objects.all()
|
|
325
|
-
fleet_count = fleets.count()
|
|
326
275
|
|
|
327
|
-
|
|
276
|
+
if not fleets.exists():
|
|
277
|
+
logger.info("No registered fleets found. Nothing to do...")
|
|
278
|
+
|
|
279
|
+
return
|
|
328
280
|
|
|
329
|
-
logger.info(
|
|
281
|
+
logger.info(f"Processing {fleets.count()} registered fleets...")
|
|
330
282
|
|
|
331
|
-
if
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
logger.warning(
|
|
335
|
-
msg="ESI doesn't seem to be available at this time. Aborting."
|
|
336
|
-
)
|
|
283
|
+
# Abort if ESI seems to be offline or above the error limit
|
|
284
|
+
if not fetch_esi_status().is_ok:
|
|
285
|
+
logger.warning("ESI doesn't seem to be available at this time. Aborting.")
|
|
337
286
|
|
|
338
|
-
|
|
287
|
+
return
|
|
339
288
|
|
|
340
|
-
|
|
341
|
-
|
|
289
|
+
for fleet in fleets:
|
|
290
|
+
_process_fleet(fleet=fleet)
|
|
342
291
|
|
|
343
292
|
|
|
344
293
|
@shared_task
|
|
345
|
-
def get_fleet_composition(
|
|
294
|
+
def get_fleet_composition( # pylint: disable=too-many-locals
|
|
295
|
+
fleet_id: int,
|
|
296
|
+
) -> FleetViewAggregate | None:
|
|
346
297
|
"""
|
|
347
|
-
|
|
298
|
+
Get the composition of a fleet by its ID
|
|
299
|
+
This task retrieves the composition of a fleet using its ESI ID.
|
|
348
300
|
|
|
349
|
-
:param fleet_id:
|
|
350
|
-
:
|
|
301
|
+
:param fleet_id: The ESI ID of the fleet to retrieve
|
|
302
|
+
:type fleet_id: int
|
|
303
|
+
:return: FleetViewAggregate containing fleet members and aggregate data
|
|
304
|
+
:rtype: FleetViewAggregate | None
|
|
351
305
|
"""
|
|
352
306
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
)
|
|
358
|
-
fleet_infos = esi.client.Fleets.get_fleets_fleet_id_members(
|
|
359
|
-
fleet_id=fleet_id, token=token.valid_access_token()
|
|
360
|
-
).result()
|
|
307
|
+
try:
|
|
308
|
+
fleet = Fleet.objects.get(fleet_id=fleet_id)
|
|
309
|
+
except Fleet.DoesNotExist:
|
|
310
|
+
logger.error(f"Fleet with ID {fleet_id} not found")
|
|
361
311
|
|
|
362
|
-
|
|
363
|
-
systems = {}
|
|
364
|
-
ship_type = {}
|
|
312
|
+
return None
|
|
365
313
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
314
|
+
logger.info(
|
|
315
|
+
f'Getting fleet composition for fleet "{fleet.name}" '
|
|
316
|
+
f"of {fleet.fleet_commander.character_name} (ESI ID: {fleet_id})"
|
|
317
|
+
)
|
|
370
318
|
|
|
371
|
-
|
|
372
|
-
ids.extend(list(characters.keys()))
|
|
373
|
-
ids.extend(list(systems.keys()))
|
|
374
|
-
ids.extend(list(ship_type.keys()))
|
|
319
|
+
required_scopes = ["esi-fleets.read_fleet.v1"]
|
|
375
320
|
|
|
376
|
-
|
|
321
|
+
try:
|
|
322
|
+
token = Token.get_token(
|
|
323
|
+
character_id=fleet.fleet_commander.character_id, scopes=required_scopes
|
|
324
|
+
)
|
|
377
325
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
326
|
+
fleet_infos = esi.client.Fleets.get_fleets_fleet_id_members(
|
|
327
|
+
fleet_id=fleet_id, token=token.valid_access_token()
|
|
328
|
+
).result()
|
|
381
329
|
|
|
382
|
-
|
|
383
|
-
|
|
330
|
+
# Get all unique IDs and fetch names in one call
|
|
331
|
+
all_ids = {
|
|
332
|
+
item_id
|
|
333
|
+
for member in fleet_infos
|
|
334
|
+
for item_id in [
|
|
335
|
+
member["character_id"],
|
|
336
|
+
member["solar_system_id"],
|
|
337
|
+
member["ship_type_id"],
|
|
338
|
+
]
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
logger.debug(
|
|
342
|
+
f"Found {len(all_ids)} unique IDs to fetch names for in fleet {fleet_id}"
|
|
384
343
|
)
|
|
385
|
-
member["solar_system_name"] = ids_to_name[index_solar_system]["name"]
|
|
386
344
|
|
|
387
|
-
|
|
388
|
-
|
|
345
|
+
# Process IDs in chunks to avoid ESI limits
|
|
346
|
+
chunk_size = 500
|
|
347
|
+
ids_to_name = []
|
|
348
|
+
all_ids_list = list(all_ids)
|
|
349
|
+
|
|
350
|
+
for i in range(0, len(all_ids_list), chunk_size):
|
|
351
|
+
chunk = all_ids_list[i : i + chunk_size]
|
|
352
|
+
chunk_result = esi.client.Universe.post_universe_names(ids=chunk).result()
|
|
353
|
+
|
|
354
|
+
ids_to_name.extend(chunk_result)
|
|
355
|
+
|
|
356
|
+
# Create a lookup dictionary for names
|
|
357
|
+
name_lookup = {item["id"]: item["name"] for item in ids_to_name}
|
|
358
|
+
|
|
359
|
+
# Add additional information to each fleet member
|
|
360
|
+
for member in fleet_infos:
|
|
361
|
+
is_fleet_boss = member["character_id"] == fleet.fleet_commander.character_id
|
|
362
|
+
|
|
363
|
+
member.update(
|
|
364
|
+
{
|
|
365
|
+
"character_name": name_lookup[member["character_id"]],
|
|
366
|
+
"solar_system_name": name_lookup[member["solar_system_id"]],
|
|
367
|
+
"ship_type_name": name_lookup[member["ship_type_id"]],
|
|
368
|
+
"is_fleet_boss": is_fleet_boss,
|
|
369
|
+
}
|
|
370
|
+
)
|
|
371
|
+
|
|
372
|
+
aggregate = _get_fleet_aggregate(fleet_infos=fleet_infos)
|
|
373
|
+
|
|
374
|
+
return FleetViewAggregate(fleet=fleet_infos, aggregate=aggregate)
|
|
389
375
|
|
|
390
|
-
|
|
376
|
+
except Exception as e: # pylint: disable=broad-exception-caught
|
|
377
|
+
logger.error(f"Failed to get fleet composition for fleet {fleet_id}: {e}")
|
|
391
378
|
|
|
392
|
-
|
|
379
|
+
return None
|