firefighter-incident 0.0.10__py3-none-any.whl → 0.0.11__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.
- firefighter/_version.py +2 -2
- firefighter/slack/views/modals/open.py +110 -60
- firefighter/slack/views/modals/opening/select_impact.py +38 -5
- {firefighter_incident-0.0.10.dist-info → firefighter_incident-0.0.11.dist-info}/METADATA +1 -1
- {firefighter_incident-0.0.10.dist-info → firefighter_incident-0.0.11.dist-info}/RECORD +9 -9
- firefighter_tests/test_slack/views/modals/test_open.py +25 -8
- {firefighter_incident-0.0.10.dist-info → firefighter_incident-0.0.11.dist-info}/WHEEL +0 -0
- {firefighter_incident-0.0.10.dist-info → firefighter_incident-0.0.11.dist-info}/entry_points.txt +0 -0
- {firefighter_incident-0.0.10.dist-info → firefighter_incident-0.0.11.dist-info}/licenses/LICENSE +0 -0
firefighter/_version.py
CHANGED
|
@@ -12,7 +12,6 @@ from django.utils.translation import ngettext
|
|
|
12
12
|
from slack_sdk.models.blocks.basic_components import MarkdownTextObject, Option
|
|
13
13
|
from slack_sdk.models.blocks.block_elements import ButtonElement, StaticSelectElement
|
|
14
14
|
from slack_sdk.models.blocks.blocks import (
|
|
15
|
-
ActionsBlock,
|
|
16
15
|
Block,
|
|
17
16
|
ContextBlock,
|
|
18
17
|
DividerBlock,
|
|
@@ -74,7 +73,9 @@ class OpenModal(SlackModal):
|
|
|
74
73
|
# 1. Check if impact form is good
|
|
75
74
|
is_impact_form_valid: bool = self._check_impact_form(open_incident_context)
|
|
76
75
|
|
|
77
|
-
# 2.
|
|
76
|
+
# 2. Auto-determine response type based on priority
|
|
77
|
+
self._auto_set_response_type(open_incident_context)
|
|
78
|
+
|
|
78
79
|
incident_type_value: str | None = open_incident_context.get(
|
|
79
80
|
"incident_type", None
|
|
80
81
|
)
|
|
@@ -181,11 +182,18 @@ class OpenModal(SlackModal):
|
|
|
181
182
|
SelectImpactModal,
|
|
182
183
|
)
|
|
183
184
|
|
|
185
|
+
# Check if we have actual impacts (not all "NO") by checking if response_type is set
|
|
186
|
+
has_real_impacts = open_incident_context.get("response_type") is not None
|
|
187
|
+
|
|
188
|
+
# Show ✅ only if form is valid AND has real impacts, otherwise 📝
|
|
189
|
+
emoji = "✅" if impact_form_done and has_real_impacts else "📝"
|
|
190
|
+
button_text = "Edit impacts" if impact_form_done and has_real_impacts else "Set impacts"
|
|
191
|
+
|
|
184
192
|
return [
|
|
185
193
|
SectionBlock(
|
|
186
|
-
text=f"{
|
|
194
|
+
text=f"{emoji} First, define the incident impacts and priority.",
|
|
187
195
|
accessory=ButtonElement(
|
|
188
|
-
text=
|
|
196
|
+
text=button_text,
|
|
189
197
|
action_id=SelectImpactModal.push_action,
|
|
190
198
|
value=json.dumps(open_incident_context, cls=SlackFormJSONEncoder),
|
|
191
199
|
),
|
|
@@ -371,40 +379,53 @@ class OpenModal(SlackModal):
|
|
|
371
379
|
|
|
372
380
|
return is_valid, details_form_class, details_form
|
|
373
381
|
|
|
382
|
+
@staticmethod
|
|
383
|
+
def _auto_set_response_type(open_incident_context: OpeningData) -> None:
|
|
384
|
+
"""Auto-determine response type based on priority from impact form."""
|
|
385
|
+
impact_form_data = open_incident_context.get("impact_form_data")
|
|
386
|
+
if not impact_form_data:
|
|
387
|
+
# Clear response_type and priority if no impact data
|
|
388
|
+
open_incident_context.pop("response_type", None)
|
|
389
|
+
open_incident_context.pop("priority", None)
|
|
390
|
+
return
|
|
391
|
+
|
|
392
|
+
impact_form = SelectImpactForm(impact_form_data)
|
|
393
|
+
if not impact_form.is_valid():
|
|
394
|
+
# Clear response_type and priority if form is invalid
|
|
395
|
+
open_incident_context.pop("response_type", None)
|
|
396
|
+
open_incident_context.pop("priority", None)
|
|
397
|
+
return
|
|
398
|
+
|
|
399
|
+
priority_value = impact_form.suggest_priority_from_impact()
|
|
400
|
+
|
|
401
|
+
# If no impacts are selected (all set to "NO"), don't set priority/response_type
|
|
402
|
+
# Priority value 6 corresponds to LevelChoices.NONE.priority
|
|
403
|
+
if priority_value == 6:
|
|
404
|
+
open_incident_context.pop("response_type", None)
|
|
405
|
+
open_incident_context.pop("priority", None)
|
|
406
|
+
return
|
|
407
|
+
|
|
408
|
+
priority = Priority.objects.get(value=priority_value)
|
|
409
|
+
|
|
410
|
+
# Set priority in context
|
|
411
|
+
open_incident_context["priority"] = priority
|
|
412
|
+
|
|
413
|
+
# Set response type based on priority recommendation
|
|
414
|
+
if priority.recommended_response_type:
|
|
415
|
+
open_incident_context["response_type"] = cast("ResponseType | None", priority.recommended_response_type)
|
|
416
|
+
else:
|
|
417
|
+
# Default fallback: P1/P2/P3 = critical, P4/P5 = normal
|
|
418
|
+
response_type = cast("ResponseType", "critical" if priority_value < 4 else "normal")
|
|
419
|
+
open_incident_context["response_type"] = response_type
|
|
420
|
+
|
|
374
421
|
@staticmethod
|
|
375
422
|
def _build_response_type_blocks(open_incident_context: OpeningData) -> list[Block]:
|
|
376
423
|
selected_response_type = open_incident_context.get("response_type")
|
|
377
424
|
if selected_response_type not in {"critical", "normal"}:
|
|
378
425
|
return []
|
|
379
426
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
)
|
|
383
|
-
elements: list[ButtonElement] = []
|
|
384
|
-
|
|
385
|
-
for response_type in response_types:
|
|
386
|
-
if response_type != selected_response_type:
|
|
387
|
-
continue
|
|
388
|
-
|
|
389
|
-
is_selected = (
|
|
390
|
-
open_incident_context.get("response_type") == response_type
|
|
391
|
-
or len(INCIDENT_TYPES) == 1
|
|
392
|
-
)
|
|
393
|
-
style: str | None = "primary" if is_selected else None
|
|
394
|
-
text = (
|
|
395
|
-
":slack: Slack :jira_new: Jira ticket"
|
|
396
|
-
if response_type == "critical"
|
|
397
|
-
else ":jira_new: Jira ticket"
|
|
398
|
-
)
|
|
399
|
-
button = ButtonElement(
|
|
400
|
-
text=text,
|
|
401
|
-
action_id=f"incident_open_set_res_type_{response_type}",
|
|
402
|
-
value=json.dumps(open_incident_context, cls=SlackFormJSONEncoder),
|
|
403
|
-
style=style,
|
|
404
|
-
)
|
|
405
|
-
elements.append(button)
|
|
406
|
-
|
|
407
|
-
blocks: list[Block] = [ActionsBlock(elements=elements)]
|
|
427
|
+
blocks: list[Block] = []
|
|
428
|
+
# No buttons needed - response type is auto-determined
|
|
408
429
|
if impact_form_data := open_incident_context.get("impact_form_data"):
|
|
409
430
|
impact_form = SelectImpactForm(impact_form_data)
|
|
410
431
|
if impact_form.is_valid():
|
|
@@ -414,6 +435,7 @@ class OpenModal(SlackModal):
|
|
|
414
435
|
process = ":slack: Slack :jira_new: Jira ticket" if open_incident_context.get("response_type") == "critical" else ":jira_new: Jira ticket"
|
|
415
436
|
|
|
416
437
|
impact_descriptions = OpenModal._get_impact_descriptions(open_incident_context)
|
|
438
|
+
|
|
417
439
|
blocks.append(
|
|
418
440
|
ContextBlock(
|
|
419
441
|
elements=[
|
|
@@ -422,12 +444,12 @@ class OpenModal(SlackModal):
|
|
|
422
444
|
f"> ⏱️ SLA: {priority.sla}\n"
|
|
423
445
|
f"> :gear: Process: {process}\n"
|
|
424
446
|
f"> :pushpin: Selected impacts:\n"
|
|
425
|
-
f"{impact_descriptions}
|
|
447
|
+
f"{impact_descriptions}"
|
|
426
448
|
+ (
|
|
427
449
|
(
|
|
428
|
-
"
|
|
450
|
+
"> :warning: Critical incidents are for *emergency* only"
|
|
429
451
|
+ (
|
|
430
|
-
f" <{SLACK_SEVERITY_HELP_GUIDE_URL}|
|
|
452
|
+
f" <{SLACK_SEVERITY_HELP_GUIDE_URL}|more info>"
|
|
431
453
|
if SLACK_SEVERITY_HELP_GUIDE_URL
|
|
432
454
|
else "."
|
|
433
455
|
)
|
|
@@ -459,18 +481,56 @@ class OpenModal(SlackModal):
|
|
|
459
481
|
@staticmethod
|
|
460
482
|
def _get_impact_descriptions(open_incident_context: OpeningData) -> str:
|
|
461
483
|
impact_form_data = open_incident_context.get("impact_form_data", {})
|
|
484
|
+
if not impact_form_data:
|
|
485
|
+
return ""
|
|
486
|
+
|
|
462
487
|
impact_descriptions = ""
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
488
|
+
for field_name, original_value in impact_form_data.items():
|
|
489
|
+
value = original_value
|
|
490
|
+
# Handle case where value might be an ID instead of an object
|
|
491
|
+
if isinstance(value, int | str) and not hasattr(value, "name"):
|
|
492
|
+
# Try to get the object from the database
|
|
493
|
+
form = SelectImpactForm()
|
|
494
|
+
if field_name in form.fields:
|
|
495
|
+
field = form.fields[field_name]
|
|
496
|
+
if hasattr(field, "queryset") and field.queryset is not None:
|
|
497
|
+
try:
|
|
498
|
+
value = field.queryset.get(pk=value)
|
|
499
|
+
except field.queryset.model.DoesNotExist:
|
|
500
|
+
logger.warning(f"Could not find impact object with pk={value} for field {field_name}")
|
|
501
|
+
continue
|
|
502
|
+
|
|
503
|
+
description = OpenModal._format_single_impact_description(value)
|
|
504
|
+
if description:
|
|
505
|
+
impact_descriptions += description
|
|
472
506
|
return impact_descriptions
|
|
473
507
|
|
|
508
|
+
@staticmethod
|
|
509
|
+
def _format_single_impact_description(value: Any) -> str:
|
|
510
|
+
"""Format a single impact value into description text."""
|
|
511
|
+
# Handle object with name and description attributes (impact levels)
|
|
512
|
+
if hasattr(value, "name") and hasattr(value, "description"):
|
|
513
|
+
if value.name == "NO" or not value.description:
|
|
514
|
+
return ""
|
|
515
|
+
|
|
516
|
+
description = ""
|
|
517
|
+
# Add impact type header if available
|
|
518
|
+
if hasattr(value, "impact_type_id") and value.impact_type_id:
|
|
519
|
+
try:
|
|
520
|
+
impact_type = ImpactType.objects.get(pk=value.impact_type_id)
|
|
521
|
+
# Use value.name instead of value to avoid showing IDs
|
|
522
|
+
description += f"> \u00A0\u00A0 :exclamation: {impact_type} - {value.name}\n"
|
|
523
|
+
except ImpactType.DoesNotExist:
|
|
524
|
+
description += f"> \u00A0\u00A0 :exclamation: {value.name}\n"
|
|
525
|
+
|
|
526
|
+
# Add description lines
|
|
527
|
+
for line in str(value.description).splitlines():
|
|
528
|
+
description += f"> \u00A0\u00A0\u00A0\u00A0\u00A0\u00A0 • {line}\n"
|
|
529
|
+
return description
|
|
530
|
+
|
|
531
|
+
# Skip string values - incident_type is handled separately, not in impact descriptions
|
|
532
|
+
return ""
|
|
533
|
+
|
|
474
534
|
@staticmethod
|
|
475
535
|
def get_details_modal_form_class(
|
|
476
536
|
open_incident_context: OpeningData,
|
|
@@ -531,21 +591,7 @@ class OpenModal(SlackModal):
|
|
|
531
591
|
logger.exception("Error triggering incident workflow")
|
|
532
592
|
# XXX warn the user via DM!
|
|
533
593
|
|
|
534
|
-
|
|
535
|
-
@app.action("incident_open_set_res_type_critical")
|
|
536
|
-
@staticmethod
|
|
537
|
-
def handle_set_incident_response_type_action(
|
|
538
|
-
ack: Ack, body: dict[str, Any]
|
|
539
|
-
) -> None:
|
|
540
|
-
action_name: str = body.get("actions", [{}])[0].get("action_id", "")
|
|
541
|
-
action_name = action_name.replace("incident_open_set_res_type_", "")
|
|
542
|
-
opening_data = cast(
|
|
543
|
-
"OpeningData", json.loads(body.get("actions", [{}])[0].get("value", {})) or {}
|
|
544
|
-
)
|
|
545
|
-
|
|
546
|
-
OpenModal._update_incident_modal(
|
|
547
|
-
action_name, "response_type", ack, body, opening_data
|
|
548
|
-
)
|
|
594
|
+
# Response type buttons removed - now auto-determined based on priority
|
|
549
595
|
|
|
550
596
|
@app.action("set_type")
|
|
551
597
|
@staticmethod
|
|
@@ -567,7 +613,11 @@ class OpenModal(SlackModal):
|
|
|
567
613
|
body: dict[str, Any],
|
|
568
614
|
opening_data: OpeningData,
|
|
569
615
|
) -> None:
|
|
570
|
-
|
|
616
|
+
# Ensure we preserve all existing data, especially impact_form_data
|
|
617
|
+
data: OpeningData = OpeningData()
|
|
618
|
+
data.update(opening_data)
|
|
619
|
+
data[metadata_key] = action_value
|
|
620
|
+
|
|
571
621
|
user = get_user_from_context(body)
|
|
572
622
|
view = cls().build_modal_fn(open_incident_context=data, user=user)
|
|
573
623
|
|
|
@@ -205,7 +205,16 @@ class SelectImpactModal(
|
|
|
205
205
|
def _calculate_proposed_incident_type(
|
|
206
206
|
suggested_priority_value: int,
|
|
207
207
|
) -> ResponseType:
|
|
208
|
-
|
|
208
|
+
try:
|
|
209
|
+
priority = Priority.objects.get(value=suggested_priority_value)
|
|
210
|
+
# Use priority recommendation if available
|
|
211
|
+
if priority.recommended_response_type:
|
|
212
|
+
return cast("ResponseType", priority.recommended_response_type)
|
|
213
|
+
except Priority.DoesNotExist:
|
|
214
|
+
logger.warning(f"Priority with value {suggested_priority_value} does not exist")
|
|
215
|
+
|
|
216
|
+
# Fallback logic: P1/P2/P3 = critical, P4/P5 = normal
|
|
217
|
+
return cast("ResponseType", "critical" if suggested_priority_value < 4 else "normal")
|
|
209
218
|
|
|
210
219
|
@staticmethod
|
|
211
220
|
def _update_private_metadata(
|
|
@@ -230,12 +239,36 @@ class SelectImpactModal(
|
|
|
230
239
|
)
|
|
231
240
|
except queryset.model.DoesNotExist:
|
|
232
241
|
form.form.data[field_name] = None # type: ignore
|
|
242
|
+
suggested_priority_value = form.form.suggest_priority_from_impact()
|
|
243
|
+
|
|
244
|
+
# If no impacts are selected (all set to "NO"), don't set priority/response_type
|
|
245
|
+
if suggested_priority_value == 6: # LevelChoices.NONE.priority
|
|
246
|
+
return OpeningData(
|
|
247
|
+
priority=None,
|
|
248
|
+
response_type=None,
|
|
249
|
+
impact_form_data=cast("dict[str, Any]", form.form.data),
|
|
250
|
+
details_form_data=private_metadata_raw.get("details_form_data", {}),
|
|
251
|
+
incident_type=private_metadata_raw.get("incident_type"),
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
try:
|
|
255
|
+
priority = Priority.objects.get(value=suggested_priority_value)
|
|
256
|
+
except Priority.DoesNotExist as err:
|
|
257
|
+
logger.exception(
|
|
258
|
+
f"Priority with value {suggested_priority_value} does not exist"
|
|
259
|
+
)
|
|
260
|
+
# Fallback to default priority (assuming P3 exists)
|
|
261
|
+
fallback_priority = Priority.objects.filter(value__gte=3).first()
|
|
262
|
+
if not fallback_priority:
|
|
263
|
+
# If no priority exists, create a minimal fallback
|
|
264
|
+
logger.exception("No priority found in database")
|
|
265
|
+
raise ValueError("No priority configuration found in database") from err
|
|
266
|
+
priority = fallback_priority
|
|
267
|
+
|
|
233
268
|
return OpeningData(
|
|
234
|
-
priority=
|
|
235
|
-
value=form.form.suggest_priority_from_impact()
|
|
236
|
-
),
|
|
269
|
+
priority=priority,
|
|
237
270
|
response_type=SelectImpactModal._calculate_proposed_incident_type(
|
|
238
|
-
|
|
271
|
+
suggested_priority_value
|
|
239
272
|
),
|
|
240
273
|
impact_form_data=cast("dict[str, Any]", form.form.data),
|
|
241
274
|
details_form_data=private_metadata_raw.get("details_form_data", {}),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: firefighter-incident
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.11
|
|
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=
|
|
9
|
+
firefighter/_version.py,sha256=rk0lhpp6Em5toAI4J7GwApfOdY7w_QTcFpJpUR4GdVY,513
|
|
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
|
|
@@ -385,7 +385,7 @@ firefighter/slack/views/modals/close.py,sha256=ur1SSRWk9NYFfL24gjOqoIiXKquDy6qeE
|
|
|
385
385
|
firefighter/slack/views/modals/downgrade_workflow.py,sha256=S0y0_GYH4q7ewZUr_eA9Ly2c1FQueZzNCTiuIiWYUoY,3109
|
|
386
386
|
firefighter/slack/views/modals/edit.py,sha256=60xav4XG4KGS9KknqsQNCQjl3qQzk7OtmHiEYTQ9pUk,3861
|
|
387
387
|
firefighter/slack/views/modals/key_event_message.py,sha256=ga3-ITZyzJExwzctX-GfgnDqyQaxTfcqpqnOwY2E38M,5620
|
|
388
|
-
firefighter/slack/views/modals/open.py,sha256=
|
|
388
|
+
firefighter/slack/views/modals/open.py,sha256=LX9aBZ4bUosoffJlIepzYjpbf7LsvzppYAjqep8tVtM,25495
|
|
389
389
|
firefighter/slack/views/modals/postmortem.py,sha256=AeEtmiam_XgCRxDmltKluNT2VN1gcuCB2VbYeeATVcA,2525
|
|
390
390
|
firefighter/slack/views/modals/select.py,sha256=Y-Ji_ALnzhYkXDBAyi497UL1Xn2vCGqXCtj8eog75Jk,3312
|
|
391
391
|
firefighter/slack/views/modals/send_sos.py,sha256=bP6HgYyDwPrIcTq7n_sQz6UQsxhYbvBDS4HjM0uRccA,4838
|
|
@@ -402,7 +402,7 @@ firefighter/slack/views/modals/base_modal/mixins.py,sha256=c7WYs0aXKXVktEMNSZ8IU
|
|
|
402
402
|
firefighter/slack/views/modals/base_modal/modal_utils.py,sha256=1uHTlLxxeXUQttH3bHaehJwCuI6a-h04s-GzdnVA4sI,2459
|
|
403
403
|
firefighter/slack/views/modals/opening/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
404
404
|
firefighter/slack/views/modals/opening/check_current_incidents.py,sha256=28GN0SXP7rVPa55arX1aI98k45w9568GCRDA73eCHEM,2535
|
|
405
|
-
firefighter/slack/views/modals/opening/select_impact.py,sha256=
|
|
405
|
+
firefighter/slack/views/modals/opening/select_impact.py,sha256=McVKE5z8vjcg0Z1kbqTsXBW9FvTqX02W6HiIPQ8cicI,11424
|
|
406
406
|
firefighter/slack/views/modals/opening/set_details.py,sha256=i6zQM2FYz3Z6s5AZH7lXgB2e8yjS0rDwgfMBZaiOqIw,5791
|
|
407
407
|
firefighter/slack/views/modals/opening/types.py,sha256=ETpp0DAz5OMI5h7iv62Of7yJCbI-Q4-3kKSS6msPQeY,563
|
|
408
408
|
firefighter/slack/views/modals/opening/details/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -444,12 +444,12 @@ firefighter_tests/test_slack/test_models/test_conversations.py,sha256=t3ttmgwiu7
|
|
|
444
444
|
firefighter_tests/test_slack/test_models/test_incident_channel.py,sha256=qWoGe9iadmK6-R8usWvjH87AHRkvhG_dHQeC3kHeJrs,17487
|
|
445
445
|
firefighter_tests/test_slack/test_models/test_slack_user.py,sha256=uzur-Rf03I5dpUTO4ZI6O1arBUrAorg1Zvgshf8M-J4,7000
|
|
446
446
|
firefighter_tests/test_slack/views/modals/test_close.py,sha256=kcwGwonjIiniGb5f78ZwlKjuvYB-xat-SrbouV9VCEc,42894
|
|
447
|
-
firefighter_tests/test_slack/views/modals/test_open.py,sha256=
|
|
447
|
+
firefighter_tests/test_slack/views/modals/test_open.py,sha256=z3lvAPOXCUSt7i_9jWYcQWGIRwRg7Z1DT6AfMOK22_s,4900
|
|
448
448
|
firefighter_tests/test_slack/views/modals/test_send_sos.py,sha256=_rE6jD-gOzcGyhlY0R9GzlGtPx65oOOguJYdENgxtLc,1289
|
|
449
449
|
firefighter_tests/test_slack/views/modals/test_status.py,sha256=oQzPfwdg2tkbo9nfkO1GfS3WydxqSC6vy1AZjZDKT30,2226
|
|
450
450
|
firefighter_tests/test_slack/views/modals/test_update_status.py,sha256=Y8Oa_fraj1vtaGig9Y28_6tOWvMrRPS-wyg3rY-DHBk,39380
|
|
451
|
-
firefighter_incident-0.0.
|
|
452
|
-
firefighter_incident-0.0.
|
|
453
|
-
firefighter_incident-0.0.
|
|
454
|
-
firefighter_incident-0.0.
|
|
455
|
-
firefighter_incident-0.0.
|
|
451
|
+
firefighter_incident-0.0.11.dist-info/METADATA,sha256=9Xvtj0AnQmzza1kfVGGGEMcJJEokzGn9vUs6FzslagA,5488
|
|
452
|
+
firefighter_incident-0.0.11.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
453
|
+
firefighter_incident-0.0.11.dist-info/entry_points.txt,sha256=c13meJbv7YNmYz7MipMOQwzQ5IeFOPXUBYAJ44XMQsM,61
|
|
454
|
+
firefighter_incident-0.0.11.dist-info/licenses/LICENSE,sha256=krRiGp-a9-1nH1bWpBEdxyTKLhjLmn6DMVVoIb0zF90,1087
|
|
455
|
+
firefighter_incident-0.0.11.dist-info/RECORD,,
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from typing import Any
|
|
4
|
-
from unittest.mock import MagicMock
|
|
4
|
+
from unittest.mock import MagicMock, Mock, patch
|
|
5
5
|
|
|
6
6
|
import pytest
|
|
7
|
-
from slack_sdk.models.blocks.block_elements import ButtonElement
|
|
8
7
|
from slack_sdk.models.blocks.blocks import (
|
|
9
|
-
|
|
8
|
+
ContextBlock,
|
|
10
9
|
)
|
|
11
10
|
|
|
12
11
|
from firefighter.incidents.forms.create_incident import CreateIncidentFormBase
|
|
@@ -102,14 +101,32 @@ def test_validate_details_form_invalid() -> None:
|
|
|
102
101
|
|
|
103
102
|
|
|
104
103
|
def test_build_response_type_blocks_bis(open_incident_context: OpeningData) -> None:
|
|
104
|
+
# With no impact_form_data, should return empty list
|
|
105
105
|
open_incident_context["response_type"] = "critical"
|
|
106
106
|
blocks = OpenModal._build_response_type_blocks(open_incident_context)
|
|
107
|
+
assert len(blocks) == 0
|
|
107
108
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
109
|
+
# With valid impact_form_data, should return context blocks
|
|
110
|
+
mock_impact_form = Mock()
|
|
111
|
+
mock_impact_form.is_valid.return_value = True
|
|
112
|
+
mock_impact_form.suggest_priority_from_impact.return_value = 1
|
|
113
|
+
|
|
114
|
+
# Mock Priority object
|
|
115
|
+
mock_priority = Mock()
|
|
116
|
+
mock_priority.emoji = "🔴"
|
|
117
|
+
mock_priority.description = "Critical"
|
|
118
|
+
mock_priority.sla = "15 min"
|
|
119
|
+
mock_priority.recommended_response_type = None
|
|
120
|
+
|
|
121
|
+
open_incident_context["impact_form_data"] = {"test_field": "test_value"}
|
|
122
|
+
|
|
123
|
+
with patch("firefighter.slack.views.modals.open.SelectImpactForm", return_value=mock_impact_form), \
|
|
124
|
+
patch("firefighter.slack.views.modals.open.Priority.objects.get", return_value=mock_priority), \
|
|
125
|
+
patch.object(OpenModal, "_get_impact_descriptions", return_value="Test impact"):
|
|
126
|
+
blocks = OpenModal._build_response_type_blocks(open_incident_context)
|
|
127
|
+
assert len(blocks) == 1
|
|
128
|
+
first_block = blocks[0]
|
|
129
|
+
assert isinstance(first_block, ContextBlock)
|
|
113
130
|
|
|
114
131
|
|
|
115
132
|
@pytest.mark.django_db
|
|
File without changes
|
{firefighter_incident-0.0.10.dist-info → firefighter_incident-0.0.11.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{firefighter_incident-0.0.10.dist-info → firefighter_incident-0.0.11.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|