firefighter-incident 0.0.15__tar.gz → 0.0.17__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 (505) hide show
  1. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/PKG-INFO +1 -1
  2. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/_version.py +2 -2
  3. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/forms/edit.py +5 -3
  4. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/forms/unified_incident.py +180 -56
  5. firefighter_incident-0.0.17/firefighter/incidents/forms/update_status.py +158 -0
  6. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/forms/utils.py +14 -0
  7. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/models/incident.py +3 -2
  8. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/raid/apps.py +0 -1
  9. firefighter_incident-0.0.17/firefighter/slack/signals/__init__.py +23 -0
  10. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/signals/incident_updated.py +43 -1
  11. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/utils.py +43 -6
  12. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/modals/base_modal/form_utils.py +3 -1
  13. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/modals/downgrade_workflow.py +3 -1
  14. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/modals/edit.py +53 -7
  15. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/modals/open.py +1 -1
  16. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/modals/opening/select_impact.py +1 -1
  17. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/modals/opening/set_details.py +20 -0
  18. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_fixtures/incidents/priorities.json +1 -1
  19. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_incidents/test_forms/test_unified_incident_form_integration.py +160 -23
  20. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_incidents/test_forms/test_unified_incident_form_p4_p5.py +38 -60
  21. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_incidents/test_forms/test_update_status_workflow.py +35 -20
  22. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_incidents/test_forms/test_workflow_transitions.py +8 -6
  23. firefighter_incident-0.0.17/firefighter_tests/test_slack/test_signals_downgrade.py +147 -0
  24. firefighter_incident-0.0.17/firefighter_tests/test_slack/views/modals/test_edit.py +324 -0
  25. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_slack/views/modals/test_opening_unified.py +42 -0
  26. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_slack/views/modals/test_update_status.py +72 -2
  27. firefighter_incident-0.0.15/firefighter/incidents/forms/update_status.py +0 -122
  28. firefighter_incident-0.0.15/firefighter/raid/signals/incident_created.py +0 -129
  29. firefighter_incident-0.0.15/firefighter/slack/signals/__init__.py +0 -7
  30. firefighter_incident-0.0.15/firefighter_tests/test_raid/test_p1_p3_jira_fields.py +0 -372
  31. firefighter_incident-0.0.15/firefighter_tests/test_raid/test_priority_mapping.py +0 -267
  32. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/.gitignore +0 -0
  33. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/LICENSE +0 -0
  34. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/README.md +0 -0
  35. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/__init__.py +0 -0
  36. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/api/__init__.py +0 -0
  37. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/api/admin.py +0 -0
  38. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/api/apps.py +0 -0
  39. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/api/authentication.py +0 -0
  40. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/api/migrations/0001_initial.py +0 -0
  41. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/api/migrations/0002_alter_apitokenproxy_options.py +0 -0
  42. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/api/migrations/0003_alter_apitokenproxy_options.py +0 -0
  43. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/api/migrations/__init__.py +0 -0
  44. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/api/models.py +0 -0
  45. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/api/permissions.py +0 -0
  46. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/api/renderer.py +0 -0
  47. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/api/serializers.py +0 -0
  48. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/api/urls.py +0 -0
  49. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/api/views/__init__.py +0 -0
  50. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/api/views/_base.py +0 -0
  51. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/api/views/components.py +0 -0
  52. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/api/views/environments.py +0 -0
  53. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/api/views/groups.py +0 -0
  54. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/api/views/incident_cost_types.py +0 -0
  55. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/api/views/incident_costs.py +0 -0
  56. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/api/views/incidents.py +0 -0
  57. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/api/views/severities.py +0 -0
  58. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/components/__init__.py +0 -0
  59. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/components/avatar/__init__.py +0 -0
  60. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/components/avatar/avatar.html +0 -0
  61. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/components/avatar/avatar.py +0 -0
  62. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/components/card/__init__.py +0 -0
  63. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/components/card/card.html +0 -0
  64. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/components/card/card.py +0 -0
  65. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/components/export_button/__init__.py +0 -0
  66. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/components/export_button/export_button.html +0 -0
  67. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/components/export_button/export_button.py +0 -0
  68. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/components/form/__init__.py +0 -0
  69. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/components/form/form.html +0 -0
  70. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/components/form/form.py +0 -0
  71. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/components/form_field/__init__.py +0 -0
  72. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/components/form_field/form_field.html +0 -0
  73. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/components/form_field/form_field.py +0 -0
  74. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/components/messages/__init__.py +0 -0
  75. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/components/messages/messages.html +0 -0
  76. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/components/messages/messages.py +0 -0
  77. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/components/modal/__init__.py +0 -0
  78. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/components/modal/modal.html +0 -0
  79. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/components/modal/modal.py +0 -0
  80. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/confluence/__init__.py +0 -0
  81. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/confluence/admin.py +0 -0
  82. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/confluence/apps.py +0 -0
  83. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/confluence/client.py +0 -0
  84. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/confluence/management/__init__.py +0 -0
  85. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/confluence/management/commands/__init__.py +0 -0
  86. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/confluence/management/commands/sort_postmortems.py +0 -0
  87. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/confluence/management/commands/sort_runbooks.py +0 -0
  88. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/confluence/management/commands/sync_postmortems.py +0 -0
  89. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/confluence/management/commands/sync_runbooks.py +0 -0
  90. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/confluence/migrations/0001_initial_oss.py +0 -0
  91. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/confluence/migrations/__init__.py +0 -0
  92. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/confluence/models.py +0 -0
  93. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/confluence/serializers.py +0 -0
  94. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/confluence/service.py +0 -0
  95. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/confluence/signals/__init__.py +0 -0
  96. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/confluence/signals/incident_updated.py +0 -0
  97. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/confluence/tables.py +0 -0
  98. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/confluence/tasks/__init__.py +0 -0
  99. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/confluence/tasks/archive_postmortems.py +0 -0
  100. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/confluence/tasks/sort_runbooks.py +0 -0
  101. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/confluence/tasks/sync_pages_content.py +0 -0
  102. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/confluence/tasks/sync_postmortems.py +0 -0
  103. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/confluence/tasks/sync_runbooks.py +0 -0
  104. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/confluence/templates/oncall_team.xml +0 -0
  105. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/confluence/templates/pages/runbook_list.html +0 -0
  106. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/confluence/urls.py +0 -0
  107. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/confluence/utils.py +0 -0
  108. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/confluence/views/__init__.py +0 -0
  109. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/confluence/views/api.py +0 -0
  110. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/confluence/views/postmortem/__init__.py +0 -0
  111. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/confluence/views/postmortem/postmortem_detail.py +0 -0
  112. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/confluence/views/runbook/__init__.py +0 -0
  113. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/confluence/views/runbook/runbook_list.py +0 -0
  114. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/firefighter/__init__.py +0 -0
  115. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/firefighter/admin.py +0 -0
  116. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/firefighter/apps.py +0 -0
  117. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/firefighter/asgi.py +0 -0
  118. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/firefighter/celery_client.py +0 -0
  119. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/firefighter/fields_forms_widgets.py +0 -0
  120. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/firefighter/filters.py +0 -0
  121. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/firefighter/formats/__init__.py +0 -0
  122. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/firefighter/formats/en/__init__.py +0 -0
  123. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/firefighter/formats/en/formats.py +0 -0
  124. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/firefighter/http_client.py +0 -0
  125. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/firefighter/management/__init__.py +0 -0
  126. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/firefighter/management/commands/__init__.py +0 -0
  127. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/firefighter/management/commands/task.py +0 -0
  128. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/firefighter/middleware.py +0 -0
  129. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/firefighter/settings/__init__.py +0 -0
  130. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/firefighter/settings/components/__init__.py +0 -0
  131. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/firefighter/settings/components/api.py +0 -0
  132. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/firefighter/settings/components/caches.py +0 -0
  133. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/firefighter/settings/components/celery.py +0 -0
  134. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/firefighter/settings/components/common.py +0 -0
  135. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/firefighter/settings/components/confluence.py +0 -0
  136. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/firefighter/settings/components/jira_app.py +0 -0
  137. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/firefighter/settings/components/logging.py +0 -0
  138. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/firefighter/settings/components/pagerduty.py +0 -0
  139. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/firefighter/settings/components/raid.py +0 -0
  140. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/firefighter/settings/components/slack.py +0 -0
  141. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/firefighter/settings/environments/__init__.py +0 -0
  142. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/firefighter/settings/environments/dev.py +0 -0
  143. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/firefighter/settings/environments/prod.py +0 -0
  144. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/firefighter/settings/settings_builder.py +0 -0
  145. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/firefighter/settings/settings_utils.py +0 -0
  146. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/firefighter/sso.py +0 -0
  147. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/firefighter/tables_utils.py +0 -0
  148. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/firefighter/templates/admin/base.html +0 -0
  149. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/firefighter/templates/admin/login.html +0 -0
  150. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/firefighter/templates/admin/send_message_conversation.html +0 -0
  151. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/firefighter/templates/robots.txt +0 -0
  152. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/firefighter/urls.py +0 -0
  153. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/firefighter/utils.py +0 -0
  154. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/firefighter/views.py +0 -0
  155. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/firefighter/wsgi.py +0 -0
  156. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/__init__.py +0 -0
  157. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/admin.py +0 -0
  158. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/apps.py +0 -0
  159. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/enums.py +0 -0
  160. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/factories.py +0 -0
  161. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/forms/__init__.py +0 -0
  162. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/forms/close_incident.py +0 -0
  163. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/forms/closure_reason.py +0 -0
  164. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/forms/create_incident.py +0 -0
  165. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/forms/select_impact.py +0 -0
  166. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/forms/update_key_events.py +0 -0
  167. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/forms/update_roles.py +0 -0
  168. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/menus.py +0 -0
  169. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/migrations/0001_initial_oss.py +0 -0
  170. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/migrations/0002_alter_severity_name_alter_user_password_featureteam.py +0 -0
  171. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/migrations/0003_delete_featureteam.py +0 -0
  172. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/migrations/0004_incidentupdate_environment.py +0 -0
  173. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/migrations/0005_enable_from_p1_to_p5_priority.py +0 -0
  174. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/migrations/0006_update_group_names.py +0 -0
  175. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/migrations/0007_update_component_name.py +0 -0
  176. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/migrations/0008_impact_level.py +0 -0
  177. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/migrations/0009_update_sla.py +0 -0
  178. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/migrations/0010_update_components.py +0 -0
  179. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/migrations/0011_update_incidents.py +0 -0
  180. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/migrations/0012_alter_impactlevel.py +0 -0
  181. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/migrations/0013_add_missing_component.py +0 -0
  182. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/migrations/0014_update_components_slack_groups.py +0 -0
  183. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/migrations/0015_update_impact_level.py +0 -0
  184. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/migrations/0016_update_business_incidents_and_level.py +0 -0
  185. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/migrations/0017_reorder_impact_types.py +0 -0
  186. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/migrations/0018_update_impactlevel_names.py +0 -0
  187. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/migrations/0019_set_security_components_private.py +0 -0
  188. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/migrations/0020_create_incident_category_model.py +0 -0
  189. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/migrations/0021_copy_component_data_to_incident_category.py +0 -0
  190. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/migrations/0022_add_incident_category_fields.py +0 -0
  191. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/migrations/0023_populate_incident_category_references.py +0 -0
  192. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/migrations/0024_remove_component_fields_and_model.py +0 -0
  193. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/migrations/0025_make_incident_category_required.py +0 -0
  194. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/migrations/0026_alter_incidentcategory_options_and_more.py +0 -0
  195. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/migrations/0027_add_closure_fields.py +0 -0
  196. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/migrations/0028_add_closure_reason_constraint.py +0 -0
  197. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/migrations/0029_add_custom_fields_to_incident.py +0 -0
  198. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/migrations/__init__.py +0 -0
  199. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/models/__init__.py +0 -0
  200. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/models/environment.py +0 -0
  201. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/models/group.py +0 -0
  202. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/models/impact.py +0 -0
  203. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/models/incident_category.py +0 -0
  204. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/models/incident_cost.py +0 -0
  205. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/models/incident_cost_type.py +0 -0
  206. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/models/incident_membership.py +0 -0
  207. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/models/incident_role_type.py +0 -0
  208. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/models/incident_update.py +0 -0
  209. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/models/metric_type.py +0 -0
  210. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/models/milestone_type.py +0 -0
  211. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/models/priority.py +0 -0
  212. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/models/severity.py +0 -0
  213. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/models/user.py +0 -0
  214. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/signals.py +0 -0
  215. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/static/css/incident.css +0 -0
  216. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/static/css/main.css +0 -0
  217. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/static/css/main.min.css +0 -0
  218. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/static/css/tailwind.css +0 -0
  219. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/static/img/favicon/android-chrome-192x192.png +0 -0
  220. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/static/img/favicon/android-chrome-512x512.png +0 -0
  221. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/static/img/favicon/apple-touch-icon.png +0 -0
  222. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/static/img/favicon/favicon-16x16.png +0 -0
  223. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/static/img/favicon/favicon-32x32.png +0 -0
  224. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/static/img/favicon/favicon.ico +0 -0
  225. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/static/img/favicon/site.webmanifest +0 -0
  226. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/static/img/gameday.png +0 -0
  227. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/static/img/logo-firefighter.png +0 -0
  228. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/static/img/p1.png +0 -0
  229. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/static/img/p2.png +0 -0
  230. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/static/img/p3.png +0 -0
  231. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/static/img/p4.png +0 -0
  232. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/static/img/p5.png +0 -0
  233. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/static/js/main.js +0 -0
  234. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/static/js/main.min.js +0 -0
  235. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/tables.py +0 -0
  236. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/tasks/__init__.py +0 -0
  237. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/tasks/updateoncall.py +0 -0
  238. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/templates/incidents/errors/base.html +0 -0
  239. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/templates/incidents/filter.html +0 -0
  240. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/templates/incidents/table/priority_column.html +0 -0
  241. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/templates/incidents/table/status_column.html +0 -0
  242. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/templates/incidents/table.html +0 -0
  243. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/templates/incidents/widgets/form_container.html +0 -0
  244. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/templates/incidents/widgets/grouped_checkbox_nested.html +0 -0
  245. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/templates/incidents/widgets/input_option.html +0 -0
  246. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/templates/layouts/index.html +0 -0
  247. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/templates/layouts/partials/created_at_help.html +0 -0
  248. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/templates/layouts/partials/environment_pill.html +0 -0
  249. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/templates/layouts/partials/footer.html +0 -0
  250. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/templates/layouts/partials/header.html +0 -0
  251. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/templates/layouts/partials/incident_card.html +0 -0
  252. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/templates/layouts/partials/incident_metrics.html +0 -0
  253. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/templates/layouts/partials/incident_timeline.html +0 -0
  254. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/templates/layouts/partials/incident_update_key_events_view.html +0 -0
  255. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/templates/layouts/partials/incident_update_key_events_view_modal.html +0 -0
  256. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/templates/layouts/partials/partial_table_list_paginated.html +0 -0
  257. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/templates/layouts/partials/priority_icon.html +0 -0
  258. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/templates/layouts/partials/priority_pill.html +0 -0
  259. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/templates/layouts/partials/status_pill.html +0 -0
  260. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/templates/layouts/partials/table.html +0 -0
  261. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/templates/layouts/partials/user_card.html +0 -0
  262. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/templates/layouts/partials/user_tooltip.html +0 -0
  263. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/templates/layouts/view_filters.html +0 -0
  264. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/templates/pages/dashboard.html +0 -0
  265. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/templates/pages/docs_metrics.html +0 -0
  266. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/templates/pages/incident_category_detail.html +0 -0
  267. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/templates/pages/incident_category_list.html +0 -0
  268. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/templates/pages/incident_create.html +0 -0
  269. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/templates/pages/incident_detail.html +0 -0
  270. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/templates/pages/incident_list.html +0 -0
  271. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/templates/pages/incident_role_types_detail.html +0 -0
  272. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/templates/pages/incident_role_types_list.html +0 -0
  273. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/templates/pages/incident_statistics.html +0 -0
  274. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/templates/pages/incident_statistics_partial.html +0 -0
  275. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/templates/pages/incident_update_key_events_form.html +0 -0
  276. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/templates/pages/user_detail.html +0 -0
  277. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/urls.py +0 -0
  278. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/views/__init__.py +0 -0
  279. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/views/components/__init__.py +0 -0
  280. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/views/components/details.py +0 -0
  281. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/views/components/list.py +0 -0
  282. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/views/date_filter.py +0 -0
  283. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/views/date_utils.py +0 -0
  284. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/views/docs/__init__.py +0 -0
  285. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/views/docs/metrics.py +0 -0
  286. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/views/docs/role_types.py +0 -0
  287. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/views/errors.py +0 -0
  288. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/views/reports.py +0 -0
  289. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/views/users/__init__.py +0 -0
  290. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/views/users/details.py +0 -0
  291. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/incidents/views/views.py +0 -0
  292. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/jira_app/__init__.py +0 -0
  293. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/jira_app/admin.py +0 -0
  294. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/jira_app/apps.py +0 -0
  295. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/jira_app/client.py +0 -0
  296. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/jira_app/migrations/0001_initial_oss.py +0 -0
  297. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/jira_app/migrations/__init__.py +0 -0
  298. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/jira_app/models.py +0 -0
  299. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/jira_app/tasks/__init__.py +0 -0
  300. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/jira_app/tasks/sync_users_jira.py +0 -0
  301. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/jira_app/types.py +0 -0
  302. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/jira_app/utils.py +0 -0
  303. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/logging/__init__.py +0 -0
  304. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/logging/custom_json_formatter.py +0 -0
  305. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/logging/pretty_formatter.py +0 -0
  306. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/pagerduty/__init__.py +0 -0
  307. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/pagerduty/admin.py +0 -0
  308. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/pagerduty/apps.py +0 -0
  309. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/pagerduty/client.py +0 -0
  310. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/pagerduty/forms/__init__.py +0 -0
  311. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/pagerduty/forms/create_pagerduty_incident.py +0 -0
  312. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/pagerduty/migrations/0001_initial_oss.py +0 -0
  313. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/pagerduty/migrations/__init__.py +0 -0
  314. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/pagerduty/models.py +0 -0
  315. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/pagerduty/service.py +0 -0
  316. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/pagerduty/signals/__init__.py +0 -0
  317. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/pagerduty/signals/get_invites_from_pagerduty.py +0 -0
  318. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/pagerduty/signals/incident_channel_done_oncall.py +0 -0
  319. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/pagerduty/tasks/__init__.py +0 -0
  320. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/pagerduty/tasks/fetch_oncall.py +0 -0
  321. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/pagerduty/tasks/fetch_services.py +0 -0
  322. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/pagerduty/tasks/fetch_users.py +0 -0
  323. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/pagerduty/tasks/trigger_oncall.py +0 -0
  324. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/pagerduty/templates/pages/oncall_list.html +0 -0
  325. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/pagerduty/templates/pages/oncall_trigger.html +0 -0
  326. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/pagerduty/templates/partials/trigger_oncall_form_view.html +0 -0
  327. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/pagerduty/templates/partials/trigger_oncall_form_view_modal.html +0 -0
  328. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/pagerduty/urls.py +0 -0
  329. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/pagerduty/views/__init__.py +0 -0
  330. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/pagerduty/views/oncall_list.py +0 -0
  331. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/pagerduty/views/oncall_trigger.py +0 -0
  332. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/raid/__init__.py +0 -0
  333. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/raid/admin.py +0 -0
  334. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/raid/client.py +0 -0
  335. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/raid/forms.py +0 -0
  336. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/raid/messages.py +0 -0
  337. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/raid/migrations/0001_initial_oss.py +0 -0
  338. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/raid/migrations/0002_featureteam_remove_qualifierrotation_jira_user_and_more.py +0 -0
  339. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/raid/migrations/0003_delete_raidarea.py +0 -0
  340. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/raid/migrations/__init__.py +0 -0
  341. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/raid/models.py +0 -0
  342. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/raid/resources.py +0 -0
  343. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/raid/serializers.py +0 -0
  344. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/raid/service.py +0 -0
  345. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/raid/signals/__init__.py +0 -0
  346. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/raid/signals/incident_updated.py +0 -0
  347. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/raid/tasks/__init__.py +0 -0
  348. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/raid/types.py +0 -0
  349. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/raid/urls.py +0 -0
  350. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/raid/utils.py +0 -0
  351. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/raid/views/__init__.py +0 -0
  352. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/__init__.py +0 -0
  353. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/admin.py +0 -0
  354. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/apps.py +0 -0
  355. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/factories.py +0 -0
  356. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/forms/__init__.py +0 -0
  357. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/forms/sos_form.py +0 -0
  358. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/management/__init__.py +0 -0
  359. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/management/commands/__init__.py +0 -0
  360. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/management/commands/generate_manifest.py +0 -0
  361. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/management/commands/switch_test_users.py +0 -0
  362. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/messages/__init__.py +0 -0
  363. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/messages/base.py +0 -0
  364. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/messages/slack_messages.py +0 -0
  365. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/migrations/0001_initial_oss.py +0 -0
  366. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/migrations/0002_usergroup_tag.py +0 -0
  367. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/migrations/0003_alter_usergroup_tag.py +0 -0
  368. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/migrations/0004_alter_usergroup_components.py +0 -0
  369. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/migrations/0005_add_incident_categories_fields.py +0 -0
  370. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/migrations/0006_copy_components_to_incident_categories.py +0 -0
  371. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/migrations/0007_remove_components_fields.py +0 -0
  372. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/migrations/0008_alter_conversation_incident_categories_and_more.py +0 -0
  373. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/migrations/__init__.py +0 -0
  374. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/models/__init__.py +0 -0
  375. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/models/conversation.py +0 -0
  376. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/models/incident_channel.py +0 -0
  377. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/models/message.py +0 -0
  378. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/models/sos.py +0 -0
  379. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/models/user.py +0 -0
  380. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/models/user_group.py +0 -0
  381. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/rules.py +0 -0
  382. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/signals/create_incident_conversation.py +0 -0
  383. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/signals/get_users.py +0 -0
  384. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/signals/handle_incident_channel_done.py +0 -0
  385. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/signals/incident_closed.py +0 -0
  386. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/signals/postmortem_created.py +0 -0
  387. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/signals/roles_reminders.py +0 -0
  388. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/slack_app.py +0 -0
  389. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/slack_incident_context.py +0 -0
  390. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/slack_templating.py +0 -0
  391. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/tasks/__init__.py +0 -0
  392. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/tasks/fetch_conversations_members.py +0 -0
  393. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/tasks/reminder_postmortem.py +0 -0
  394. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/tasks/send_message.py +0 -0
  395. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/tasks/send_reminders.py +0 -0
  396. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/tasks/sync_users.py +0 -0
  397. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/tasks/update_usergroups_members.py +0 -0
  398. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/tasks/update_users.py +0 -0
  399. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/urls.py +0 -0
  400. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/__init__.py +0 -0
  401. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/events/__init__.py +0 -0
  402. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/events/actions_and_shortcuts.py +0 -0
  403. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/events/channel_archive.py +0 -0
  404. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/events/channel_id_changed.py +0 -0
  405. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/events/channel_rename.py +0 -0
  406. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/events/channel_shared.py +0 -0
  407. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/events/channel_unarchive.py +0 -0
  408. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/events/channel_unshared.py +0 -0
  409. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/events/commands.py +0 -0
  410. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/events/home.py +0 -0
  411. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/events/member_joined_channel.py +0 -0
  412. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/events/member_left_channel.py +0 -0
  413. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/events/message.py +0 -0
  414. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/events/message_deleted.py +0 -0
  415. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/events/reaction_added.py +0 -0
  416. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/modals/__init__.py +0 -0
  417. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/modals/base_modal/__init__.py +0 -0
  418. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/modals/base_modal/base.py +0 -0
  419. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/modals/base_modal/base_mixins.py +0 -0
  420. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/modals/base_modal/mixins.py +0 -0
  421. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/modals/base_modal/modal_utils.py +0 -0
  422. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/modals/close.py +0 -0
  423. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/modals/closure_reason.py +0 -0
  424. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/modals/key_event_message.py +0 -0
  425. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/modals/opening/__init__.py +0 -0
  426. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/modals/opening/check_current_incidents.py +0 -0
  427. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/modals/opening/details/__init__.py +0 -0
  428. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/modals/opening/details/unified.py +0 -0
  429. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/modals/opening/types.py +0 -0
  430. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/modals/postmortem.py +0 -0
  431. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/modals/select.py +0 -0
  432. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/modals/send_sos.py +0 -0
  433. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/modals/status.py +0 -0
  434. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/modals/trigger_oncall.py +0 -0
  435. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/modals/update.py +0 -0
  436. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/modals/update_roles.py +0 -0
  437. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/modals/update_status.py +0 -0
  438. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/modals/utils.py +0 -0
  439. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter/slack/views/views.py +0 -0
  440. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_fixtures/incidents/environments.json +0 -0
  441. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_fixtures/incidents/groups.json +0 -0
  442. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_fixtures/incidents/impact_level.json +0 -0
  443. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_fixtures/incidents/impact_type.json +0 -0
  444. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_fixtures/incidents/incident_categories.json +0 -0
  445. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_fixtures/incidents/incident_role_type.json +0 -0
  446. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_fixtures/incidents/metric_type.json +0 -0
  447. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_fixtures/incidents/milestone_type.json +0 -0
  448. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_fixtures/incidents/severities.json +0 -0
  449. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/__init__.py +0 -0
  450. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/conftest.py +0 -0
  451. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_api/test_api_landbot.py +0 -0
  452. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_api/test_api_urls.py +0 -0
  453. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_confluence/test_confluence_utils.py +0 -0
  454. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_firefighter/test_firefighter_utils.py +0 -0
  455. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_firefighter/test_logging.py +0 -0
  456. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_firefighter/test_sso.py +0 -0
  457. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_firefighter/test_urls.py +0 -0
  458. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_incidents/test_enums.py +0 -0
  459. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_incidents/test_forms/conftest.py +0 -0
  460. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_incidents/test_forms/test_closure_reason.py +0 -0
  461. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_incidents/test_forms/test_form_select_impact.py +0 -0
  462. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_incidents/test_forms/test_form_utils.py +0 -0
  463. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_incidents/test_forms/test_unified_incident_form.py +0 -0
  464. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_incidents/test_forms/test_update_key_events.py +0 -0
  465. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_incidents/test_incident_urls.py +0 -0
  466. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_incidents/test_models/test_incident_category.py +0 -0
  467. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_incidents/test_models/test_incident_model.py +0 -0
  468. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_incidents/test_models/test_migrations/test_incident_migrations.py +0 -0
  469. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_incidents/test_utils/test_date_utils.py +0 -0
  470. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_incidents/test_views/test_incident_detail_view.py +0 -0
  471. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_incidents/test_views/test_index_view.py +0 -0
  472. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_raid/conftest.py +0 -0
  473. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_raid/test_raid_client.py +0 -0
  474. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_raid/test_raid_client_users.py +0 -0
  475. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_raid/test_raid_forms.py +0 -0
  476. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_raid/test_raid_models.py +0 -0
  477. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_raid/test_raid_serializers.py +0 -0
  478. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_raid/test_raid_service.py +0 -0
  479. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_raid/test_raid_signals.py +0 -0
  480. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_raid/test_raid_transitions.py +0 -0
  481. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_raid/test_raid_utils.py +0 -0
  482. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_raid/test_raid_views.py +0 -0
  483. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_slack/conftest.py +0 -0
  484. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_slack/messages/__init__.py +0 -0
  485. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_slack/messages/test_slack_messages.py +0 -0
  486. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_slack/test_models/test_conversations.py +0 -0
  487. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_slack/test_models/test_incident_channel.py +0 -0
  488. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_slack/test_models/test_slack_user.py +0 -0
  489. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_slack/test_slack_utils.py +0 -0
  490. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_slack/views/modals/conftest.py +0 -0
  491. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_slack/views/modals/test_close.py +0 -0
  492. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_slack/views/modals/test_closure_reason_modal.py +0 -0
  493. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_slack/views/modals/test_form_utils_multiple_choice.py +0 -0
  494. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_slack/views/modals/test_open.py +0 -0
  495. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_slack/views/modals/test_send_sos.py +0 -0
  496. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_slack/views/modals/test_status.py +0 -0
  497. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/firefighter_tests/test_slack/views/modals/test_utils.py +0 -0
  498. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/gunicorn.conf.py +0 -0
  499. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/main.py +0 -0
  500. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/manage.py +0 -0
  501. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/package-lock.json +0 -0
  502. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/package.json +0 -0
  503. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/pyproject.toml +0 -0
  504. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/scripts/gen_credits.py +0 -0
  505. {firefighter_incident-0.0.15 → firefighter_incident-0.0.17}/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.15
