aa-structures 2.9.1__tar.gz → 2.11.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 (226) hide show
  1. {aa_structures-2.9.1 → aa_structures-2.11.0}/PKG-INFO +1 -1
  2. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/__init__.py +1 -1
  3. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/admin.py +43 -4
  4. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/app_settings.py +1 -1
  5. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/auth_hooks.py +6 -1
  6. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/managers.py +17 -4
  7. aa_structures-2.11.0/structures/migrations/0006_add_ownercharacter_disabled.py +27 -0
  8. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/models/owners.py +104 -51
  9. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/integration/test_tasks.py +2 -3
  10. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/integration/test_views.py +2 -2
  11. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/models/test_owners_1.py +95 -52
  12. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/models/test_owners_4.py +21 -5
  13. aa_structures-2.11.0/structures/tests/models/test_owners_6.py +31 -0
  14. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/test_admin.py +65 -0
  15. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/test_managers_2.py +3 -2
  16. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/testdata/factories.py +3 -4
  17. aa_structures-2.11.0/structures/tests/views/test_service_status.py +113 -0
  18. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/views/test_structures.py +52 -80
  19. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/urls.py +3 -2
  20. aa_structures-2.11.0/structures/views/status.py +22 -0
  21. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/views/structures.py +3 -19
  22. {aa_structures-2.9.1 → aa_structures-2.11.0}/LICENSE +0 -0
  23. {aa_structures-2.9.1 → aa_structures-2.11.0}/README.md +0 -0
  24. {aa_structures-2.9.1 → aa_structures-2.11.0}/pyproject.toml +0 -0
  25. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/apps.py +0 -0
  26. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/constants.py +0 -0
  27. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/core/__init__.py +0 -0
  28. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/core/notification_embeds/__init__.py +0 -0
  29. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/core/notification_embeds/billing_embeds.py +0 -0
  30. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/core/notification_embeds/corporate_embeds.py +0 -0
  31. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/core/notification_embeds/helpers.py +0 -0
  32. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/core/notification_embeds/main.py +0 -0
  33. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/core/notification_embeds/moonmining_embeds.py +0 -0
  34. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/core/notification_embeds/orbital_embeds.py +0 -0
  35. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/core/notification_embeds/sov_embeds.py +0 -0
  36. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/core/notification_embeds/structures_embeds.py +0 -0
  37. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/core/notification_embeds/tower_embeds.py +0 -0
  38. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/core/notification_embeds/war_embeds.py +0 -0
  39. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/core/notification_timers.py +0 -0
  40. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/core/notification_types.py +0 -0
  41. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/core/serializers.py +0 -0
  42. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/core/sovereignty.py +0 -0
  43. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/core/starbases.py +0 -0
  44. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/forms.py +0 -0
  45. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/helpers.py +0 -0
  46. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/locale/de/LC_MESSAGES/django.mo +0 -0
  47. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/locale/de/LC_MESSAGES/django.po +0 -0
  48. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/locale/django.pot +0 -0
  49. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/locale/en/LC_MESSAGES/django.mo +0 -0
  50. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/locale/en/LC_MESSAGES/django.po +0 -0
  51. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/locale/es/LC_MESSAGES/django.mo +0 -0
  52. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/locale/es/LC_MESSAGES/django.po +0 -0
  53. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/locale/fr_FR/LC_MESSAGES/django.mo +0 -0
  54. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/locale/fr_FR/LC_MESSAGES/django.po +0 -0
  55. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/locale/it_IT/LC_MESSAGES/django.mo +0 -0
  56. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/locale/it_IT/LC_MESSAGES/django.po +0 -0
  57. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/locale/ja/LC_MESSAGES/django.mo +0 -0
  58. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/locale/ja/LC_MESSAGES/django.po +0 -0
  59. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/locale/ko_KR/LC_MESSAGES/django.mo +0 -0
  60. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/locale/ko_KR/LC_MESSAGES/django.po +0 -0
  61. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/locale/ru/LC_MESSAGES/django.mo +0 -0
  62. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/locale/ru/LC_MESSAGES/django.po +0 -0
  63. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/locale/uk/LC_MESSAGES/django.mo +0 -0
  64. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/locale/uk/LC_MESSAGES/django.po +0 -0
  65. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/locale/zh_Hans/LC_MESSAGES/django.mo +0 -0
  66. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/locale/zh_Hans/LC_MESSAGES/django.po +0 -0
  67. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/management/commands/__init__.py +0 -0
  68. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/management/commands/structures_load_eve.py +0 -0
  69. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/management/commands/structures_preload_eveuniverse.py +0 -0
  70. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/management/commands/structures_update_poco_planets.py +0 -0
  71. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/migrations/0001_initial_new.py +0 -0
  72. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/migrations/0002_remove_eveuniverse_relation_names.py +0 -0
  73. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/migrations/0003_add_localization_and_unique_key.py +0 -0
  74. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/migrations/0004_improve_localization.py +0 -0
  75. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/migrations/0005_add_notification_types.py +0 -0
  76. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/migrations/__init__.py +0 -0
  77. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/models/__init__.py +0 -0
  78. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/models/eveuniverse.py +0 -0
  79. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/models/notifications.py +0 -0
  80. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/models/structures_1.py +0 -0
  81. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/models/structures_2.py +0 -0
  82. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/providers.py +0 -0
  83. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/css/global.css +0 -0
  84. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/css/main.css +0 -0
  85. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/css/public.css +0 -0
  86. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/css/statistics.css +0 -0
  87. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/css/structures.css +0 -0
  88. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/bars-rotate-fade-black-36.svg +0 -0
  89. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/bars-rotate-fade-white-36.svg +0 -0
  90. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/eve_symbol_128.png +0 -0
  91. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/0h.png +0 -0
  92. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/0l.png +0 -0
  93. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/0m.png +0 -0
  94. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/0r.png +0 -0
  95. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/0s.png +0 -0
  96. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/1h.png +0 -0
  97. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/1l.png +0 -0
  98. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/1m.png +0 -0
  99. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/1r.png +0 -0
  100. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/2h.png +0 -0
  101. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/2l.png +0 -0
  102. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/2m.png +0 -0
  103. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/2r.png +0 -0
  104. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/3h.png +0 -0
  105. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/3l.png +0 -0
  106. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/3m.png +0 -0
  107. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/3r.png +0 -0
  108. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/4h.png +0 -0
  109. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/4l.png +0 -0
  110. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/4m.png +0 -0
  111. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/4s.png +0 -0
  112. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/5h.png +0 -0
  113. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/5l.png +0 -0
  114. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/5m.png +0 -0
  115. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/5s.png +0 -0
  116. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/6h.png +0 -0
  117. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/6l.png +0 -0
  118. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/6m.png +0 -0
  119. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/7h.png +0 -0
  120. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/7l.png +0 -0
  121. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/7m.png +0 -0
  122. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/8h.png +0 -0
  123. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/8l.png +0 -0
  124. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/8m.png +0 -0
  125. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/blank.png +0 -0
  126. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/circle.png +0 -0
  127. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/dustwheel.png +0 -0
  128. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/h.png +0 -0
  129. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/l.png +0 -0
  130. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/m.png +0 -0
  131. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/noship.png +0 -0
  132. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/r.png +0 -0
  133. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/tyrannis.png +0 -0
  134. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/tyrannis_blue.png +0 -0
  135. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/tyrannis_darkred.png +0 -0
  136. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/tyrannis_default.png +0 -0
  137. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/panel/tyrannis_revelations.png +0 -0
  138. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/img/structures_logo.png +0 -0
  139. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/js/global.js +0 -0
  140. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/js/public.js +0 -0
  141. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/js/statistics.js +0 -0
  142. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/js/structures.js +0 -0
  143. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/vendor/datatables/plugins/dataTables.rowGroup.min.js +0 -0
  144. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/vendor/datatables/plugins/datetime.js +0 -0
  145. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/vendor/datatables/plugins/filterDropDown.min.js +0 -0
  146. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/vendor/datatables/plugins/rowGroup.bootstrap.min.css +0 -0
  147. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/static/structures/vendor/datatables/plugins/rowGroup.dataTables.min.css +0 -0
  148. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tasks.py +0 -0
  149. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/templates/structures/base.html +0 -0
  150. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/templates/structures/modals/fitting_assets.html +0 -0
  151. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/templates/structures/modals/fitting_gfx.html +0 -0
  152. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/templates/structures/modals/poco_details.html +0 -0
  153. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/templates/structures/modals/starbase_detail.html +0 -0
  154. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/templates/structures/modals/structure_details.html +0 -0
  155. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/templates/structures/modals/tab_general_detail.html +0 -0
  156. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/templates/structures/modals/tab_services_detail.html +0 -0
  157. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/templates/structures/partials/menu.html +0 -0
  158. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/templates/structures/partials/public/poco_list.html +0 -0
  159. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/templates/structures/partials/statistics/structure_summary.html +0 -0
  160. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/templates/structures/partials/structures/active_tags.html +0 -0
  161. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/templates/structures/partials/structures/jump_gates_list.html +0 -0
  162. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/templates/structures/partials/structures/poco_list.html +0 -0
  163. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/templates/structures/partials/structures/starbase_list.html +0 -0
  164. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/templates/structures/partials/structures/structure_list.html +0 -0
  165. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/templates/structures/public.html +0 -0
  166. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/templates/structures/statistics.html +0 -0
  167. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/templates/structures/structures.html +0 -0
  168. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/templates/structures/templatetags/detail_title.html +0 -0
  169. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/templates/structures/templatetags/list_asset.html +0 -0
  170. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/templates/structures/templatetags/list_item.html +0 -0
  171. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/templates/structures/templatetags/list_tax_item.html +0 -0
  172. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/templates/structures/templatetags/list_title.html +0 -0
  173. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/templatetags/__init__.py +0 -0
  174. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/templatetags/structures.py +0 -0
  175. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/__init__.py +0 -0
  176. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/core/__init__.py +0 -0
  177. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/core/notification_embeds/__init__.py +0 -0
  178. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/core/notification_embeds/test_helpers.py +0 -0
  179. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/core/notification_embeds/test_main.py +0 -0
  180. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/core/test_notification_structuretimers.py +0 -0
  181. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/core/test_notification_types.py +0 -0
  182. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/core/test_notifications_timerboard.py +0 -0
  183. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/core/test_serializers.py +0 -0
  184. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/core/test_sovereignty.py +0 -0
  185. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/core/test_starbases.py +0 -0
  186. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/integration/__init__.py +0 -0
  187. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/models/__init__.py +0 -0
  188. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/models/test_eveuniverse.py +0 -0
  189. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/models/test_notifications_1.py +0 -0
  190. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/models/test_notifications_2.py +0 -0
  191. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/models/test_notifications_3.py +0 -0
  192. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/models/test_notifications_discord.py +0 -0
  193. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/models/test_owners_2.py +0 -0
  194. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/models/test_owners_3.py +0 -0
  195. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/models/test_owners_5.py +0 -0
  196. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/models/test_structures.py +0 -0
  197. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/test_helpers.py +0 -0
  198. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/test_managers_1.py +0 -0
  199. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/test_tasks.py +0 -0
  200. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/testdata/__init__.py +0 -0
  201. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/testdata/create_eveuniverse.py +0 -0
  202. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/testdata/entities.json +0 -0
  203. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/testdata/esi_data.json +0 -0
  204. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/testdata/eveuniverse.json +0 -0
  205. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/testdata/generate_notifications.py +0 -0
  206. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/testdata/generate_notifications_2.py +0 -0
  207. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/testdata/generate_structures.py +0 -0
  208. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/testdata/helpers.py +0 -0
  209. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/testdata/load_eveuniverse.py +0 -0
  210. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/testdata/tasks_loadtest.py +0 -0
  211. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/testdata/test_generate_structures.py +0 -0
  212. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/views/__init__.py +0 -0
  213. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/views/test_public.py +0 -0
  214. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/views/test_statistics.py +0 -0
  215. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/tests/views/utils.py +0 -0
  216. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/views/__init__.py +0 -0
  217. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/views/common.py +0 -0
  218. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/views/public.py +0 -0
  219. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/views/statistics.py +0 -0
  220. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/webhooks/__init__.py +0 -0
  221. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/webhooks/core.py +0 -0
  222. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/webhooks/managers.py +0 -0
  223. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/webhooks/models.py +0 -0
  224. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/webhooks/tests/__init__.py +0 -0
  225. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/webhooks/tests/test_core.py +0 -0
  226. {aa_structures-2.9.1 → aa_structures-2.11.0}/structures/webhooks/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: aa-structures
