aa-structures 2.2.0__py3-none-any.whl → 2.3.1b1__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.
Files changed (29) hide show
  1. {aa_structures-2.2.0.dist-info → aa_structures-2.3.1b1.dist-info}/METADATA +1 -1
  2. {aa_structures-2.2.0.dist-info → aa_structures-2.3.1b1.dist-info}/RECORD +28 -23
  3. {aa_structures-2.2.0.dist-info → aa_structures-2.3.1b1.dist-info}/WHEEL +1 -1
  4. structures/__init__.py +1 -1
  5. structures/admin.py +13 -13
  6. structures/core/notification_embeds.py +47 -47
  7. structures/locale/de/LC_MESSAGES/django.po +314 -305
  8. structures/locale/django.pot +2227 -0
  9. structures/locale/en/LC_MESSAGES/django.po +312 -305
  10. structures/locale/es/LC_MESSAGES/django.po +314 -305
  11. structures/locale/fr_FR/LC_MESSAGES/django.po +2227 -0
  12. structures/locale/it_IT/LC_MESSAGES/django.po +2227 -0
  13. structures/locale/ja/LC_MESSAGES/django.po +2228 -0
  14. structures/locale/ko_KR/LC_MESSAGES/django.po +2227 -0
  15. structures/locale/ru/LC_MESSAGES/django.po +312 -305
  16. structures/locale/uk/LC_MESSAGES/django.po +2231 -0
  17. structures/locale/zh_Hans/LC_MESSAGES/django.po +314 -305
  18. structures/managers.py +12 -12
  19. structures/models/notifications.py +20 -17
  20. structures/models/owners.py +1 -3
  21. structures/models/structures.py +1 -1
  22. structures/tests/core/test_notification_embeds.py +125 -36
  23. structures/tests/models/test_notifications_1.py +38 -12
  24. structures/tests/test_admin.py +48 -22
  25. structures/tests/test_integration.py +88 -1
  26. structures/tests/testdata/factories_2.py +34 -1
  27. structures/views.py +3 -2
  28. structures/tests/core/test_notification_embeds_2.py +0 -78
  29. {aa_structures-2.2.0.dist-info → aa_structures-2.3.1b1.dist-info}/licenses/LICENSE +0 -0
@@ -11,15 +11,16 @@ from eveuniverse.models import EveEntity
11
11
 
12
12
  from allianceauth.eveonline.models import EveCorporationInfo
13
13
 