3
+ Version: 0.0.17
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.15'
32
- __version_tuple__ = version_tuple = (0, 0, 15)
31
+ __version__ = version = '0.0.17'
32
+ __version_tuple__ = version_tuple = (0, 0, 17)
33
33
 
34
34
  __commit_id__ = commit_id = None
@@ -5,8 +5,9 @@ from django import forms
5
5
  from firefighter.incidents.models import Environment
6
6
 
7
7
 
8
- def initial_environments() -> Environment:
9
- return Environment.objects.get(default=True)
8
+ def initial_environments() -> list[Environment]:
9
+ """Get default environments for the form."""
10
+ return list(Environment.objects.filter(default=True))
10
11
 
11
12
 
12
13
  class EditMetaForm(forms.Form):
@@ -26,8 +27,9 @@ class EditMetaForm(forms.Form):
26
27
  min_length=10,
27
28
  max_length=1200,
28
29
  )
29
- environment = forms.ModelChoiceField(
30
+ environment = forms.ModelMultipleChoiceField(
30
31
  label="Environment",
31
32
  queryset=Environment.objects.all(),
32
33
  initial=initial_environments,
34
+ required=True,
33
35
  )
@@ -287,120 +287,244 @@ class UnifiedIncidentForm(CreateIncidentFormBase):
287
287
  response_type: str = "critical",
288
288
  *args: Any,
289
289
  **kwargs: Any,
290
- ) -> None:
291
- """Trigger the appropriate incident workflow based on response type.
290
+ ) -> Incident:
291
+ """Trigger unified incident workflow for all priorities.
292
+
293
+ This unified workflow:
294
+ 1. Always creates an Incident in the database (P1-P5)
295
+ 2. Conditionally creates a Slack channel (P1-P3 only)
296
+ 3. Always creates a Jira ticket linked to the Incident (P1-P5)
292
297
 
