aa-killtracker 0.14.0__tar.gz → 0.15.0__tar.gz

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 (66) hide show
  1. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/PKG-INFO +5 -1
  2. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/README.md +4 -0
  3. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/__init__.py +1 -1
  4. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/admin.py +24 -14
  5. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/core/killmails.py +4 -0
  6. aa_killtracker-0.15.0/killtracker/migrations/0004_add_faction_clauses.py +69 -0
  7. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/models/trackers.py +97 -25
  8. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/tests/core/test_killmails.py +6 -0
  9. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/tests/models/test_trackers_1.py +333 -149
  10. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/tests/testdata/factories.py +23 -0
  11. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/LICENSE +0 -0
  12. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/app_settings.py +0 -0
  13. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/apps.py +0 -0
  14. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/constants.py +0 -0
  15. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/core/__init__.py +0 -0
  16. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/core/discord_messages.py +0 -0
  17. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/exceptions.py +0 -0
  18. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/forms.py +0 -0
  19. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/management/commands/killtracker_load_eve.py +0 -0
  20. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/managers.py +0 -0
  21. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/migrations/0001_initial_new.py +0 -0
  22. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/migrations/0001_squashed_all.py +0 -0
  23. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/migrations/0002_fix_webhook_notes_field.py +0 -0
  24. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/migrations/0002_tracker_require_attackers_weapon_groups_and_more.py +0 -0
  25. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/migrations/0003_add_state_clauses.py +0 -0
  26. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/migrations/0003_optimize_tracker_form.py +0 -0
  27. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/migrations/0004_django4_update.py +0 -0
  28. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/migrations/0005_add_final_blow_clause_and_more.py +0 -0
  29. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/migrations/0006_evetypeplus.py +0 -0
  30. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/migrations/0007_restructure_killsmails.py +0 -0
  31. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/migrations/0008_copy_data_to_new_structure.py +0 -0
  32. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/migrations/0009_remove_old_models.py +0 -0
  33. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/migrations/__init__.py +0 -0
  34. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/models/__init__.py +0 -0
  35. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/models/killmails.py +0 -0
  36. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/models/webhooks.py +0 -0
  37. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/providers.py +0 -0
  38. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/static/killtracker/killtracker_logo.png +0 -0
  39. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/static/killtracker/zkb_icon.png +0 -0
  40. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/tasks.py +0 -0
  41. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/templates/admin/killtracker/tracker/killmail_test.html +0 -0
  42. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/tests/__init__.py +0 -0
  43. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/tests/core/__init__.py +0 -0
  44. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/tests/core/test_discord_messages_1.py +0 -0
  45. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/tests/core/test_discord_messages_2.py +0 -0
  46. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/tests/models/__init__.py +0 -0
  47. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/tests/models/test_killmails.py +0 -0
  48. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/tests/models/test_trackers_2.py +0 -0
  49. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/tests/models/test_webhook.py +0 -0
  50. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/tests/test_admin.py +0 -0
  51. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/tests/test_admin_2.py +0 -0
  52. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/tests/test_exceptions.py +0 -0
  53. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/tests/test_integration.py +0 -0
  54. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/tests/test_tasks.py +0 -0
  55. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/tests/testdata/__init__.py +0 -0
  56. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/tests/testdata/create_eveuniverse.py +0 -0
  57. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/tests/testdata/evealliances.json +0 -0
  58. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/tests/testdata/evecorporations.json +0 -0
  59. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/tests/testdata/eveentities.json +0 -0
  60. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/tests/testdata/eveuniverse.json +0 -0
  61. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/tests/testdata/helpers.py +0 -0
  62. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/tests/testdata/killmails.json +0 -0
  63. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/tests/testdata/load_eveuniverse.py +0 -0
  64. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/tools/drop_tables_killtracker.sql +0 -0
  65. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/killtracker/tools/generate_conditions_text.py +0 -0
  66. {aa_killtracker-0.14.0 → aa_killtracker-0.15.0}/pyproject.toml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: aa-killtracker
3
- Version: 0.14.0
3
+ Version: 0.15.0
4
4
  Summary: "An app for running killmail trackers with Alliance Auth and Discord.
5
5
  Author-email: Erik Kalkoken <kalkoken87@gmail.com>
6
6
  Requires-Python: >=3.8
@@ -90,6 +90,8 @@ And here is how posted killmails look on Discord:
90
90
 
