firefighter-incident 0.0.16__py3-none-any.whl → 0.0.17__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. firefighter/_version.py +2 -2
  2. firefighter/incidents/forms/edit.py +5 -3
  3. firefighter/incidents/forms/unified_incident.py +180 -56
  4. firefighter/incidents/forms/update_status.py +94 -58
  5. firefighter/incidents/forms/utils.py +14 -0
  6. firefighter/incidents/models/incident.py +3 -2
  7. firefighter/raid/apps.py +0 -1
  8. firefighter/slack/signals/__init__.py +16 -0
  9. firefighter/slack/signals/incident_updated.py +43 -1
  10. firefighter/slack/utils.py +43 -6
  11. firefighter/slack/views/modals/base_modal/form_utils.py +3 -1
  12. firefighter/slack/views/modals/downgrade_workflow.py +3 -1
  13. firefighter/slack/views/modals/edit.py +53 -7
  14. firefighter/slack/views/modals/opening/set_details.py +20 -0
  15. firefighter_fixtures/incidents/priorities.json +1 -1
  16. {firefighter_incident-0.0.16.dist-info → firefighter_incident-0.0.17.dist-info}/METADATA +1 -1
  17. {firefighter_incident-0.0.16.dist-info → firefighter_incident-0.0.17.dist-info}/RECORD +28 -29
  18. firefighter_tests/test_incidents/test_forms/test_unified_incident_form_integration.py +160 -23
  19. firefighter_tests/test_incidents/test_forms/test_unified_incident_form_p4_p5.py +38 -60
  20. firefighter_tests/test_incidents/test_forms/test_update_status_workflow.py +35 -20
  21. firefighter_tests/test_incidents/test_forms/test_workflow_transitions.py +8 -6
  22. firefighter_tests/test_slack/test_signals_downgrade.py +147 -0
  23. firefighter_tests/test_slack/views/modals/test_edit.py +324 -0
  24. firefighter_tests/test_slack/views/modals/test_opening_unified.py +42 -0
  25. firefighter_tests/test_slack/views/modals/test_update_status.py +72 -2
  26. firefighter/raid/signals/incident_created.py +0 -129
  27. firefighter_tests/test_raid/test_p1_p3_jira_fields.py +0 -372
  28. firefighter_tests/test_raid/test_priority_mapping.py +0 -267
  29. {firefighter_incident-0.0.16.dist-info → firefighter_incident-0.0.17.dist-info}/WHEEL +0 -0
  30. {firefighter_incident-0.0.16.dist-info → firefighter_incident-0.0.17.dist-info}/entry_points.txt +0 -0
  31. {firefighter_incident-0.0.16.dist-info → firefighter_incident-0.0.17.dist-info}/licenses/LICENSE +0 -0
@@ -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,
@@ -85,7 +85,12 @@ def get_slack_user_id_from_body(body: dict[str, Any]) -> str | None:
85
85
 
86
86
 
87
87
  def channel_name_from_incident(incident: Incident) -> str:
88
- """Lowercase, truncated at 80 chars, this is obviously the channel #name."""
88
+ """Lowercase, truncated at 80 chars, this is obviously the channel #name.
89
+
90
+ The environment(s) are included in the channel name to clearly indicate scope.
91
+ When multiple environments are affected, all are displayed sorted by priority.
92
+ If the name exceeds 80 characters, environments are abbreviated progressively.
93
+ """
89
94
  if (
90
95
  not hasattr(incident, "created_at")
91
96
  or not hasattr(incident, "id")
@@ -96,13 +101,45 @@ def channel_name_from_incident(incident: Incident) -> str:
96
101
  "Incident must be saved before slack_channel_name can be computed"
97
102
  )
98
103
  date_formatted = localtime(incident.created_at).strftime("%Y%m%d")
99
- if incident.environment is not None and incident.environment.value != "PRD":
100
- topic = f"{date_formatted}-{str(incident.id)[:8]}-{incident.environment.value}-{incident.incident_category.name}"
104
+
105
+ # Get all environments from custom_fields, fallback to single environment field
106
+ environments_list = incident.custom_fields.get("environments", [])
107
+ if not environments_list and incident.environment is not None:
108
+ environments_list = [incident.environment.value]
109
+
110
+ # Sort environments by priority (assuming order: PRD < STG < INT < support)
111
+ # This puts the most important environment first
112
+ env_priority = {"PRD": 0, "STG": 1, "INT": 2, "support": 3}
113
+ if environments_list:
114
+ sorted_envs = sorted(environments_list, key=lambda e: env_priority.get(e, 99))
115
+ env_str = "-".join(sorted_envs)
116
+ else:
117
+ env_str = ""
118
+
119
+ # Build channel name with all environments
120
+ if env_str:
121
+ topic = f"{date_formatted}-{str(incident.id)[:8]}-{env_str}-{incident.incident_category.name}"
101
122
  else:
102
123
  topic = f"{date_formatted}-{str(incident.id)[:8]}-{incident.incident_category.name}"
103
124
 
104
- # Strip non-alphanumeric characters, cut at 80 chars
105
- # XXX django.utils.text.slugify should be used instead
125
+ # Strip non-alphanumeric characters
106
126
  topic = topic.replace(" ", "-")
107
127
  topic = NON_ALPHANUMERIC_CHARACTERS.sub("-", topic)