293
298
  Args:
294
299
  creator: User creating the incident
295
300
  impacts_data: Dictionary of impact data
296
- response_type: "critical" or "normal"
301
+ response_type: "critical" (P1-P3) or "normal" (P4-P5)
297
302
  *args: Additional positional arguments (unused)
298
303
  **kwargs: Additional keyword arguments (unused)
304
+
305
+ Returns:
306
+ The created Incident object
299
307
  """
300
- if response_type == "critical":
301
- self._trigger_critical_incident_workflow(creator, impacts_data)
302
- else:
303
- self._trigger_normal_incident_workflow(creator, impacts_data)
308
+ # Step 1: Always create Incident in database (ALL priorities)
309
+ incident = self._create_incident(creator)
304
310
 
305
- def _trigger_critical_incident_workflow(
306
- self,
307
- creator: User,
308
- impacts_data: dict[str, ImpactLevel],
309
- ) -> None:
310
- """Create a critical incident (P1-P3) with Slack channel."""
311
- # Create incident with first environment only (critical incidents use single env)
311
+ # Save impacts
312
+ impacts_form = SelectImpactForm(impacts_data)
313
+ impacts_form.save(incident=incident)
314
+
315
+ # Step 2: Conditionally create Slack channel (P1-P3 only)
316
+ if self._should_create_slack_channel(response_type):
317
+ self._create_slack_channel(incident, impacts_data)
318
+
319
+ # Step 3: Always create Jira ticket (ALL priorities) - UNIFIED
320
+ self._create_jira_ticket(incident, creator, impacts_data)
321
+
322
+ return incident
323
+
324
+ def _should_create_slack_channel(self, response_type: str) -> bool:
325
+ """Determine if incident needs Slack channel based on priority.
326
+
327
+ Args:
328
+ response_type: "critical" or "normal"
329
+
330
+ Returns:
331
+ True if Slack channel should be created (P1-P3), False otherwise (P4-P5)
332
+ """
333
+ return response_type == "critical"
334
+
335
+ def _create_incident(self, creator: User) -> Incident:
336
+ """Create Incident object in database for ALL priorities.
337
+
338
+ Args:
339
+ creator: User creating the incident
340
+
341
+ Returns:
342
+ Created Incident object
343
+ """
312
344
  cleaned_data_copy = self.cleaned_data.copy()
313
345
  logger.info(f"UNIFIED FORM - cleaned_data keys: {list(self.cleaned_data.keys())}")
314
346
  logger.info(f"UNIFIED FORM - cleaned_data values: {self.cleaned_data}")
315
347
 
348
+ # Extract environments and platforms (not stored directly in Incident model)
316
349
  environments = cleaned_data_copy.pop("environment", [])
317
350
  platforms = cleaned_data_copy.pop("platform", [])
318
351
 
319
- # Extract customer/seller fields for Jira ticket (not stored in Incident model)
320
- jira_extra_fields = {
321
- "suggested_team_routing": cleaned_data_copy.pop("suggested_team_routing", None),
352
+ # Extract Jira-only fields (not stored in Incident model)
353
+ # Convert suggested_team_routing to JSON-serializable value (name string)
354
+ team_routing = cleaned_data_copy.pop("suggested_team_routing", None)
355
+ team_routing_name = team_routing.name if team_routing else None
356
+
357
+ self._jira_extra_fields = {
358
+ "suggested_team_routing": team_routing_name, # Store name string, not model instance
322
359
  "zendesk_ticket_id": cleaned_data_copy.pop("zendesk_ticket_id", None),
323
360
  "seller_contract_id": cleaned_data_copy.pop("seller_contract_id", None),
324
361
  "is_key_account": cleaned_data_copy.pop("is_key_account", None),
325
362
  "is_seller_in_golden_list": cleaned_data_copy.pop("is_seller_in_golden_list", None),
326
363
  "zoho_desk_ticket_id": cleaned_data_copy.pop("zoho_desk_ticket_id", None),
327
- # Pass full lists for Jira ticket creation
328
- "environments": [env.value for env in environments], # Convert QuerySet to list of values
329
- "platforms": platforms, # Already a list of strings
364
+ "environments": [env.value for env in environments],
365
+ "platforms": platforms,
330
366
  }
331
- logger.info(f"UNIFIED FORM - jira_extra_fields extracted: {jira_extra_fields}")
367
+ logger.info(f"UNIFIED FORM - jira_extra_fields extracted: {self._jira_extra_fields}")
332
368
 
333
- # Use first environment
369
+ # Use highest priority environment (lowest order value) for main environment field
334
370
  if environments:
335
- cleaned_data_copy["environment"] = environments[0]
371
+ cleaned_data_copy["environment"] = min(environments, key=lambda env: env.order)
336
372
 
337
- # Store custom fields in the incident
373
+ # Store custom fields in the incident (including all environments)
338
374
  cleaned_data_copy["custom_fields"] = {
339
- k: v for k, v in jira_extra_fields.items() if v is not None
375
+ k: v for k, v in self._jira_extra_fields.items() if v is not None
340
376
  }
341
377
 
378
+ # Create Incident in database (ALL priorities)
342
379
  incident = Incident.objects.declare(created_by=creator, **cleaned_data_copy)
343
- impacts_form = SelectImpactForm(impacts_data)
344
- impacts_form.save(incident=incident)
380
+ logger.info(f"UNIFIED FORM - Incident created: {incident.id}")
381
+
382
+ return incident
345
383
 
384
+ def _create_slack_channel(
385
+ self,
386
+ incident: Incident,
387
+ impacts_data: dict[str, ImpactLevel],
388
+ ) -> None:
389
+ """Create Slack channel for P1-P3 incidents only.
390
+
391
+ Args:
392
+ incident: The created Incident object
393
+ impacts_data: Dictionary of impact data
394
+ """
395
+ logger.info(f"UNIFIED FORM - Creating Slack channel for incident {incident.id}")
396
+
397
+ # Signal to create Slack channel (triggers bookmarks, roles message, etc.)
346
398
  create_incident_conversation.send(
347
399
  "unified_incident_form",
348
400
  incident=incident,
349
- jira_extra_fields=jira_extra_fields,
350
- impacts_data=impacts_data, # Pass impacts_data for business_impact computation
401
+ jira_extra_fields=self._jira_extra_fields,
402
+ impacts_data=impacts_data,
351
403
  )
352
404
 
353
- def _trigger_normal_incident_workflow(
405
+ def _create_jira_ticket(
354
406
  self,
407
+ incident: Incident,
355
408
  creator: User,
356
409
  impacts_data: dict[str, ImpactLevel],
357
410
  ) -> None:
358
- """Create a normal incident (P4-P5) with Jira ticket only."""
411
+ """Create Jira ticket for ALL priorities - UNIFIED method.
412
+
413
+ Args:
414
+ incident: The created Incident object
415
+ creator: User creating the incident
416
+ impacts_data: Dictionary of impact data
417
+ """
418
+ from firefighter.incidents.forms.select_impact import ( # noqa: PLC0415
419
+ SelectImpactForm,
420
+ )
359
421
  from firefighter.raid.client import client as jira_client # noqa: PLC0415
360
422
  from firefighter.raid.forms import ( # noqa: PLC0415
423
+ alert_slack_new_jira_ticket,
361
424
  prepare_jira_fields,
362
- process_jira_issue,
425
+ set_jira_ticket_watchers_raid,
363
426
  )
427
+ from firefighter.raid.models import JiraTicket # noqa: PLC0415
364
428
  from firefighter.raid.service import ( # noqa: PLC0415
365
429
  get_jira_user_from_user,
366
430
  )
431
+ from firefighter.slack.messages.slack_messages import ( # noqa: PLC0415
432
+ SlackMessageIncidentDeclaredAnnouncement,
433
+ )
434
+
435
+ logger.info(f"UNIFIED FORM - Creating Jira ticket for incident {incident.id}")
367
436
 
437
+ # Get Jira user
368
438
  jira_user: JiraUser = get_jira_user_from_user(creator)
369
439
 
370
- # Extract environments and platforms
371
- environments_qs = self.cleaned_data.get("environment", [])
372
- environments = [env.value for env in environments_qs] # Convert QuerySet to list of values
373
- platforms = self.cleaned_data.get("platform", [])
440
+ # Extract environments and platforms from jira_extra_fields
441
+ environments = self._jira_extra_fields.get("environments", [])
442
+ platforms = self._jira_extra_fields.get("platforms", [])
374
443
 
375
- # Extract suggested team routing (convert FeatureTeam instance to string)
376
- team_routing = self.cleaned_data.get("suggested_team_routing")
377
- team_routing_name = team_routing.name if team_routing else None
444
+ # Build description (enhanced for P1-P3 with Slack channel, simple for P4-P5)
445
+ if hasattr(incident, "conversation"):
446
+ # P1-P3: Enhanced description with emoji and formatting
447
+ description = f"""{incident.description}
448
+
449
+ 🧯 This incident has been created for a critical incident.
450
+ 📦 Incident category: {incident.incident_category.name}
451
+ {incident.priority.emoji} Priority: {incident.priority.name}
452
+ """
453
+ else:
454
+ # P4-P5: Simple description
455
+ description = incident.description
378
456
 
379
- # Prepare all Jira fields using the common function
380
- # P4-P5 pass all environments (unlike P1-P3 which pass first only)
457
+ # Prepare all Jira fields using common function (UNIFIED for all priorities)
381
458
  jira_fields = prepare_jira_fields(
382
- title=self.cleaned_data["title"],
383
- description=self.cleaned_data["description"],
384
- priority=self.cleaned_data["priority"].value,
459
+ title=incident.title,
460
+ description=description,
461
+ priority=incident.priority.value,
385
462
  reporter=jira_user.id,
386
- incident_category=self.cleaned_data["incident_category"].name,
387
- environments=environments, # P4-P5: pass ALL environments
463
+ incident_category=incident.incident_category.name,
464
+ environments=environments, # All environments for all priorities
388
465
  platforms=platforms,
389
466
  impacts_data=impacts_data,
390
467
  optional_fields={
391
- "zendesk_ticket_id": self.cleaned_data.get("zendesk_ticket_id", ""),
392
- "seller_contract_id": self.cleaned_data.get("seller_contract_id", ""),
393
- "zoho_desk_ticket_id": self.cleaned_data.get("zoho_desk_ticket_id", ""),
394
- "is_key_account": self.cleaned_data.get("is_key_account"),
395
- "is_seller_in_golden_list": self.cleaned_data.get("is_seller_in_golden_list"),
396
- "suggested_team_routing": team_routing_name,
468
+ "zendesk_ticket_id": self._jira_extra_fields.get("zendesk_ticket_id", ""),
469
+ "seller_contract_id": self._jira_extra_fields.get("seller_contract_id", ""),
470
+ "zoho_desk_ticket_id": self._jira_extra_fields.get("zoho_desk_ticket_id", ""),
471
+ "is_key_account": self._jira_extra_fields.get("is_key_account"),
472
+ "is_seller_in_golden_list": self._jira_extra_fields.get("is_seller_in_golden_list"),
473
+ "suggested_team_routing": self._jira_extra_fields.get("suggested_team_routing"),
397
474
  },
398
475
  )
399
476
 
400
- # Create Jira issue with all prepared fields
477
+ # Create Jira issue via API (UNIFIED)
401
478
  issue_data = jira_client.create_issue(**jira_fields)
479
+ logger.info(f"UNIFIED FORM - Jira issue created: {issue_data.get('key')}")
480
+
481
+ # Create JiraTicket in DB, linked to Incident (UNIFIED)
482
+ jira_ticket = JiraTicket.objects.create(**issue_data, incident=incident)
402
483
 
403
- # Process the created Jira ticket (create JiraTicket in DB, save impacts, alert Slack)
404
- process_jira_issue(
405
- issue_data, creator, jira_user=jira_user, impacts_data=impacts_data
484
+ # Save impact levels
485
+ impacts_form = SelectImpactForm(impacts_data)
486
+ impacts_form.save(incident=jira_ticket)
487
+
488
+ # Set up Jira watchers
489
+ set_jira_ticket_watchers_raid(jira_ticket)
490
+
491
+ # Add Jira links to incident and Slack channel (if exists)
492
+ jira_client.jira.add_simple_link(
493
+ issue=str(jira_ticket.id),
494
+ object={
495
+ "url": incident.status_page_url,
496
+ "title": f"FireFighter incident #{incident.id}",
497
+ },
406
498
  )
499
+
500
+ # Send Slack notifications based on priority
501
+ # P1-P3 incidents have Slack channels, P4-P5 incidents don't
502
+ if incident.priority.value <= 3:
503
+ # P1-P3: Add Jira link to Slack channel (if exists)
504
+ if hasattr(incident, "conversation"):
505
+ logger.info(f"UNIFIED FORM - Adding Jira link to Slack channel for incident {incident.id}")
506
+ jira_client.jira.add_simple_link(
507
+ issue=str(jira_ticket.id),
508
+ object={
509
+ "url": incident.conversation.link,
510
+ "title": f"Slack conversation #{incident.conversation.name}",
511
+ },
512
+ )
513
+
514
+ # Add Jira bookmark to channel
515
+ incident.conversation.add_bookmark(
516
+ title="Jira ticket",
517
+ link=jira_ticket.url,
518
+ emoji=":jira_new:",
519
+ )
520
+
521
+ # Send incident announcement in channel
522
+ incident.conversation.send_message_and_save(
523
+ SlackMessageIncidentDeclaredAnnouncement(incident)
524
+ )
525
+ else:
526
+ # P4-P5: Send DM and raid_alert notifications
527
+ logger.info(f"UNIFIED FORM - Sending Slack alerts for P4-P5 incident {incident.id}")
528
+ alert_slack_new_jira_ticket(jira_ticket)
529
+
530
+ logger.info(f"UNIFIED FORM - Jira ticket creation complete for incident {incident.id}")
@@ -0,0 +1,158 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ from typing import TYPE_CHECKING, Any
5
+
6
+ from django import forms
7
+
8
+ from firefighter.incidents.enums import IncidentStatus
9
+ from firefighter.incidents.forms.utils import EnumChoiceField, GroupedModelChoiceField
10
+ from firefighter.incidents.models import IncidentCategory, Priority
11
+
12
+ if TYPE_CHECKING:
13
+ from firefighter.incidents.models import Incident
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ class UpdateStatusForm(forms.Form):
19
+ message = forms.CharField(
20
+ label="Update message",
21
+ widget=forms.Textarea,
22
+ min_length=10,
23
+ max_length=1200,
24
+ required=False,
25
+ )
26
+ status = EnumChoiceField(
27
+ enum_class=IncidentStatus,
28
+ label="Status",
29
+ choices=IncidentStatus.choices_lte(IncidentStatus.CLOSED),
30
+ )
31
+ priority = forms.ModelChoiceField(
32
+ label="Priority",
33
+ queryset=Priority.objects.filter(enabled_update=True),
34
+ )
35
+ incident_category = GroupedModelChoiceField(
36
+ choices_groupby="group",
37
+ label="Incident category",
38
+ queryset=IncidentCategory.objects.all()
39
+ .select_related("group")
40
+ .order_by(
41
+ "group__order",
42
+ "name",
43
+ ),
44
+ )
45
+
46
+ def __init__(self, *args: Any, incident: Incident | None = None, **kwargs: Any) -> None:
47
+ super().__init__(*args, **kwargs)
48
+
49
+ # Dynamically adjust status choices based on incident requirements
50
+ if incident:
51
+ self._set_status_choices(incident)
52
+
53
+ def _set_status_choices(self, incident: Incident) -> None:
54
+ """Set the status field choices based on the incident's current state and requirements."""
55
+ current_status = incident.status
56
+ status_field = self.fields["status"]
57
+
58
+ # Check if incident requires post-mortem (P1/P2 in PRD)
59
+ requires_postmortem = bool(
60
+ incident.priority
61
+ and incident.environment
62
+ and incident.priority.needs_postmortem
63
+ and incident.environment.value == "PRD"
64
+ )
65
+
66
+ allowed_statuses = self._get_allowed_statuses(current_status, requires_postmortem=requires_postmortem)
67
+
68
+ # If we got a list of enum values, convert to choices and include current status
69
+ if allowed_statuses:
70
+ if current_status not in allowed_statuses:
71
+ allowed_statuses.insert(0, current_status)
72
+ # Convert values to strings to match what Slack sends in form submissions
73
+ choices = [(str(s.value), s.label) for s in allowed_statuses]
74
+ status_field.choices = choices # type: ignore[attr-defined]
75
+ logger.debug(
76
+ f"Set status choices for incident #{incident.id}: {choices} "
77
+ f"(current_status={current_status}, requires_postmortem={requires_postmortem})"
78
+ )
79
+
80
+ def _get_allowed_statuses(
81
+ self, current_status: IncidentStatus, *, requires_postmortem: bool
82
+ ) -> list[IncidentStatus] | None:
83
+ """Get allowed status transitions based on current status and postmortem requirement.
84
+
85
+ Returns None if choices should be set directly (for default fallback cases).
86
+ """
87
+ status_field = self.fields["status"]
88
+
89
+ # For incidents requiring post-mortem (P1/P2 in PRD)
90
+ if requires_postmortem:
91
+ return self._get_postmortem_allowed_statuses(current_status, status_field)
92
+
93
+ # For P3+ incidents (no post-mortem needed)
94
+ return self._get_no_postmortem_allowed_statuses(current_status, status_field)
95
+
96
+ def _get_postmortem_allowed_statuses(
97
+ self, current_status: IncidentStatus, status_field: Any
98
+ ) -> list[IncidentStatus] | None:
99
+ """Get allowed statuses for incidents requiring postmortem."""
100
+ if current_status == IncidentStatus.OPEN:
101
+ return [IncidentStatus.INVESTIGATING, IncidentStatus.CLOSED]
102
+ if current_status == IncidentStatus.INVESTIGATING:
103
+ return [IncidentStatus.MITIGATING, IncidentStatus.CLOSED]
104
+ if current_status == IncidentStatus.MITIGATING:
105
+ return [IncidentStatus.MITIGATED]
106
+ if current_status == IncidentStatus.MITIGATED:
107
+ return [IncidentStatus.POST_MORTEM]
108
+ if current_status == IncidentStatus.POST_MORTEM:
109
+ return [IncidentStatus.CLOSED]
110
+
111
+ # Default: all statuses up to closed
112
+ self._set_default_choices(status_field, current_status, IncidentStatus.choices_lte(IncidentStatus.CLOSED))
113
+ return None
114
+
115
+ def _get_no_postmortem_allowed_statuses(
116
+ self, current_status: IncidentStatus, status_field: Any
117
+ ) -> list[IncidentStatus] | None:
118
+ """Get allowed statuses for incidents not requiring postmortem."""
119
+ if current_status == IncidentStatus.OPEN:
120
+ return [IncidentStatus.INVESTIGATING, IncidentStatus.CLOSED]
121
+ if current_status == IncidentStatus.INVESTIGATING:
122
+ return [IncidentStatus.MITIGATING, IncidentStatus.CLOSED]
123
+ if current_status == IncidentStatus.MITIGATING:
124
+ return [IncidentStatus.MITIGATED]
125
+ if current_status == IncidentStatus.MITIGATED:
126
+ return [IncidentStatus.CLOSED]
127
+
128
+ # Default fallback
129
+ self._set_default_choices(
130
+ status_field, current_status, IncidentStatus.choices_lte_skip_postmortem(IncidentStatus.CLOSED)
131
+ )
132
+ return None
133
+
134
+ def _set_default_choices(
135
+ self, status_field: Any, current_status: IncidentStatus, default_choices: Any
136
+ ) -> None:
137
+ """Set status field choices to default, ensuring current status is included."""
138
+ # Convert default_choices to string keys to match Slack form submissions
139
+ status_field.choices = [(str(choice[0]), choice[1]) for choice in default_choices]
140
+ existing_values = {choice[0] for choice in status_field.choices}
141
+ if str(current_status.value) not in existing_values:
142
+ # Insert current status at the beginning
143
+ status_field.choices = [(str(current_status.value), current_status.label), *status_field.choices]
144
+
145
+ @staticmethod
146
+ def requires_closure_reason(incident: Incident, target_status: IncidentStatus) -> bool:
147
+ """Check if closing this incident to the target status requires a closure reason.
148
+
149
+ Based on the workflow diagram:
150
+ - P1/P2 and P3/P4/P5: require reason when closing from Opened or Investigating
151
+ """
152
+ if target_status != IncidentStatus.CLOSED:
153
+ return False
154
+
155
+ current_status = incident.status
156
+
157
+ # Require reason if closing from Opened or Investigating (for any priority)
158
+ return current_status.value in {IncidentStatus.OPEN, IncidentStatus.INVESTIGATING}
@@ -77,8 +77,22 @@ class EnumChoiceField(TypedChoiceField):
77
77
  self.enum_class = enum_class
