aa-structures 4.0.3__tar.gz → 4.0.4__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.
- {aa_structures-4.0.3 → aa_structures-4.0.4}/PKG-INFO +7 -6
- {aa_structures-4.0.3 → aa_structures-4.0.4}/README.md +4 -4
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/__init__.py +1 -1
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/admin.py +0 -1
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/core/notification_embeds/corporate_embeds.py +17 -21
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/core/notification_embeds/skyhook_embeds.py +4 -8
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/core/notification_embeds/structures_embeds.py +14 -6
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/core/notification_embeds/war_embeds.py +1 -1
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/core/notification_timers.py +1 -2
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/core/serializers.py +4 -4
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/models/notifications.py +2 -4
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/models/owners.py +9 -1
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/models/structures_1.py +2 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/providers.py +0 -2
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tasks.py +13 -8
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/core/notification_embeds/test_main.py +68 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/models/test_notifications_1.py +52 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/models/test_notifications_3.py +35 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/models/test_owners_2.py +44 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/models/test_owners_5.py +22 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/test_admin.py +23 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/test_tasks.py +9 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/views/test_public.py +17 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/views/test_structures.py +60 -1
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/views/public.py +4 -1
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/views/structures.py +23 -11
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/webhooks/core.py +25 -15
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/webhooks/tests/test_core.py +29 -1
- aa_structures-4.0.3/.coveragerc +0 -18
- aa_structures-4.0.3/.github/workflows/ci-cd.yaml +0 -124
- aa_structures-4.0.3/.gitignore +0 -24
- aa_structures-4.0.3/.pre-commit-config.yaml +0 -19
- aa_structures-4.0.3/.readthedocs.yml +0 -17
- aa_structures-4.0.3/.tx/config +0 -10
- aa_structures-4.0.3/CHANGELOG.md +0 -1674
- aa_structures-4.0.3/CONTRIBUTING.md +0 -14
- aa_structures-4.0.3/Makefile +0 -58
- aa_structures-4.0.3/aa-structures_models.png +0 -0
- aa_structures-4.0.3/codecov.yml +0 -16
- aa_structures-4.0.3/docs/Makefile +0 -20
- aa_structures-4.0.3/docs/_static/css/rtd_dark.css +0 -114
- aa_structures-4.0.3/docs/conf.py +0 -73
- aa_structures-4.0.3/docs/index.rst +0 -8
- aa_structures-4.0.3/docs/make.bat +0 -35
- aa_structures-4.0.3/docs/operations.md +0 -165
- aa_structures-4.0.3/docs/requirements.txt +0 -5
- aa_structures-4.0.3/docs/user.md +0 -246
- aa_structures-4.0.3/runtests.py +0 -20
- aa_structures-4.0.3/testauth/__init__.py +0 -1
- aa_structures-4.0.3/testauth/celery.py +0 -39
- aa_structures-4.0.3/testauth/settings_aa4/__init__.py +0 -0
- aa_structures-4.0.3/testauth/settings_aa4/base.py +0 -340
- aa_structures-4.0.3/testauth/settings_aa4/local.py +0 -98
- aa_structures-4.0.3/testauth/settings_aa5/__init__.py +0 -0
- aa_structures-4.0.3/testauth/settings_aa5/base.py +0 -352
- aa_structures-4.0.3/testauth/settings_aa5/local.py +0 -98
- aa_structures-4.0.3/testauth/urls.py +0 -13
- aa_structures-4.0.3/testauth/wsgi.py +0 -14
- aa_structures-4.0.3/tools/drop_tables.sql +0 -27
- aa_structures-4.0.3/tox.ini +0 -52
- {aa_structures-4.0.3 → aa_structures-4.0.4}/LICENSE +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/pyproject.toml +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/app_settings.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/apps.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/auth_hooks.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/checks.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/constants.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/core/__init__.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/core/notification_embeds/__init__.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/core/notification_embeds/billing_embeds.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/core/notification_embeds/helpers.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/core/notification_embeds/main.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/core/notification_embeds/moonmining_embeds.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/core/notification_embeds/orbital_embeds.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/core/notification_embeds/sov_embeds.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/core/notification_embeds/tower_embeds.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/core/notification_types.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/core/sovereignty.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/core/starbases.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/forms.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/helpers.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/locale/de/LC_MESSAGES/django.mo +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/locale/de/LC_MESSAGES/django.po +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/locale/django.pot +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/locale/en/LC_MESSAGES/django.mo +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/locale/en/LC_MESSAGES/django.po +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/locale/es/LC_MESSAGES/django.mo +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/locale/es/LC_MESSAGES/django.po +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/locale/fr_FR/LC_MESSAGES/django.mo +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/locale/fr_FR/LC_MESSAGES/django.po +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/locale/it_IT/LC_MESSAGES/django.mo +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/locale/it_IT/LC_MESSAGES/django.po +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/locale/ja/LC_MESSAGES/django.mo +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/locale/ja/LC_MESSAGES/django.po +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/locale/ko_KR/LC_MESSAGES/django.mo +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/locale/ko_KR/LC_MESSAGES/django.po +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/locale/ru/LC_MESSAGES/django.mo +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/locale/ru/LC_MESSAGES/django.po +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/locale/uk/LC_MESSAGES/django.mo +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/locale/uk/LC_MESSAGES/django.po +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/locale/zh_Hans/LC_MESSAGES/django.mo +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/locale/zh_Hans/LC_MESSAGES/django.po +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/management/commands/__init__.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/management/commands/structures_load_eve.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/management/commands/structures_preload_eveuniverse.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/management/commands/structures_update_poco_planets.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/managers.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/migrations/0001_initial_new.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/migrations/0002_remove_eveuniverse_relation_names.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/migrations/0003_add_localization_and_unique_key.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/migrations/0004_improve_localization.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/migrations/0005_add_notification_types.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/migrations/0006_add_ownercharacter_disabled.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/migrations/0007_add_notificationtypes_skyhook_metenox.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/migrations/0008_add_notificationtypes_skyhook_metenox.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/migrations/0009_add_project_goal_notifications.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/migrations/__init__.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/models/__init__.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/models/eveuniverse.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/models/structures_2.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/openapi_2025-12-16.json +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/css/global.css +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/css/main.css +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/css/public.css +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/css/statistics.css +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/css/structures.css +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/bars-rotate-fade-black-36.svg +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/bars-rotate-fade-white-36.svg +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/eve_symbol_128.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/0h.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/0l.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/0m.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/0r.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/0s.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/1h.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/1l.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/1m.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/1r.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/1s.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/2h.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/2l.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/2m.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/2r.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/2s.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/3h.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/3l.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/3m.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/3r.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/3s.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/4h.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/4l.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/4m.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/4s.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/5h.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/5l.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/5m.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/5s.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/6h.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/6l.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/6m.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/7h.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/7l.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/7m.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/8h.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/8l.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/8m.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/blank.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/circle.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/dustwheel.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/h.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/l.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/m.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/noship.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/r.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/tyrannis.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/tyrannis_blue.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/tyrannis_darkred.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/tyrannis_default.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/panel/tyrannis_revelations.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/img/structures_logo.png +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/js/global.js +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/js/public.js +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/js/statistics.js +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/js/structures.js +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/vendor/datatables/plugins/dataTables.rowGroup.min.js +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/vendor/datatables/plugins/datetime.js +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/vendor/datatables/plugins/filterDropDown.min.js +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/vendor/datatables/plugins/rowGroup.bootstrap.min.css +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/static/structures/vendor/datatables/plugins/rowGroup.dataTables.min.css +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/templates/structures/base.html +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/templates/structures/modals/fitting_assets.html +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/templates/structures/modals/fitting_gfx.html +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/templates/structures/modals/poco_details.html +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/templates/structures/modals/starbase_detail.html +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/templates/structures/modals/structure_details.html +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/templates/structures/modals/tab_general_detail.html +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/templates/structures/modals/tab_services_detail.html +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/templates/structures/partials/menu.html +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/templates/structures/partials/public/poco_list.html +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/templates/structures/partials/statistics/structure_summary.html +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/templates/structures/partials/structures/active_tags.html +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/templates/structures/partials/structures/jump_gate_list.html +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/templates/structures/partials/structures/orbital_list.html +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/templates/structures/partials/structures/starbase_list.html +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/templates/structures/partials/structures/structure_list.html +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/templates/structures/public.html +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/templates/structures/statistics.html +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/templates/structures/structures.html +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/templates/structures/templatetags/detail_title.html +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/templates/structures/templatetags/list_asset.html +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/templates/structures/templatetags/list_item.html +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/templates/structures/templatetags/list_tax_item.html +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/templates/structures/templatetags/list_title.html +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/templatetags/__init__.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/templatetags/structures.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/__init__.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/core/__init__.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/core/notification_embeds/__init__.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/core/notification_embeds/test_helpers.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/core/test_notification_structuretimers.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/core/test_notification_types.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/core/test_notifications_timers.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/core/test_serializers.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/core/test_sovereignty.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/core/test_starbases.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/helpers.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/integration/__init__.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/integration/test_tasks.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/integration/test_views.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/models/__init__.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/models/test_eveuniverse.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/models/test_notifications_2.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/models/test_notifications_discord.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/models/test_owners_1.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/models/test_owners_3.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/models/test_owners_4.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/models/test_owners_6.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/models/test_structures.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/test_helpers.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/test_managers_1.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/test_managers_2.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/testdata/__init__.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/testdata/constants.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/testdata/factories.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/testdata/generate_notifications.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/testdata/generate_notifications_2.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/testdata/generate_structures.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/testdata/helpers.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/testdata/notifications.json +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/testdata/tasks_loadtest.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/testdata/test_generate_structures.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/views/__init__.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/views/test_service_status.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/views/test_statistics.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/urls.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/views/__init__.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/views/common.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/views/statistics.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/views/status.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/webhooks/__init__.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/webhooks/managers.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/webhooks/models.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/webhooks/tests/__init__.py +0 -0
- {aa_structures-4.0.3 → aa_structures-4.0.4}/structures/webhooks/tests/test_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: aa-structures
|
|
3
|
-
Version: 4.0.
|
|
3
|
+
Version: 4.0.4
|
|
4
4
|
Summary: An app for managing Eve Online structures with Alliance Auth.
|
|
5
5
|
Author-email: Erik Kalkoken <erik.kalkoken@gmail.com>
|
|
6
6
|
Requires-Python: >=3.10
|
|
@@ -35,6 +35,7 @@ Requires-Dist: pook ; extra == "test"
|
|
|
35
35
|
Project-URL: Documentation, https://aa-structures.readthedocs.io
|
|
36
36
|
Project-URL: Homepage, https://github.com/AllianceAuth-Apps/aa-structures
|
|
37
37
|
Provides-Extra: test
|
|
38
|
+
Import-Name: structures
|
|
38
39
|
|
|
39
40
|
# Structures
|
|
40
41
|
|
|
@@ -53,7 +54,7 @@ An app for managing Eve Online structures with Alliance Auth.
|
|
|
53
54
|
|
|
54
55
|
## Overview
|
|
55
56
|
|
|
56
|
-
|
|
57
|
+
Built for [Alliance Auth](https://gitlab.com/allianceauth/allianceauth), it allows all member corporations to see a current list of all their structures in Auth. In addition it allows forwarding Eve Online notifications to Discord.
|
|
57
58
|
|
|
58
59
|
## Features
|
|
59
60
|
|
|
@@ -72,7 +73,7 @@ Structures adds the following main features to Alliance Auth:
|
|
|
72
73
|
- Automatically adds timers from relevant notifications to [Alliance Auth Structure Timers](https://allianceauth.readthedocs.io/en/latest/features/apps/timerboard.html) or [Structure Timers II](https://github.com/AllianceAuth-Apps/aa-structuretimers) app (if installed)
|
|
73
74
|
- Fittings, contents of Upwell structures (e.g. fuel blocks and ammo) and current fuel usage
|
|
74
75
|
- Additional structure notifications generated by the app:
|
|
75
|
-
- Configurable alerts to warn about fuel running
|
|
76
|
+
- Configurable alerts to warn about fuel running low in structures and POSes, and which can replace the ESI notifications
|
|
76
77
|
- Notifications to inform when structures have been refueled (BETA)
|
|
77
78
|
- Configurable alerts to warn about jump fuel (liquid ozone) running low in jump gates
|
|
78
79
|
- POS reinforced (BETA)
|
|
@@ -80,7 +81,7 @@ Structures adds the following main features to Alliance Auth:
|
|
|
80
81
|
- Permissions define which structures are visible to a user based on organization membership
|
|
81
82
|
- Self-defined tags help to better organize structures
|
|
82
83
|
- Ability to increase notification response time and sync resilience with multiple sync characters per structure owner
|
|
83
|
-
- Automatically sends alerts to users and
|
|
84
|
+
- Automatically sends alerts to users and admins when tokens become invalid or sync from ESI fails
|
|
84
85
|
- Interface for 3rd party monitoring of the services status
|
|
85
86
|
- Chinese :cn:, English :us:, German :de: and Russian :ru: localization
|
|
86
87
|
|
|
@@ -103,7 +104,7 @@ The tax rate and access configuration of customs offices is visible too:
|
|
|
103
104
|
|
|
104
105
|
And you can see the configuration for starbases:
|
|
105
106
|
|
|
106
|
-

|
|
107
108
|
|
|
108
109
|
This is an example for a notification posted on Discord:
|
|
109
110
|
|
|
@@ -15,7 +15,7 @@ An app for managing Eve Online structures with Alliance Auth.
|
|
|
15
15
|
|
|
16
16
|
## Overview
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
Built for [Alliance Auth](https://gitlab.com/allianceauth/allianceauth), it allows all member corporations to see a current list of all their structures in Auth. In addition it allows forwarding Eve Online notifications to Discord.
|
|
19
19
|
|
|
20
20
|
## Features
|
|
21
21
|
|
|
@@ -34,7 +34,7 @@ Structures adds the following main features to Alliance Auth:
|
|
|
34
34
|
- Automatically adds timers from relevant notifications to [Alliance Auth Structure Timers](https://allianceauth.readthedocs.io/en/latest/features/apps/timerboard.html) or [Structure Timers II](https://github.com/AllianceAuth-Apps/aa-structuretimers) app (if installed)
|
|
35
35
|
- Fittings, contents of Upwell structures (e.g. fuel blocks and ammo) and current fuel usage
|
|
36
36
|
- Additional structure notifications generated by the app:
|
|
37
|
-
- Configurable alerts to warn about fuel running
|
|
37
|
+
- Configurable alerts to warn about fuel running low in structures and POSes, and which can replace the ESI notifications
|
|
38
38
|
- Notifications to inform when structures have been refueled (BETA)
|
|
39
39
|
- Configurable alerts to warn about jump fuel (liquid ozone) running low in jump gates
|
|
40
40
|
- POS reinforced (BETA)
|
|
@@ -42,7 +42,7 @@ Structures adds the following main features to Alliance Auth:
|
|
|
42
42
|
- Permissions define which structures are visible to a user based on organization membership
|
|
43
43
|
- Self-defined tags help to better organize structures
|
|
44
44
|
- Ability to increase notification response time and sync resilience with multiple sync characters per structure owner
|
|
45
|
-
- Automatically sends alerts to users and
|
|
45
|
+
- Automatically sends alerts to users and admins when tokens become invalid or sync from ESI fails
|
|
46
46
|
- Interface for 3rd party monitoring of the services status
|
|
47
47
|
- Chinese :cn:, English :us:, German :de: and Russian :ru: localization
|
|
48
48
|
|
|
@@ -65,7 +65,7 @@ The tax rate and access configuration of customs offices is visible too:
|
|
|
65
65
|
|
|
66
66
|
And you can see the configuration for starbases:
|
|
67
67
|
|
|
68
|
-

|
|
69
69
|
|
|
70
70
|
This is an example for a notification posted on Discord:
|
|
71
71
|
|
{aa_structures-4.0.3 → aa_structures-4.0.4}/structures/core/notification_embeds/corporate_embeds.py
RENAMED
|
@@ -38,12 +38,11 @@ class NotificationCorpAppNewMsg(NotificationCorpCharEmbed):
|
|
|
38
38
|
self._description = _(
|
|
39
39
|
"New application from %(character_name)s to join %(corporation_name)s:\n"
|
|
40
40
|
"> %(application_text)s"
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
)
|
|
41
|
+
) % {
|
|
42
|
+
"character_name": self._character_link,
|
|
43
|
+
"corporation_name": self._corporation_link,
|
|
44
|
+
"application_text": self._application_text,
|
|
45
|
+
}
|
|
47
46
|
self._color = Webhook.Color.INFO
|
|
48
47
|
|
|
49
48
|
|
|
@@ -178,11 +177,10 @@ class NotificationCorpGoalClosed(NotificationCorpGoalEmbed):
|
|
|
178
177
|
self._description = _(
|
|
179
178
|
"Project **%(goal_name)s** has ben closed by %(closer)s "
|
|
180
179
|
"and will not accept further contributions."
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
)
|
|
180
|
+
) % {
|
|
181
|
+
"goal_name": self._goal_name,
|
|
182
|
+
"closer": gen_eve_entity_link(closer),
|
|
183
|
+
}
|
|
186
184
|
self._color = Webhook.Color.INFO
|
|
187
185
|
|
|
188
186
|
|
|
@@ -193,11 +191,10 @@ class NotificationCorpGoalCompleted(NotificationCorpGoalEmbed):
|
|
|
193
191
|
self._description = _(
|
|
194
192
|
"Project **%(goal_name)s** created by %(creator)s "
|
|
195
193
|
"has been successfully completed after reaching it's target."
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
)
|
|
194
|
+
) % {
|
|
195
|
+
"goal_name": self._goal_name,
|
|
196
|
+
"creator": self._creator_link,
|
|
197
|
+
}
|
|
201
198
|
self._color = Webhook.Color.SUCCESS
|
|
202
199
|
|
|
203
200
|
|
|
@@ -208,9 +205,8 @@ class NotificationCorpGoalCreated(NotificationCorpGoalEmbed):
|
|
|
208
205
|
self._description = _(
|
|
209
206
|
"Project **%(goal_name)s** has been created by %(creator)s "
|
|
210
207
|
"and is open for contributions."
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
)
|
|
208
|
+
) % {
|
|
209
|
+
"goal_name": self._goal_name,
|
|
210
|
+
"creator": self._creator_link,
|
|
211
|
+
}
|
|
216
212
|
self._color = Webhook.Color.INFO
|
{aa_structures-4.0.3 → aa_structures-4.0.4}/structures/core/notification_embeds/skyhook_embeds.py
RENAMED
|
@@ -77,12 +77,8 @@ class NotificationSkyhookUnderAttack(NotificationSkyhookEmbed):
|
|
|
77
77
|
def __init__(self, n: Notification) -> None:
|
|
78
78
|
super().__init__(n)
|
|
79
79
|
self._title = _("Skyhook under attack")
|
|
80
|
-
self._description += _(
|
|
81
|
-
"
|
|
82
|
-
"
|
|
83
|
-
|
|
84
|
-
"attacker": self.gen_attacker_link(),
|
|
85
|
-
"damage_text": self.compile_damage_text("Percentage"),
|
|
86
|
-
}
|
|
87
|
-
)
|
|
80
|
+
self._description += _("is under attack by %(attacker)s.\n%(damage_text)s") % {
|
|
81
|
+
"attacker": self.gen_attacker_link(),
|
|
82
|
+
"damage_text": self.compile_damage_text("Percentage"),
|
|
83
|
+
}
|
|
88
84
|
self._color = Webhook.Color.DANGER
|
{aa_structures-4.0.3 → aa_structures-4.0.4}/structures/core/notification_embeds/structures_embeds.py
RENAMED
|
@@ -95,7 +95,9 @@ class NotificationStructureJumpFuelAlert(NotificationStructureEmbed):
|
|
|
95
95
|
super().__init__(notification)
|
|
96
96
|
self._title = _("Jump gate low on Liquid Ozone")
|
|
97
97
|
threshold_str = f"{self._data['threshold']:,}"
|
|
98
|
-
quantity_str =
|
|
98
|
+
quantity_str = (
|
|
99
|
+
f"{self._structure.jump_fuel_quantity():,}" if self._structure else "?"
|
|
100
|
+
)
|
|
99
101
|
self._description += _(
|
|
100
102
|
"is below %(threshold)s units on Liquid Ozone.\n"
|
|
101
103
|
"Remaining units: %(remaining)s."
|
|
@@ -262,13 +264,19 @@ class NotificationStructureReinforceChange(NotificationBaseEmbed):
|
|
|
262
264
|
|
|
263
265
|
def __init__(self, notification: Notification) -> None:
|
|
264
266
|
super().__init__(notification)
|
|
267
|
+
structure_ids = [
|
|
268
|
+
structure_info[0] for structure_info in self._data["allStructureInfo"]
|
|
269
|
+
]
|
|
270
|
+
structures_by_id = {
|
|
271
|
+
structure.id: structure
|
|
272
|
+
for structure in Structure.objects.select_related_defaults().filter(
|
|
273
|
+
id__in=structure_ids
|
|
274
|
+
)
|
|
275
|
+
}
|
|
265
276
|
all_structure_info = []
|
|
266
277
|
for structure_info in self._data["allStructureInfo"]:
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
id=structure_info[0]
|
|
270
|
-
)
|
|
271
|
-
except Structure.DoesNotExist:
|
|
278
|
+
structure = structures_by_id.get(structure_info[0])
|
|
279
|
+
if structure is None:
|
|
272
280
|
all_structure_info.append(
|
|
273
281
|
self.StructureInfo(
|
|
274
282
|
name=structure_info[1],
|
{aa_structures-4.0.3 → aa_structures-4.0.4}/structures/core/notification_embeds/war_embeds.py
RENAMED
|
@@ -296,7 +296,7 @@ class NotificationCorpWarSurrenderMsg(NotificationWarBaseEmbed):
|
|
|
296
296
|
class NotificationWarHQRemovedFromSpace(NotificationWarBaseEmbed):
|
|
297
297
|
def __init__(self, notification: Notification) -> None:
|
|
298
298
|
super().__init__(notification)
|
|
299
|
-
war_hq = self._data["warHQ"]
|
|
299
|
+
war_hq = strip_tags(self._data["warHQ"])
|
|
300
300
|
time_declared = ldap_time_2_datetime(self._data["timeDeclared"])
|
|
301
301
|
self._title = _("WarHQ %s lost") % war_hq
|
|
302
302
|
self._description = _(
|
|
@@ -323,8 +323,6 @@ def _gen_timer_moon_extraction(notif: Notification) -> bool:
|
|
|
323
323
|
timer_processed = True
|
|
324
324
|
|
|
325
325
|
case NotificationType.MOONMINING_EXTRACTION_CANCELLED:
|
|
326
|
-
timer_processed = True
|
|
327
|
-
|
|
328
326
|
for notification in Notification.objects.filter(
|
|
329
327
|
notif_type=NotificationType.MOONMINING_EXTRACTION_STARTED,
|
|
330
328
|
owner=notif.owner,
|
|
@@ -335,6 +333,7 @@ def _gen_timer_moon_extraction(notif: Notification) -> bool:
|
|
|
335
333
|
parsed_text_2 = notification.parsed_text()
|
|
336
334
|
my_structure_type_id = parsed_text_2["structureTypeID"]
|
|
337
335
|
if my_structure_type_id == parsed_text["structureTypeID"]:
|
|
336
|
+
timer_processed = True
|
|
338
337
|
eve_time_2 = _extract_eve_time(parsed_text_2)
|
|
339
338
|
|
|
340
339
|
if AuthTimer:
|
|
@@ -140,10 +140,10 @@ class _AbstractStructureListSerializer(ABC):
|
|
|
140
140
|
self, structure: Structure, row: dict, check_tags: bool = True
|
|
141
141
|
):
|
|
142
142
|
structure_name_html = escape(structure.name)
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
143
|
+
if check_tags:
|
|
144
|
+
tags = [x.html for x in structure.tags.all()]
|
|
145
|
+
if tags:
|
|
146
|
+
structure_name_html += format_html("<br>{}", mark_safe(" ".join(tags)))
|
|
147
147
|
|
|
148
148
|
row["structure_name_and_tags"] = structure_name_html
|
|
149
149
|
|
|
@@ -309,10 +309,7 @@ class NotificationBase(models.Model):
|
|
|
309
309
|
else:
|
|
310
310
|
structures_qs = self.calc_related_structures()
|
|
311
311
|
|
|
312
|
-
if (
|
|
313
|
-
structures_qs.exists()
|
|
314
|
-
and structures_qs.filter(webhooks__isnull=False).count() == 1
|
|
315
|
-
):
|
|
312
|
+
if structures_qs.count() == 1 and structures_qs.first().webhooks.exists():
|
|
316
313
|
webhooks_qs = structures_qs.first().webhooks
|
|
317
314
|
else:
|
|
318
315
|
webhooks_qs = self.owner.webhooks
|
|
@@ -896,6 +893,7 @@ class JumpFuelAlertConfig(BaseFuelAlertConfig):
|
|
|
896
893
|
)
|
|
897
894
|
.filter(is_active=True)
|
|
898
895
|
.filter(Q(owners__isnull=False) | Q(structures__isnull=False))
|
|
896
|
+
.distinct()
|
|
899
897
|
)
|
|
900
898
|
|
|
901
899
|
|
|
@@ -633,6 +633,11 @@ class Owner(models.Model):
|
|
|
633
633
|
self, token: Token, structures: List[dict]
|
|
634
634
|
) -> bool:
|
|
635
635
|
count = 0
|
|
636
|
+
existing_names = dict(
|
|
637
|
+
self.structures.filter(
|
|
638
|
+
id__in=[s["structure_id"] for s in structures]
|
|
639
|
+
).values_list("id", "name")
|
|
640
|
+
)
|
|
636
641
|
for s in structures:
|
|
637
642
|
try:
|
|
638
643
|
structure_info_obj = (
|
|
@@ -654,7 +659,8 @@ class Owner(models.Model):
|
|
|
654
659
|
self._report_esi_issue(
|
|
655
660
|
f"fetch structure #{s['structure_id']}", ex, token
|
|
656
661
|
)
|
|
657
|
-
|
|
662
|
+
# Don't clobber a previously resolved name on a transient failure.
|
|
663
|
+
s["name"] = existing_names.get(s["structure_id"]) or "(no data)"
|
|
658
664
|
else:
|
|
659
665
|
structure_info = structure_info_obj.model_dump()
|
|
660
666
|
count += 1
|
|
@@ -1215,6 +1221,7 @@ class Owner(models.Model):
|
|
|
1215
1221
|
)
|
|
1216
1222
|
for notif in new_eve_notifications:
|
|
1217
1223
|
notif.send_to_configured_webhooks()
|
|
1224
|
+
notifications_count += 1
|
|
1218
1225
|
|
|
1219
1226
|
new_generated_notifications: models.QuerySet[GeneratedNotification] = (
|
|
1220
1227
|
self.generatednotification_set.filter(**my_filter)
|
|
@@ -1223,6 +1230,7 @@ class Owner(models.Model):
|
|
|
1223
1230
|
)
|
|
1224
1231
|
for notif in new_generated_notifications:
|
|
1225
1232
|
notif.send_to_configured_webhooks()
|
|
1233
|
+
notifications_count += 1
|
|
1226
1234
|
|
|
1227
1235
|
if (
|
|
1228
1236
|
not new_eve_notifications.exists()
|
|
@@ -259,6 +259,8 @@ class Structure(models.Model): # pylint: disable = too-many-public-methods
|
|
|
259
259
|
verbose_name=_("fuel expires at"),
|
|
260
260
|
help_text=_("Date on which the structure will run out of fuel"),
|
|
261
261
|
)
|
|
262
|
+
# despite the name, also true when the structure only has fuel/cargo/fighters, not just a fit
|
|
263
|
+
# TODO: rename to has_items with the next migration
|
|
262
264
|
has_fitting = models.BooleanField(
|
|
263
265
|
null=True,
|
|
264
266
|
default=None,
|
|
@@ -20,10 +20,8 @@ esi = ESIClientProvider(
|
|
|
20
20
|
"GetCorporationsCorporationIdStructures",
|
|
21
21
|
"GetSovereigntyMap",
|
|
22
22
|
"GetUniverseStructuresStructureId",
|
|
23
|
-
"GetUniverseStructuresStructureId",
|
|
24
23
|
"PostCorporationsCorporationIdAssetsNames",
|
|
25
24
|
"PostCorporationsCorporationIdAssetsLocations",
|
|
26
|
-
"PostCorporationsCorporationIdAssetsNames",
|
|
27
25
|
],
|
|
28
26
|
spec_file=spec_file,
|
|
29
27
|
)
|
|
@@ -49,14 +49,15 @@ def update_sov_map(_self):
|
|
|
49
49
|
@shared_task(time_limit=STRUCTURES_TASKS_TIME_LIMIT)
|
|
50
50
|
def update_structures():
|
|
51
51
|
"""Update all structures for all active owners from ESI."""
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
has_active_owner = False
|
|
53
|
+
has_alliance_main = False
|
|
54
|
+
for owner in Owner.objects.filter(is_active=True):
|
|
55
|
+
has_active_owner = True
|
|
56
|
+
update_structures_for_owner.delay(owner.pk)
|
|
57
|
+
if owner.is_alliance_main:
|
|
58
|
+
has_alliance_main = True
|
|
55
59
|
|
|
56
|
-
if
|
|
57
|
-
Owner.objects.filter(is_active=True).count() > 0
|
|
58
|
-
and Owner.objects.filter(is_active=True, is_alliance_main=True).count() == 0
|
|
59
|
-
):
|
|
60
|
+
if has_active_owner and not has_alliance_main:
|
|
60
61
|
logger.warning(
|
|
61
62
|
"No owner configured to process alliance wide notifications. "
|
|
62
63
|
"Please set 'is alliance main' to True for the designated owner."
|
|
@@ -204,7 +205,11 @@ def generate_new_timers_for_owner(owner_pk: int):
|
|
|
204
205
|
owner.add_or_remove_timers_from_notifications()
|
|
205
206
|
|
|
206
207
|
|
|
207
|
-
@shared_task(
|
|
208
|
+
@shared_task(
|
|
209
|
+
base=QueueOnce,
|
|
210
|
+
once={"keys": ["owner_pk"]},
|
|
211
|
+
time_limit=STRUCTURES_TASKS_TIME_LIMIT,
|
|
212
|
+
)
|
|
208
213
|
def send_new_notifications_for_owner(owner_pk: int):
|
|
209
214
|
"""Send new notifications to Discord."""
|
|
210
215
|
owner = Owner.objects.get(pk=owner_pk)
|
{aa_structures-4.0.3 → aa_structures-4.0.4}/structures/tests/core/notification_embeds/test_main.py
RENAMED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import datetime as dt
|
|
2
|
+
import re
|
|
2
3
|
|
|
3
4
|
import dhooks_lite
|
|
4
5
|
|
|
5
6
|
from django.core.cache import cache
|
|
7
|
+
from django.db import connection
|
|
6
8
|
from django.test import TestCase, override_settings
|
|
9
|
+
from django.test.utils import CaptureQueriesContext
|
|
7
10
|
from django.utils.timezone import now
|
|
8
11
|
from eveuniverse.tests.testdata.factories_2 import EveMoonFactory, EveSolarSystemFactory
|
|
9
12
|
|
|
@@ -240,6 +243,23 @@ class TestNotificationEmbedsGenerate(NoSocketsTestCase):
|
|
|
240
243
|
self.assertEqual(discord_embed.footer.text, "Structures")
|
|
241
244
|
self.assertIn("structures_logo.png", discord_embed.footer.icon_url)
|
|
242
245
|
|
|
246
|
+
def test_should_generate_jump_fuel_alert_embed_when_structure_no_longer_exists(
|
|
247
|
+
self,
|
|
248
|
+
):
|
|
249
|
+
# given
|
|
250
|
+
structure = StructureFactory(owner=self.owner)
|
|
251
|
+
notification = Notification.create_from_structure(
|
|
252
|
+
structure,
|
|
253
|
+
notif_type=NotificationType.STRUCTURE_JUMP_FUEL_ALERT,
|
|
254
|
+
threshold=1000,
|
|
255
|
+
)
|
|
256
|
+
structure.delete()
|
|
257
|
+
notification_embed = NotificationBaseEmbed.create(notification)
|
|
258
|
+
# when
|
|
259
|
+
discord_embed = notification_embed.generate_embed()
|
|
260
|
+
# then
|
|
261
|
+
self.assertIsInstance(discord_embed, dhooks_lite.Embed)
|
|
262
|
+
|
|
243
263
|
def test_should_not_break_with_too_large_description(self):
|
|
244
264
|
# given
|
|
245
265
|
notification = Notification.objects.get(notification_id=1000000403)
|
|
@@ -404,4 +424,52 @@ class TestEveNotificationEmbeds(NoSocketsTestCase):
|
|
|
404
424
|
self.assertTrue(obj.description)
|
|
405
425
|
self.assertTrue(obj.description)
|
|
406
426
|
self.assertTrue(obj.description)
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
class TestNotificationStructureReinforceChange(NoSocketsTestCase):
|
|
430
|
+
@classmethod
|
|
431
|
+
def setUpClass(cls):
|
|
432
|
+
super().setUpClass()
|
|
433
|
+
cls.owner = OwnerFactory()
|
|
434
|
+
|
|
435
|
+
def test_should_batch_fetch_structures_and_handle_missing_ones(self):
|
|
436
|
+
# given
|
|
437
|
+
structure_1 = StructureFactory(owner=self.owner)
|
|
438
|
+
structure_2 = StructureFactory(owner=self.owner)
|
|
439
|
+
missing_structure_id = 1_599_999_999_999
|
|
440
|
+
notif = NotificationFactory(
|
|
441
|
+
owner=self.owner,
|
|
442
|
+
notif_type=NotificationType.STRUCTURE_REINFORCEMENT_CHANGED,
|
|
443
|
+
text_from_dict={
|
|
444
|
+
"allStructureInfo": [
|
|
445
|
+
[structure_1.id, structure_1.name, structure_1.eve_type_id],
|
|
446
|
+
[
|
|
447
|
+
missing_structure_id,
|
|
448
|
+
"Ghost Structure",
|
|
449
|
+
structure_2.eve_type_id,
|
|
450
|
+
],
|
|
451
|
+
[structure_2.id, structure_2.name, structure_2.eve_type_id],
|
|
452
|
+
],
|
|
453
|
+
"hour": 19,
|
|
454
|
+
"numStructures": 3,
|
|
455
|
+
"timestamp": 132141703753688216,
|
|
456
|
+
"weekday": 255,
|
|
457
|
+
},
|
|
458
|
+
)
|
|
459
|
+
# when
|
|
460
|
+
with CaptureQueriesContext(connection) as ctx:
|
|
461
|
+
embed = NotificationBaseEmbed.create(notif)
|
|
462
|
+
# then: structures are fetched with a single batched query, not one per entry
|
|
463
|
+
structure_queries = [
|
|
464
|
+
query
|
|
465
|
+
for query in ctx.captured_queries
|
|
466
|
+
if re.search(r"\bstructures_structure\b", query["sql"])
|
|
467
|
+
]
|
|
468
|
+
self.assertEqual(len(structure_queries), 1)
|
|
469
|
+
|
|
470
|
+
obj = embed.generate_embed()
|
|
471
|
+
self.assertIn(structure_1.name, obj.description)
|
|
472
|
+
self.assertIn(structure_2.name, obj.description)
|
|
473
|
+
self.assertIn("Ghost Structure", obj.description)
|
|
474
|
+
self.assertIn("(unknown)", obj.description)
|
|
407
475
|
self.assertTrue(obj.description)
|
|
@@ -369,6 +369,58 @@ class TestNotificationRelevantWebhooks(NoSocketsTestCase):
|
|
|
369
369
|
result_qs, Webhook.objects.filter(pk=webhook_structure.pk)
|
|
370
370
|
)
|
|
371
371
|
|
|
372
|
+
def test_should_return_structure_webhooks_when_structure_has_multiple_webhooks(
|
|
373
|
+
self,
|
|
374
|
+
):
|
|
375
|
+
# given
|
|
376
|
+
webhook_owner = WebhookFactory(
|
|
377
|
+
notification_types=[NotificationType.STRUCTURE_UNDER_ATTACK]
|
|
378
|
+
)
|
|
379
|
+
owner = OwnerFactory(webhooks=[webhook_owner])
|
|
380
|
+
structure = StructureFactory(owner=owner)
|
|
381
|
+
webhook_structure_1 = WebhookFactory(
|
|
382
|
+
notification_types=[NotificationType.STRUCTURE_UNDER_ATTACK]
|
|
383
|
+
)
|
|
384
|
+
webhook_structure_2 = WebhookFactory(
|
|
385
|
+
notification_types=[NotificationType.STRUCTURE_UNDER_ATTACK]
|
|
386
|
+
)
|
|
387
|
+
structure.webhooks.add(webhook_structure_1, webhook_structure_2)
|
|
388
|
+
notif = NotificationFactory(
|
|
389
|
+
owner=owner,
|
|
390
|
+
notif_type=NotificationType.STRUCTURE_UNDER_ATTACK,
|
|
391
|
+
text_from_dict={
|
|
392
|
+
"allianceID": 3011,
|
|
393
|
+
"allianceLinkData": ["showinfo", 16159, 3011],
|
|
394
|
+
"allianceName": "Big Bad Alliance",
|
|
395
|
+
"armorPercentage": 98.65129050962584,
|
|
396
|
+
"charID": 1011,
|
|
397
|
+
"corpLinkData": ["showinfo", 2, 2011],
|
|
398
|
+
"corpName": "Bad Company",
|
|
399
|
+
"hullPercentage": 100.0,
|
|
400
|
+
"shieldPercentage": 4.704536686417284e-14,
|
|
401
|
+
"solarsystemID": structure.eve_solar_system_id,
|
|
402
|
+
"structureID": structure.id,
|
|
403
|
+
"structureShowInfoData": [
|
|
404
|
+
"showinfo",
|
|
405
|
+
structure.eve_type_id,
|
|
406
|
+
structure.id,
|
|
407
|
+
],
|
|
408
|
+
"structureTypeID": structure.eve_type_id,
|
|
409
|
+
},
|
|
410
|
+
)
|
|
411
|
+
# when
|
|
412
|
+
result_qs = notif.relevant_webhooks()
|
|
413
|
+
# then
|
|
414
|
+
# A structure with 2+ direct webhooks must still use its own webhooks,
|
|
415
|
+
# not silently fall back to the owner's defaults.
|
|
416
|
+
self.assertQuerySetEqual(
|
|
417
|
+
result_qs,
|
|
418
|
+
Webhook.objects.filter(
|
|
419
|
+
pk__in=[webhook_structure_1.pk, webhook_structure_2.pk]
|
|
420
|
+
),
|
|
421
|
+
ordered=False,
|
|
422
|
+
)
|
|
423
|
+
|
|
372
424
|
def test_should_return_owner_webhooks_when_notif_has_multiple_structures(self):
|
|
373
425
|
# given
|
|
374
426
|
webhook_owner = WebhookFactory(
|
|
@@ -15,8 +15,10 @@ from structures.tests.testdata.factories import (
|
|
|
15
15
|
StarbaseFactory,
|
|
16
16
|
StructureFactory,
|
|
17
17
|
)
|
|
18
|
+
from structures.tests.testdata.helpers import load_notification_entities
|
|
18
19
|
|
|
19
20
|
MODULE_PATH = "structures.models.notifications"
|
|
21
|
+
TIMERS_MODULE_PATH = "structures.core.notification_timers"
|
|
20
22
|
|
|
21
23
|
|
|
22
24
|
class TestGeneratedNotification(NoSocketsTestCase):
|
|
@@ -194,3 +196,36 @@ class TestProcessTimers(NoSocketsTestCase):
|
|
|
194
196
|
result = notif.add_or_remove_timer()
|
|
195
197
|
# then
|
|
196
198
|
self.assertFalse(result)
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
@mock.patch(MODULE_PATH + ".STRUCTURES_ADD_TIMERS", True)
|
|
202
|
+
@mock.patch(TIMERS_MODULE_PATH + ".STRUCTURES_MOON_EXTRACTION_TIMERS_ENABLED", True)
|
|
203
|
+
class TestMoonExtractionCancelledTimer(NoSocketsTestCase):
|
|
204
|
+
@classmethod
|
|
205
|
+
def setUpClass(cls):
|
|
206
|
+
super().setUpClass()
|
|
207
|
+
cls.owner = OwnerFactory()
|
|
208
|
+
load_notification_entities(cls.owner)
|
|
209
|
+
|
|
210
|
+
def test_should_not_mark_processed_when_no_matching_started_notification(self):
|
|
211
|
+
# given
|
|
212
|
+
notif = NotificationFactory(
|
|
213
|
+
owner=self.owner,
|
|
214
|
+
notif_type=NotificationType.MOONMINING_EXTRACTION_CANCELLED,
|
|
215
|
+
text_from_dict={
|
|
216
|
+
"cancelledBy": 1001,
|
|
217
|
+
"cancelledByLink": '<a href="showinfo:1383//1001">Bruce Wayne</a>',
|
|
218
|
+
"moonID": 40161465,
|
|
219
|
+
"solarSystemID": 30002537,
|
|
220
|
+
"structureID": 1000000000002,
|
|
221
|
+
"structureLink": ('<a href="showinfo:35835//1000000000002">Dummy</a>'),
|
|
222
|
+
"structureName": "Dummy",
|
|
223
|
+
"structureTypeID": 35835,
|
|
224
|
+
},
|
|
225
|
+
)
|
|
226
|
+
# when
|
|
227
|
+
result = notif.add_or_remove_timer()
|
|
228
|
+
# then
|
|
229
|
+
self.assertFalse(result)
|
|
230
|
+
notif.refresh_from_db()
|
|
231
|
+
self.assertFalse(notif.is_timer_added)
|
|
@@ -343,6 +343,50 @@ class TestUpdateStructuresEsi(TestCaseWithClearCache):
|
|
|
343
343
|
structure = Structure.objects.get(id=structure_id)
|
|
344
344
|
self.assertEqual(structure.name, "(no data)")
|
|
345
345
|
|
|
346
|
+
@pook.on
|
|
347
|
+
def test_should_keep_last_known_name_when_universe_endpoint_fails(self):
|
|
348
|
+
# given
|
|
349
|
+
owner = OwnerFactory(user=self.user, structures_last_update_at=None)
|
|
350
|
+
structure_id = 1000000000001
|
|
351
|
+
solar_system = EveSolarSystemFactory()
|
|
352
|
+
structure_type = CitadelTypeFactory()
|
|
353
|
+
StructureFactory(
|
|
354
|
+
id=structure_id,
|
|
355
|
+
owner=owner,
|
|
356
|
+
eve_type=structure_type,
|
|
357
|
+
eve_solar_system=solar_system,
|
|
358
|
+
name="My Awesome Structure",
|
|
359
|
+
)
|
|
360
|
+
pook.get(
|
|
361
|
+
f"https://esi.evetech.net/corporations/{self.corporation_id}/structures",
|
|
362
|
+
reply=200,
|
|
363
|
+
response_json=[
|
|
364
|
+
{
|
|
365
|
+
"corporation_id": self.corporation_id,
|
|
366
|
+
"profile_id": 101853,
|
|
367
|
+
"reinforce_hour": 18,
|
|
368
|
+
"state": "shield_vulnerable",
|
|
369
|
+
"structure_id": structure_id,
|
|
370
|
+
"system_id": solar_system.id,
|
|
371
|
+
"type_id": structure_type.id,
|
|
372
|
+
},
|
|
373
|
+
],
|
|
374
|
+
)
|
|
375
|
+
pook.get(
|
|
376
|
+
f"https://esi.evetech.net/universe/structures/{structure_id}",
|
|
377
|
+
reply=500,
|
|
378
|
+
response_json={"error": "internal_error"},
|
|
379
|
+
)
|
|
380
|
+
|
|
381
|
+
# when
|
|
382
|
+
owner.update_structures_esi()
|
|
383
|
+
|
|
384
|
+
# then
|
|
385
|
+
owner.refresh_from_db()
|
|
386
|
+
self.assertFalse(owner.is_structure_sync_fresh)
|
|
387
|
+
structure = Structure.objects.get(id=structure_id)
|
|
388
|
+
self.assertEqual(structure.name, "My Awesome Structure")
|
|
389
|
+
|
|
346
390
|
@pook.on
|
|
347
391
|
def test_tags_are_not_modified_by_update(self):
|
|
348
392
|
# given
|