91
91
  2. Killtracker needs the app [django-eveuniverse](https://gitlab.com/ErikKalkoken/django-eveuniverse) to function. Please make sure it is installed, before continuing.
92
92
 
93
+ 3. Killtracker will generate a lot of tasks. For optimal performance we recommend a threads-based configuration of your celery workers. Please see [this guide](https://aa-memberaudit.readthedocs.io/en/latest/operations.html#configuring-celery-workers) for details.
94
+
93
95
  ### Step 2 - Install app
94
96
 
95
97
  Make sure you are in the virtual environment (venv) of your Alliance Auth installation. Then install the newest release from PyPI:
@@ -179,6 +181,8 @@ To test that your webhook works correctly you can send a test notification.
179
181
 
180
182
  Next you can create your trackers under **Tracker**. Make sure you link each tracker to the right webhook. Once you save a tracker that is **enabled** it will start working.
181
183
 
184
+ >**Hint**:<br>A common mistake is to set both attacker alliance and victim alliance to your alliance in the same tracker. This will only match awox kills though, which is usually not what you want. Instead create separate trackers to capture kills and losses for your alliance.
185
+
182
186
  As final test that your setup is correct you may want to create a "Catch all" tracker. for that just create a new tracker without any conditions and it will forward all killmails to your Discord channel as they are received.
183
187
 
184
188
  Congratulations you are now ready to use killtracker!
@@ -61,6 +61,8 @@ And here is how posted killmails look on Discord:
61
61
 
62
62
  2. Killtracker needs the app [django-eveuniverse](https://gitlab.com/ErikKalkoken/django-eveuniverse) to function. Please make sure it is installed, before continuing.
63
63
 
64
+ 3. Killtracker will generate a lot of tasks. For optimal performance we recommend a threads-based configuration of your celery workers. Please see [this guide](https://aa-memberaudit.readthedocs.io/en/latest/operations.html#configuring-celery-workers) for details.
65
+
64
66
  ### Step 2 - Install app
65
67
 
66
68
  Make sure you are in the virtual environment (venv) of your Alliance Auth installation. Then install the newest release from PyPI:
@@ -150,6 +152,8 @@ To test that your webhook works correctly you can send a test notification.
150
152
 
151
153
  Next you can create your trackers under **Tracker**. Make sure you link each tracker to the right webhook. Once you save a tracker that is **enabled** it will start working.
152
154
 
155
+ >**Hint**:<br>A common mistake is to set both attacker alliance and victim alliance to your alliance in the same tracker. This will only match awox kills though, which is usually not what you want. Instead create separate trackers to capture kills and losses for your alliance.
156
+
153
157
  As final test that your setup is correct you may want to create a "Catch all" tracker. for that just create a new tracker without any conditions and it will forward all killmails to your Discord channel as they are received.
154
158
 
155
159
  Congratulations you are now ready to use killtracker!
@@ -3,7 +3,7 @@
3
3
  # pylint: disable = invalid-name
4
4
  default_app_config = "killtracker.apps.KillmailsConfig"
5
5
 
6
- __version__ = "0.14.0"
6
+ __version__ = "0.15.0"
7
7
  __title__ = "Killtracker"
8
8
 
9
9
  APP_NAME = "aa-killtracker"
@@ -101,13 +101,17 @@ class TrackerAdmin(admin.ModelAdmin):
101
101
  "require_constellations",
102
102
  "require_solar_systems",
103
103
  "exclude_attacker_alliances",
104
- "exclude_attacker_corporations",
104
+ "exclude_victim_alliances",
105
+ "require_victim_alliances",
105
106
  "require_attacker_alliances",
107
+ "exclude_attacker_corporations",
106
108
  "require_attacker_corporations",
107
- "require_victim_alliances",
108
- "exclude_victim_alliances",
109
- "require_victim_corporations",
110
109
  "exclude_victim_corporations",
110
+ "require_victim_corporations",
111
+ "exclude_attacker_factions",
112
+ "require_attacker_factions",
113
+ "exclude_victim_factions",
114
+ "require_victim_factions",
111
115
  "require_attackers_ship_types",
112
116
  "require_attackers_ship_groups",
113
117
  "require_attackers_weapon_groups",
@@ -118,6 +122,7 @@ class TrackerAdmin(admin.ModelAdmin):
118
122
  filter_horizontal = (
119
123
  "exclude_attacker_states",
120
124
  "require_attacker_states",
125
+ "exclude_victim_states",
121
126
  "require_victim_states",
122
127
  "ping_groups",
123
128
  )
@@ -154,28 +159,33 @@ class TrackerAdmin(admin.ModelAdmin):
154
159
  },
155
160
  ),
156
161
  (
157
- "Organizations",
162
+ "Attackers",
158
163
  {
159
164
  "fields": (
160
- "exclude_attacker_alliances",
161
- "exclude_attacker_corporations",
162
165
  "require_attacker_alliances",
166
+ "exclude_attacker_alliances",
163
167
  "require_attacker_corporations",
168
+ "exclude_attacker_corporations",
169
+ "require_attacker_factions",
170
+ "exclude_attacker_factions",
171
+ "require_attacker_states",
172
+ "exclude_attacker_states",
164
173
  "require_attacker_organizations_final_blow",
165
- "require_victim_alliances",
166
- "exclude_victim_alliances",
167
- "require_victim_corporations",
168
- "exclude_victim_corporations",
169
174
  ),
170
175
  },
171
176
  ),
172
177
  (
173
- "Auth State",
178
+ "Victims",
174
179
  {
175
180
  "fields": (
176
- "exclude_attacker_states",
177
- "require_attacker_states",
181
+ "require_victim_alliances",
182
+ "exclude_victim_alliances",
183
+ "require_victim_corporations",
184
+ "exclude_victim_corporations",
185
+ "require_victim_factions",
186
+ "exclude_victim_factions",
178
187
  "require_victim_states",
188
+ "exclude_victim_states",
179
189
  ),
180
190
  },
181
191
  ),
@@ -182,6 +182,10 @@ class Killmail(_KillmailBase):
182
182
  """Return distinct character IDs of all attackers."""
183
183
  return {obj.character_id for obj in self.attackers if obj.character_id}
184
184
 
185
+ def attackers_distinct_faction_ids(self) -> Set[int]:
186
+ """Return distinct faction IDs of all attackers."""
187
+ return {obj.faction_id for obj in self.attackers if obj.faction_id}
188
+
185
189
  def attackers_ship_type_ids(self) -> List[int]:
186
190
  """Returns ship type IDs of all attackers with duplicates."""
187
191
  return [obj.ship_type_id for obj in self.attackers if obj.ship_type_id]
@@ -0,0 +1,69 @@
1
+ # Generated by Django 4.0.10 on 2024-07-04 12:40
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+ dependencies = [
8
+ ("authentication", "0021_alter_userprofile_language"),
9
+ ("eveonline", "0017_alliance_and_corp_names_are_not_unique"),
10
+ ("killtracker", "0003_optimize_tracker_form"),
11
+ ]
12
+
13
+ operations = [
14
+ migrations.AddField(
15
+ model_name="tracker",
16
+ name="exclude_attacker_factions",
17
+ field=models.ManyToManyField(
18
+ blank=True,
19
+ default=None,
20
+ help_text="Exclude killmails with attackers from one of these factions. ",
21
+ related_name="+",
22
+ to="eveonline.evefactioninfo",
23
+ ),
24
+ ),
25
+ migrations.AddField(
26
+ model_name="tracker",
27
+ name="exclude_victim_factions",
28
+ field=models.ManyToManyField(
29
+ blank=True,
30
+ default=None,
31
+ help_text="Exclude killmails where the victim belongs to one of these factions. ",
32
+ related_name="+",
33
+ to="eveonline.evefactioninfo",
34
+ ),
35
+ ),
36
+ migrations.AddField(
37
+ model_name="tracker",
38
+ name="exclude_victim_states",
39
+ field=models.ManyToManyField(
40
+ blank=True,
41
+ default=None,
42
+ help_text="Exclude killmails where the victim belongs to one of these Auth states. ",
43
+ related_name="+",
44
+ to="authentication.state",
45
+ ),
46
+ ),
47
+ migrations.AddField(
48
+ model_name="tracker",
49
+ name="require_attacker_factions",
50
+ field=models.ManyToManyField(
51
+ blank=True,
52
+ default=None,
53
+ help_text="Only include killmails with attackers from one of these factions. ",
54
+ related_name="+",
55
+ to="eveonline.evefactioninfo",
56
+ ),
57
+ ),
58
+ migrations.AddField(
59
+ model_name="tracker",
60
+ name="require_victim_factions",
61
+ field=models.ManyToManyField(
62
+ blank=True,
63
+ default=None,
64
+ help_text="Only include killmails where the victim belongs to one of these factions. ",
65
+ related_name="+",
66
+ to="eveonline.evefactioninfo",
67
+ ),
68
+ ),
69
+ ]
@@ -17,7 +17,11 @@ from eveuniverse.models import (
17
17
  )
18
18
 
19
19
  from allianceauth.authentication.models import State
20
- from allianceauth.eveonline.models import EveAllianceInfo, EveCorporationInfo
20
+ from allianceauth.eveonline.models import (
21
+ EveAllianceInfo,
22
+ EveCorporationInfo,
23
+ EveFactionInfo,
24
+ )
21
25
  from allianceauth.services.hooks import get_extension_logger
22
26
  from app_utils.logging import LoggerAddTag
23
27
 
@@ -170,6 +174,25 @@ class Tracker(models.Model):
170
174
  blank=True,
171
175
  help_text="Only include killmails with attackers from one of these alliances. ",
172
176
  )
177
+ require_victim_alliances = models.ManyToManyField(
178
+ EveAllianceInfo,
179
+ related_name="+",
180
+ default=None,
181
+ blank=True,
182
+ help_text=(
183
+ "Only include killmails where the victim belongs "
184
+ "to one of these alliances. "
185
+ ),
186
+ )
187
+ exclude_victim_alliances = models.ManyToManyField(
188
+ EveAllianceInfo,
189
+ related_name="+",
190
+ default=None,
191
+ blank=True,
192
+ help_text=(
193
+ "Exclude killmails where the victim belongs to one of these alliances. "
194
+ ),
195
+ )
173
196
  exclude_attacker_corporations = models.ManyToManyField(
174
197
  EveCorporationInfo,
175
198
  related_name="+",
@@ -196,6 +219,25 @@ class Tracker(models.Model):
196
219
  "has the final blow."
197
220
  ),
198
221
  )