14
- from ..admin import (
14
+ from structures.admin import (
15
15
  NotificationAdmin,
16
16
  OwnerAdmin,
17
17
  OwnerAllianceFilter,
18
18
  OwnerCorporationsFilter,
19
19
  StructureAdmin,
20
+ StructureFuelAlertConfigAdmin,
20
21
  WebhookAdmin,
21
22
  )
22
- from ..models import (
23
+ from structures.models import (
23
24
  FuelAlertConfig,
24
25
  Notification,
25
26
  Owner,
@@ -27,6 +28,13 @@ from ..models import (
27
28
  StructureTag,
28
29
  Webhook,
29
30
  )
31
+
32
+ from .testdata.factories_2 import (
33
+ FuelAlertConfigFactory,
34
+ NotificationFactory,
35
+ OwnerFactory,
36
+ StructureFactory,
37
+ )
30
38
  from .testdata.helpers import (
31
39
  create_structures,
32
40
  create_user,
@@ -44,7 +52,7 @@ class MockRequest(object):
44
52
  self.user = user
45
53
 
46
54
 
47
- class TestFuelNotificationConfigAdmin(TestCase):
55
+ class TestFuelNotificationConfigAdminView(TestCase):
48
56
  @classmethod
49
57
  def setUpClass(cls):
50
58
  super().setUpClass()
@@ -55,7 +63,6 @@ class TestFuelNotificationConfigAdmin(TestCase):
55
63
  }
56
64
  cls.user = User.objects.create_superuser("Clark Kent")
57
65
  load_eveuniverse()
58
- create_structures()
59
66
 
60
67
  def test_should_create_new_config(self):
61
68
  # given
@@ -74,7 +81,7 @@ class TestFuelNotificationConfigAdmin(TestCase):
74
81
  def test_should_update_existing_config(self):
75
82
  # given
76
83
  self.client.force_login(self.user)
77
- config = FuelAlertConfig.objects.create(start=48, end=24, repeat=12)
84
+ config = FuelAlertConfigFactory(start=48, end=24, repeat=12)
78
85
  # when
79
86
  response = self.client.post(
80
87
  reverse("admin:structures_fuelalertconfig_change", args=[config.pk]),
@@ -89,8 +96,8 @@ class TestFuelNotificationConfigAdmin(TestCase):
89
96
  def test_should_remove_existing_fuel_notifications_when_timing_changed(self):
90
97
  # given
91
98
  self.client.force_login(self.user)
92
- config = FuelAlertConfig.objects.create(start=48, end=24, repeat=12)
93
- structure = Structure.objects.get(id=1000000000001)
99
+ config = FuelAlertConfigFactory(start=48, end=24, repeat=12)
100
+ structure = StructureFactory()
94
101
  structure.structure_fuel_alerts.create(
95
102
  config=config, structure=structure, hours=5
96
103
  )
@@ -108,8 +115,8 @@ class TestFuelNotificationConfigAdmin(TestCase):
108
115
  def test_should_not_remove_existing_fuel_notifications_on_other_changes(self):
109
116
  # given
110
117
  self.client.force_login(self.user)
111
- config = FuelAlertConfig.objects.create(start=48, end=24, repeat=12)
112
- structure = Structure.objects.get(id=1000000000001)
118
+ config = FuelAlertConfigFactory(start=48, end=24, repeat=12)
119
+ structure = StructureFactory()
113
120
  structure.structure_fuel_alerts.create(
114
121
  config=config, structure=structure, hours=5
115
122
  )
@@ -156,7 +163,7 @@ class TestFuelNotificationConfigAdmin(TestCase):
156
163
  def test_should_not_allow_creating_overlapping(self):
157
164
  # given
158
165
  self.client.force_login(self.user)
159
- FuelAlertConfig.objects.create(start=48, end=24, repeat=12)
166
+ FuelAlertConfigFactory(start=48, end=24, repeat=12)
160
167
  # when
161
168
  response = self.client.post(
162
169
  reverse("admin:structures_fuelalertconfig_add"),
@@ -207,6 +214,29 @@ class TestFuelNotificationConfigAdmin(TestCase):
207
214
  self.assertEqual(FuelAlertConfig.objects.count(), 0)
208
215
 
209
216
 
217
+ class TestStructureFuelAlertAdmin(TestCase):
218
+ @classmethod
219
+ def setUpClass(cls):
220
+ super().setUpClass()
221
+ cls.modeladmin = StructureFuelAlertConfigAdmin(
222
+ model=FuelAlertConfig, admin_site=AdminSite()
223
+ )
224
+ load_eveuniverse()
225
+
226
+ @patch(MODULE_PATH + ".StructureFuelAlertConfigAdmin.message_user", spec=True)
227
+ @patch(MODULE_PATH + ".tasks", spec=True)
228
+ def test_should_send_fuel_notifications(self, mock_tasks, mock_message_user):
229
+ # given
230
+ config = FuelAlertConfigFactory()
231
+ request = MockRequest()
232
+ queryset = FuelAlertConfig.objects.filter(pk=config.pk)
233
+ # when
234
+ self.modeladmin.send_fuel_notifications(request, queryset)
235
+ # then
236
+ self.assertTrue(mock_tasks.send_queued_messages_for_webhooks.called)
237
+ self.assertTrue(mock_message_user.called)
238
+
239
+
210
240
  class TestNotificationAdmin(TestCase):
211
241
  @classmethod
212
242
  def setUpClass(cls):
@@ -337,10 +367,10 @@ class TestOwnerAdmin(TestCase):
337
367
  )
338
368
  def test_should_return_correct_turnaround_times(self):
339
369
  # given
340
- my_owner = Owner.objects.get(corporation__corporation_id=2001)
370
+ my_owner = OwnerFactory()
341
371
  my_sender = EveEntity.objects.get(id=1001)
342
372
  my_now = now()
343
- Notification.objects.create(
373
+ NotificationFactory(
344
374
  owner=my_owner,
345
375
  notification_id=1,
346
376
  sender=my_sender,
@@ -350,7 +380,7 @@ class TestOwnerAdmin(TestCase):
350
380
  )
351
381
  for i in range(50):
352
382
  timestamp = my_now + dt.timedelta(minutes=i)
353
- Notification.objects.create(
383
+ NotificationFactory(
354
384
  owner=my_owner,
355
385
  notification_id=2 + i,
356
386
  sender=my_sender,
@@ -422,12 +452,10 @@ class TestStructureAdmin(TestCase):
422
452
  list_filter = (OwnerCorporationsFilter,)
423
453
 
424
454
  Owner.objects.all().delete()
425
- owner_2001 = Owner.objects.create(
455
+ owner_2001 = OwnerFactory(
426
456
  corporation=EveCorporationInfo.objects.get(corporation_id=2001)
427
457
  )
428
- Owner.objects.create(
429
- corporation=EveCorporationInfo.objects.get(corporation_id=2002)
430
- )
458
+ OwnerFactory(corporation=EveCorporationInfo.objects.get(corporation_id=2002))
431
459
  my_modeladmin = StructureAdminTest(Structure, AdminSite())
432
460
 
433
461
  # Make sure the lookups are correct
@@ -451,15 +479,13 @@ class TestStructureAdmin(TestCase):
451
479
  list_filter = (OwnerAllianceFilter,)
452
480
 
453
481
  Owner.objects.all().delete()
454
- owner_2001 = Owner.objects.create(
482
+ owner_2001 = OwnerFactory(
455
483
  corporation=EveCorporationInfo.objects.get(corporation_id=2001)
456
484
  )
457
- owner_2002 = Owner.objects.create(
485
+ owner_2002 = OwnerFactory(
458
486
  corporation=EveCorporationInfo.objects.get(corporation_id=2002)
459
487
  )
460
- Owner.objects.create(
461
- corporation=EveCorporationInfo.objects.get(corporation_id=2102)
462
- )
488
+ OwnerFactory(corporation=EveCorporationInfo.objects.get(corporation_id=2102))
463
489
  modeladmin = StructureAdminTest(Structure, AdminSite())
464
490
 
465
491
  # Make sure the lookups are correct
@@ -16,9 +16,11 @@ from app_utils.esi_testing import EsiClientStub, EsiEndpoint
16
16
  from .. import tasks
17
17
  from ..models import NotificationType, Structure
18
18
  from .testdata.factories_2 import (
19
+ EveEntityAllianceFactory,
19
20
  EveEntityCorporationFactory,
20
21
  NotificationFactory,
21
22
  OwnerFactory,
23
+ RawNotificationFactory,
22
24
  StarbaseFactory,
23
25
  StructureFactory,
24
26
  WebhookFactory,
@@ -431,6 +433,91 @@ class TestTasks(TestCase):
431
433
  if AuthTimer:
432
434
  self.assertTrue(AuthTimer.objects.exists())
433
435
 
436
+ def test_should_fetch_and_send_notification_when_enabled_for_webhook(
437
+ self, mock_esi_2, mock_esi, mock_execute
438
+ ):
439
+ # given
440
+ webhook = WebhookFactory(
441
+ notification_types=[NotificationType.WAR_CORPORATION_BECAME_ELIGIBLE]
442
+ )
443
+ owner = OwnerFactory(webhooks=[webhook], is_alliance_main=True)
444
+ eve_character = owner.characters.first().character_ownership.character
445
+ # corporation_id = owner.corporation.corporation_id
446
+ notif = RawNotificationFactory()
447
+ endpoints = [
448
+ EsiEndpoint(
449
+ "Character",
450
+ "get_characters_character_id_notifications",
451
+ "character_id",
452
+ needs_token=True,
453
+ data={
454
+ str(eve_character.character_id): [notif],
455
+ },
456
+ ),
457
+ ]
458
+ mock_esi.client = mock_esi_2.client = EsiClientStub.create_from_endpoints(
459
+ endpoints
460
+ )
461
+ # when
462
+ tasks.fetch_all_notifications.delay()
463
+ # then
464
+ self.assertTrue(mock_execute.called)
465
+ embed = mock_execute.call_args[1]["embeds"][0]
466
+ self.assertIn("now eligible", embed.description)
467
+
468
+ def test_should_fetch_and_send_notification_when_enabled_for_webhook_all_anchoring(
469
+ self, mock_esi_2, mock_esi, mock_execute
470
+ ):
471
+ # given
472
+ webhook = WebhookFactory(
473
+ notification_types=[NotificationType.SOV_ALL_ANCHORING_MSG]
474
+ )
475
+ owner = OwnerFactory(webhooks=[webhook], is_alliance_main=False)
476
+ eve_character = owner.characters.first().character_ownership.character
477
+ alliance = EveEntityAllianceFactory(
478
+ id=owner.corporation.alliance_id,
479
+ name=owner.corporation.alliance.alliance_name,
480
+ )
481
+ corporation = EveEntityCorporationFactory(
482
+ id=owner.corporation.corporation_id, name=owner.corporation.corporation_name
483
+ )
484
+ starbase = StarbaseFactory(owner=owner)
485
+ notif = RawNotificationFactory(
486
+ type="AllAnchoringMsg",
487
+ sender=corporation,
488
+ data={
489
+ "allianceID": alliance.id,
490
+ "corpID": corporation.id,
491
+ "corpsPresent": [{"allianceID": alliance.id, "corpID": corporation.id}],
492
+ "moonID": starbase.eve_moon.id,
493
+ "solarSystemID": starbase.eve_solar_system.id,
494
+ "towers": [
495
+ {"moonID": starbase.eve_moon.id, "typeID": starbase.eve_type.id}
496
+ ],
497
+ "typeID": starbase.eve_type.id,
498
+ },
499
+ )
500
+ endpoints = [
501
+ EsiEndpoint(
502
+ "Character",
503
+ "get_characters_character_id_notifications",
504
+ "character_id",
505
+ needs_token=True,
506
+ data={
507
+ str(eve_character.character_id): [notif],
508
+ },
509
+ ),
510
+ ]
511
+ mock_esi.client = mock_esi_2.client = EsiClientStub.create_from_endpoints(
512
+ endpoints
513
+ )
514
+ # when
515
+ tasks.fetch_all_notifications.delay()
516
+ # then
517
+ self.assertTrue(mock_execute.called)
518
+ embed = mock_execute.call_args[1]["embeds"][0]
519
+ self.assertIn("has anchored in", embed.description)
520
+
434
521
  @patch(NOTIFICATIONS_PATH + ".STRUCTURES_ADD_TIMERS", True)
435
522
  def test_should_fetch_new_notification_from_esi_and_send_to_webhook_and_create_timers(
436
523
  self, mock_esi_2, mock_esi, mock_execute
@@ -508,7 +595,7 @@ class TestTasks(TestCase):
508
595
  NotificationType.SOV_ALL_CLAIM_LOST_MSG,
509
596
  ]
510
597
  )
511
- owner = OwnerFactory(webhooks=[webhook])
598
+ owner = OwnerFactory(webhooks=[webhook], is_alliance_main=True)
512
599
  NotificationFactory(
513
600
  owner=owner, notif_type=NotificationType.STRUCTURE_DESTROYED
514
601
  )
@@ -142,7 +142,7 @@ class OwnerFactory(factory.django.DjangoModelFactory):
142
142
  assets_last_update_at = factory.LazyFunction(now)
143
143
  character_ownership = None # no longer used
144
144
  forwarding_last_update_at = factory.LazyFunction(now)
145
- is_alliance_main = True
145
+ is_alliance_main = False
146
146
  is_up = True
147
147
  notifications_last_update_at = factory.LazyFunction(now)
148
148
  structures_last_update_at = factory.LazyFunction(now)
@@ -330,3 +330,36 @@ class GeneratedNotificationFactory(factory.django.DjangoModelFactory):
330
330
  state_timer_end=reinforced_until,
331
331
  )
332
332
  obj.structures.add(starbase)
333
+
334
+
335
+ class RawNotificationFactory(factory.DictFactory):
336
+ """Create a raw notification as received from ESI."""
337
+
338
+ class Meta:
339
+ exclude = ("data", "timestamp_dt", "sender")
340
+
341
+ # excluded
342
+ data = None
343
+ timestamp_dt = None
344
+ sender = factory.SubFactory(EveEntityCorporationFactory, id=2902, name="CONCORD")
345
+
346
+ # included
347
+ notification_id = factory.Sequence(lambda o: 1999000000 + o)
348
+ type = "CorpBecameWarEligible"
349
+ sender_id = factory.LazyAttribute(lambda o: o.sender.id)
350
+ sender_type = factory.LazyAttribute(lambda o: o.sender.category)
351
+ is_read = True
352
+
353
+ @factory.lazy_attribute
354
+ def timestamp(self):
355
+ if not self.timestamp_dt:
356
+ timestamp_dt = now()
357
+ else:
358
+ timestamp_dt = self.timestamp_dt
359
+ return datetime_to_esi(timestamp_dt)
360
+
361
+ @factory.lazy_attribute
362
+ def text(self):
363
+ if not self.data:
364
+ return ""
365
+ return yaml.dump(self.data)
structures/views.py CHANGED
@@ -1,6 +1,7 @@
1
1
  import functools
2
2
  from collections import defaultdict
3
3
  from enum import IntEnum
4
+ from typing import Dict
4
5
  from urllib.parse import urlencode
5
6
 
6
7
  from django.contrib.auth.decorators import login_required, permission_required
@@ -354,7 +355,7 @@ def starbase_detail(request, structure_id):
354
355
  assets = defaultdict(int)
355
356
  for item in structure.items.select_related("eve_type"):
356
357
  assets[item.eve_type_id] += item.quantity
357
- eve_types = EveType.objects.in_bulk(id_list=assets.keys())
358
+ eve_types: Dict[int, EveType] = EveType.objects.in_bulk(id_list=assets.keys())
358
359
  modules = sorted(
359
360
  [
360
361
  {"eve_type": eve_types.get(eve_type_id), "quantity": quantity}
@@ -432,7 +433,7 @@ def add_structure_owner(request, token):
432
433
  owner.save()
433
434
 
434
435
  if owner.characters.count() == 1:
435
- tasks.update_all_for_owner.delay(owner_pk=owner.pk, user_pk=request.user.pk)
436
+ tasks.update_all_for_owner.delay(owner_pk=owner.pk, user_pk=request.user.pk) # type: ignore
436
437
  messages_plus.info(
437
438
  request,
438
439
  format_html(
@@ -1,78 +0,0 @@
1
- import dhooks_lite
2
-
3
- from app_utils.testing import NoSocketsTestCase
4
-
5
- from ...core.notification_embeds import (
6
- NotificationBaseEmbed,
7
- NotificationTowerReinforcedExtra,
8
- )
9
- from ...models import NotificationType
10
- from ..testdata.factories_2 import (
11
- EveEntityAllianceFactory,
12
- GeneratedNotificationFactory,
13
- NotificationFactory,
14
- OwnerFactory,
15
- )
16
- from ..testdata.load_eveuniverse import load_eveuniverse
17
-
18
-
19
- class TestGeneratedNotification(NoSocketsTestCase):
20
- @classmethod
21
- def setUpClass(cls):
22
- super().setUpClass()
23
- load_eveuniverse()
24
-
25
- def test_should_create_tower_reinforced_embed(self):
26
- # given
27
- notif = GeneratedNotificationFactory()
28
- # when
29
- obj = NotificationBaseEmbed.create(notif)
30
- # then
31
- self.assertIsInstance(obj, NotificationTowerReinforcedExtra)
32
-
33
- def test_should_generate_embed(self):
34
- # given
35
- notif = GeneratedNotificationFactory()
36
- embed = NotificationBaseEmbed.create(notif)
37
- # when
38
- obj = embed.generate_embed()
39
- # then
40
- self.assertIsInstance(obj, dhooks_lite.Embed)
41
- starbase = notif.structures.first()
42
- self.assertIn(starbase.name, obj.description)
43
-
44
-
45
- class TestEveNotificationEmbeds(NoSocketsTestCase):
46
- @classmethod
47
- def setUpClass(cls):
48
- super().setUpClass()
49
- load_eveuniverse()
50
- cls.owner = OwnerFactory()
51
-
52
- def test_should_create_sov_embed(self):
53
- # given
54
- notif = NotificationFactory(
55
- owner=self.owner,
56
- sender=EveEntityAllianceFactory(),
57
- notif_type=NotificationType.SOV_ENTOSIS_CAPTURE_STARTED,
58
- text_from_dict={"solarSystemID": 30000474, "structureTypeID": 32226},
59
- )
60
- embed = NotificationBaseEmbed.create(notif)
61
- # when
62
- obj = embed.generate_embed()
63
- # then
64
- self.assertIsInstance(obj, dhooks_lite.Embed)
65
-
66
- def test_should_create_sov_embed_without_sender(self):
67
- # given
68
- notif = NotificationFactory(
69
- owner=self.owner,
70
- sender=None,
71
- notif_type=NotificationType.SOV_ENTOSIS_CAPTURE_STARTED,
72
- text_from_dict={"solarSystemID": 30000474, "structureTypeID": 32226},
73
- )
74
- embed = NotificationBaseEmbed.create(notif)
75
- # when
76
- obj = embed.generate_embed()
77
- # then
78
- self.assertIsInstance(obj, dhooks_lite.Embed)