firefighter-incident 0.0.26__tar.gz → 0.0.27__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 (533) hide show
  1. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/PKG-INFO +1 -1
  2. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/_version.py +2 -2
  3. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/confluence/models.py +16 -1
  4. firefighter_incident-0.0.27/firefighter/incidents/management/__init__.py +1 -0
  5. firefighter_incident-0.0.27/firefighter/incidents/management/commands/__init__.py +1 -0
  6. firefighter_incident-0.0.27/firefighter/incidents/management/commands/backdate_incident_mitigated.py +94 -0
  7. firefighter_incident-0.0.27/firefighter/incidents/management/commands/test_postmortem_reminders.py +113 -0
  8. firefighter_incident-0.0.27/firefighter/incidents/migrations/0030_add_mitigated_at_field.py +22 -0
  9. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/models/incident.py +43 -8
  10. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/jira_app/service_postmortem.py +13 -0
  11. firefighter_incident-0.0.27/firefighter/jira_app/signals/postmortem_created.py +217 -0
  12. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/messages/slack_messages.py +162 -0
  13. firefighter_incident-0.0.27/firefighter/slack/migrations/0009_add_postmortem_reminder_periodic_task.py +60 -0
  14. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/rules.py +22 -0
  15. firefighter_incident-0.0.27/firefighter/slack/tasks/send_postmortem_reminders.py +127 -0
  16. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/modals/close.py +113 -3
  17. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/modals/closure_reason.py +39 -15
  18. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/modals/update_status.py +4 -4
  19. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_incidents/test_incident_urls.py +4 -0
  20. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_incidents/test_models/test_incident_model.py +109 -1
  21. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_incidents/test_views/test_incident_detail_view.py +4 -0
  22. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_slack/messages/test_slack_messages.py +4 -0
  23. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_slack/views/modals/test_close.py +4 -0
  24. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_slack/views/modals/test_closure_reason_modal.py +109 -26
  25. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_slack/views/modals/test_update_status.py +45 -51
  26. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/pyproject.toml +0 -2
  27. firefighter_incident-0.0.26/firefighter/jira_app/signals/postmortem_created.py +0 -155
  28. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/.gitignore +0 -0
  29. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/LICENSE +0 -0
  30. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/README.md +0 -0
  31. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/__init__.py +0 -0
  32. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/api/__init__.py +0 -0
  33. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/api/admin.py +0 -0
  34. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/api/apps.py +0 -0
  35. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/api/authentication.py +0 -0
  36. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/api/migrations/0001_initial.py +0 -0
  37. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/api/migrations/0002_alter_apitokenproxy_options.py +0 -0
  38. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/api/migrations/0003_alter_apitokenproxy_options.py +0 -0
  39. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/api/migrations/__init__.py +0 -0
  40. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/api/models.py +0 -0
  41. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/api/permissions.py +0 -0
  42. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/api/renderer.py +0 -0
  43. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/api/serializers.py +0 -0
  44. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/api/urls.py +0 -0
  45. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/api/views/__init__.py +0 -0
  46. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/api/views/_base.py +0 -0
  47. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/api/views/components.py +0 -0
  48. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/api/views/environments.py +0 -0
  49. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/api/views/groups.py +0 -0
  50. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/api/views/incident_cost_types.py +0 -0
  51. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/api/views/incident_costs.py +0 -0
  52. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/api/views/incidents.py +0 -0
  53. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/api/views/severities.py +0 -0
  54. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/components/__init__.py +0 -0
  55. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/components/avatar/__init__.py +0 -0
  56. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/components/avatar/avatar.html +0 -0
  57. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/components/avatar/avatar.py +0 -0
  58. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/components/card/__init__.py +0 -0
  59. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/components/card/card.html +0 -0
  60. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/components/card/card.py +0 -0
  61. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/components/export_button/__init__.py +0 -0
  62. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/components/export_button/export_button.html +0 -0
  63. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/components/export_button/export_button.py +0 -0
  64. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/components/form/__init__.py +0 -0
  65. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/components/form/form.html +0 -0
  66. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/components/form/form.py +0 -0
  67. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/components/form_field/__init__.py +0 -0
  68. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/components/form_field/form_field.html +0 -0
  69. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/components/form_field/form_field.py +0 -0
  70. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/components/messages/__init__.py +0 -0
  71. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/components/messages/messages.html +0 -0
  72. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/components/messages/messages.py +0 -0
  73. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/components/modal/__init__.py +0 -0
  74. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/components/modal/modal.html +0 -0
  75. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/components/modal/modal.py +0 -0
  76. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/confluence/__init__.py +0 -0
  77. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/confluence/admin.py +0 -0
  78. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/confluence/apps.py +0 -0
  79. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/confluence/client.py +0 -0
  80. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/confluence/management/__init__.py +0 -0
  81. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/confluence/management/commands/__init__.py +0 -0
  82. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/confluence/management/commands/sort_postmortems.py +0 -0
  83. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/confluence/management/commands/sort_runbooks.py +0 -0
  84. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/confluence/management/commands/sync_postmortems.py +0 -0
  85. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/confluence/management/commands/sync_runbooks.py +0 -0
  86. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/confluence/migrations/0001_initial_oss.py +0 -0
  87. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/confluence/migrations/__init__.py +0 -0
  88. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/confluence/serializers.py +0 -0
  89. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/confluence/service.py +0 -0
  90. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/confluence/signals/__init__.py +0 -0
  91. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/confluence/signals/incident_updated.py +0 -0
  92. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/confluence/tables.py +0 -0
  93. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/confluence/tasks/__init__.py +0 -0
  94. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/confluence/tasks/archive_postmortems.py +0 -0
  95. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/confluence/tasks/sort_runbooks.py +0 -0
  96. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/confluence/tasks/sync_pages_content.py +0 -0
  97. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/confluence/tasks/sync_postmortems.py +0 -0
  98. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/confluence/tasks/sync_runbooks.py +0 -0
  99. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/confluence/templates/oncall_team.xml +0 -0
  100. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/confluence/templates/pages/runbook_list.html +0 -0
  101. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/confluence/urls.py +0 -0
  102. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/confluence/utils.py +0 -0
  103. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/confluence/views/__init__.py +0 -0
  104. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/confluence/views/api.py +0 -0
  105. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/confluence/views/postmortem/__init__.py +0 -0
  106. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/confluence/views/postmortem/postmortem_detail.py +0 -0
  107. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/confluence/views/runbook/__init__.py +0 -0
  108. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/confluence/views/runbook/runbook_list.py +0 -0
  109. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/firefighter/__init__.py +0 -0
  110. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/firefighter/admin.py +0 -0
  111. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/firefighter/apps.py +0 -0
  112. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/firefighter/asgi.py +0 -0
  113. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/firefighter/celery_client.py +0 -0
  114. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/firefighter/fields_forms_widgets.py +0 -0
  115. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/firefighter/filters.py +0 -0
  116. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/firefighter/formats/__init__.py +0 -0
  117. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/firefighter/formats/en/__init__.py +0 -0
  118. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/firefighter/formats/en/formats.py +0 -0
  119. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/firefighter/http_client.py +0 -0
  120. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/firefighter/management/__init__.py +0 -0
  121. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/firefighter/management/commands/__init__.py +0 -0
  122. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/firefighter/management/commands/task.py +0 -0
  123. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/firefighter/middleware.py +0 -0
  124. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/firefighter/settings/__init__.py +0 -0
  125. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/firefighter/settings/components/__init__.py +0 -0
  126. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/firefighter/settings/components/api.py +0 -0
  127. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/firefighter/settings/components/caches.py +0 -0
  128. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/firefighter/settings/components/celery.py +0 -0
  129. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/firefighter/settings/components/common.py +0 -0
  130. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/firefighter/settings/components/confluence.py +0 -0
  131. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/firefighter/settings/components/jira_app.py +0 -0
  132. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/firefighter/settings/components/logging.py +0 -0
  133. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/firefighter/settings/components/pagerduty.py +0 -0
  134. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/firefighter/settings/components/raid.py +0 -0
  135. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/firefighter/settings/components/slack.py +0 -0
  136. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/firefighter/settings/environments/__init__.py +0 -0
  137. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/firefighter/settings/environments/dev.py +0 -0
  138. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/firefighter/settings/environments/prod.py +0 -0
  139. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/firefighter/settings/settings_builder.py +0 -0
  140. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/firefighter/settings/settings_utils.py +0 -0
  141. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/firefighter/sso.py +0 -0
  142. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/firefighter/tables_utils.py +0 -0
  143. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/firefighter/templates/admin/base.html +0 -0
  144. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/firefighter/templates/admin/login.html +0 -0
  145. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/firefighter/templates/admin/send_message_conversation.html +0 -0
  146. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/firefighter/templates/robots.txt +0 -0
  147. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/firefighter/urls.py +0 -0
  148. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/firefighter/utils.py +0 -0
  149. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/firefighter/views.py +0 -0
  150. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/firefighter/wsgi.py +0 -0
  151. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/__init__.py +0 -0
  152. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/admin.py +0 -0
  153. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/apps.py +0 -0
  154. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/enums.py +0 -0
  155. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/factories.py +0 -0
  156. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/forms/__init__.py +0 -0
  157. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/forms/close_incident.py +0 -0
  158. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/forms/closure_reason.py +0 -0
  159. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/forms/create_incident.py +0 -0
  160. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/forms/edit.py +0 -0
  161. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/forms/select_impact.py +0 -0
  162. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/forms/unified_incident.py +0 -0
  163. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/forms/update_key_events.py +0 -0
  164. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/forms/update_roles.py +0 -0
  165. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/forms/update_status.py +0 -0
  166. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/forms/utils.py +0 -0
  167. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/menus.py +0 -0
  168. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/migrations/0001_initial_oss.py +0 -0
  169. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/migrations/0002_alter_severity_name_alter_user_password_featureteam.py +0 -0
  170. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/migrations/0003_delete_featureteam.py +0 -0
  171. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/migrations/0004_incidentupdate_environment.py +0 -0
  172. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/migrations/0005_enable_from_p1_to_p5_priority.py +0 -0
  173. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/migrations/0006_update_group_names.py +0 -0
  174. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/migrations/0007_update_component_name.py +0 -0
  175. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/migrations/0008_impact_level.py +0 -0
  176. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/migrations/0009_update_sla.py +0 -0
  177. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/migrations/0010_update_components.py +0 -0
  178. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/migrations/0011_update_incidents.py +0 -0
  179. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/migrations/0012_alter_impactlevel.py +0 -0
  180. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/migrations/0013_add_missing_component.py +0 -0
  181. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/migrations/0014_update_components_slack_groups.py +0 -0
  182. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/migrations/0015_update_impact_level.py +0 -0
  183. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/migrations/0016_update_business_incidents_and_level.py +0 -0
  184. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/migrations/0017_reorder_impact_types.py +0 -0
  185. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/migrations/0018_update_impactlevel_names.py +0 -0
  186. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/migrations/0019_set_security_components_private.py +0 -0
  187. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/migrations/0020_create_incident_category_model.py +0 -0
  188. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/migrations/0021_copy_component_data_to_incident_category.py +0 -0
  189. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/migrations/0022_add_incident_category_fields.py +0 -0
  190. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/migrations/0023_populate_incident_category_references.py +0 -0
  191. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/migrations/0024_remove_component_fields_and_model.py +0 -0
  192. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/migrations/0025_make_incident_category_required.py +0 -0
  193. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/migrations/0026_alter_incidentcategory_options_and_more.py +0 -0
  194. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/migrations/0027_add_closure_fields.py +0 -0
  195. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/migrations/0028_add_closure_reason_constraint.py +0 -0
  196. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/migrations/0029_add_custom_fields_to_incident.py +0 -0
  197. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/migrations/__init__.py +0 -0
  198. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/models/__init__.py +0 -0
  199. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/models/environment.py +0 -0
  200. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/models/group.py +0 -0
  201. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/models/impact.py +0 -0
  202. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/models/incident_category.py +0 -0
  203. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/models/incident_cost.py +0 -0
  204. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/models/incident_cost_type.py +0 -0
  205. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/models/incident_membership.py +0 -0
  206. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/models/incident_role_type.py +0 -0
  207. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/models/incident_update.py +0 -0
  208. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/models/metric_type.py +0 -0
  209. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/models/milestone_type.py +0 -0
  210. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/models/priority.py +0 -0
  211. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/models/severity.py +0 -0
  212. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/models/user.py +0 -0
  213. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/signals.py +0 -0
  214. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/static/css/incident.css +0 -0
  215. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/static/css/main.css +0 -0
  216. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/static/css/main.min.css +0 -0
  217. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/static/css/tailwind.css +0 -0
  218. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/static/img/favicon/android-chrome-192x192.png +0 -0
  219. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/static/img/favicon/android-chrome-512x512.png +0 -0
  220. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/static/img/favicon/apple-touch-icon.png +0 -0
  221. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/static/img/favicon/favicon-16x16.png +0 -0
  222. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/static/img/favicon/favicon-32x32.png +0 -0
  223. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/static/img/favicon/favicon.ico +0 -0
  224. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/static/img/favicon/site.webmanifest +0 -0
  225. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/static/img/gameday.png +0 -0
  226. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/static/img/logo-firefighter.png +0 -0
  227. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/static/img/p1.png +0 -0
  228. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/static/img/p2.png +0 -0
  229. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/static/img/p3.png +0 -0
  230. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/static/img/p4.png +0 -0
  231. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/static/img/p5.png +0 -0
  232. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/static/js/main.js +0 -0
  233. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/static/js/main.min.js +0 -0
  234. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/tables.py +0 -0
  235. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/tasks/__init__.py +0 -0
  236. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/tasks/updateoncall.py +0 -0
  237. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/templates/incidents/errors/base.html +0 -0
  238. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/templates/incidents/filter.html +0 -0
  239. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/templates/incidents/table/priority_column.html +0 -0
  240. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/templates/incidents/table/status_column.html +0 -0
  241. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/templates/incidents/table.html +0 -0
  242. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/templates/incidents/widgets/form_container.html +0 -0
  243. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/templates/incidents/widgets/grouped_checkbox_nested.html +0 -0
  244. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/templates/incidents/widgets/input_option.html +0 -0
  245. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/templates/layouts/index.html +0 -0
  246. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/templates/layouts/partials/created_at_help.html +0 -0
  247. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/templates/layouts/partials/environment_pill.html +0 -0
  248. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/templates/layouts/partials/footer.html +0 -0
  249. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/templates/layouts/partials/header.html +0 -0
  250. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/templates/layouts/partials/incident_card.html +0 -0
  251. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/templates/layouts/partials/incident_metrics.html +0 -0
  252. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/templates/layouts/partials/incident_timeline.html +0 -0
  253. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/templates/layouts/partials/incident_update_key_events_view.html +0 -0
  254. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/templates/layouts/partials/incident_update_key_events_view_modal.html +0 -0
  255. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/templates/layouts/partials/partial_table_list_paginated.html +0 -0
  256. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/templates/layouts/partials/priority_icon.html +0 -0
  257. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/templates/layouts/partials/priority_pill.html +0 -0
  258. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/templates/layouts/partials/status_pill.html +0 -0
  259. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/templates/layouts/partials/table.html +0 -0
  260. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/templates/layouts/partials/user_card.html +0 -0
  261. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/templates/layouts/partials/user_tooltip.html +0 -0
  262. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/templates/layouts/view_filters.html +0 -0
  263. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/templates/pages/dashboard.html +0 -0
  264. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/templates/pages/docs_metrics.html +0 -0
  265. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/templates/pages/incident_category_detail.html +0 -0
  266. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/templates/pages/incident_category_list.html +0 -0
  267. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/templates/pages/incident_create.html +0 -0
  268. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/templates/pages/incident_detail.html +0 -0
  269. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/templates/pages/incident_list.html +0 -0
  270. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/templates/pages/incident_role_types_detail.html +0 -0
  271. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/templates/pages/incident_role_types_list.html +0 -0
  272. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/templates/pages/incident_statistics.html +0 -0
  273. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/templates/pages/incident_statistics_partial.html +0 -0
  274. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/templates/pages/incident_update_key_events_form.html +0 -0
  275. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/templates/pages/user_detail.html +0 -0
  276. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/urls.py +0 -0
  277. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/views/__init__.py +0 -0
  278. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/views/components/__init__.py +0 -0
  279. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/views/components/details.py +0 -0
  280. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/views/components/list.py +0 -0
  281. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/views/date_filter.py +0 -0
  282. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/views/date_utils.py +0 -0
  283. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/views/docs/__init__.py +0 -0
  284. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/views/docs/metrics.py +0 -0
  285. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/views/docs/role_types.py +0 -0
  286. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/views/errors.py +0 -0
  287. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/views/reports.py +0 -0
  288. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/views/users/__init__.py +0 -0
  289. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/views/users/details.py +0 -0
  290. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/incidents/views/views.py +0 -0
  291. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/jira_app/__init__.py +0 -0
  292. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/jira_app/admin.py +0 -0
  293. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/jira_app/apps.py +0 -0
  294. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/jira_app/client.py +0 -0
  295. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/jira_app/management/__init__.py +0 -0
  296. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/jira_app/management/commands/__init__.py +0 -0
  297. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/jira_app/migrations/0001_initial_oss.py +0 -0
  298. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/jira_app/migrations/0002_add_jira_postmortem_model.py +0 -0
  299. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/jira_app/migrations/__init__.py +0 -0
  300. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/jira_app/models.py +0 -0
  301. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/jira_app/signals/__init__.py +0 -0
  302. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/jira_app/signals/incident_key_events_updated.py +0 -0
  303. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/jira_app/tasks/__init__.py +0 -0
  304. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/jira_app/tasks/sync_users_jira.py +0 -0
  305. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/jira_app/templates/jira/postmortem/impact.txt +0 -0
  306. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/jira_app/templates/jira/postmortem/incident_summary.txt +0 -0
  307. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/jira_app/templates/jira/postmortem/mitigation_actions.txt +0 -0
  308. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/jira_app/templates/jira/postmortem/root_causes.txt +0 -0
  309. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/jira_app/templates/jira/postmortem/timeline.txt +0 -0
  310. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/jira_app/types.py +0 -0
  311. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/jira_app/utils.py +0 -0
  312. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/logging/__init__.py +0 -0
  313. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/logging/custom_json_formatter.py +0 -0
  314. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/logging/pretty_formatter.py +0 -0
  315. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/pagerduty/__init__.py +0 -0
  316. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/pagerduty/admin.py +0 -0
  317. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/pagerduty/apps.py +0 -0
  318. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/pagerduty/client.py +0 -0
  319. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/pagerduty/forms/__init__.py +0 -0
  320. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/pagerduty/forms/create_pagerduty_incident.py +0 -0
  321. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/pagerduty/migrations/0001_initial_oss.py +0 -0
  322. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/pagerduty/migrations/__init__.py +0 -0
  323. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/pagerduty/models.py +0 -0
  324. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/pagerduty/service.py +0 -0
  325. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/pagerduty/signals/__init__.py +0 -0
  326. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/pagerduty/signals/get_invites_from_pagerduty.py +0 -0
  327. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/pagerduty/signals/incident_channel_done_oncall.py +0 -0
  328. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/pagerduty/tasks/__init__.py +0 -0
  329. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/pagerduty/tasks/fetch_oncall.py +0 -0
  330. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/pagerduty/tasks/fetch_services.py +0 -0
  331. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/pagerduty/tasks/fetch_users.py +0 -0
  332. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/pagerduty/tasks/trigger_oncall.py +0 -0
  333. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/pagerduty/templates/pages/oncall_list.html +0 -0
  334. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/pagerduty/templates/pages/oncall_trigger.html +0 -0
  335. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/pagerduty/templates/partials/trigger_oncall_form_view.html +0 -0
  336. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/pagerduty/templates/partials/trigger_oncall_form_view_modal.html +0 -0
  337. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/pagerduty/urls.py +0 -0
  338. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/pagerduty/views/__init__.py +0 -0
  339. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/pagerduty/views/oncall_list.py +0 -0
  340. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/pagerduty/views/oncall_trigger.py +0 -0
  341. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/raid/__init__.py +0 -0
  342. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/raid/admin.py +0 -0
  343. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/raid/apps.py +0 -0
  344. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/raid/client.py +0 -0
  345. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/raid/forms.py +0 -0
  346. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/raid/messages.py +0 -0
  347. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/raid/migrations/0001_initial_oss.py +0 -0
  348. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/raid/migrations/0002_featureteam_remove_qualifierrotation_jira_user_and_more.py +0 -0
  349. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/raid/migrations/0003_delete_raidarea.py +0 -0
  350. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/raid/migrations/__init__.py +0 -0
  351. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/raid/models.py +0 -0
  352. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/raid/resources.py +0 -0
  353. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/raid/serializers.py +0 -0
  354. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/raid/service.py +0 -0
  355. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/raid/signals/__init__.py +0 -0
  356. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/raid/signals/incident_updated.py +0 -0
  357. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/raid/tasks/__init__.py +0 -0
  358. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/raid/types.py +0 -0
  359. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/raid/urls.py +0 -0
  360. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/raid/utils.py +0 -0
  361. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/raid/views/__init__.py +0 -0
  362. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/__init__.py +0 -0
  363. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/admin.py +0 -0
  364. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/apps.py +0 -0
  365. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/factories.py +0 -0
  366. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/forms/__init__.py +0 -0
  367. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/forms/sos_form.py +0 -0
  368. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/management/__init__.py +0 -0
  369. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/management/commands/__init__.py +0 -0
  370. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/management/commands/generate_manifest.py +0 -0
  371. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/management/commands/switch_test_users.py +0 -0
  372. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/messages/__init__.py +0 -0
  373. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/messages/base.py +0 -0
  374. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/migrations/0001_initial_oss.py +0 -0
  375. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/migrations/0002_usergroup_tag.py +0 -0
  376. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/migrations/0003_alter_usergroup_tag.py +0 -0
  377. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/migrations/0004_alter_usergroup_components.py +0 -0
  378. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/migrations/0005_add_incident_categories_fields.py +0 -0
  379. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/migrations/0006_copy_components_to_incident_categories.py +0 -0
  380. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/migrations/0007_remove_components_fields.py +0 -0
  381. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/migrations/0008_alter_conversation_incident_categories_and_more.py +0 -0
  382. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/migrations/__init__.py +0 -0
  383. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/models/__init__.py +0 -0
  384. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/models/conversation.py +0 -0
  385. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/models/incident_channel.py +0 -0
  386. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/models/message.py +0 -0
  387. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/models/sos.py +0 -0
  388. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/models/user.py +0 -0
  389. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/models/user_group.py +0 -0
  390. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/signals/__init__.py +0 -0
  391. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/signals/create_incident_conversation.py +0 -0
  392. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/signals/get_users.py +0 -0
  393. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/signals/handle_incident_channel_done.py +0 -0
  394. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/signals/incident_closed.py +0 -0
  395. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/signals/incident_updated.py +0 -0
  396. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/signals/postmortem_created.py +0 -0
  397. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/signals/roles_reminders.py +0 -0
  398. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/slack_app.py +0 -0
  399. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/slack_incident_context.py +0 -0
  400. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/slack_templating.py +0 -0
  401. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/tasks/__init__.py +0 -0
  402. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/tasks/fetch_conversations_members.py +0 -0
  403. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/tasks/reminder_postmortem.py +0 -0
  404. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/tasks/send_message.py +0 -0
  405. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/tasks/send_reminders.py +0 -0
  406. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/tasks/sync_users.py +0 -0
  407. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/tasks/update_usergroups_members.py +0 -0
  408. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/tasks/update_users.py +0 -0
  409. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/urls.py +0 -0
  410. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/utils.py +0 -0
  411. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/__init__.py +0 -0
  412. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/events/__init__.py +0 -0
  413. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/events/actions_and_shortcuts.py +0 -0
  414. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/events/channel_archive.py +0 -0
  415. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/events/channel_id_changed.py +0 -0
  416. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/events/channel_rename.py +0 -0
  417. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/events/channel_shared.py +0 -0
  418. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/events/channel_unarchive.py +0 -0
  419. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/events/channel_unshared.py +0 -0
  420. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/events/commands.py +0 -0
  421. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/events/home.py +0 -0
  422. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/events/member_joined_channel.py +0 -0
  423. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/events/member_left_channel.py +0 -0
  424. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/events/message.py +0 -0
  425. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/events/message_deleted.py +0 -0
  426. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/events/reaction_added.py +0 -0
  427. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/modals/__init__.py +0 -0
  428. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/modals/base_modal/__init__.py +0 -0
  429. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/modals/base_modal/base.py +0 -0
  430. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/modals/base_modal/base_mixins.py +0 -0
  431. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/modals/base_modal/form_utils.py +0 -0
  432. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/modals/base_modal/mixins.py +0 -0
  433. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/modals/base_modal/modal_utils.py +0 -0
  434. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/modals/downgrade_workflow.py +0 -0
  435. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/modals/edit.py +0 -0
  436. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/modals/key_event_message.py +0 -0
  437. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/modals/open.py +0 -0
  438. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/modals/opening/__init__.py +0 -0
  439. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/modals/opening/check_current_incidents.py +0 -0
  440. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/modals/opening/details/__init__.py +0 -0
  441. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/modals/opening/details/unified.py +0 -0
  442. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/modals/opening/select_impact.py +0 -0
  443. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/modals/opening/set_details.py +0 -0
  444. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/modals/opening/types.py +0 -0
  445. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/modals/postmortem.py +0 -0
  446. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/modals/select.py +0 -0
  447. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/modals/send_sos.py +0 -0
  448. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/modals/status.py +0 -0
  449. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/modals/trigger_oncall.py +0 -0
  450. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/modals/update.py +0 -0
  451. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/modals/update_roles.py +0 -0
  452. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/modals/utils.py +0 -0
  453. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter/slack/views/views.py +0 -0
  454. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_fixtures/incidents/environments.json +0 -0
  455. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_fixtures/incidents/groups.json +0 -0
  456. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_fixtures/incidents/impact_level.json +0 -0
  457. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_fixtures/incidents/impact_type.json +0 -0
  458. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_fixtures/incidents/incident_categories.json +0 -0
  459. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_fixtures/incidents/incident_role_type.json +0 -0
  460. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_fixtures/incidents/metric_type.json +0 -0
  461. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_fixtures/incidents/milestone_type.json +0 -0
  462. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_fixtures/incidents/priorities.json +0 -0
  463. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_fixtures/incidents/severities.json +0 -0
  464. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/__init__.py +0 -0
  465. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/conftest.py +0 -0
  466. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_api/test_api_landbot.py +0 -0
  467. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_api/test_api_urls.py +0 -0
  468. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_api/test_renderer.py +0 -0
  469. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_confluence/test_confluence_utils.py +0 -0
  470. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_firefighter/test_firefighter_utils.py +0 -0
  471. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_firefighter/test_logging.py +0 -0
  472. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_firefighter/test_sso.py +0 -0
  473. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_firefighter/test_urls.py +0 -0
  474. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_incidents/test_enums.py +0 -0
  475. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_incidents/test_forms/conftest.py +0 -0
  476. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_incidents/test_forms/test_closure_reason.py +0 -0
  477. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_incidents/test_forms/test_form_select_impact.py +0 -0
  478. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_incidents/test_forms/test_form_utils.py +0 -0
  479. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_incidents/test_forms/test_unified_incident_form.py +0 -0
  480. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_incidents/test_forms/test_unified_incident_form_integration.py +0 -0
  481. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_incidents/test_forms/test_unified_incident_form_p4_p5.py +0 -0
  482. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_incidents/test_forms/test_update_key_events.py +0 -0
  483. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_incidents/test_forms/test_update_status_workflow.py +0 -0
  484. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_incidents/test_forms/test_workflow_transitions.py +0 -0
  485. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_incidents/test_models/test_incident_category.py +0 -0
  486. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_incidents/test_models/test_migrations/test_incident_migrations.py +0 -0
  487. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_incidents/test_utils/test_date_utils.py +0 -0
  488. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_incidents/test_views/test_index_view.py +0 -0
  489. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_jira_app/__init__.py +0 -0
  490. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_jira_app/conftest.py +0 -0
  491. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_jira_app/test_incident_key_events_sync.py +0 -0
  492. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_jira_app/test_jira_client_watchers.py +0 -0
  493. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_jira_app/test_models.py +0 -0
  494. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_jira_app/test_postmortem_issue_link.py +0 -0
  495. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_jira_app/test_postmortem_service.py +0 -0
  496. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_jira_app/test_timeline_template.py +0 -0
  497. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_raid/conftest.py +0 -0
  498. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_raid/test_raid_alert_p4_p5.py +0 -0
  499. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_raid/test_raid_client.py +0 -0
  500. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_raid/test_raid_client_users.py +0 -0
  501. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_raid/test_raid_forms.py +0 -0
  502. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_raid/test_raid_models.py +0 -0
  503. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_raid/test_raid_serializers.py +0 -0
  504. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_raid/test_raid_service.py +0 -0
  505. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_raid/test_raid_signals.py +0 -0
  506. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_raid/test_raid_transitions.py +0 -0
  507. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_raid/test_raid_utils.py +0 -0
  508. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_raid/test_raid_views.py +0 -0
  509. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_raid/test_zendesk_integration.py +0 -0
  510. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_slack/conftest.py +0 -0
  511. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_slack/messages/__init__.py +0 -0
  512. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_slack/test_conversation_tags.py +0 -0
  513. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_slack/test_models/test_conversations.py +0 -0
  514. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_slack/test_models/test_incident_channel.py +0 -0
  515. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_slack/test_models/test_slack_user.py +0 -0
  516. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_slack/test_signals_downgrade.py +0 -0
  517. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_slack/test_slack_utils.py +0 -0
  518. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_slack/views/modals/conftest.py +0 -0
  519. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_slack/views/modals/test_edit.py +0 -0
  520. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_slack/views/modals/test_form_utils_multiple_choice.py +0 -0
  521. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_slack/views/modals/test_key_event_message.py +0 -0
  522. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_slack/views/modals/test_open.py +0 -0
  523. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_slack/views/modals/test_opening_unified.py +0 -0
  524. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_slack/views/modals/test_send_sos.py +0 -0
  525. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_slack/views/modals/test_status.py +0 -0
  526. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/firefighter_tests/test_slack/views/modals/test_utils.py +0 -0
  527. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/gunicorn.conf.py +0 -0
  528. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/main.py +0 -0
  529. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/manage.py +0 -0
  530. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/package-lock.json +0 -0
  531. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/package.json +0 -0
  532. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/scripts/gen_credits.py +0 -0
  533. {firefighter_incident-0.0.26 → firefighter_incident-0.0.27}/scripts/hatch_build.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: firefighter-incident