3
- Version: 2.9.1
3
+ Version: 2.11.0
4
4
  Summary: App for managing Eve Online structures with Alliance Auth.
5
5
  Author-email: Erik Kalkoken <kalkoken87@gmail.com>
6
6
  Requires-Python: >=3.8
@@ -3,5 +3,5 @@
3
3
  # pylint: disable = invalid-name
4
4
  default_app_config = "structures.apps.StructuresConfig"
5
5
 
6
- __version__ = "2.9.1"
6
+ __version__ = "2.11.0"
7
7
  __title__ = "Structures"
@@ -348,6 +348,29 @@ class OwnerCharacterAdminInline(admin.TabularInline):
348
348
  return False
349
349
 
350
350
 
351
+ class DisabledCharactersFilter(admin.SimpleListFilter):
352
+ title = _("has disabled characters")
353
+ parameter_name = "has_disabled_characters"
354
+
355
+ def lookups(self, request, model_admin):
356
+ return (
357
+ ("yes", _("yes")),
358
+ ("no", _("no")),
359
+ )
360
+
361
+ def queryset(self, request, queryset):
362
+ """Return the filtered queryset"""
363
+ if self.value() == "yes":
364
+ return queryset.annotate_characters_count().filter(
365
+ characters_disabled_count__gt=0
366
+ )
367
+ if self.value() == "no":
368
+ return queryset.annotate_characters_count().filter(
369
+ characters_disabled_count=0
370
+ )
371
+ return queryset
372
+
373
+
351
374
  @admin.register(Owner)