78
78
  if "choices" not in kwargs:
79
79
  kwargs["choices"] = enum_class.choices
80
+
81
+ # Customize error messages for better UX
82
+ if "error_messages" not in kwargs:
83
+ kwargs["error_messages"] = {}
84
+ if "invalid_choice" not in kwargs["error_messages"]:
85
+ kwargs["error_messages"]["invalid_choice"] = (
86
+ "The selected value is not valid. Please select a value from the dropdown list."
87
+ )
88
+
80
89
  super().__init__(*args, coerce=self.coerce_func, **kwargs)
81
90
 
91
+ def validate(self, value: Any) -> None:
92
+ """Log validation for debugging."""
93
+ logger.debug(f"EnumChoiceField.validate: value={value!r} (type={type(value).__name__}), choices={self.choices}")
94
+ return super().validate(value)
95
+
82
96
  def to_python(self, value: Any) -> int | str | Any:
83
97
  """Return a value from the enum class."""
84
98
  if value in self.empty_values:
@@ -582,6 +582,9 @@ class Incident(models.Model):
582
582
  ) -> IncidentUpdate:
583
583
  updated_fields: list[str] = []
584
584
 
585
+ # Save old priority BEFORE modifying the incident
586
+ old_priority = self.priority if priority_id is not None else None
587
+
585
588
  def _update_incident_field(
586
589
  incident: Incident, field_name: str, value: Any, updated_fields: list[str]
587
590
  ) -> None:
@@ -596,8 +599,6 @@ class Incident(models.Model):
596
599
  _update_incident_field(self, "description", description, updated_fields)
597
600
  _update_incident_field(self, "environment_id", environment_id, updated_fields)
598
601
 
599
- old_priority = self.priority if priority_id is not None else None
600
-
601
602
  if updated_fields:
602
603
  self.save(update_fields=[*updated_fields, "updated_at"])
603
604
 
@@ -17,7 +17,6 @@ class RaidConfig(AppConfig):
17
17
  import firefighter.raid.tasks
18
18
  import firefighter.raid.urls
19
19
  from firefighter.raid.signals import (
20
- incident_created,
21
20
  incident_updated,
22
21
  )
23
22
  from firefighter.slack.views.modals.open import INCIDENT_TYPES
@@ -0,0 +1,23 @@
1
+ from __future__ import annotations
2
+
3
+ import importlib
4
+ from typing import TYPE_CHECKING, Any
5
+
6
+ import django.dispatch
7
+
8
+ from firefighter.slack.signals.incident_closed import incident_closed_slack
9
+
10
+ if TYPE_CHECKING:
11
+ from firefighter.slack.signals import incident_updated
12
+
13
+ incident_channel_done = django.dispatch.Signal()
14
+
15
+ __all__ = ["incident_channel_done", "incident_closed_slack", "incident_updated"]
16
+
17
+
18
+ def __getattr__(name: str) -> Any:
19
+ """Lazy import to avoid circular dependencies."""
20
+ if name == "incident_updated":
21
+ return importlib.import_module(".incident_updated", package="firefighter.slack.signals")
22
+ msg = f"module {__name__!r} has no attribute {name!r}"
23
+ raise AttributeError(msg)
@@ -38,6 +38,11 @@ def incident_updated_update_status_handler(
38
38
  updated_fields: list[str],
39
39
  **kwargs: Any,
40
40
  ) -> None:
41
+ # Skip Slack operations for incidents without channels (e.g., P4-P5)
42
+ if not hasattr(incident, "conversation"):
43
+ logger.debug(f"Skipping Slack channel update for incident {incident.id} (no conversation)")
44
+ return
45
+
41
46
  # Update Slack channel if needed
42
47
  incident.conversation.rename_if_needed()
43
48
 
@@ -65,7 +70,25 @@ def incident_updated_check_dowmgrade_handler(
65
70
  updated_fields: list[str],
66
71
  **kwargs: Any,
67
72
  ) -> None:
68
- if not incident_update.priority or incident_update.priority.value <= 2:
73
+ # Skip Slack operations for incidents without channels (e.g., P4-P5)
74
+ if not hasattr(incident, "conversation"):
75
+ return
76
+
77
+ # Only show downgrade hint when downgrading from critical (P1/P2/P3) to normal (P4/P5)
78
+ old_priority: Priority | None = kwargs.get("old_priority")
79
+
80
+ # Check if priority was actually changed
81
+ if not incident_update.priority or "priority_id" not in updated_fields:
82
+ return
83
+
84
+ # New priority must be P4 or P5 (normal incident)
85
+ new_priority_is_normal = incident_update.priority.value >= 4
86
+
87
+ # Old priority must have been P1, P2, or P3 (critical incident)
88
+ old_priority_was_critical = old_priority is not None and old_priority.value <= 3
89
+
90
+ # Only show hint if downgrading from critical to normal
91
+ if not (new_priority_is_normal and old_priority_was_critical):
69
92
  return