3
- Version: 0.0.26
3
+ Version: 0.0.27
4
4
  Summary: Incident Management tool made for Slack using Django
5
5
  Project-URL: Repository, https://github.com/ManoManoTech/firefighter-incident
6
6
  Project-URL: Documentation, https://manomanotech.github.io/firefighter-incident/latest/
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '0.0.26'
32
- __version_tuple__ = version_tuple = (0, 0, 26)
31
+ __version__ = version = '0.0.27'
32
+ __version_tuple__ = version_tuple = (0, 0, 27)
33
33
 
34
34
  __commit_id__ = commit_id = None
@@ -12,7 +12,6 @@ from django.db import models
12
12
  from django.urls import reverse
13
13
  from django_filters.filters import AllValuesMultipleFilter
14
14
 
15
- from firefighter.confluence.service import confluence_service
16
15
  from firefighter.firefighter.fields_forms_widgets import CustomCheckboxSelectMultiple
17
16
  from firefighter.incidents.models.incident import Incident
18
17
  from firefighter.incidents.signals import postmortem_created
@@ -87,11 +86,18 @@ class PostMortemManager(models.Manager["PostMortem"]):
87
86
 
88
87
  return confluence_pm, jira_pm
89
88
 
89
+ @staticmethod
90
+ def create_confluence_postmortem(incident: Incident) -> PostMortem:
91
+ """Create Confluence post-mortem (existing logic)."""
92
+ return PostMortemManager._create_confluence_postmortem(incident)
93
+
90
94
  @staticmethod