352
375
  class OwnerAdmin(admin.ModelAdmin):
353
376
  list_display = (
@@ -364,6 +387,7 @@ class OwnerAdmin(admin.ModelAdmin):
364
387
  list_filter = (
365
388
  "is_active",
366
389
  "is_up",
390
+ DisabledCharactersFilter,
367
391
  ("corporation__alliance", admin.RelatedOnlyFieldListFilter),
368
392
  "has_default_pings_enabled",
369
393
  "is_alliance_main",
@@ -376,6 +400,7 @@ class OwnerAdmin(admin.ModelAdmin):
376
400
  "fetch_notifications",
377
401
  "deactivate_owners",
378
402
  "activate_owners",
403
+ "reset_characters",
379
404
  )
380
405
  inlines = (OwnerCharacterAdminInline,)
381
406
  filter_horizontal = ("ping_groups", "webhooks")
@@ -485,9 +510,13 @@ class OwnerAdmin(admin.ModelAdmin):
485
510
  def has_add_permission(self, request):
486
511
  return False
487
512
 
488
- @admin.display(ordering="characters_count_2", description=_("characters"))
489
- def _characters(self, obj: Owner) -> int:
490
- return obj.characters_count_2
513
+ @admin.display(ordering="characters_enabled_count", description=_("characters"))
514
+ def _characters(self, obj: Owner) -> str:
515
+ enabled = obj.characters_enabled_count
516
+ disabled = obj.characters_disabled_count
517
+ if not disabled:
518
+ return enabled
519
+ return f"{enabled} ({disabled})"
491
520
 
492
521
  @admin.display(description=_("default pings"), boolean=True)
493
522
  def _has_default_pings_enabled(self, obj: Owner):
@@ -549,6 +578,16 @@ class OwnerAdmin(admin.ModelAdmin):
549
578
  queryset.update(is_active=False)
550
579
  self.message_user(request, _("Deactivated %d owners") % queryset.count())
551
580
 
581
+ @admin.action(description=_("Reset disabled characters for selected owners"))
582
+ def reset_characters(self, request, queryset):
583
+ owner_pks = queryset.values_list("pk", flat=True)
584
+ OwnerCharacter.objects.filter(
585
+ owner__pk__in=list(owner_pks), is_enabled=False
586
+ ).update(is_enabled=True, disabled_reason="", error_count=0)
587
+ self.message_user(
588
+ request, _("Characters have been reset for %d owners") % len(owner_pks)
589
+ )
590
+
552
591
  @admin.action(description=_("Update all from EVE server for selected owners"))
553
592
  def update_all(self, request, queryset):
554
593
  for obj in queryset:
@@ -631,7 +670,7 @@ class OwnerAdmin(admin.ModelAdmin):
631
670
  def _assets_last_update_fresh(self, obj: Owner) -> bool:
632
671
  return obj.is_assets_sync_fresh
633
672
 
634
- @admin.action(description=_("structures Count"))
673
+ @admin.display(description=_("structures Count"))
635
674
  def _structures_count(self, obj: Owner) -> int:
636
675
  return obj.structures.count()
637
676
 
@@ -55,7 +55,7 @@ STRUCTURES_FEATURE_STARBASES = clean_setting("STRUCTURES_FEATURE_STARBASES", Tru
55
55
  STRUCTURES_ESI_DIRECTOR_ERROR_MAX_RETRIES = clean_setting(
56
56
  "STRUCTURES_ESI_DIRECTOR_ERROR_MAX_RETRIES", 3
57
57
  )
58
- """Max retries before a character is deleted when ESI claims the character
58
+ """Max retries before a character is disabled when ESI claims the character
59
59
  is not a director (Since this sometimes is reported wrongly by ESI).
60
60
  """
61
61
 
@@ -32,4 +32,9 @@ def register_menu():
32
32
 
33
33
  @hooks.register("url_hook")
34
34
  def register_urls():
35
- return UrlHook(urls, "structures", r"^structures/")
35
+ return UrlHook(
36
+ urls,
37
+ "structures",
38
+ r"^structures/",
39
+ excluded_views=["structures.views.status.service_status"],
40
+ )
@@ -181,14 +181,27 @@ GeneratedNotificationManager = GeneratedNotificationManagerBase.from_queryset(
181
181
 
182
182
  class OwnerQuerySet(models.QuerySet):
183
183
  def annotate_characters_count(self) -> models.QuerySet:
184
- """Add character count annotation."""
185
- return self.annotate(
186
- characters_count_2=Count(
184
+ """Add character count annotations."""
185
+ qs = self.annotate(
186
+ characters_enabled_count=Count(
187
+ "characters",
188
+ filter=Q(
189
+ characters__character_ownership__isnull=False,
190
+ characters__is_enabled=True,
191
+ ),
192
+ distinct=True,
193
+ )
194
+ ).annotate(
195
+ characters_disabled_count=Count(
187
196
  "characters",
188
- filter=Q(characters__character_ownership__isnull=False),
197
+ filter=Q(
198
+ characters__character_ownership__isnull=False,
199
+ characters__is_enabled=False,
200
+ ),
189
201
  distinct=True,
190
202
  )
191
203
  )
204
+ return qs
192
205
 
193
206
  def structures_last_updated(self) -> Optional[dt.datetime]:
194
207
  """Date/time when structures were last updated for any of the active owners."""
@@ -0,0 +1,27 @@
1
+ # Generated by Django 4.0.10 on 2024-06-23 14:26
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ("structures", "0005_add_notification_types"),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.AddField(
14
+ model_name="ownercharacter",
15
+ name="disabled_reason",
16
+ field=models.TextField(default=""),
17
+ ),
18
+ migrations.AddField(
19
+ model_name="ownercharacter",
20
+ name="is_enabled",
21
+ field=models.BooleanField(
22
+ default=True,
23
+ help_text="Disabled characters are not used for syncing owners",
24
+ verbose_name="is enabled",
25
+ ),
26
+ ),
27
+ ]
@@ -338,12 +338,15 @@ class Owner(models.Model):
338
338
  f"Character {character_ownership.character} does not belong "
339
339
  "to owner corporation."
340
340
  )
341
- obj, _ = self.characters.get_or_create(character_ownership=character_ownership)
341
+ obj: OwnerCharacter = self.characters.get_or_create(
342
+ character_ownership=character_ownership
343
+ )[0]
344
+ obj.reset()
342
345
  return obj
343
346
 
344
- def characters_count(self) -> int:
347
+ def valid_characters_count(self) -> int:
345
348
  """Count of valid owner characters."""
346
- return self.characters.count()
349
+ return self.characters.filter(is_enabled=True).count()
347
350
 
348
351
  def has_sov(self, eve_solar_system: EveSolarSystem) -> bool:
349
352
  """Determine whether this owner has sov in the given solar system."""
@@ -351,42 +354,31 @@ class Owner(models.Model):
351
354
  eve_solar_system=eve_solar_system, corporation=self.corporation
352
355
  )
353
356
 
354
- def delete_character(
357
+ def disable_character(
355
358
  self,
356
359
  character: "OwnerCharacter",
357
- error: str,
358
- level: str = "warning",
360
+ reason: str,
359
361
  max_allowed_errors: int = 0,
360
362
  ) -> None:
361
- """Delete character and notify it's owner and admin about the reason
363
+ """Disable character and notify it's owner and admins about it.
362
364
 
363
365
  Args:
364
- - character: Character this error refers to
365
- - error: Error text
366
- - level: context level for the notification
367
- - max_error: how many errors are permitted before character is deleted
366
+ - character: Character to disable
367
+ - reason: User friendly reason for the deletion
368
+ - max_allowed_errors: Maximum number of allowed errors for this type of error
368
369
  """
369
370
  if character.error_count < max_allowed_errors:
370
- logger.warning(
371
- (
372
- "%s: Character encountered an error and will be deleted "
373
- "if this occurs more often (%d/%d): %s"
374
- ),
375
- character,
376
- character.error_count + 1,
377
- max_allowed_errors,
378
- error,
379
- )
380
- with transaction.atomic():
381
- character.error_count = F("error_count") + 1
382
- character.save(update_fields=["error_count"])
371
+ character.increase_error_count()
383
372
  return
384
373
 
385
- title = f"{__title__}: {self}: Invalid character has been removed"
374
+ character.disable(reason)
375
+
376
+ title = f"{__title__}: {self}: Character has been disabled"
377
+ level = "warning"
386
378
  message = (
387
- f"{character.character_ownership}: {error}\n"
388
- "The character has been removed. "
389
- "Please add a new character to restore the previous service level."
379
+ f"{character.character_ownership}: {reason}\n"
380
+ "This character caused too many errors and has been disabled. "
381
+ "Administrator action is required to resolve this issue."
390
382
  )
391
383
  notify(
392
384
  user=character.character_ownership.user,
@@ -394,15 +386,44 @@ class Owner(models.Model):
394
386
  message=message,
395
387
  level=level,
396
388
  )
397
- if self.characters.count() == 1:
389
+ if not self.valid_characters_count():
398
390
  message += (
399
391
  " This owner has no configured characters anymore "
400
392
  "and it's services are now down."
401
393
  )
402
394
  level = "danger"
395
+
403
396
  notify_admins(title=f"FYI: {title}", message=message, level=level)
397
+
398
+ def delete_character(self, character: "OwnerCharacter", reason: str) -> None:
399
+ """Delete character and notify it's owner and admin about the reason
400
+
401
+ Args:
402
+ - character: Character this error refers to
403
+ - reason: User friendly reason for the deletion
404
+ """
404
405
  character.delete()
405
406
 
407
+ title = f"{__title__}: {self}: Invalid character has been removed"
408
+ level = "warning"
409
+ message = (
410
+ f"{character.character_ownership}: {reason}\n"
411
+ "Your character is no longer valid for syncing this owner and has been removed. "
412
+ )
413
+ notify(
414
+ user=character.character_ownership.user,
415
+ title=title,
416
+ message=message,
417
+ level=level,
418
+ )
419
+ if not self.valid_characters_count():
420
+ message += (
421
+ " This owner has no valid characters anymore "
422
+ "and it's services are now down."
423
+ )
424
+ level = "danger"
425
+ notify_admins(title=f"FYI: {title}", message=message, level=level)
426
+
406
427
  def _rotate_character(
407
428
  self,
408
429
  character: "OwnerCharacter",
@@ -421,7 +442,7 @@ class Owner(models.Model):
421
442
  )
422
443
  try:
423
444
  minimum_time_between_rotations = max(
424
- rotate_characters.esi_cache_duration / self.characters.count(),
445
+ rotate_characters.esi_cache_duration / self.valid_characters_count(),
425
446
  60,
426
447
  )
427
448
  except ZeroDivisionError:
@@ -453,14 +474,18 @@ class Owner(models.Model):
453
474
  if rotate_characters
454
475
  else "notifications_last_used_at"
455
476
  )
456
- for character in self.characters.order_by(order_by_last_used):
477
+ enabled_characters: models.QuerySet[OwnerCharacter] = self.characters.filter(
478
+ is_enabled=True
479
+ ).order_by(order_by_last_used)
480
+ for character in enabled_characters:
457
481
  if (
458
482
  character.character_ownership.character.corporation_id
459
483
  != self.corporation.corporation_id
460
484
  ):
485
+ corporation_name = self.corporation.corporation_name
461
486
  self.delete_character(
462
487
  character=character,
463
- error="Character does no longer belong to the owner's corporation.",
488
+ reason=f"Character is no longer a member of {corporation_name}",
464
489
  )
465
490
  continue
466
491
 
@@ -469,17 +494,17 @@ class Owner(models.Model):
469
494
  ):