70
93
 
71
94
  try:
@@ -103,6 +126,10 @@ def incident_updated_update_roles_handler(
103
126
  updated_fields: list[str],
104
127
  **kwargs: Any,
105
128
  ) -> None:
129
+ # Skip Slack operations for incidents without channels (e.g., P4-P5)
130
+ if not hasattr(incident, "conversation"):
131
+ return
132
+
106
133
  # Publish a message to the conversation
107
134
  update_roles_message = SlackMessageIncidentRolesUpdated(
108
135
  incident=incident,
@@ -135,6 +162,10 @@ def incident_updated_reinvite_handler(
135
162
  updated_fields: list[str],
136
163
  **kwargs: Any,
137
164
  ) -> None:
165
+ # Skip Slack operations for incidents without channels (e.g., P4-P5)
166
+ if not hasattr(incident, "conversation"):
167
+ return
168
+
138
169
  if incident.conversation.type == ConversationType.PRIVATE_CHANNEL:
139
170
  return
140
171
 
@@ -159,6 +190,12 @@ def incident_key_events_updated_handler(
159
190
  **kwargs: Any,
160
191
  ) -> None:
161
192
  logger.info("Received incident_key_events_updated signal")
193
+
194
+ # Skip Slack operations for incidents without channels (e.g., P4-P5)
195
+ if not hasattr(incident, "conversation"):
196
+ logger.debug(f"Skipping key events update for incident {incident.id} (no conversation)")
197
+ return
198
+
162
199
  # Skip key events for incidents closed directly
163
200
  if incident.closure_reason:
164
201
  logger.info(f"Skipping key events update for incident {incident.id} (direct closure)")
@@ -180,6 +217,11 @@ def publish_status_update(
180
217
  old_priority: Priority | None = None,
181
218
  ) -> None:
182
219
  """Publishes an update to the incident status."""
220
+ # Skip Slack operations for incidents without channels (e.g., P4-P5)
221
+ if not hasattr(incident, "conversation"):
222
+ logger.debug(f"Skipping status update publication for incident {incident.id} (no conversation)")
223
+ return
224
+
183
225
  message = SlackMessageIncidentStatusUpdated(
184
226
  incident=incident,
185
227
  incident_update=incident_update,