108
- return topic.lower()[:80]
128
+ topic_clean = topic.lower()
129
+
130
+ # Slack channel name limit is 80 characters
131
+ # If too long, try to abbreviate environments progressively
132
+ if len(topic_clean) > 80:
133
+ # Try with abbreviated environments (first 3 chars)
134
+ if environments_list:
135
+ abbrev_envs = "-".join([e[:3] for e in sorted_envs])
136
+ topic = f"{date_formatted}-{str(incident.id)[:8]}-{abbrev_envs}-{incident.incident_category.name}"
137
+ topic = topic.replace(" ", "-")
138
+ topic = NON_ALPHANUMERIC_CHARACTERS.sub("-", topic)
139
+ topic_clean = topic.lower()
140
+
141
+ # If still too long, truncate at 80 chars
142
+ if len(topic_clean) > 80:
143
+ topic_clean = topic_clean[:80]
144
+
145
+ return topic_clean
@@ -147,7 +147,9 @@ class SlackForm(Generic[T]):
147
147
  else:
148
148
  initial = self.form.initial.get(field_name, f.initial)
149
149
 
150
- if callable(f.initial):
150
+ # Only call the callable if we don't have an initial value from form.initial
151
+ # This allows form-level initial values to override field-level defaults
152
+ if initial is None and callable(f.initial):
151
153
  initial = f.initial()
152
154
  return initial
153
155
 
@@ -67,6 +67,9 @@ class DowngradeWorkflowModal(
67
67
 
68
68
  @staticmethod
69
69
  def handle_modal_fn(ack: Ack, user: User, incident: Incident) -> None: # type: ignore[override]
70
+ # Acknowledge the modal submission immediately (must be within 3 seconds)
71
+ ack()
72
+
70
73
  # XXX(dugab): error handling
71
74
  incident.ignore = True
72
75
  incident.save()
@@ -80,7 +83,6 @@ class DowngradeWorkflowModal(
80
83
  status=IncidentStatus.CLOSED,
81
84
  message=f"Incident channel closed - follow the incident on its Jira Ticket{jira_txt}",
82
85
  )
83
- ack()
84
86
 
85
87
  def get_select_title(self) -> str:
86
88
  return "Select a critical incident you want to convert to a Jira incident"
@@ -38,7 +38,7 @@ class EditMetaFormSlack(EditMetaForm):
38
38
  },