470
495
  self.delete_character(
471
496
  character=character,
472
- error="Character does not have sufficient permission to sync.",
497
+ reason="Character no longer has permission to sync",
473
498
  )
474
499
  continue
475
500
 
476
501
  token = character.valid_token()
477
502
  if not token:
478
- self.delete_character(
479
- character=character,
480
- error="Character has no valid token for sync.",
503
+ self.disable_character(
504
+ character=character, reason="No valid token found for character"
481
505
  )
482
506
  continue
507
+
483
508
  found_character = character
484
509
  break # leave the for loop if we have found a valid token
485
510
 
@@ -797,6 +822,13 @@ class Owner(models.Model):
797
822
 
798
823
  Return True when successful, else False.
799
824
  """
825
+ try:
826
+ character: OwnerCharacter = self.characters.get(
827
+ character_ownership__character__character_id=token.character_id
828
+ )
829
+ except ObjectDoesNotExist:
830
+ return False
831
+
800
832
  structures = []
801
833
  try:
802
834
  starbases_data = (
@@ -824,21 +856,11 @@ class Owner(models.Model):
824
856
  self._store_raw_data("starbases", structures)
825
857
 
826
858
  except HTTPForbidden:
827
- try:
828
- character = self.characters.get(
829
- character_ownership__character__character_id=token.character_id
830
- )
831
- except ObjectDoesNotExist:
832
- pass
833
- else:
834
- self.delete_character(
835
- character=character,
836
- error=(
837
- "Character is not a director or CEO and therefore "
838
- "can not fetch starbases."
839
- ),
840
- max_allowed_errors=STRUCTURES_ESI_DIRECTOR_ERROR_MAX_RETRIES,
841
- )
859
+ self.disable_character(
860
+ character=character,
861
+ reason=("This character is not a director or CEO"),
862
+ max_allowed_errors=STRUCTURES_ESI_DIRECTOR_ERROR_MAX_RETRIES,
863
+ )
842
864
  return False
843
865
 
844
866
  except OSError as ex:
@@ -849,6 +871,7 @@ class Owner(models.Model):
849
871
  structures_qs=self.structures.filter_starbases(),
850
872
  new_structures=structures,
851
873
  )
874
+ character.reset_error_counter()
852
875
  return True
853
876
 
854
877
  def _store_updates_for_starbases(self, token, structures):
@@ -1337,6 +1360,12 @@ class OwnerCharacter(models.Model):
1337
1360
  verbose_name=_("error count"),
1338
1361
  help_text="Count of ESI errors which happened with this character.",
1339
1362
  )
1363
+ is_enabled = models.BooleanField(
1364
+ default=True,
1365
+ verbose_name=_("is enabled"),
1366
+ help_text=_("Disabled characters are not used for syncing owners"),
1367
+ )
1368
+ disabled_reason = models.TextField(default="")
1340
1369
  created_at = models.DateTimeField(auto_now_add=True)
1341
1370
 
1342
1371
  class Meta:
@@ -1369,3 +1398,27 @@ class OwnerCharacter(models.Model):
1369
1398
  .require_valid()
1370
1399
  .first()
1371
1400
  )
1401
+
1402
+ def reset(self) -> None:
1403
+ """Resets a disabled owner character."""
1404
+ self.is_enabled = True
1405
+ self.disabled_reason = ""
1406
+ self.error_count = 0
1407
+ self.save()
1408
+
1409
+ def reset_error_counter(self) -> None:
1410
+ """Reset the error counter"""
1411
+ self.error_count = 0
1412
+ self.save(update_fields=["error_count"])
1413
+
1414
+ def disable(self, reason: str = "") -> None:
1415
+ """Disables a character."""
1416
+ self.is_enabled = False
1417
+ self.disabled_reason = reason
1418
+ self.save()
1419
+
1420
+ def increase_error_count(self):
1421
+ """Increase error count of this character by one."""
1422
+ with transaction.atomic():
1423
+ self.error_count = F("error_count") + 1
1424
+ self.save(update_fields=["error_count"])
@@ -16,8 +16,7 @@ from app_utils.esi_testing import EsiClientStub, EsiEndpoint
16
16
  from structures import tasks
17
17
  from structures.core.notification_types import NotificationType
18
18
  from structures.models import Structure
19
-
20
- from ..testdata.factories import (
19
+ from structures.tests.testdata.factories import (
21
20
  EveEntityAllianceFactory,
22
21
  EveEntityCorporationFactory,
23
22
  NotificationFactory,
@@ -28,7 +27,7 @@ from ..testdata.factories import (
28
27
  WebhookFactory,
29
28
  datetime_to_esi,
30
29
  )
31
- from ..testdata.load_eveuniverse import load_eveuniverse
30
+ from structures.tests.testdata.load_eveuniverse import load_eveuniverse
32
31
 
33
32
  if "structuretimers" in app_labels():
34
33
  from structuretimers.models import Timer as StructureTimer
@@ -5,7 +5,7 @@ from django.urls import reverse
5
5
 
6
6
  from app_utils.testing import add_character_to_user
7
7
 
8
- from ..testdata.factories import (
8
+ from structures.tests.testdata.factories import (
9
9
  EveCharacterFactory,
10
10
  JumpGateFactory,
11
11
  OwnerFactory,
@@ -15,7 +15,7 @@ from ..testdata.factories import (
15
15
  UserMainBasicFactory,
16
16
  UserMainDefaultFactory,
17
17
  )
18
- from ..testdata.load_eveuniverse import load_eveuniverse
18
+ from structures.tests.testdata.load_eveuniverse import load_eveuniverse
19
19
 
20
20
  STRUCTURES_PATH = "structures.views.structures"
21
21
  PUBLIC_PATH = "structures.views.public"