91
95
  def _create_confluence_postmortem(incident: Incident) -> PostMortem:
92
96
  """Create Confluence post-mortem (existing logic)."""
93
97
  logger.info("Creating Confluence PostMortem for %s", incident)
94
98
 
99
+ from firefighter.confluence.service import confluence_service
100
+
95
101
  topic_prefix = (
96
102
  ""
97
103
  if settings.ENV in {"support", "prod"}
@@ -163,6 +169,9 @@ class ConfluencePage(models.Model):
163
169
 
164
170
  version = models.JSONField(default=dict) # We need a callable
165
171
 
172
+ class Meta:
173
+ app_label = "confluence"
174
+
166
175
  def __str__(self) -> str:
167
176
  return self.name
168
177
 
@@ -176,6 +185,9 @@ class PostMortem(ConfluencePage):
176
185
  Incident, on_delete=models.CASCADE, related_name="postmortem_for"
177
186
  )
178
187
 
188
+ class Meta:
189
+ app_label = "confluence"
190
+
179
191
  def __str__(self) -> str:
180
192
  return self.name
181
193
 
@@ -222,6 +234,9 @@ class Runbook(ConfluencePage):
222
234
  service_name = models.CharField(max_length=255)
223
235
  service_type = models.CharField(max_length=255)