39
39
  "environment": {
40
40
  "input": {
41
- "placeholder": "Select an environment",
41
+ "placeholder": "Select environments (multiple allowed)",
42
42
  },
43
43
  "widget": {
44
44
  "label_from_instance": lambda obj: f"{obj.value} - {obj.description}",
@@ -57,11 +57,24 @@ class EditMetaModal(ModalForm[EditMetaFormSlack]):
57
57
  form_class = EditMetaFormSlack
58
58
 
59
59
  def build_modal_fn(self, incident: Incident, **kwargs: Any) -> View:
60
+ from firefighter.incidents.models import Environment # noqa: PLC0415
61
+
62
+ # Get all environments from custom_fields, fallback to single environment
63
+ environments_values = incident.custom_fields.get("environments", [])
64
+ if environments_values:
65
+ # Convert environment value strings to Environment objects
66
+ environments = list(
67
+ Environment.objects.filter(value__in=environments_values)
68
+ )
69
+ else:
70
+ # Fallback to single environment field
71
+ environments = [incident.environment] if incident.environment else []
72
+
60
73
  blocks = self.get_form_class()(
61
74
  initial={
62
75
  "title": incident.title,
63
76
  "description": incident.description,
64
- "environment": incident.environment,
77
+ "environment": environments,
65
78
  },
66
79
  ).slack_blocks()
67
80
 
@@ -77,6 +90,18 @@ class EditMetaModal(ModalForm[EditMetaFormSlack]):
77
90
  def handle_modal_fn( # type: ignore
78
91
  self, ack: Ack, body: dict[str, Any], incident: Incident, user: User
79
92
  ):
93
+ from firefighter.incidents.models import Environment # noqa: PLC0415
94
+
95
+ # Get current environments for initial comparison
96
+ environments_values = incident.custom_fields.get("environments", [])
97
+ if environments_values:
98
+ current_environments = list(
99
+ Environment.objects.filter(value__in=environments_values)
100
+ )
101
+ else:
102
+ current_environments = (
103
+ [incident.environment] if incident.environment else []
104
+ )
80
105
 
81
106
  slack_form = self.handle_form_errors(
82
107
  ack,
@@ -85,7 +110,7 @@ class EditMetaModal(ModalForm[EditMetaFormSlack]):
85
110
  "initial": {
86
111
  "title": incident.title,
87
112
  "description": incident.description,
88
- "environment": incident.environment,
113
+ "environment": current_environments,
89
114
  }
90
115
  },
91
116
  )
@@ -97,15 +122,36 @@ class EditMetaModal(ModalForm[EditMetaFormSlack]):
97
122
 
98
123
  return
99
124
  update_kwargs: dict[str, Any] = {}
125
+ update_custom_fields = False
126
+
100
127
  for changed_key in form.changed_data:
101
128
  if changed_key == "environment":
102
- update_kwargs[f"{changed_key}_id"] = form.cleaned_data[changed_key].id
129
+ # Handle multiple environments
130
+ environments = form.cleaned_data[changed_key]
131
+ if environments:
132
+ # Select highest priority environment (lowest order) for main field
133
+ primary_env = min(environments, key=lambda env: env.order)
134
+ update_kwargs["environment_id"] = primary_env.id
135
+
136
+ # Update custom_fields with all selected environments
137
+ custom_fields = incident.custom_fields.copy()
138
+ custom_fields["environments"] = [env.value for env in environments]
139
+ incident.custom_fields = custom_fields
140
+ update_custom_fields = True
103
141
  if changed_key in {"description", "title"}:
104
142
  update_kwargs[changed_key] = form.cleaned_data[changed_key]
105
- if len(update_kwargs) == 0:
106
- logger.warning("No update to incident status")
143
+
144
+ if len(update_kwargs) == 0 and not update_custom_fields:
145
+ logger.warning("No update to incident")
107
146
  return
108
- self._trigger_incident_workflow(incident, user, **update_kwargs)
147
+
148
+ # Save custom_fields if updated
149
+ if update_custom_fields:
150
+ incident.save(update_fields=["custom_fields"])
151
+
152
+ # Create incident update for tracked fields
153
+ if update_kwargs:
154
+ self._trigger_incident_workflow(incident, user, **update_kwargs)
109
155
 
110
156
  @staticmethod
111
157
  def _trigger_incident_workflow(
@@ -58,6 +58,25 @@ class SetIncidentDetails(ModalForm[T], Generic[T]):
58
58
  )
59
59
  for field_name, field in self.form_class.base_fields.items():
60
60
  if (
61
+ isinstance(field, forms.ModelMultipleChoiceField)
62
+ and field_name in details_form_data
63
+ and field.queryset is not None
64
+ and field.queryset.model
65
+ and hasattr(field.queryset.model, "DoesNotExist")
66
+ ):
67
+ # Handle ModelMultipleChoiceField (e.g., environment)
68
+ value = details_form_data[field_name]
69
+ if isinstance(value, list) and value and not isinstance(value[0], Model):
70
+ # Convert list of UUIDs to list of model instances, preserving order
71
+ objects_dict = {
72
+ str(obj.pk): obj
73
+ for obj in field.queryset.filter(pk__in=value)
74
+ }
75
+ # Preserve the original order from the value list
76
+ details_form_data[field_name] = [
77
+ objects_dict[str(pk)] for pk in value if str(pk) in objects_dict
78
+ ]
79
+ elif (
61
80
  isinstance(field, forms.ModelChoiceField)
62
81
  and field_name in details_form_data
63
82
  and not isinstance(details_form_data[field_name], Model)
@@ -65,6 +84,7 @@ class SetIncidentDetails(ModalForm[T], Generic[T]):
65
84
  and field.queryset.model
66
85
  and hasattr(field.queryset.model, "DoesNotExist")
67
86
  ):
87
+ # Handle single ModelChoiceField
68
88
  try:
69
89
  details_form_data[field_name] = field.queryset.get(
70
90
  pk=details_form_data[field_name]
@@ -85,7 +85,7 @@
85
85
  "description": "Minor issue affecting customers.",
86
86
  "order": 2,
87
87
  "default": false,
88
- "needs_postmortem": true,
88
+ "needs_postmortem": false,
89
89
  "enabled_create": true,
90
90
  "enabled_update": true,
91
91
  "reminder_time": "01:00:00",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: firefighter-incident
3
- Version: 0.0.16
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/
@@ -6,7 +6,7 @@ gunicorn.conf.py,sha256=vHsTGjaKOr8FDMp6fTKYTX4AtokmPgYvvt5Mr0Q6APc,273
6
6
  main.py,sha256=CsbprHoOYhjCLpTJmq9Z_aRYFoFgWxoz2pDLuwm8Eqg,1558
7
7
  manage.py,sha256=5ivHGD13C6nJ8QvltKsJ9T9akA5he8da70HLWaEP3k8,689
8
8
  firefighter/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- firefighter/_version.py,sha256=-Wsac7GwIa9vRUxL0XYF7OQESx0pigPYBlGyyiRu8nY,706
9
+ firefighter/_version.py,sha256=S11KPmKYJXKQX0D8GWJ9ou0JkWsMIQoAxzWzBzTnRp4,706
10
10
  firefighter/api/__init__.py,sha256=JQW0Bv6xwGqy7ioxx3h6UGMzkkJ4DntDpbvV1Ncgi8k,136
11
11
  firefighter/api/admin.py,sha256=x9Ysy-GiYjb0rynmFdS9g56e6n24fkN0ouGy5QD9Yrc,4629
12
12
  firefighter/api/apps.py,sha256=P5uU1_gMrDfzurdMbfqw1Bnb2uNKKcMq17WBPg2sLhc,204
@@ -140,13 +140,13 @@ firefighter/incidents/forms/__init__.py,sha256=OU0r5eZc2A0UJNsL83n8AI5EvwUvg4Yx0
140
140
  firefighter/incidents/forms/close_incident.py,sha256=wyLIlNXx6eU183SkR8H--k9YEOVehOWMecY82Bc2PmM,965
141
141
  firefighter/incidents/forms/closure_reason.py,sha256=rwWC9Ks8iuuelCv2oqSpGUjL13yogpdbWHdG2yM23Rc,1564
142
142
  firefighter/incidents/forms/create_incident.py,sha256=cm5EWIvkJ1BZ-JfRJrh4TAE2wYYLV694gQ3MRIkcrGQ,2764
143
- firefighter/incidents/forms/edit.py,sha256=2rQkiKak-vac-K3cIsqlGv4R5nhI7JLxw3DhFMXbWms,956
143
+ firefighter/incidents/forms/edit.py,sha256=RxjmYpSeVo9Xbrs09hbmKO6siy3-PusKqg1VV5xAVr4,1051
144
144
  firefighter/incidents/forms/select_impact.py,sha256=jLbzVj4UeUGwOYYa5P92PXkEu1J_6H43UATZYzDgSLY,4630
145
- firefighter/incidents/forms/unified_incident.py,sha256=duLMT_Jba3ZO8qMkP3Stdkd4f3tJpnvw-KjrIMSCfrk,14849
145
+ firefighter/incidents/forms/unified_incident.py,sha256=3xDB3IFJVwrRe9C_G52SjQ9-Xeqe1ivAGb0e8xtXJaY,19564
146
146
  firefighter/incidents/forms/update_key_events.py,sha256=1Xmnxe5OgZqLFS2HmMzQm3VGFPQipsdrLgKSwdh-fKc,4441
147
147
  firefighter/incidents/forms/update_roles.py,sha256=Q26UPfwAj-8N23RNZLQkvmHGnS1_j_X5KQWjJmPjMKY,3635
148
- firefighter/incidents/forms/update_status.py,sha256=LlQNufJ3YHbVnTk81WEwazds1JjbSzfaFjvvNW3q_oM,6196
149
- firefighter/incidents/forms/utils.py,sha256=g2azRXQE4GwBNvq47z_Q51yKcGYSBzFyITTDkLlC_Gk,3651
148
+ firefighter/incidents/forms/update_status.py,sha256=7GSno_EqD2Brd6wWcSb3zsP6nz8_mUTXXnl0QCRhv48,6682
149
+ firefighter/incidents/forms/utils.py,sha256=15e_dBebVd9SvX03DYd0FyZ8s0YpxyBlZfIzEZattwg,4267
150
150
  firefighter/incidents/migrations/0001_initial_oss.py,sha256=OCrPbxf90h3NW9xolGGcsAryHKptD1TtKj5FucjBjg8,60311
151
151
  firefighter/incidents/migrations/0002_alter_severity_name_alter_user_password_featureteam.py,sha256=YfIJhw_-Yqm8qrkbp01461bkcUr7v5Zy90oHjkY3bSA,1113
152
152
  firefighter/incidents/migrations/0003_delete_featureteam.py,sha256=kH5UUSx3k5DtjR_goDxROdV0htCC2JZfBGwJpn-dEQs,336
@@ -181,7 +181,7 @@ firefighter/incidents/models/__init__.py,sha256=FLVyBwIdyxLdgSvXRAKC3fry9Ywwqlqh
181
181
  firefighter/incidents/models/environment.py,sha256=51txwua3dCrWZ1iSG3ZA8rbDn9c00pyMAZujl9gwE5c,827
182
182
  firefighter/incidents/models/group.py,sha256=VrVL315VFUvKW69AZuRUBg1h0jZJvn8zWeMxMOWec1Y,700
183
183
  firefighter/incidents/models/impact.py,sha256=URoMsQBJQnyfaNRpVl1o4A1IllM7dg94sd6tf5Ssr-k,4868
184
- firefighter/incidents/models/incident.py,sha256=Rory-6YF_iBuHMNTbV8VbHK77i1nu9NWF2cgYSQT-zg,27243
184
+ firefighter/incidents/models/incident.py,sha256=PoeNq7NDn_9sP65YURQ1_DQDBXW8q6wltxy6BblR3Ag,27301
185
185
  firefighter/incidents/models/incident_category.py,sha256=g4OHv_XQhWcH6dvkqkyCgjlruo_1eih_CdtAPgPhaW4,7744
186
186
  firefighter/incidents/models/incident_cost.py,sha256=juwOfJKRaNQpOHkRUCHShDDba0FU98YjRPkU4I0ofAU,1346
187
187
  firefighter/incidents/models/incident_cost_type.py,sha256=wm8diry_VySJzIjC9M3Yavv2tYbvJgpN9UDb2gFRuH4,845
@@ -310,7 +310,7 @@ firefighter/pagerduty/views/oncall_list.py,sha256=o8h0ln7YsYcJp_N8DePzIBO2NMc2bJ
310
310
  firefighter/pagerduty/views/oncall_trigger.py,sha256=LYHpWyEaR6O8NazmsTl5ydtw1XHynUfaTB1IU429eZ8,2526
311
311
  firefighter/raid/__init__.py,sha256=nMNmvHCSkyLQsdhTow7myMU62vXk1e755gUntVfFFlY,154
312
312
  firefighter/raid/admin.py,sha256=WhIHaRAv7JPp2NH27w7_0JfvGHrvoyRJhYr3_WwedrA,1117
313
- firefighter/raid/apps.py,sha256=cMT87gw_Nur3Kx-Ws9spJWZQZ35SqcU-1_7oa5CEPc8,1147
313
+ firefighter/raid/apps.py,sha256=olDKua1rqhhIJUhCu6A2PnPWloW_jbeD4XWL94b2owo,1117
314
314
  firefighter/raid/client.py,sha256=ja_tiKAcBFpI5ZwbGxSVyf7_ETq2K1Qauq26pMR-Ze4,8124
315
315
  firefighter/raid/forms.py,sha256=gbbXDizCYDs8vz33ZFClTVZ_yM3jqZtWFMYRy3K3xuM,11863
316
316
  firefighter/raid/messages.py,sha256=e75kwi0hCe5ChwU4t-_6Q3Rcy22MLLdVSsYyjvG2SCM,5542
@@ -326,7 +326,6 @@ firefighter/raid/migrations/0002_featureteam_remove_qualifierrotation_jira_user_
326
326
  firefighter/raid/migrations/0003_delete_raidarea.py,sha256=M_XkKCu73ib2H09co2L-ssLQakJJFNOfqJpKrzOYP2Y,332
327
327
  firefighter/raid/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
328
328
  firefighter/raid/signals/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
329
- firefighter/raid/signals/incident_created.py,sha256=_XVgS20fvB3Oy9xfDv8apX6ETpoG3mGxBFhZwfgD5qU,5261
330
329
  firefighter/raid/signals/incident_updated.py,sha256=5LYeqvgTrfINu_SOwkZa3hD6rvTsl8BL8Py-immqK3I,1374
331
330
  firefighter/raid/tasks/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
332
331
  firefighter/raid/views/__init__.py,sha256=noK-M1X4L46OMAp6S29jqajovzL6sIMSnIBv5l9vxIM,5174
@@ -339,7 +338,7 @@ firefighter/slack/slack_app.py,sha256=mvaH0hPFaNIUxEB7J0fy6y-PNPGsdPqjXFVmpTQ_hC
339
338
  firefighter/slack/slack_incident_context.py,sha256=PjE7-w-pGFyV4faw8EMsEFp4RG_T251RhofmqrsDG7Q,7277
340
339
  firefighter/slack/slack_templating.py,sha256=rWe8m1n648wizw08U_vLz8daRnp4zmkcWRqocIBpQj4,3841
341
340
  firefighter/slack/urls.py,sha256=3HKbEPcjV-XzFvGFBS3FWsAOshp33hssOxRAmSaBIgE,247
342
- firefighter/slack/utils.py,sha256=wsSQs-WnV2WybvQixfYputcVdzEjr7eFsGZxbrUJm8s,4095
341
+ firefighter/slack/utils.py,sha256=-3r2mCtBQFMQgvojWrsqh4TNoHv9puD07aC32iGDc0s,5611
343
342
  firefighter/slack/forms/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
344
343
  firefighter/slack/forms/sos_form.py,sha256=v544RMMzUjVgInSaZh_75PmbZf0FIKy4fcjdlV78pCE,257
345
344
  firefighter/slack/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -365,12 +364,12 @@ firefighter/slack/models/message.py,sha256=E1MQoZJz4MsgCeqgP94_jtSrz2RYuWdoys8tz
365
364
  firefighter/slack/models/sos.py,sha256=Sji-7DxgsrLs7vFRJKPw7nmYyo2tIjNwoTcmdCmzEvA,1418
366
365
  firefighter/slack/models/user.py,sha256=2Thcz5qQUsWGV9q77U5Z1b_jePZQJfE7BehwN_BlYH8,17230
367
366
  firefighter/slack/models/user_group.py,sha256=9bedrDwDwj641oTy65ucw63oQasCyKWhBZ1xx6peMBM,7141
368
- firefighter/slack/signals/__init__.py,sha256=dqMf2x-PVKgmwzH2d9uHuQ8hZ4fbu74eRd4Ij2_dNSg,186
367
+ firefighter/slack/signals/__init__.py,sha256=hzA6_s8V6J-hp6fNC-aaXwxQEaoF-zXCisFMUd9uXho,714
369
368
  firefighter/slack/signals/create_incident_conversation.py,sha256=6oxNJzprU312-3Hd6ACijQcbmcHkm7ikJsWaQNo54ig,5224
370
369
  firefighter/slack/signals/get_users.py,sha256=-ZUI3ORJZJ4tLiGhVwIU-pWHoriALtOC7Kh_bFR4bGU,2287
371
370
  firefighter/slack/signals/handle_incident_channel_done.py,sha256=pYoS_ZJf2u9seHCqahfPHz4BrfvF1vIZjE1_yy0P5mY,1726
372
371
  firefighter/slack/signals/incident_closed.py,sha256=6QyUmTjEGVg0Wn5W-i2F8DlJuhvHjg3MxkcvAXFn9Bk,687
373
- firefighter/slack/signals/incident_updated.py,sha256=HiJlyHHzGhkip5v6aOky4xNzbrfG_kD4cqEnrASfr6g,8407
372
+ firefighter/slack/signals/incident_updated.py,sha256=MBouWXbLByEynGoytdFeRyioDxi5VFO8dlgI0kygX1E,10137
374
373
  firefighter/slack/signals/postmortem_created.py,sha256=XY8_lEmBEG3VSsankpbOWdEB9dom9Ke6u8ss4-aDX6Y,1152
375
374
  firefighter/slack/signals/roles_reminders.py,sha256=1Ef_J1PubY8WTVs2WDXz4KWa6X2Lvp1RFObIjSGpiOM,4041
376
375
  firefighter/slack/tasks/__init__.py,sha256=28QxZkakyi9l7Ae83fQuzOS-9EaBiwuh_peUZwIxCx4,179
@@ -401,8 +400,8 @@ firefighter/slack/views/events/reaction_added.py,sha256=AipwBnrU5B35D97YIZCXdSW8
401
400
  firefighter/slack/views/modals/__init__.py,sha256=U9PapAIlpuYqBonOUmBGWT8_HjQa35ilMQJXGaFLgd0,1945
402
401
  firefighter/slack/views/modals/close.py,sha256=4j5iA-lmIFuCz7B9pgDmjxrqmfWFysqWEn1YIsE75zc,12161
403
402
  firefighter/slack/views/modals/closure_reason.py,sha256=eEBK1_sfY9TAKFsajS-As0kZgDPwuU_8DE0z2OANbvc,6943
404
- firefighter/slack/views/modals/downgrade_workflow.py,sha256=S0y0_GYH4q7ewZUr_eA9Ly2c1FQueZzNCTiuIiWYUoY,3109
405
- firefighter/slack/views/modals/edit.py,sha256=60xav4XG4KGS9KknqsQNCQjl3qQzk7OtmHiEYTQ9pUk,3861
403
+ firefighter/slack/views/modals/downgrade_workflow.py,sha256=cRWsm3DmKRRI1-Jpjprb5xeY2U7HvRo6eZlUbGuzr1A,3192
404
+ firefighter/slack/views/modals/edit.py,sha256=1N0OBSxsDuN6lJoH-djbEljy7f0LcDEpJF-U5YoEFXA,5895
406
405
  firefighter/slack/views/modals/key_event_message.py,sha256=ga3-ITZyzJExwzctX-GfgnDqyQaxTfcqpqnOwY2E38M,5620
407
406
  firefighter/slack/views/modals/open.py,sha256=YIxpo8_C4cWCy_pQ3YRWl7NMyLmjqNjggTQINTBW6mo,29189
408
407
  firefighter/slack/views/modals/postmortem.py,sha256=YlBZ1ziONmbA818hPo0H54deWogiH3Xy1jArMiazx-4,2851
@@ -417,13 +416,13 @@ firefighter/slack/views/modals/utils.py,sha256=zKLJD2KhTGcX2d9WCYwshYRa6ok_9-ED1
417
416
  firefighter/slack/views/modals/base_modal/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
418
417
  firefighter/slack/views/modals/base_modal/base.py,sha256=7mvOxZTtegSmitSMnDvu8BK0qLUXoudUsda6CaLjdkY,12479
419
418
  firefighter/slack/views/modals/base_modal/base_mixins.py,sha256=Xl1koQsPpHO_kKIiuSSJHJnIBmytDXseI1KcAZQZC3M,230
420
- firefighter/slack/views/modals/base_modal/form_utils.py,sha256=4-eBpOR770nMvYM6DF0yCe9P7PaIXMaedL4kQOkZRsE,25039
419
+ firefighter/slack/views/modals/base_modal/form_utils.py,sha256=Ha-qTFUdr5UzGcI-x3teIMMdsQZiAA56ni6lfKPyimc,25225
421
420
  firefighter/slack/views/modals/base_modal/mixins.py,sha256=c7WYs0aXKXVktEMNSZ8IUQbAmustrLbRzbOoo4nyYGA,1917
422
421
  firefighter/slack/views/modals/base_modal/modal_utils.py,sha256=1uHTlLxxeXUQttH3bHaehJwCuI6a-h04s-GzdnVA4sI,2459
423
422
  firefighter/slack/views/modals/opening/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
424
423
  firefighter/slack/views/modals/opening/check_current_incidents.py,sha256=4hFp6nEKH55j0BBYE2Ks9KNwCPImCKQdxyweIWmW5E4,2551
425
424
  firefighter/slack/views/modals/opening/select_impact.py,sha256=JFpStRhvGDcqR5DptJQajuA2VJOypM8r6_XnJcQMGB4,11699
426
- firefighter/slack/views/modals/opening/set_details.py,sha256=oLFE6ZHtOp1hbZbu3COYP8_vfaV7FtCmzkLJbihAj3M,5899
425
+ firefighter/slack/views/modals/opening/set_details.py,sha256=YxA2jJfxkuScSIwNOzZOBdDUzx22FMWXfsnD6cK3k50,6963
427
426
  firefighter/slack/views/modals/opening/types.py,sha256=ETpp0DAz5OMI5h7iv62Of7yJCbI-Q4-3kKSS6msPQeY,563
428
427
  firefighter/slack/views/modals/opening/details/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
429
428
  firefighter/slack/views/modals/opening/details/unified.py,sha256=Ubgu1It_SpxScmSChzVm8nScCqZ5TtFYJBEcUOA6XN8,7422
@@ -435,7 +434,7 @@ firefighter_fixtures/incidents/incident_categories.json,sha256=_O42ONXXhy9_J8Y3I
435
434
  firefighter_fixtures/incidents/incident_role_type.json,sha256=74hkFOHynhAAfYIDDRBXF3AciW2F_nUpMX01DN3M3rs,1738
436
435
  firefighter_fixtures/incidents/metric_type.json,sha256=3OuNdzSYzFXDz460C-SYulNIKKxIHrToL9e2kp09tGA,2750
437
436
  firefighter_fixtures/incidents/milestone_type.json,sha256=oOtWOb5YM3JDc7yj0ErKPNFLN15qqyqL0m1f5fF7zuk,2317
438
- firefighter_fixtures/incidents/priorities.json,sha256=RZO7F7TBuyV9tZ9Vg_Nsr0NOfoFiaDohh3xv4E8VI8U,3765
437
+ firefighter_fixtures/incidents/priorities.json,sha256=ZPqfC2GD7vgLBnGNxVcDpjxCLtTtkF2RJBkV8zZhErE,3766
439
438
  firefighter_fixtures/incidents/severities.json,sha256=hsaG3TT0oaRVvZVaeU6BJGddFn_gewJ4E7Lk7ufII6U,2467
440
439
  firefighter_tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
441
440
  firefighter_tests/conftest.py,sha256=fyVZNk4PX0ATjIjmq0BYjC9k3og26kkpC73npEgFlv8,3228
@@ -453,11 +452,11 @@ firefighter_tests/test_incidents/test_forms/test_closure_reason.py,sha256=H6RObq
453
452
  firefighter_tests/test_incidents/test_forms/test_form_select_impact.py,sha256=DTaPGrJi8mXHfh7mhvDTKYVvDCxqarILauE59UDlwqo,3210
454
453
  firefighter_tests/test_incidents/test_forms/test_form_utils.py,sha256=tisEDCacCrG5usEyPkFLCZeG9ebp9b9N27dcUtGmYA4,2467
455
454
  firefighter_tests/test_incidents/test_forms/test_unified_incident_form.py,sha256=tb2LSn4rtGbYblAdYXthD0UlKL4h-_u-Bj8nqvDVlGM,22701
456
- firefighter_tests/test_incidents/test_forms/test_unified_incident_form_integration.py,sha256=8_lbhnMO5FIJewYtxueRv2M6-mOBcdOjMIHRUGGzIHM,23860
457
- firefighter_tests/test_incidents/test_forms/test_unified_incident_form_p4_p5.py,sha256=7x_JVsgnpJvxN-QSsD_JeEyZatsoVKj6vPMf4VXzsIQ,16364
455
+ firefighter_tests/test_incidents/test_forms/test_unified_incident_form_integration.py,sha256=q7NKYeCgFMpfSj3V3zGWFA4wr3OzC4yEGCU1zB5RRsY,33082
456
+ firefighter_tests/test_incidents/test_forms/test_unified_incident_form_p4_p5.py,sha256=3MUWwvoZiXZFhoDmYzBS-1lPS8tj28ZF_f30dzsFOZY,15937
458
457
  firefighter_tests/test_incidents/test_forms/test_update_key_events.py,sha256=rHRGRU9iFXDdMr_kK3pMB7gyeZuMf7Dyq8bRZkddBC4,1644
459
- firefighter_tests/test_incidents/test_forms/test_update_status_workflow.py,sha256=OyFTcG3VCTIucdT7HfNgB6SDd1BmcukSRdwyw5q7xuY,15181
460
- firefighter_tests/test_incidents/test_forms/test_workflow_transitions.py,sha256=wJd6CKuoN3NGR00eJjRLHJHSazzkymf-_z_2qgBSVSE,7068
458
+ firefighter_tests/test_incidents/test_forms/test_update_status_workflow.py,sha256=q0xXU2BbBG8B0uvvyBWlo4HM8ckbcNAP05Fq8oJNtOw,16270
459
+ firefighter_tests/test_incidents/test_forms/test_workflow_transitions.py,sha256=priKh7QYZxGDPu2SvPC8pGnqOsZWg5cLkyC40pDvLAU,7184
461
460
  firefighter_tests/test_incidents/test_models/test_incident_category.py,sha256=aRoBOhb8fNjLF9CMPZ1FXM8AT51Cd80XPsY2Y3wHY_M,5701
462
461
  firefighter_tests/test_incidents/test_models/test_incident_model.py,sha256=c0A73G50SuzExHaEWJyByjmJmISChCClQYd2AydnYxY,3649
463
462
  firefighter_tests/test_incidents/test_models/test_migrations/test_incident_migrations.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -465,8 +464,6 @@ firefighter_tests/test_incidents/test_utils/test_date_utils.py,sha256=ogP7qOEwIt
465
464
  firefighter_tests/test_incidents/test_views/test_incident_detail_view.py,sha256=gKKFWIZVrD_P4p6DJjeHCW5uGXBUBVlCd95gJJYDpWQ,680
466
465
  firefighter_tests/test_incidents/test_views/test_index_view.py,sha256=InpxbaWOFwRn4YWeIKZhj17vMymrQQf2p2LFhe2Bcdw,816
467
466
  firefighter_tests/test_raid/conftest.py,sha256=i_TOquYIMLDyVQ97uqxTqPJszVz4qq7L_Q7YJxTuS1o,4090
468
- firefighter_tests/test_raid/test_p1_p3_jira_fields.py,sha256=eMicF70ov5jXGIvKwtZduRmTM7rXrphhj2gKJGSVD7s,17618
469
- firefighter_tests/test_raid/test_priority_mapping.py,sha256=h8YproDbCVbsP4DTmN0xFWfdHdhIy2Jdn7X4e4kqgYs,11969
470
467
  firefighter_tests/test_raid/test_raid_client.py,sha256=8iRBR4bKewPPbtz33hCLOHiZDTELPQBOrQb7EdNDS4c,21227
471
468
  firefighter_tests/test_raid/test_raid_client_users.py,sha256=9uma1wBhaiCoG75XAZHqpT8oGTnqFJRMCi7a3XctNtM,3631
472
469
  firefighter_tests/test_raid/test_raid_forms.py,sha256=y89ZqP6Wf9h3S2hegJHVfVdCuVbfL4SvT-kPVoAYyy8,19618
@@ -478,6 +475,7 @@ firefighter_tests/test_raid/test_raid_transitions.py,sha256=mtmMKwukxmZSM-R619BQ
478
475
  firefighter_tests/test_raid/test_raid_utils.py,sha256=i6JBwim1G-qynwxprNZekxl9K7Vis4FFvNkw3wT2jTM,1016
479
476
  firefighter_tests/test_raid/test_raid_views.py,sha256=paAhh4k2EDlmG1ehwNhMuYIhr1okqrvM7xlkaTAo2V0,6825
480
477
  firefighter_tests/test_slack/conftest.py,sha256=MCg04JFQ0iBeYUN_moEvvH4PVA3wE48Q6LkrIw7Bic0,2015
478
+ firefighter_tests/test_slack/test_signals_downgrade.py,sha256=mgl4H5vwr2kImf6g4IZbhv7YEPmMzbYSaVr8E6taL88,5420
481
479
  firefighter_tests/test_slack/test_slack_utils.py,sha256=9PLobMNXh3xDyFuwzcQFpKJhe4j__sIgf_WRHIpANJw,3957
482
480
  firefighter_tests/test_slack/messages/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
483
481
  firefighter_tests/test_slack/messages/test_slack_messages.py,sha256=60ATcQKWVuLvBbyCEiSyzvR4cnDTgEEhDclg8jrE4Hg,14391
@@ -487,15 +485,16 @@ firefighter_tests/test_slack/test_models/test_slack_user.py,sha256=uzur-Rf03I5dp
487
485
  firefighter_tests/test_slack/views/modals/conftest.py,sha256=TKJVQgqWaFs3Gg1T526pti9XpZBtQs47WBH6L_qSDeo,4532
488
486
  firefighter_tests/test_slack/views/modals/test_close.py,sha256=wuqMkpyUWKvC_gaTnJvRmdm8-wsmbLpCU_ith4ihsLY,45447
489
487
  firefighter_tests/test_slack/views/modals/test_closure_reason_modal.py,sha256=R-a8NJZmbNKZeVbAS3DFe_U7sw-GM4p_fKRkqBP6yPM,5099
488
+ firefighter_tests/test_slack/views/modals/test_edit.py,sha256=ykirry-S3i6PtoSs3rff_k6jqmvv1oMWC_iR8e5Jsg0,12022
490
489
  firefighter_tests/test_slack/views/modals/test_form_utils_multiple_choice.py,sha256=Svab_ZyYTMf0T-uJEQcm7gS1WzxtC4gPh1W--Z2v_Y8,8415
491
490
  firefighter_tests/test_slack/views/modals/test_open.py,sha256=IzgG9le5NN_CvltehAIqkj94ioTKCqdA6yoRp2NlNsE,10700
492
- firefighter_tests/test_slack/views/modals/test_opening_unified.py,sha256=y-8WSqS7529_tDyz85MzVLKNGAR7NsGmjhvHfx5L2l0,15244
491
+ firefighter_tests/test_slack/views/modals/test_opening_unified.py,sha256=OejtLyc_mehav2TDaLzUnhilMNvhCzc6T4FodCqfQPk,17406
493
492
  firefighter_tests/test_slack/views/modals/test_send_sos.py,sha256=_rE6jD-gOzcGyhlY0R9GzlGtPx65oOOguJYdENgxtLc,1289
494
493
  firefighter_tests/test_slack/views/modals/test_status.py,sha256=oQzPfwdg2tkbo9nfkO1GfS3WydxqSC6vy1AZjZDKT30,2226
495
- firefighter_tests/test_slack/views/modals/test_update_status.py,sha256=FPyFwvr6f1C3RIRPJh0Kyy6xC_HfNHtTqqkqVbV_mOg,52543
494
+ firefighter_tests/test_slack/views/modals/test_update_status.py,sha256=aqLQ_9TV4Zn-S2sSXL8VNqTMygcbgOIrxg4OUovgUrw,55630
496
495
  firefighter_tests/test_slack/views/modals/test_utils.py,sha256=DJd2n9q6fFu8UuCRdiq9U_Cn19MdnC5c-ydLLrk6rkc,5218
497
- firefighter_incident-0.0.16.dist-info/METADATA,sha256=DkJJ8Pm9Q18G7K_d0QmYYNzPiIRapidWrtXF7g7vzkk,5541
498
- firefighter_incident-0.0.16.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
499
- firefighter_incident-0.0.16.dist-info/entry_points.txt,sha256=c13meJbv7YNmYz7MipMOQwzQ5IeFOPXUBYAJ44XMQsM,61
500
- firefighter_incident-0.0.16.dist-info/licenses/LICENSE,sha256=krRiGp-a9-1nH1bWpBEdxyTKLhjLmn6DMVVoIb0zF90,1087
501
- firefighter_incident-0.0.16.dist-info/RECORD,,
496
+ firefighter_incident-0.0.17.dist-info/METADATA,sha256=qrPtjiXYF-NEUMYvaUcymcj6fttbJ1b60ev7XzWla3Q,5541
497
+ firefighter_incident-0.0.17.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
498
+ firefighter_incident-0.0.17.dist-info/entry_points.txt,sha256=c13meJbv7YNmYz7MipMOQwzQ5IeFOPXUBYAJ44XMQsM,61
499
+ firefighter_incident-0.0.17.dist-info/licenses/LICENSE,sha256=krRiGp-a9-1nH1bWpBEdxyTKLhjLmn6DMVVoIb0zF90,1087
500
+ firefighter_incident-0.0.17.dist-info/RECORD,,