222
+ require_victim_corporations = models.ManyToManyField(
223
+ EveCorporationInfo,
224
+ related_name="+",
225
+ default=None,
226
+ blank=True,
227
+ help_text=(
228
+ "Only include killmails where the victim belongs "
229
+ "to one of these corporations. "
230
+ ),
231
+ )
232
+ exclude_victim_corporations = models.ManyToManyField(
233
+ EveCorporationInfo,
234
+ related_name="+",
235
+ default=None,
236
+ blank=True,
237
+ help_text=(
238
+ "Exclude killmails where the victim belongs to one of these corporations. "
239
+ ),
240
+ )
199
241
  exclude_attacker_states = models.ManyToManyField(
200
242
  State,
201
243
  related_name="+",
@@ -216,52 +258,58 @@ class Tracker(models.Model):
216
258
  "to users with these Auth states. "
217
259
  ),
218
260
  )
219
- require_victim_alliances = models.ManyToManyField(
220
- EveAllianceInfo,
261
+ exclude_victim_states = models.ManyToManyField(
262
+ State,
221
263
  related_name="+",
222
264
  default=None,
223
265
  blank=True,
224
266
  help_text=(
225
- "Only include killmails where the victim belongs "
226
- "to one of these alliances. "
267
+ "Exclude killmails where the victim belongs to one of these Auth states. "
227
268
  ),
228
269
  )
229
- exclude_victim_alliances = models.ManyToManyField(
230
- EveAllianceInfo,
270
+ require_victim_states = models.ManyToManyField(
271
+ State,
231
272
  related_name="+",
232
273
  default=None,
233
274
  blank=True,
234
275
  help_text=(
235
- "Exclude killmails where the victim belongs to one of these alliances. "
276
+ "Only include killmails where the victim characters belong "
277
+ "to users with these Auth states. "
236
278
  ),
237
279
  )
238
- require_victim_corporations = models.ManyToManyField(
239
- EveCorporationInfo,
280
+ exclude_attacker_factions = models.ManyToManyField(
281
+ EveFactionInfo,
282
+ related_name="+",
283
+ default=None,
284
+ blank=True,
285
+ help_text="Exclude killmails with attackers from one of these factions. ",
286
+ )
287
+ require_attacker_factions = models.ManyToManyField(
288
+ EveFactionInfo,
240
289
  related_name="+",
241
290
  default=None,
242
291
  blank=True,
243
292
  help_text=(
244
- "Only include killmails where the victim belongs "
245
- "to one of these corporations. "
293
+ "Only include killmails with attackers from one of these factions. "
246
294
  ),
247
295
  )
248
- exclude_victim_corporations = models.ManyToManyField(
249
- EveCorporationInfo,
296
+ require_victim_factions = models.ManyToManyField(
297
+ EveFactionInfo,
250
298
  related_name="+",
251
299
  default=None,
252
300
  blank=True,
253
301
  help_text=(
254
- "Exclude killmails where the victim belongs to one of these corporations. "
302
+ "Only include killmails where the victim belongs "
303
+ "to one of these factions. "
255
304
  ),
256
305
  )
257
- require_victim_states = models.ManyToManyField(
258
- State,
306
+ exclude_victim_factions = models.ManyToManyField(
307
+ EveFactionInfo,
259
308
  related_name="+",
260
309
  default=None,
261
310
  blank=True,
262
311
  help_text=(
263
- "Only include killmails where the victim characters belong "
264
- "to users with these Auth states. "
312
+ "Exclude killmails where the victim belongs to one of these factions. "
265
313
  ),
266
314
  )
267
315
  identify_fleets = models.BooleanField(
@@ -506,6 +554,7 @@ class Tracker(models.Model):
506
554
  is_matching = self._match_value(killmail, is_matching)
507
555
  is_matching, jumps, distance = self._match_geography(killmail, is_matching)
508
556
  is_matching = self._match_attackers(killmail, is_matching)
557
+ is_matching = self._match_states(killmail, is_matching)
509
558
  is_matching, matching_ship_type_ids = self._match_attacker_ships(
510
559
  killmail, is_matching, matching_ship_type_ids
511
560
  )
@@ -641,6 +690,16 @@ class Tracker(models.Model):
641
690
  corporation_id__in=killmail.attackers_distinct_corporation_ids()
642
691
  ).exists()
643
692
 
693
+ if is_matching and self.require_attacker_factions.exists():
694
+ is_matching = self.require_attacker_factions.filter(
695
+ faction_id__in=killmail.attackers_distinct_faction_ids()
696
+ ).exists()
697
+
698
+ if is_matching and self.exclude_attacker_factions.exists():
699
+ is_matching = self.exclude_attacker_factions.exclude(
700
+ faction_id__in=killmail.attackers_distinct_faction_ids()
701
+ ).exists()
702
+
644
703
  if is_matching:
645
704
  if self.require_attacker_organizations_final_blow:
646
705
  attacker_final_blow = killmail.attacker_final_blow()
@@ -668,6 +727,9 @@ class Tracker(models.Model):
668
727
  corporation_id__in=killmail.attackers_distinct_corporation_ids()
669
728
  ).exists()
670
729
 
730
+ return is_matching
731
+
732
+ def _match_states(self, killmail: Killmail, is_matching: bool) -> bool:
671
733
  if is_matching and self.require_attacker_states.exists():
672
734
  is_matching = User.objects.filter(
673
735
  profile__state__in=list(self.require_attacker_states.all()),
@@ -684,6 +746,14 @@ class Tracker(models.Model):
684
746
  ),
685
747
  ).exists()
686
748
 
749
+ if is_matching and self.require_victim_states.exists():
750
+ is_matching = User.objects.filter(
751
+ profile__state__in=list(self.require_victim_states.all()),
752
+ character_ownerships__character__character_id=(
753
+ killmail.victim.character_id
754
+ ),
755
+ ).exists()
756
+
687
757
  return is_matching
688
758
 
689
759
  def _match_attacker_ships(
@@ -765,12 +835,14 @@ class Tracker(models.Model):
765
835
  corporation_id=killmail.victim.corporation_id
766
836
  ).exists()
767
837
 
768
- if is_matching and self.require_victim_states.exists():
769
- is_matching = User.objects.filter(
770
- profile__state__in=list(self.require_victim_states.all()),
771
- character_ownerships__character__character_id=(
772
- killmail.victim.character_id
773
- ),
838
+ if is_matching and self.require_victim_factions.exists():
839
+ is_matching = self.require_victim_factions.filter(
840
+ faction_id=killmail.victim.faction_id
841
+ ).exists()
842
+
843
+ if is_matching and self.exclude_victim_factions.exists():
844
+ is_matching = self.exclude_victim_factions.exclude(
845
+ faction_id=killmail.victim.faction_id
774
846
  ).exists()
775
847
 
776
848
  return is_matching
@@ -262,6 +262,12 @@ class TestKillmailBasics(NoSocketsTestCase):
262
262
  # then
263
263
  self.assertSetEqual(set(result), {3001})
264
264
 
265
+ def test_should_return_attacker_faction_ids(self):
266
+ # when
267
+ result = self.killmail.attackers_distinct_faction_ids()
268
+ # then
269
+ self.assertSetEqual(set(result), {500001})
270
+
265
271
  def test_should_return_attacker_corporation_ids(self):
266
272
  # when
267
273
  result = self.killmail.attackers_distinct_corporation_ids()