224
236
 
237
+ class Meta:
238
+ app_label = "confluence"
239
+
225
240
  def __str__(self) -> str:
226
241
  return self.name
227
242
 
@@ -0,0 +1 @@
1
+ # Management commands for incidents app
@@ -0,0 +1 @@
1
+ # Django management commands
@@ -0,0 +1,94 @@
1
+ """Django management command to backdate an incident's mitigated_at timestamp for testing."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from datetime import timedelta
6
+ from typing import Any
7
+
8
+ from django.core.management.base import BaseCommand, CommandParser
9
+ from django.utils import timezone
10
+
11
+ from firefighter.incidents.models.incident import Incident
12
+
13
+
14
+ class Command(BaseCommand):
15
+ """Backdate an incident's mitigated_at timestamp for testing post-mortem reminders."""
16
+
17
+ help = "Backdate an incident's mitigated_at timestamp by a specified number of days"
18
+
19
+ def add_arguments(self, parser: CommandParser) -> None:
20
+ parser.add_argument(
21
+ "incident_id",
22
+ type=int,
23
+ help="ID of the incident to backdate",
24
+ )
25
+ parser.add_argument(
26
+ "--days",
27
+ type=int,
28
+ default=6,
29
+ help="Number of days to backdate (default: 6, to trigger 5-day reminder)",
30
+ )
31
+ parser.add_argument(
32
+ "--reset",
33
+ action="store_true",
34
+ help="Reset mitigated_at to current time instead of backdating",
35
+ )
36
+
37
+ def handle(self, *args: Any, **options: Any) -> None:
38
+ incident_id = options["incident_id"]
39
+ days = options["days"]
40
+ reset = options["reset"]
41
+
42
+ try:
43
+ incident = Incident.objects.get(id=incident_id)
44
+ except Incident.DoesNotExist:
45
+ self.stdout.write(
46
+ self.style.ERROR(f"Incident #{incident_id} does not exist")
47
+ )
48
+ return
49
+
50
+ if reset:
51
+ incident.mitigated_at = timezone.now()
52
+ incident.save(update_fields=["mitigated_at"])
53
+ self.stdout.write(
54
+ self.style.SUCCESS(
55
+ f"✅ Reset mitigated_at for incident #{incident_id} to current time: {incident.mitigated_at}"
56
+ )
57
+ )
58
+ else:
59
+ old_value = incident.mitigated_at
60
+ new_value = timezone.now() - timedelta(days=days)
61
+ incident.mitigated_at = new_value
62
+ incident.save(update_fields=["mitigated_at"])
63
+
64
+ self.stdout.write(
65
+ self.style.SUCCESS(
66
+ f"✅ Backdated incident #{incident_id} mitigated_at:"
67
+ )
68
+ )
69
+ self.stdout.write(f" Old value: {old_value}")
70
+ self.stdout.write(f" New value: {new_value}")
71
+ self.stdout.write(f" Backdated by {days} days")
72
+
73
+ self.stdout.write("\nIncident details:")
74
+ self.stdout.write(f" ID: {incident.id}")
75
+ self.stdout.write(f" Title: {incident.title}")
76
+ self.stdout.write(f" Priority: {incident.priority.name}")
77
+ self.stdout.write(f" Status: {incident.status.label}")
78
+ self.stdout.write(f" Needs postmortem: {incident.needs_postmortem}")
79
+ self.stdout.write(f" Mitigated at: {incident.mitigated_at}")
80
+
81
+ if incident.needs_postmortem and days >= 5:
82
+ self.stdout.write(
83
+ self.style.WARNING(
84
+ "\n⚠️ This incident should now trigger a 5-day reminder!"
85
+ )
86
+ )
87
+ self.stdout.write(
88
+ "\nTo test the reminder, run:"
89
+ )
90
+ self.stdout.write(
91
+ self.style.NOTICE(
92
+ " pdm run python manage.py test_postmortem_reminders"
93
+ )
94
+ )
@@ -0,0 +1,113 @@
1
+ """Django management command to test post-mortem reminders."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from datetime import timedelta
6
+ from typing import Any
7
+
8
+ from django.core.management.base import BaseCommand, CommandParser
9
+ from django.utils import timezone
10
+
11
+ from firefighter.incidents.enums import IncidentStatus
12
+ from firefighter.incidents.models.incident import Incident
13
+ from firefighter.slack.tasks.send_postmortem_reminders import (
14
+ POSTMORTEM_REMINDER_DAYS,
15
+ send_postmortem_reminders,
16
+ )
17
+
18
+
19
+ class Command(BaseCommand):
20
+ """Test post-mortem reminders by executing the task manually."""
21
+
22
+ help = "Execute the post-mortem reminder task manually for testing"
23
+
24
+ def add_arguments(self, parser: CommandParser) -> None:
25
+ parser.add_argument(
26
+ "--list-only",
27
+ action="store_true",
28
+ help="Only list eligible incidents without sending reminders",
29
+ )
30
+
31
+ def handle(self, *args: Any, **options: Any) -> None:
32
+ list_only = options["list_only"]
33
+
34
+ self.stdout.write(self.style.MIGRATE_HEADING("Post-Mortem Reminder Testing"))
35
+ self.stdout.write("=" * 70)
36
+
37
+ # Calculate cutoff date
38
+ cutoff_date = timezone.now() - timedelta(days=POSTMORTEM_REMINDER_DAYS)
39
+
40
+ self.stdout.write(f"\n⏰ Reminder threshold: {POSTMORTEM_REMINDER_DAYS} days")
41
+ self.stdout.write(f"📅 Cutoff date: {cutoff_date}")
42
+ self.stdout.write(f"🕐 Current time: {timezone.now()}\n")
43
+
44
+ # Find eligible incidents
45
+ eligible_incidents = Incident.objects.filter(
46
+ mitigated_at__lte=cutoff_date,
47
+ mitigated_at__isnull=False,
48
+ _status__in=[
49
+ IncidentStatus.MITIGATED.value,
50
+ IncidentStatus.POST_MORTEM.value,
51
+ ],
52
+ priority__needs_postmortem=True,
53
+ ignore=False,
54
+ ).select_related("priority", "environment", "conversation")
55
+
56
+ count = eligible_incidents.count()
57
+ self.stdout.write(f"🔍 Found {count} incident(s) eligible for reminder\n")
58
+
59
+ if count == 0:
60
+ self.stdout.write(
61
+ self.style.WARNING("⚠️ No incidents found needing reminders")
62
+ )
63
+ self.stdout.write("\nTo test, you can backdate an incident with:")
64
+ self.stdout.write(
65
+ self.style.NOTICE(
66
+ " pdm run python manage.py backdate_incident_mitigated <incident_id> --days 6"
67
+ )
68
+ )
69
+ return
70
+
71
+ # Display eligible incidents
72
+ for incident in eligible_incidents:
73
+ days_since_mitigated = (
74
+ timezone.now() - incident.mitigated_at
75
+ ).days if incident.mitigated_at else 0
76
+
77
+ self.stdout.write(f" 📋 Incident #{incident.id}")
78
+ self.stdout.write(f" Title: {incident.title}")
79
+ self.stdout.write(f" Priority: {incident.priority.name}")
80
+ self.stdout.write(f" Status: {incident.status.label}")
81
+ self.stdout.write(f" Mitigated: {incident.mitigated_at}")
82
+ self.stdout.write(
83
+ f" Days since mitigated: {days_since_mitigated} days"
84
+ )
85
+ self.stdout.write(f" Environment: {incident.environment.value}")
86
+ self.stdout.write(f" Private: {incident.private}")
87
+ self.stdout.write("")
88
+
89
+ if list_only:
90
+ self.stdout.write(
91
+ self.style.SUCCESS(
92
+ "✅ List-only mode: No reminders sent"
93
+ )
94
+ )
95
+ self.stdout.write("\nTo send reminders, run without --list-only flag")
96
+ return
97
+
98
+ # Execute the task
99
+ self.stdout.write("=" * 70)
100
+ self.stdout.write(
101
+ self.style.WARNING("🚀 Executing post-mortem reminder task...\n")
102
+ )
103
+
104
+ try:
105
+ send_postmortem_reminders()
106
+ self.stdout.write("\n" + "=" * 70)
107
+ self.stdout.write(
108
+ self.style.SUCCESS("✅ Task execution completed successfully!")
109
+ )
110
+ except Exception as e:
111
+ self.stdout.write("\n" + "=" * 70)
112
+ self.stdout.write(self.style.ERROR(f"❌ Task execution failed: {e}"))
113
+ raise
@@ -0,0 +1,22 @@
1
+ # Generated by Django 4.2.21 on 2025-12-19 14:02
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ("incidents", "0029_add_custom_fields_to_incident"),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.AddField(
14
+ model_name="incident",
15
+ name="mitigated_at",
16
+ field=models.DateTimeField(
17
+ blank=True,
18
+ help_text="Timestamp when incident status changed to MITIGATED",
19
+ null=True,
20
+ ),
21
+ ),
22
+ ]
@@ -214,12 +214,8 @@ class Incident(models.Model):
214
214
  on_delete=models.PROTECT,
215
215
  help_text="Priority",
216
216
  )
217
- incident_category = models.ForeignKey(
218
- IncidentCategory, on_delete=models.PROTECT
219
- )
220
- environment = models.ForeignKey(
221
- Environment, on_delete=models.PROTECT
222
- )
217
+ incident_category = models.ForeignKey(IncidentCategory, on_delete=models.PROTECT)
218
+ environment = models.ForeignKey(Environment, on_delete=models.PROTECT)
223
219
  created_by = models.ForeignKey(
224
220
  User,
225
221
  on_delete=models.PROTECT,
@@ -229,6 +225,11 @@ class Incident(models.Model):
229
225
 
230
226
  created_at = models.DateTimeField(auto_now_add=True)
231
227
  updated_at = models.DateTimeField(auto_now=True)
228
+ mitigated_at = models.DateTimeField(
229
+ null=True,
230
+ blank=True,
231
+ help_text="Timestamp when incident status changed to MITIGATED",
232
+ )
232
233
  closed_at = models.DateTimeField(
233
234
  null=True, blank=True
234
235
  ) # XXX-ZOR make this an event
@@ -380,6 +381,36 @@ class Incident(models.Model):
380
381
  f"Incident is not in PostMortem status, and needs one because of its priority and environment ({self.priority.name}/{self.environment.value}).",
381
382
  )
382
383
  )
384
+ # If a Jira post-mortem exists, ensure it is in the expected "Ready" status
385
+ if hasattr(self, "jira_postmortem_for"):
386
+ try:
387
+ from firefighter.jira_app.service_postmortem import ( # noqa: PLC0415
388
+ jira_postmortem_service,
389
+ )
390
+
391
+ is_ready, current_status = (
392
+ jira_postmortem_service.is_postmortem_ready(
393
+ self.jira_postmortem_for
394
+ )
395
+ )
396
+ if not is_ready:
397
+ cant_closed_reasons.append(
398
+ (
399
+ "POSTMORTEM_NOT_READY",
400
+ f"Jira post-mortem {self.jira_postmortem_for.jira_issue_key} is not Ready (current status: {current_status}).",
401
+ )
402
+ )
403
+ except Exception: # pragma: no cover - defensive guard
404
+ logger.exception(
405
+ "Failed to verify Jira post-mortem status for incident #%s",
406
+ self.id,
407
+ )
408
+ cant_closed_reasons.append(
409
+ (
410
+ "POSTMORTEM_STATUS_UNKNOWN",
411
+ "Could not verify Jira post-mortem status. Please check it in Jira.",
412
+ )
413
+ )
383
414
  elif self.status.value < IncidentStatus.MITIGATED:
384
415
  cant_closed_reasons.append(
385
416
  (
@@ -606,7 +637,9 @@ class Incident(models.Model):
606
637
 
607
638
  _update_incident_field(self, "_status", status, updated_fields)
608
639
  _update_incident_field(self, "priority_id", priority_id, updated_fields)
609
- _update_incident_field(self, "incident_category_id", incident_category_id, updated_fields)
640
+ _update_incident_field(
641
+ self, "incident_category_id", incident_category_id, updated_fields
642
+ )
610
643
  _update_incident_field(self, "title", title, updated_fields)
611
644
  _update_incident_field(self, "description", description, updated_fields)
612
645
  _update_incident_field(self, "environment_id", environment_id, updated_fields)
@@ -706,7 +739,9 @@ class IncidentFilterSet(django_filters.FilterSet):
706
739
  widget=CustomCheckboxSelectMultiple,
707
740
  )
708
741
  group = ModelMultipleChoiceFilter(
709
- queryset=Group.objects.all(), field_name="incident_category__group_id", label="Group"
742
+ queryset=Group.objects.all(),
743
+ field_name="incident_category__group_id",
744
+ label="Group",
710
745
  )
711
746
  incident_category = ModelMultipleChoiceFilter(
712
747
  queryset=incident_category_filter_choices_queryset,
@@ -30,6 +30,9 @@ class JiraPostMortemService:
30
30
  self.client = JiraClient()
31
31
  self.project_key = getattr(settings, "JIRA_POSTMORTEM_PROJECT_KEY", "INCIDENT")
32
32
  self.issue_type = getattr(settings, "JIRA_POSTMORTEM_ISSUE_TYPE", "Post-mortem")
33
+ self.ready_status_name = getattr(
34
+ settings, "JIRA_POSTMORTEM_READY_STATUS", "Ready"
35
+ )
33
36
  self.field_ids = getattr(
34
37
  settings,
35
38
  "JIRA_POSTMORTEM_FIELDS",
@@ -136,6 +139,16 @@ class JiraPostMortemService:
136
139
 
137
140
  return jira_postmortem
138
141
 
142
+ def is_postmortem_ready(self, jira_postmortem: JiraPostMortem) -> tuple[bool, str]:
143
+ """Check if the Jira post-mortem issue is in the Ready status.
144
+
145
+ Returns:
146
+ Tuple of (is_ready, current_status_name)
147
+ """
148
+ issue = self.client.jira.issue(jira_postmortem.jira_issue_id)
149
+ status_name: str = getattr(issue.fields.status, "name", "")
150
+ return status_name == self.ready_status_name, status_name
151
+
139
152
  def _generate_issue_fields(
140
153
  self, incident: Incident
141
154
  ) -> dict[str, str | dict[str, str] | list[dict[str, str]]]:
@@ -0,0 +1,217 @@
1
+ from __future__ import annotations
2
+
3
+ import importlib
4
+ import logging
5
+ from typing import TYPE_CHECKING, Any, Never
6
+
7
+ from django.apps import apps
8
+ from django.conf import settings
9
+ from django.dispatch.dispatcher import receiver
10
+ from django.utils import timezone
11
+
12
+ from firefighter.incidents.enums import IncidentStatus
13
+ from firefighter.incidents.signals import incident_updated
14
+
15
+ if TYPE_CHECKING:
16
+ from firefighter.confluence.models import PostMortemManager
17
+ from firefighter.incidents.models.incident import Incident
18
+ from firefighter.incidents.models.incident_update import IncidentUpdate
19
+ from firefighter.jira_app.service_postmortem import JiraPostMortemService
20
+
21
+ logger = logging.getLogger(__name__)
22
+
23
+
24
+ def _get_jira_postmortem_service() -> JiraPostMortemService:
25
+ """Lazy import to avoid circular dependency."""
26
+ module = importlib.import_module("firefighter.jira_app.service_postmortem")
27
+ return module.jira_postmortem_service
28
+
29
+
30
+ def _get_confluence_postmortem_manager() -> type[PostMortemManager] | None:
31
+ """Lazy import to avoid circular dependency with Confluence."""
32
+ if not apps.is_installed("firefighter.confluence"):
33
+ return None
34
+ module = importlib.import_module("firefighter.confluence.models")
35
+ return module.PostMortemManager
36
+
37
+
38
+ def _update_mitigated_at_timestamp(
39
+ incident: Incident, incident_update: IncidentUpdate, updated_fields: list[str]
40
+ ) -> None:
41
+ """Update mitigated_at timestamp when incident status changes to MITIGATED."""
42
+ if (
43
+ "_status" in updated_fields
44
+ and incident_update.status == IncidentStatus.MITIGATED
45
+ and incident.mitigated_at is None
46
+ ):
47
+ incident.mitigated_at = timezone.now()
48
+ incident.save(update_fields=["mitigated_at"])
49
+ logger.info(f"Set mitigated_at timestamp for incident #{incident.id}")
50
+
51
+
52
+ def _create_confluence_postmortem(incident: Incident) -> Any | None:
53
+ """Create Confluence post-mortem if needed."""
54
+ has_confluence = hasattr(incident, "postmortem_for")
55
+ logger.debug(f"Confluence enabled, has_confluence={has_confluence}")
56
+
57
+ if has_confluence:
58
+ logger.debug(f"Confluence post-mortem already exists for incident #{incident.id}")
59
+ return None
60
+
61
+ confluence_manager = _get_confluence_postmortem_manager()
62
+ if not confluence_manager:
63
+ return None
64
+
65
+ logger.info(f"Creating Confluence post-mortem for incident #{incident.id}")
66
+ try:
67
+ # Use the public API specifically for Confluence creation
68
+ return confluence_manager.create_confluence_postmortem(incident)
69
+ except Exception:
70
+ logger.exception(
71
+ f"Failed to create Confluence post-mortem for incident #{incident.id}"
72
+ )
73
+ return None
74
+
75
+
76
+ def _create_jira_postmortem(incident: Incident) -> Any | None:
77
+ """Create Jira post-mortem if needed."""
78
+ has_jira = hasattr(incident, "jira_postmortem_for")
79
+ logger.debug(f"Jira post-mortem enabled, has_jira={has_jira}")
80
+
81
+ if has_jira:
82
+ logger.debug(f"Jira post-mortem already exists for incident #{incident.id}")
83
+ return None
84
+
85
+ logger.info(f"Creating Jira post-mortem for incident #{incident.id}")
86
+ try:
87
+ jira_service = _get_jira_postmortem_service()
88
+ return jira_service.create_postmortem_for_incident(incident)
89
+ except Exception:
90
+ logger.exception(
91
+ f"Failed to create Jira post-mortem for incident #{incident.id}"
92
+ )
93
+ return None
94
+
95
+
96
+ def _publish_postmortem_announcement(incident: Incident) -> None:
97
+ """Publish post-mortem creation announcement to #critical-incidents."""
98
+ # Dynamic imports to avoid circular dependencies
99
+ slack_messages = importlib.import_module("firefighter.slack.messages.slack_messages")
100
+ slack_models = importlib.import_module("firefighter.slack.models.conversation")
101
+ slack_rules = importlib.import_module("firefighter.slack.rules")
102
+
103
+ announcement_class = slack_messages.SlackMessageIncidentPostMortemCreatedAnnouncement
104
+ conversation_class = slack_models.Conversation
105
+ should_publish_pm_in_general_channel = slack_rules.should_publish_pm_in_general_channel
106
+
107
+ if not should_publish_pm_in_general_channel(incident):
108
+ return
109
+
110
+ tech_incidents_conversation = conversation_class.objects.get_or_none(
111
+ tag="tech_incidents"
112
+ )
113
+ if tech_incidents_conversation:
114
+ announcement = announcement_class(incident)
115
+ tech_incidents_conversation.send_message_and_save(announcement)
116
+ logger.info(
117
+ f"Post-mortem creation announced in tech_incidents for incident #{incident.id}"
118
+ )
119
+ else:
120
+ logger.warning(
121
+ "Could not find tech_incidents conversation! Is there a channel with tag tech_incidents?"
122
+ )
123
+
124
+
125
+ @receiver(signal=incident_updated)
126
+ def postmortem_created_handler(
127
+ sender: Any,
128
+ incident: Incident,
129
+ incident_update: IncidentUpdate,
130
+ updated_fields: list[str],
131
+ **kwargs: Never,
132
+ ) -> None:
133
+ """Handle post-mortem creation when incident reaches MITIGATED status.
134
+
135
+ This handler is registered in jira_app to ensure it works independently
136
+ of Confluence being enabled. It creates post-mortems for both Confluence
137
+ and Jira based on their respective feature flags.
138
+ """
139
+ logger.debug(
140
+ f"postmortem_created_handler called with sender={sender}, "
141
+ f"incident_id={incident.id}, status={incident_update.status}, "
142
+ f"updated_fields={updated_fields}"
143
+ )
144
+
145
+ if not apps.is_installed("firefighter.slack"):
146
+ logger.error("Slack app is not installed. Skipping.")
147
+ return
148
+
149
+ # Import Slack tasks after apps are loaded
150
+ slack_tasks = importlib.import_module("firefighter.slack.tasks.reminder_postmortem")
151
+ publish_fixed_next_actions = slack_tasks.publish_fixed_next_actions
152
+ publish_postmortem_reminder = slack_tasks.publish_postmortem_reminder
153
+
154
+ logger.debug(f"Checking sender: sender={sender}, type={type(sender)}")
155
+ if sender != "update_status":
156
+ logger.debug(f"Ignoring signal from sender={sender}")
157
+ return
158
+
159
+ logger.debug("Sender is update_status, checking postmortem conditions")
160
+
161
+ # Update mitigated_at timestamp
162
+ _update_mitigated_at_timestamp(incident, incident_update, updated_fields)
163
+
164
+ # Check if we should create post-mortem(s)
165
+ if (
166
+ "_status" not in updated_fields
167
+ or incident_update.status
168
+ not in {IncidentStatus.MITIGATED, IncidentStatus.POST_MORTEM}
169
+ or not incident.needs_postmortem
170
+ ):
171
+ logger.debug(
172
+ f"Not creating post-mortem: _status in fields={('_status' in updated_fields)}, "
173
+ f"status={incident_update.status}, needs_postmortem={incident.needs_postmortem}"
174
+ )
175
+ # For P3+ incidents, publish next actions reminder
176
+ if (
177
+ "_status" in updated_fields
178
+ and incident_update.status
179
+ in {IncidentStatus.MITIGATED, IncidentStatus.POST_MORTEM}
180
+ and not incident.needs_postmortem
181
+ ):
182
+ publish_fixed_next_actions(incident)
183
+ return
184
+
185
+ logger.info(
186
+ f"Creating post-mortem(s) for incident #{incident.id} "
187
+ f"(status={incident_update.status}, needs_postmortem={incident.needs_postmortem})"
188
+ )
189
+
190
+ enable_confluence = getattr(settings, "ENABLE_CONFLUENCE", False)
191
+ enable_jira_postmortem = getattr(settings, "ENABLE_JIRA_POSTMORTEM", False)
192
+
193
+ confluence_pm = None
194
+ jira_pm = None
195
+
196
+ # Create Confluence post-mortem if enabled
197
+ if enable_confluence:
198
+ confluence_pm = _create_confluence_postmortem(incident)
199
+
200
+ # Create Jira post-mortem if enabled
201
+ if enable_jira_postmortem:
202
+ jira_pm = _create_jira_postmortem(incident)
203
+
204
+ # Send signal and announcements if at least one post-mortem was created
205
+ if confluence_pm or jira_pm:
206
+ signals_module = importlib.import_module("firefighter.incidents.signals")
207
+ postmortem_created = signals_module.postmortem_created
208
+
209
+ logger.info(
210
+ f"Post-mortem(s) created for incident #{incident.id}: "
211
+ f"confluence={confluence_pm is not None}, jira={jira_pm is not None}"
212
+ )
213
+ postmortem_created.send_robust(sender=__name__, incident=incident)
214
+ _publish_postmortem_announcement(incident)
215
+
216
+ # Publish reminder
217
+ publish_postmortem_reminder(incident)