firefighter-incident 0.0.26__py3-none-any.whl → 0.0.27__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/confluence/models.py +16 -1
- firefighter/incidents/management/__init__.py +1 -0
- firefighter/incidents/management/commands/__init__.py +1 -0
- firefighter/incidents/management/commands/backdate_incident_mitigated.py +94 -0
- firefighter/incidents/management/commands/test_postmortem_reminders.py +113 -0
- firefighter/incidents/migrations/0030_add_mitigated_at_field.py +22 -0
- firefighter/incidents/models/incident.py +43 -8
- firefighter/jira_app/service_postmortem.py +13 -0
- firefighter/jira_app/signals/postmortem_created.py +108 -46
- firefighter/slack/messages/slack_messages.py +162 -0
- firefighter/slack/migrations/0009_add_postmortem_reminder_periodic_task.py +60 -0
- firefighter/slack/rules.py +22 -0
- firefighter/slack/tasks/send_postmortem_reminders.py +127 -0
- firefighter/slack/views/modals/close.py +113 -3
- firefighter/slack/views/modals/closure_reason.py +39 -15
- firefighter/slack/views/modals/update_status.py +4 -4
- {firefighter_incident-0.0.26.dist-info → firefighter_incident-0.0.27.dist-info}/METADATA +1 -1
- {firefighter_incident-0.0.26.dist-info → firefighter_incident-0.0.27.dist-info}/RECORD +29 -22
- firefighter_tests/test_incidents/test_incident_urls.py +4 -0
- firefighter_tests/test_incidents/test_models/test_incident_model.py +109 -1
- firefighter_tests/test_incidents/test_views/test_incident_detail_view.py +4 -0
- firefighter_tests/test_slack/messages/test_slack_messages.py +4 -0
- firefighter_tests/test_slack/views/modals/test_close.py +4 -0
- firefighter_tests/test_slack/views/modals/test_closure_reason_modal.py +109 -26
- firefighter_tests/test_slack/views/modals/test_update_status.py +45 -51
- {firefighter_incident-0.0.26.dist-info → firefighter_incident-0.0.27.dist-info}/WHEEL +0 -0
- {firefighter_incident-0.0.26.dist-info → firefighter_incident-0.0.27.dist-info}/entry_points.txt +0 -0
- {firefighter_incident-0.0.26.dist-info → firefighter_incident-0.0.27.dist-info}/licenses/LICENSE +0 -0
|
@@ -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=vq5GihUa4KrDz-Hix5Er9gtVMhfHNDBoLhzP1VsvNuE,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
|
|
@@ -55,7 +55,7 @@ firefighter/confluence/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3
|
|
|
55
55
|
firefighter/confluence/admin.py,sha256=aDXghuuLc7G_TLt-655M31smx-H6vkIgLtEmmNCA3lg,1490
|
|
56
56
|
firefighter/confluence/apps.py,sha256=vKswBwQL7L9e2JQwvRb7xy3myyE_GRldYX78jSY3XCM,406
|
|
57
57
|
firefighter/confluence/client.py,sha256=xjSsrsGPF75JANNvam2YgiUkztuXhOcs9pMmPbb7ymk,6361
|
|
58
|
-
firefighter/confluence/models.py,sha256=
|
|
58
|
+
firefighter/confluence/models.py,sha256=66RNfD-lRdixZtOo5pNW2e-LZboTRjdoH2h-R7ne-q0,9154
|
|
59
59
|
firefighter/confluence/serializers.py,sha256=CzuHVXIJNS47NCAJLXSTDOevtg5sf309XXEcWKQ1sAQ,258
|
|
60
60
|
firefighter/confluence/service.py,sha256=dOQXj0uDInEm25nvL6lXiSH4hQ5oC2VDyBd1zbEcZ5U,12296
|
|
61
61
|
firefighter/confluence/tables.py,sha256=ANEtFXzXyPK6E5FIrBC5XoQt5R3ZUY1DME_RbD1h_NE,732
|
|
@@ -147,6 +147,10 @@ firefighter/incidents/forms/update_key_events.py,sha256=1Xmnxe5OgZqLFS2HmMzQm3VG
|
|
|
147
147
|
firefighter/incidents/forms/update_roles.py,sha256=Q26UPfwAj-8N23RNZLQkvmHGnS1_j_X5KQWjJmPjMKY,3635
|
|
148
148
|
firefighter/incidents/forms/update_status.py,sha256=7GSno_EqD2Brd6wWcSb3zsP6nz8_mUTXXnl0QCRhv48,6682
|
|
149
149
|
firefighter/incidents/forms/utils.py,sha256=15e_dBebVd9SvX03DYd0FyZ8s0YpxyBlZfIzEZattwg,4267
|
|
150
|
+
firefighter/incidents/management/__init__.py,sha256=A2LtnedT5NvTcNAN5nXMkPwK56JBNLuptcyObvq7zcc,40
|
|
151
|
+
firefighter/incidents/management/commands/__init__.py,sha256=wc5DFEklUo-wB-6VAAmsV5UTbo5s3t936Lu61z4lojs,29
|
|
152
|
+
firefighter/incidents/management/commands/backdate_incident_mitigated.py,sha256=phAXH18TNvzA03o1XtJfRVeOPbrKp8wdsBMx-QGAIeo,3410
|
|
153
|
+
firefighter/incidents/management/commands/test_postmortem_reminders.py,sha256=Bx-AVhkSjkL6c2_Eh7mRHa7qOEtytDl9T2hJYxcBC-4,4233
|
|
150
154
|
firefighter/incidents/migrations/0001_initial_oss.py,sha256=OCrPbxf90h3NW9xolGGcsAryHKptD1TtKj5FucjBjg8,60311
|
|
151
155
|
firefighter/incidents/migrations/0002_alter_severity_name_alter_user_password_featureteam.py,sha256=YfIJhw_-Yqm8qrkbp01461bkcUr7v5Zy90oHjkY3bSA,1113
|
|
152
156
|
firefighter/incidents/migrations/0003_delete_featureteam.py,sha256=kH5UUSx3k5DtjR_goDxROdV0htCC2JZfBGwJpn-dEQs,336
|
|
@@ -176,12 +180,13 @@ firefighter/incidents/migrations/0026_alter_incidentcategory_options_and_more.py
|
|
|
176
180
|
firefighter/incidents/migrations/0027_add_closure_fields.py,sha256=MDWckXmjJNC2iVoFJD6IIwDmmqyeL1VG_pHR568JAtk,1344
|
|
177
181
|
firefighter/incidents/migrations/0028_add_closure_reason_constraint.py,sha256=z6FjCURDt9c-hyBeCvCKsbZOiuReYtbjtguIh3T6dnk,920
|
|
178
182
|
firefighter/incidents/migrations/0029_add_custom_fields_to_incident.py,sha256=G6DsnP5bM4Hy0s8IqXhLYzFKt3eumEsCnJfPIw5tcX4,567
|
|
183
|
+
firefighter/incidents/migrations/0030_add_mitigated_at_field.py,sha256=pELNJWbAuctv_dA-pdD3fsqg4qMm5f6upW9hFrjNLDI,546
|
|
179
184
|
firefighter/incidents/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
180
185
|
firefighter/incidents/models/__init__.py,sha256=FLVyBwIdyxLdgSvXRAKC3fry9YwwqlqhitTIuG0vWrk,877
|
|
181
186
|
firefighter/incidents/models/environment.py,sha256=51txwua3dCrWZ1iSG3ZA8rbDn9c00pyMAZujl9gwE5c,827
|
|
182
187
|
firefighter/incidents/models/group.py,sha256=VrVL315VFUvKW69AZuRUBg1h0jZJvn8zWeMxMOWec1Y,700
|
|
183
188
|
firefighter/incidents/models/impact.py,sha256=D9NngMtg4XdDWnMgdVYaWCoUZ-fMXTvfL0eTEk9sc7M,4854
|
|
184
|
-
firefighter/incidents/models/incident.py,sha256=
|
|
189
|
+
firefighter/incidents/models/incident.py,sha256=4G4vLurh2bgMRo5eOuYgKWNRC8Xf_07cFf_UdpLPOOg,29638
|
|
185
190
|
firefighter/incidents/models/incident_category.py,sha256=g4OHv_XQhWcH6dvkqkyCgjlruo_1eih_CdtAPgPhaW4,7744
|
|
186
191
|
firefighter/incidents/models/incident_cost.py,sha256=juwOfJKRaNQpOHkRUCHShDDba0FU98YjRPkU4I0ofAU,1346
|
|
187
192
|
firefighter/incidents/models/incident_cost_type.py,sha256=wm8diry_VySJzIjC9M3Yavv2tYbvJgpN9UDb2gFRuH4,845
|
|
@@ -273,7 +278,7 @@ firefighter/jira_app/admin.py,sha256=ZHAAbhy0hm_DcklK59KMmid_ZiPn8n5V6g7cZCSNrpc
|
|
|
273
278
|
firefighter/jira_app/apps.py,sha256=T6vHrQuMZHJoTth-xjy3CbNfPv6DyXgcR3PSMju2JS4,504
|
|
274
279
|
firefighter/jira_app/client.py,sha256=qpMqNTjJUq5OqAxmwvVOE20uJe7kp737HSdsiqUu1G4,21982
|
|
275
280
|
firefighter/jira_app/models.py,sha256=2zKy5VaKkhiHYA8Dukz8g0NTG82Qy5UHAHY9eMv67NE,3097
|
|
276
|
-
firefighter/jira_app/service_postmortem.py,sha256=
|
|
281
|
+
firefighter/jira_app/service_postmortem.py,sha256=tqJN91vZPX5ISd_PAGWDebHK225eZvDvwhi7ONy_D-A,11325
|
|
277
282
|
firefighter/jira_app/types.py,sha256=Ukak1U1EhcH2jQPN-UoEL6AMZ-kzPsQ8c7FUr7GmahE,956
|
|
278
283
|
firefighter/jira_app/utils.py,sha256=3xuzr8viZCBm6j2J9oFzA4bUvVW8TN1DOdlpbruJ_TE,3443
|
|
279
284
|
firefighter/jira_app/management/__init__.py,sha256=wy4qMZb7_K-INwwGGEhMtEeI0XTLqgUw4P8_-VEnrEw,40
|
|
@@ -283,7 +288,7 @@ firefighter/jira_app/migrations/0002_add_jira_postmortem_model.py,sha256=oFSbYNc
|
|
|
283
288
|
firefighter/jira_app/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
284
289
|
firefighter/jira_app/signals/__init__.py,sha256=OpXFlbRgIrh73DGlUzQ6WUTedKsD5wYW9bxGMq_DnIs,325
|
|
285
290
|
firefighter/jira_app/signals/incident_key_events_updated.py,sha256=uaV3MON1QzeOZizzAwSdyktBwe2mWxHJeNSvy9MYc3k,3204
|
|
286
|
-
firefighter/jira_app/signals/postmortem_created.py,sha256=
|
|
291
|
+
firefighter/jira_app/signals/postmortem_created.py,sha256=S7sKbEgo5RroC5ji1OepAT3HMckwS120dpKeUteNaXA,8300
|
|
287
292
|
firefighter/jira_app/tasks/__init__.py,sha256=XLCPkolM6LwIUGv0MNbk_0lCuBHyzgRFHsE3vTRD5ds,86
|
|
288
293
|
firefighter/jira_app/tasks/sync_users_jira.py,sha256=sSSLsVCdzkPNRS6Gt8j0YwCTuoRqkJAJLxDBu7IElmM,1437
|
|
289
294
|
firefighter/jira_app/templates/jira/postmortem/impact.txt,sha256=eYlX0rytUiKZZIrWxMN23QXkLZ8JwlwPe5S2oiqZyFA,259
|
|
@@ -345,7 +350,7 @@ firefighter/slack/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU
|
|
|
345
350
|
firefighter/slack/admin.py,sha256=pNJbA-szxUUrghxv_Z0BNezu6lULDzFcOu_K5i4m7Cs,13963
|
|
346
351
|
firefighter/slack/apps.py,sha256=gR0zWTtqT58tjPayBX22ZSzMkLiNpmoOvLShNvhJA6Q,664
|
|
347
352
|
firefighter/slack/factories.py,sha256=tnrUTbtgehCuBr24MtTyJ3uezKC6gJbOdHuYZ5JBoyU,3886
|
|
348
|
-
firefighter/slack/rules.py,sha256=
|
|
353
|
+
firefighter/slack/rules.py,sha256=Y-DYJ_1D13a4nQNESCbhalNe2nC9xVNpYtSeWTgDcYc,2374
|
|
349
354
|
firefighter/slack/slack_app.py,sha256=mvaH0hPFaNIUxEB7J0fy6y-PNPGsdPqjXFVmpTQ_hCo,4201
|
|
350
355
|
firefighter/slack/slack_incident_context.py,sha256=PjE7-w-pGFyV4faw8EMsEFp4RG_T251RhofmqrsDG7Q,7277
|
|
351
356
|
firefighter/slack/slack_templating.py,sha256=rWe8m1n648wizw08U_vLz8daRnp4zmkcWRqocIBpQj4,3841
|
|
@@ -359,7 +364,7 @@ firefighter/slack/management/commands/generate_manifest.py,sha256=zFWHAC7ioozcDd
|
|
|
359
364
|
firefighter/slack/management/commands/switch_test_users.py,sha256=2KTSvCBxsEvZa61J8p0r3huPNhwuytcj2J7IawwZWpQ,11064
|
|
360
365
|
firefighter/slack/messages/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
361
366
|
firefighter/slack/messages/base.py,sha256=biH-YEAaldJ-OLHEs5ZjW-gtUYUbjOqxrAEflqV2XS0,4593
|
|
362
|
-
firefighter/slack/messages/slack_messages.py,sha256=
|
|
367
|
+
firefighter/slack/messages/slack_messages.py,sha256=eCJUPSjzF_itXH9Z0VlfhloMNvjN3tsB1lmziO9Ksg0,41469
|
|
363
368
|
firefighter/slack/migrations/0001_initial_oss.py,sha256=XmTPgq7zCME2xDwzRFoVi4OegSIG9eSKoyTNoW05Qtg,12933
|
|
364
369
|
firefighter/slack/migrations/0002_usergroup_tag.py,sha256=098tmGA81mT-R2uhb6uQfZ7gKiRG9bFhEwQ8rrp4SKM,583
|
|
365
370
|
firefighter/slack/migrations/0003_alter_usergroup_tag.py,sha256=ncH3KUWEPZHlbdcAtOJ0KGt5H6EX-cKspTGU3osrAhE,591
|
|
@@ -368,6 +373,7 @@ firefighter/slack/migrations/0005_add_incident_categories_fields.py,sha256=KMdKf
|
|
|
368
373
|
firefighter/slack/migrations/0006_copy_components_to_incident_categories.py,sha256=xUF7lLyWERux6SyIYHK2Uk1Yb4QLCGTaHW_KXVqX8n4,2478
|
|
369
374
|
firefighter/slack/migrations/0007_remove_components_fields.py,sha256=_GXmcpB3enpVBT1NZ-tGDlh16r_cM-JkH2gebrmwIOs,563
|
|
370
375
|
firefighter/slack/migrations/0008_alter_conversation_incident_categories_and_more.py,sha256=yzuAnunYvlF-wcYd7oe5h-kL5aOoawSXv_QGfmTFoBo,1034
|
|
376
|
+
firefighter/slack/migrations/0009_add_postmortem_reminder_periodic_task.py,sha256=Vze5TvhQExaF7-KymByzMZZE1wa0GHlWZXP1v1hub5w,2035
|
|
371
377
|
firefighter/slack/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
372
378
|
firefighter/slack/models/__init__.py,sha256=MGc4yuDnVhmAiHy1-5rjaLIfVv9JOup5arRutcUs8Ak,332
|
|
373
379
|
firefighter/slack/models/conversation.py,sha256=f7a0muD0lrpf8mIhF6E2gEhNsgwZFw9jlKIQppZhNL0,16227
|
|
@@ -388,6 +394,7 @@ firefighter/slack/tasks/__init__.py,sha256=28QxZkakyi9l7Ae83fQuzOS-9EaBiwuh_peUZ
|
|
|
388
394
|
firefighter/slack/tasks/fetch_conversations_members.py,sha256=lLQ491_l8HEJrjoDpD0AETqoFUFogkyMJ002hguA-Dg,5381
|
|
389
395
|
firefighter/slack/tasks/reminder_postmortem.py,sha256=mZvT4cpzmMhC6JrWhZb1uFvTJJrbkEKgcCy6liKHrKM,2322
|
|
390
396
|
firefighter/slack/tasks/send_message.py,sha256=N0FIE93bUnzbHdWkSWC-4-eLn737u6hHq8F8erMu8kI,810
|
|
397
|
+
firefighter/slack/tasks/send_postmortem_reminders.py,sha256=uyF9v8um2uxuYFyDSe2GhmG3iX0iAJrG1yE3LS0_NSo,4741
|
|
391
398
|
firefighter/slack/tasks/send_reminders.py,sha256=hy1Q_rG2RUQdXNYEYiLyLnT7rkG8PFOmxur62YCCDrk,4370
|
|
392
399
|
firefighter/slack/tasks/sync_users.py,sha256=T5ytYnZpcUqrh4sOklxWttsUk82C_2bwayg_fdcdg1g,2391
|
|
393
400
|
firefighter/slack/tasks/update_usergroups_members.py,sha256=W-rPt3r2c9UboVMNiyQFvi_W7XWrR8ireVBWcCJMj5A,4642
|
|
@@ -410,8 +417,8 @@ firefighter/slack/views/events/message.py,sha256=c8tvo0btOUu_5Bc83oiO3IQbaEyoRiU
|
|
|
410
417
|
firefighter/slack/views/events/message_deleted.py,sha256=tyA1-sAlG9ImcKIhqSn6EgujHmbvj4Uw2QzQ4JH4QwI,747
|
|
411
418
|
firefighter/slack/views/events/reaction_added.py,sha256=AipwBnrU5B35D97YIZCXdSW8W7-9QTIIQqUcrLTLQ5c,4241
|
|
412
419
|
firefighter/slack/views/modals/__init__.py,sha256=U9PapAIlpuYqBonOUmBGWT8_HjQa35ilMQJXGaFLgd0,1945
|
|
413
|
-
firefighter/slack/views/modals/close.py,sha256=
|
|
414
|
-
firefighter/slack/views/modals/closure_reason.py,sha256=
|
|
420
|
+
firefighter/slack/views/modals/close.py,sha256=eTT1IVEMXUrdUXsu5VSmC6-cGUsOYUGG7CN-3yAnuDo,17482
|
|
421
|
+
firefighter/slack/views/modals/closure_reason.py,sha256=qgjg6x5JBh5ggR6Z6aVhpnc3k8En38UxKtFb5RkTU4U,9016
|
|
415
422
|
firefighter/slack/views/modals/downgrade_workflow.py,sha256=cRWsm3DmKRRI1-Jpjprb5xeY2U7HvRo6eZlUbGuzr1A,3192
|
|
416
423
|
firefighter/slack/views/modals/edit.py,sha256=1N0OBSxsDuN6lJoH-djbEljy7f0LcDEpJF-U5YoEFXA,5895
|
|
417
424
|
firefighter/slack/views/modals/key_event_message.py,sha256=C6yhQLQ6jBuhIr-YAoAyt-qZKu0V6nJMGZ_t3DLtUbo,5943
|
|
@@ -423,7 +430,7 @@ firefighter/slack/views/modals/status.py,sha256=C8-eJRtquSeaHe568SC7yCFef1k14m2_
|
|
|
423
430
|
firefighter/slack/views/modals/trigger_oncall.py,sha256=h_LAD5X5rjMFWiDYTEp5VB9OaF7sTvKZhNaW3KQkw5M,5065
|
|
424
431
|
firefighter/slack/views/modals/update.py,sha256=OF9sf-Z6IiviNmjN28MQNYiUbJ5tha0MdHUQyPpVFiY,2150
|
|
425
432
|
firefighter/slack/views/modals/update_roles.py,sha256=De3Gv67MZQHyNdonX3S99F5MtKF_Rj3y71gdWibxBaM,2419
|
|
426
|
-
firefighter/slack/views/modals/update_status.py,sha256=
|
|
433
|
+
firefighter/slack/views/modals/update_status.py,sha256=SYjQLXnWSZLk461b-L9WFRSxy7clIA4O0C4ZMrNWiuc,5964
|
|
427
434
|
firefighter/slack/views/modals/utils.py,sha256=zKLJD2KhTGcX2d9WCYwshYRa6ok_9-ED1_pgOLp028s,2133
|
|
428
435
|
firefighter/slack/views/modals/base_modal/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
429
436
|
firefighter/slack/views/modals/base_modal/base.py,sha256=7mvOxZTtegSmitSMnDvu8BK0qLUXoudUsda6CaLjdkY,12479
|
|
@@ -459,7 +466,7 @@ firefighter_tests/test_firefighter/test_logging.py,sha256=4HUH73vLDwmOCpMiXwDasM
|
|
|
459
466
|
firefighter_tests/test_firefighter/test_sso.py,sha256=uX2ry0REDgXzQc9Y1BmAgI0OgbmzWoOv9H_GDyOqQmQ,5205
|
|
460
467
|
firefighter_tests/test_firefighter/test_urls.py,sha256=UMGx4oW98RoL0ceePkIIKEVjbHdFECvQuGNXYAJForQ,4839
|
|
461
468
|
firefighter_tests/test_incidents/test_enums.py,sha256=wMxxL1uakrmzJIi-2xkAvG-Y3NDDmIt0PHyOAJBz0yQ,4341
|
|
462
|
-
firefighter_tests/test_incidents/test_incident_urls.py,sha256=
|
|
469
|
+
firefighter_tests/test_incidents/test_incident_urls.py,sha256=VD9dj0IHHKXJHC5ApZg-L9CMtotaQb9uRAKcZIhOrDI,3978
|
|
463
470
|
firefighter_tests/test_incidents/test_forms/conftest.py,sha256=YYF5Lm-Jmt-HM9zt_gjrNkiuqOaNMW8lLBr1crAP6J8,5423
|
|
464
471
|
firefighter_tests/test_incidents/test_forms/test_closure_reason.py,sha256=H6RObqazFAit_pvo7N-lotiSsLOYMafZIk23A5Wiodg,3533
|
|
465
472
|
firefighter_tests/test_incidents/test_forms/test_form_select_impact.py,sha256=DTaPGrJi8mXHfh7mhvDTKYVvDCxqarILauE59UDlwqo,3210
|
|
@@ -471,10 +478,10 @@ firefighter_tests/test_incidents/test_forms/test_update_key_events.py,sha256=rHR
|
|
|
471
478
|
firefighter_tests/test_incidents/test_forms/test_update_status_workflow.py,sha256=q0xXU2BbBG8B0uvvyBWlo4HM8ckbcNAP05Fq8oJNtOw,16270
|
|
472
479
|
firefighter_tests/test_incidents/test_forms/test_workflow_transitions.py,sha256=priKh7QYZxGDPu2SvPC8pGnqOsZWg5cLkyC40pDvLAU,7184
|
|
473
480
|
firefighter_tests/test_incidents/test_models/test_incident_category.py,sha256=aRoBOhb8fNjLF9CMPZ1FXM8AT51Cd80XPsY2Y3wHY_M,5701
|
|
474
|
-
firefighter_tests/test_incidents/test_models/test_incident_model.py,sha256=
|
|
481
|
+
firefighter_tests/test_incidents/test_models/test_incident_model.py,sha256=AWyWfQYcHNP9GPizIo0wRxNGTJTEJnAwNSd4UmRq-dk,8626
|
|
475
482
|
firefighter_tests/test_incidents/test_models/test_migrations/test_incident_migrations.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
476
483
|
firefighter_tests/test_incidents/test_utils/test_date_utils.py,sha256=ogP7qOEwItL4YGI5gbQPVssOS9ilwiuZC8OrT2qngBY,6568
|
|
477
|
-
firefighter_tests/test_incidents/test_views/test_incident_detail_view.py,sha256=
|
|
484
|
+
firefighter_tests/test_incidents/test_views/test_incident_detail_view.py,sha256=lkCIRfz99Ea0o0Id08LFWrjXLDmHv6XvezaSsjg-eYQ,871
|
|
478
485
|
firefighter_tests/test_incidents/test_views/test_index_view.py,sha256=InpxbaWOFwRn4YWeIKZhj17vMymrQQf2p2LFhe2Bcdw,816
|
|
479
486
|
firefighter_tests/test_jira_app/__init__.py,sha256=JxZ3v-0kiHOoO-N3kR8NHTmD8tEvuEYKW1GX_S1ZLMY,33
|
|
480
487
|
firefighter_tests/test_jira_app/conftest.py,sha256=HmZd7EBZgng-rb3kIaB14TPVMixMG4YEvnShVqgjodE,545
|
|
@@ -502,13 +509,13 @@ firefighter_tests/test_slack/test_conversation_tags.py,sha256=nNqTZRRBfF6Z4wpFSY
|
|
|
502
509
|
firefighter_tests/test_slack/test_signals_downgrade.py,sha256=mgl4H5vwr2kImf6g4IZbhv7YEPmMzbYSaVr8E6taL88,5420
|
|
503
510
|
firefighter_tests/test_slack/test_slack_utils.py,sha256=9PLobMNXh3xDyFuwzcQFpKJhe4j__sIgf_WRHIpANJw,3957
|
|
504
511
|
firefighter_tests/test_slack/messages/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
505
|
-
firefighter_tests/test_slack/messages/test_slack_messages.py,sha256=
|
|
512
|
+
firefighter_tests/test_slack/messages/test_slack_messages.py,sha256=uyxfeAy1BQxx1zcCzlSJWn5YF1EnH-5Kt2XoIn9dekM,17484
|
|
506
513
|
firefighter_tests/test_slack/test_models/test_conversations.py,sha256=t3ttmgwiu7c-N55iU3XZPmrkEhvkTzJoXszJncy4Bts,793
|
|
507
514
|
firefighter_tests/test_slack/test_models/test_incident_channel.py,sha256=qWoGe9iadmK6-R8usWvjH87AHRkvhG_dHQeC3kHeJrs,17487
|
|
508
515
|
firefighter_tests/test_slack/test_models/test_slack_user.py,sha256=uzur-Rf03I5dpUTO4ZI6O1arBUrAorg1Zvgshf8M-J4,7000
|
|
509
516
|
firefighter_tests/test_slack/views/modals/conftest.py,sha256=TKJVQgqWaFs3Gg1T526pti9XpZBtQs47WBH6L_qSDeo,4532
|
|
510
|
-
firefighter_tests/test_slack/views/modals/test_close.py,sha256=
|
|
511
|
-
firefighter_tests/test_slack/views/modals/test_closure_reason_modal.py,sha256=
|
|
517
|
+
firefighter_tests/test_slack/views/modals/test_close.py,sha256=FWNV7RIUpqp3tiz9IBbBxaZk1XQt2f7vWB5TzJKYK3o,45630
|
|
518
|
+
firefighter_tests/test_slack/views/modals/test_closure_reason_modal.py,sha256=mvg5RiCXQEp1GhyOBCNW4idkNR1StgZjPvFrjzJ549Q,8333
|
|
512
519
|
firefighter_tests/test_slack/views/modals/test_edit.py,sha256=ykirry-S3i6PtoSs3rff_k6jqmvv1oMWC_iR8e5Jsg0,12022
|
|
513
520
|
firefighter_tests/test_slack/views/modals/test_form_utils_multiple_choice.py,sha256=Svab_ZyYTMf0T-uJEQcm7gS1WzxtC4gPh1W--Z2v_Y8,8415
|
|
514
521
|
firefighter_tests/test_slack/views/modals/test_key_event_message.py,sha256=BCg-c27ZLJqNgFuG4JDgXrSTp8_sT4FeBtpASzSq8NI,1107
|
|
@@ -516,10 +523,10 @@ firefighter_tests/test_slack/views/modals/test_open.py,sha256=IzgG9le5NN_CvltehA
|
|
|
516
523
|
firefighter_tests/test_slack/views/modals/test_opening_unified.py,sha256=OejtLyc_mehav2TDaLzUnhilMNvhCzc6T4FodCqfQPk,17406
|
|
517
524
|
firefighter_tests/test_slack/views/modals/test_send_sos.py,sha256=_rE6jD-gOzcGyhlY0R9GzlGtPx65oOOguJYdENgxtLc,1289
|
|
518
525
|
firefighter_tests/test_slack/views/modals/test_status.py,sha256=oQzPfwdg2tkbo9nfkO1GfS3WydxqSC6vy1AZjZDKT30,2226
|
|
519
|
-
firefighter_tests/test_slack/views/modals/test_update_status.py,sha256=
|
|
526
|
+
firefighter_tests/test_slack/views/modals/test_update_status.py,sha256=vbHGx6dkM_0swE1vJ0HrkhI1oJzD_WHZuIQ-_arAxXo,55686
|
|
520
527
|
firefighter_tests/test_slack/views/modals/test_utils.py,sha256=DJd2n9q6fFu8UuCRdiq9U_Cn19MdnC5c-ydLLrk6rkc,5218
|
|
521
|
-
firefighter_incident-0.0.
|
|
522
|
-
firefighter_incident-0.0.
|
|
523
|
-
firefighter_incident-0.0.
|
|
524
|
-
firefighter_incident-0.0.
|
|
525
|
-
firefighter_incident-0.0.
|
|
528
|
+
firefighter_incident-0.0.27.dist-info/METADATA,sha256=lHCUnR9PYiRLl_zG_MfvG23UsE_FZWbgQ4zlRdeIilY,5570
|
|
529
|
+
firefighter_incident-0.0.27.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
530
|
+
firefighter_incident-0.0.27.dist-info/entry_points.txt,sha256=c13meJbv7YNmYz7MipMOQwzQ5IeFOPXUBYAJ44XMQsM,61
|
|
531
|
+
firefighter_incident-0.0.27.dist-info/licenses/LICENSE,sha256=krRiGp-a9-1nH1bWpBEdxyTKLhjLmn6DMVVoIb0zF90,1087
|
|
532
|
+
firefighter_incident-0.0.27.dist-info/RECORD,,
|
|
@@ -4,6 +4,7 @@ import logging
|
|
|
4
4
|
from typing import TYPE_CHECKING
|
|
5
5
|
|
|
6
6
|
import pytest
|
|
7
|
+
from django.apps import apps
|
|
7
8
|
from django.urls import reverse
|
|
8
9
|
|
|
9
10
|
from firefighter.incidents.factories import IncidentFactory, UserFactory
|
|
@@ -15,6 +16,9 @@ if TYPE_CHECKING:
|
|
|
15
16
|
|
|
16
17
|
logger = logging.getLogger(__name__)
|
|
17
18
|
|
|
19
|
+
if not apps.is_installed("firefighter.confluence"):
|
|
20
|
+
pytest.skip("Confluence app not installed; skipping incident URLs tests", allow_module_level=True)
|
|
21
|
+
|
|
18
22
|
|
|
19
23
|
@pytest.mark.django_db
|
|
20
24
|
def test_incidents_dashboard_unauthorized(client: Client) -> None:
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from typing import TYPE_CHECKING
|
|
4
|
+
from unittest.mock import PropertyMock, patch
|
|
4
5
|
|
|
5
6
|
import pytest
|
|
6
7
|
from hypothesis import given
|
|
@@ -10,8 +11,11 @@ from hypothesis.strategies import builds
|
|
|
10
11
|
from firefighter.incidents.enums import ClosureReason, IncidentStatus
|
|
11
12
|
from firefighter.incidents.factories import IncidentFactory
|
|
12
13
|
from firefighter.incidents.models import IncidentUpdate
|
|
14
|
+
from firefighter.jira_app.models import JiraPostMortem
|
|
13
15
|
|
|
14
16
|
if TYPE_CHECKING:
|
|
17
|
+
from pytest_mock import MockerFixture
|
|
18
|
+
|
|
15
19
|
from firefighter.incidents.models import Incident
|
|
16
20
|
|
|
17
21
|
|
|
@@ -58,7 +62,9 @@ class TestIncidentCanBeClosed:
|
|
|
58
62
|
can_close, reasons = incident.can_be_closed
|
|
59
63
|
|
|
60
64
|
# Should be closable (assuming no missing milestones)
|
|
61
|
-
assert can_close is True or "STATUS_NOT_MITIGATED" not in [
|
|
65
|
+
assert can_close is True or "STATUS_NOT_MITIGATED" not in [
|
|
66
|
+
r[0] for r in reasons
|
|
67
|
+
]
|
|
62
68
|
|
|
63
69
|
def test_can_close_incident_with_closure_reason(self) -> None:
|
|
64
70
|
"""Test that incidents with closure_reason can always be closed."""
|
|
@@ -73,6 +79,108 @@ class TestIncidentCanBeClosed:
|
|
|
73
79
|
assert can_close is True
|
|
74
80
|
assert reasons == []
|
|
75
81
|
|
|
82
|
+
def test_cannot_close_when_jira_postmortem_not_ready(self, settings: None) -> None:
|
|
83
|
+
"""Block closure if Jira post-mortem exists but is not in Ready status."""
|
|
84
|
+
settings.ENABLE_JIRA_POSTMORTEM = True
|
|
85
|
+
incident = IncidentFactory.create(
|
|
86
|
+
_status=IncidentStatus.POST_MORTEM,
|
|
87
|
+
priority__value=1,
|
|
88
|
+
priority__needs_postmortem=True,
|
|
89
|
+
environment__value="PRD",
|
|
90
|
+
)
|
|
91
|
+
JiraPostMortem.objects.create(
|
|
92
|
+
incident=incident,
|
|
93
|
+
jira_issue_key="INC-999",
|
|
94
|
+
jira_issue_id="999",
|
|
95
|
+
created_by=incident.created_by,
|
|
96
|
+
)
|
|
97
|
+
incident.refresh_from_db()
|
|
98
|
+
assert hasattr(incident, "jira_postmortem_for")
|
|
99
|
+
|
|
100
|
+
with (
|
|
101
|
+
patch.object(
|
|
102
|
+
type(incident),
|
|
103
|
+
"needs_postmortem",
|
|
104
|
+
new_callable=PropertyMock,
|
|
105
|
+
return_value=True,
|
|
106
|
+
),
|
|
107
|
+
patch.object(type(incident), "missing_milestones", return_value=[]),
|
|
108
|
+
patch(
|
|
109
|
+
"firefighter.jira_app.service_postmortem.jira_postmortem_service.is_postmortem_ready",
|
|
110
|
+
return_value=(False, "In Progress"),
|
|
111
|
+
),
|
|
112
|
+
):
|
|
113
|
+
can_close, reasons = incident.can_be_closed
|
|
114
|
+
|
|
115
|
+
assert can_close is False
|
|
116
|
+
assert any(r[0] == "POSTMORTEM_NOT_READY" for r in reasons)
|
|
117
|
+
|
|
118
|
+
def test_postmortem_ready_allows_closure(
|
|
119
|
+
self, mocker: MockerFixture, settings: None
|
|
120
|
+
) -> None:
|
|
121
|
+
"""When Jira PM is Ready, can_be_closed should allow closure for PM incidents."""
|
|
122
|
+
settings.ENABLE_JIRA_POSTMORTEM = True
|
|
123
|
+
incident = IncidentFactory.create(
|
|
124
|
+
_status=IncidentStatus.POST_MORTEM,
|
|
125
|
+
priority__value=1,
|
|
126
|
+
priority__needs_postmortem=True,
|
|
127
|
+
environment__value="PRD",
|
|
128
|
+
)
|
|
129
|
+
JiraPostMortem.objects.create(
|
|
130
|
+
incident=incident,
|
|
131
|
+
jira_issue_key="INC-READY",
|
|
132
|
+
jira_issue_id="123",
|
|
133
|
+
created_by=incident.created_by,
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
mocker.patch.object(type(incident), "missing_milestones", return_value=[])
|
|
137
|
+
mocker.patch(
|
|
138
|
+
"firefighter.jira_app.service_postmortem.jira_postmortem_service.is_postmortem_ready",
|
|
139
|
+
return_value=(True, "Ready"),
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
can_close, reasons = incident.can_be_closed
|
|
143
|
+
|
|
144
|
+
assert can_close is True
|
|
145
|
+
assert reasons == []
|
|
146
|
+
|
|
147
|
+
def test_postmortem_status_unknown_sets_reason(
|
|
148
|
+
self, mocker: MockerFixture, settings: None
|
|
149
|
+
) -> None:
|
|
150
|
+
"""Errors while checking Jira PM should return POSTMORTEM_STATUS_UNKNOWN."""
|
|
151
|
+
settings.ENABLE_JIRA_POSTMORTEM = True
|
|
152
|
+
incident = IncidentFactory.create(
|
|
153
|
+
_status=IncidentStatus.POST_MORTEM,
|
|
154
|
+
priority__value=1,
|
|
155
|
+
priority__needs_postmortem=True,
|
|
156
|
+
environment__value="PRD",
|
|
157
|
+
)
|
|
158
|
+
JiraPostMortem.objects.create(
|
|
159
|
+
incident=incident,
|
|
160
|
+
jira_issue_key="INC-ERR",
|
|
161
|
+
jira_issue_id="124",
|
|
162
|
+
created_by=incident.created_by,
|
|
163
|
+
)
|
|
164
|
+
incident.refresh_from_db()
|
|
165
|
+
assert hasattr(incident, "jira_postmortem_for")
|
|
166
|
+
|
|
167
|
+
mocker.patch.object(type(incident), "missing_milestones", return_value=[])
|
|
168
|
+
mocker.patch(
|
|
169
|
+
"firefighter.jira_app.service_postmortem.jira_postmortem_service.is_postmortem_ready",
|
|
170
|
+
side_effect=Exception("boom"),
|
|
171
|
+
)
|
|
172
|
+
mocker.patch.object(
|
|
173
|
+
type(incident),
|
|
174
|
+
"needs_postmortem",
|
|
175
|
+
new_callable=PropertyMock,
|
|
176
|
+
return_value=True,
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
can_close, reasons = incident.can_be_closed
|
|
180
|
+
|
|
181
|
+
assert can_close is False
|
|
182
|
+
assert any(r[0] == "POSTMORTEM_STATUS_UNKNOWN" for r in reasons)
|
|
183
|
+
|
|
76
184
|
|
|
77
185
|
@pytest.mark.django_db
|
|
78
186
|
class TestIncidentSetStatus:
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import pytest
|
|
4
|
+
from django.apps import apps
|
|
4
5
|
from django.test import Client
|
|
5
6
|
from django.urls import reverse
|
|
6
7
|
|
|
7
8
|
from firefighter.incidents.models import Incident
|
|
8
9
|
from firefighter.incidents.models.user import User
|
|
9
10
|
|
|
11
|
+
if not apps.is_installed("firefighter.confluence"):
|
|
12
|
+
pytest.skip("Confluence app not installed; skipping incident detail view test", allow_module_level=True)
|
|
13
|
+
|
|
10
14
|
|
|
11
15
|
@pytest.mark.django_db
|
|
12
16
|
def test_incident_detail_view(
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import pytest
|
|
4
|
+
from django.apps import apps
|
|
4
5
|
|
|
5
6
|
from firefighter.incidents.enums import IncidentStatus
|
|
6
7
|
from firefighter.incidents.factories import IncidentFactory, UserFactory
|
|
@@ -18,6 +19,9 @@ try:
|
|
|
18
19
|
except (ImportError, AttributeError):
|
|
19
20
|
PostMortem = None
|
|
20
21
|
|
|
22
|
+
if not apps.is_installed("firefighter.confluence"):
|
|
23
|
+
pytest.skip("Confluence app not installed; skipping slack message tests", allow_module_level=True)
|
|
24
|
+
|
|
21
25
|
|
|
22
26
|
@pytest.mark.django_db
|
|
23
27
|
class TestSlackMessageIncidentStatusUpdated:
|
|
@@ -5,6 +5,7 @@ from copy import deepcopy
|
|
|
5
5
|
from unittest.mock import MagicMock, PropertyMock
|
|
6
6
|
|
|
7
7
|
import pytest
|
|
8
|
+
from django.apps import apps
|
|
8
9
|
from pytest_mock import MockerFixture
|
|
9
10
|
|
|
10
11
|
from firefighter.incidents.enums import IncidentStatus
|
|
@@ -14,6 +15,9 @@ from firefighter.slack.views import CloseModal
|
|
|
14
15
|
|
|
15
16
|
logger = logging.getLogger(__name__)
|
|
16
17
|
|
|
18
|
+
if not apps.is_installed("firefighter.confluence"):
|
|
19
|
+
pytest.skip("Confluence app not installed; skipping close modal tests", allow_module_level=True)
|
|
20
|
+
|
|
17
21
|
|
|
18
22
|
@pytest.mark.django_db
|
|
19
23
|
class TestCloseModal:
|
|
@@ -9,6 +9,7 @@ from slack_sdk.errors import SlackApiError
|
|
|
9
9
|
|
|
10
10
|
from firefighter.incidents.enums import ClosureReason, IncidentStatus
|
|
11
11
|
from firefighter.incidents.factories import IncidentFactory, UserFactory
|
|
12
|
+
from firefighter.incidents.models import Environment, Priority
|
|
12
13
|
from firefighter.slack.views.modals.closure_reason import ClosureReasonModal
|
|
13
14
|
|
|
14
15
|
|
|
@@ -16,12 +17,16 @@ from firefighter.slack.views.modals.closure_reason import ClosureReasonModal
|
|
|
16
17
|
class TestClosureReasonModalMessageTabDisabled:
|
|
17
18
|
"""Test ClosureReasonModal handles messages_tab_disabled gracefully."""
|
|
18
19
|
|
|
19
|
-
def test_closure_reason_handles_messages_tab_disabled(
|
|
20
|
+
def test_closure_reason_handles_messages_tab_disabled(
|
|
21
|
+
self, caplog: pytest.LogCaptureFixture, mocker
|
|
22
|
+
) -> None:
|
|
20
23
|
"""Test that messages_tab_disabled error is handled gracefully with warning log."""
|
|
21
24
|
# Create test data
|
|
22
25
|
user = UserFactory.build()
|
|
23
26
|
user.save()
|
|
24
|
-
incident = IncidentFactory.build(
|
|
27
|
+
incident = IncidentFactory.build(
|
|
28
|
+
_status=IncidentStatus.INVESTIGATING, created_by=user
|
|
29
|
+
)
|
|
25
30
|
incident.save()
|
|
26
31
|
|
|
27
32
|
# Mock can_be_closed to return True so the closure can proceed
|
|
@@ -29,7 +34,7 @@ class TestClosureReasonModalMessageTabDisabled:
|
|
|
29
34
|
type(incident),
|
|
30
35
|
"can_be_closed",
|
|
31
36
|
new_callable=mocker.PropertyMock,
|
|
32
|
-
return_value=(True, [])
|
|
37
|
+
return_value=(True, []),
|
|
33
38
|
)
|
|
34
39
|
|
|
35
40
|
# Create modal and mock
|
|
@@ -46,9 +51,7 @@ class TestClosureReasonModalMessageTabDisabled:
|
|
|
46
51
|
"selected_option": {"value": ClosureReason.CANCELLED}
|
|
47
52
|
}
|
|
48
53
|
},
|
|
49
|
-
"closure_reference": {
|
|
50
|
-
"input_closure_reference": {"value": ""}
|
|
51
|
-
},
|
|
54
|
+
"closure_reference": {"input_closure_reference": {"value": ""}},
|
|
52
55
|
"closure_message": {
|
|
53
56
|
"input_closure_message": {"value": "Test closure message"}
|
|
54
57
|
},
|
|
@@ -63,18 +66,17 @@ class TestClosureReasonModalMessageTabDisabled:
|
|
|
63
66
|
slack_error_response = MagicMock()
|
|
64
67
|
slack_error_response.get.return_value = "messages_tab_disabled"
|
|
65
68
|
|
|
66
|
-
with patch(
|
|
69
|
+
with patch(
|
|
70
|
+
"firefighter.slack.views.modals.closure_reason.respond"
|
|
71
|
+
) as mock_respond:
|
|
67
72
|
mock_respond.side_effect = SlackApiError(
|
|
68
73
|
message="The request to the Slack API failed.",
|
|
69
|
-
response=slack_error_response
|
|
74
|
+
response=slack_error_response,
|
|
70
75
|
)
|
|
71
76
|
|
|
72
77
|
# Execute
|
|
73
78
|
result = modal.handle_modal_fn(
|
|
74
|
-
ack=ack,
|
|
75
|
-
body=body,
|
|
76
|
-
incident=incident,
|
|
77
|
-
user=user
|
|
79
|
+
ack=ack, body=body, incident=incident, user=user
|
|
78
80
|
)
|
|
79
81
|
|
|
80
82
|
# Assertions
|
|
@@ -87,7 +89,8 @@ class TestClosureReasonModalMessageTabDisabled:
|
|
|
87
89
|
|
|
88
90
|
# Verify warning was logged
|
|
89
91
|
assert any(
|
|
90
|
-
"Cannot send DM to user" in record.message
|
|
92
|
+
"Cannot send DM to user" in record.message
|
|
93
|
+
and record.levelname == "WARNING"
|
|
91
94
|
for record in caplog.records
|
|
92
95
|
)
|
|
93
96
|
|
|
@@ -96,7 +99,9 @@ class TestClosureReasonModalMessageTabDisabled:
|
|
|
96
99
|
# Create test data
|
|
97
100
|
user = UserFactory.build()
|
|
98
101
|
user.save()
|
|
99
|
-
incident = IncidentFactory.build(
|
|
102
|
+
incident = IncidentFactory.build(
|
|
103
|
+
_status=IncidentStatus.INVESTIGATING, created_by=user
|
|
104
|
+
)
|
|
100
105
|
incident.save()
|
|
101
106
|
|
|
102
107
|
# Mock can_be_closed to return True so the closure can proceed
|
|
@@ -104,7 +109,7 @@ class TestClosureReasonModalMessageTabDisabled:
|
|
|
104
109
|
type(incident),
|
|
105
110
|
"can_be_closed",
|
|
106
111
|
new_callable=mocker.PropertyMock,
|
|
107
|
-
return_value=(True, [])
|
|
112
|
+
return_value=(True, []),
|
|
108
113
|
)
|
|
109
114
|
|
|
110
115
|
# Create modal and mock
|
|
@@ -121,9 +126,7 @@ class TestClosureReasonModalMessageTabDisabled:
|
|
|
121
126
|
"selected_option": {"value": ClosureReason.CANCELLED}
|
|
122
127
|
}
|
|
123
128
|
},
|
|
124
|
-
"closure_reference": {
|
|
125
|
-
"input_closure_reference": {"value": ""}
|
|
126
|
-
},
|
|
129
|
+
"closure_reference": {"input_closure_reference": {"value": ""}},
|
|
127
130
|
"closure_message": {
|
|
128
131
|
"input_closure_message": {"value": "Test closure message"}
|
|
129
132
|
},
|
|
@@ -138,17 +141,97 @@ class TestClosureReasonModalMessageTabDisabled:
|
|
|
138
141
|
slack_error_response = MagicMock()
|
|
139
142
|
slack_error_response.get.return_value = "channel_not_found"
|
|
140
143
|
|
|
141
|
-
with patch(
|
|
144
|
+
with patch(
|
|
145
|
+
"firefighter.slack.views.modals.closure_reason.respond"
|
|
146
|
+
) as mock_respond:
|
|
142
147
|
mock_respond.side_effect = SlackApiError(
|
|
143
148
|
message="The request to the Slack API failed.",
|
|
144
|
-
response=slack_error_response
|
|
149
|
+
response=slack_error_response,
|
|
145
150
|
)
|
|
146
151
|
|
|
147
152
|
# Execute and expect exception
|
|
148
153
|
with pytest.raises(SlackApiError):
|
|
149
|
-
modal.handle_modal_fn(
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
154
|
+
modal.handle_modal_fn(ack=ack, body=body, incident=incident, user=user)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
@pytest.mark.django_db
|
|
158
|
+
class TestClosureReasonModalEarlyClosureBypass:
|
|
159
|
+
"""Test early-closure path respects submitted closure reason."""
|
|
160
|
+
|
|
161
|
+
def test_allows_early_closure_with_submitted_reason(self, settings) -> None:
|
|
162
|
+
"""Ensure can_be_closed passes when a closure reason is provided for early closure."""
|
|
163
|
+
settings.ENABLE_JIRA_POSTMORTEM = True
|
|
164
|
+
|
|
165
|
+
# Ensure required priority/environment for needs_postmortem + PRD
|
|
166
|
+
priority = Priority.objects.create(
|
|
167
|
+
name="P1-test",
|
|
168
|
+
value=9991,
|
|
169
|
+
description="P1 test",
|
|
170
|
+
order=9991,
|
|
171
|
+
needs_postmortem=True,
|
|
172
|
+
)
|
|
173
|
+
env, _ = Environment.objects.get_or_create(
|
|
174
|
+
value="PRD",
|
|
175
|
+
defaults={
|
|
176
|
+
"name": "Production",
|
|
177
|
+
"description": "Production",
|
|
178
|
+
"order": 9991,
|
|
179
|
+
},
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
user = UserFactory.create()
|
|
183
|
+
incident = IncidentFactory.create(
|
|
184
|
+
_status=IncidentStatus.INVESTIGATING,
|
|
185
|
+
created_by=user,
|
|
186
|
+
priority=priority,
|
|
187
|
+
environment=env,
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
modal = ClosureReasonModal()
|
|
191
|
+
ack = MagicMock()
|
|
192
|
+
|
|
193
|
+
body = {
|
|
194
|
+
"view": {
|
|
195
|
+
"state": {
|
|
196
|
+
"values": {
|
|
197
|
+
"closure_reason": {
|
|
198
|
+
"select_closure_reason": {
|
|
199
|
+
"selected_option": {"value": ClosureReason.CANCELLED}
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
"closure_reference": {
|
|
203
|
+
"input_closure_reference": {"value": "INC-42"}
|
|
204
|
+
},
|
|
205
|
+
"closure_message": {
|
|
206
|
+
"input_closure_message": {
|
|
207
|
+
"value": "Closing early with reason"
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
"private_metadata": str(incident.id),
|
|
213
|
+
},
|
|
214
|
+
"user": {"id": "U123456"},
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
with patch(
|
|
218
|
+
"firefighter.slack.views.modals.closure_reason.respond"
|
|
219
|
+
) as mock_respond:
|
|
220
|
+
mock_respond.return_value = None
|
|
221
|
+
|
|
222
|
+
result = modal.handle_modal_fn(
|
|
223
|
+
ack=ack,
|
|
224
|
+
body=body,
|
|
225
|
+
incident=incident,
|
|
226
|
+
user=user,
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
# Early closure should succeed and close the incident
|
|
230
|
+
assert result is True
|
|
231
|
+
incident.refresh_from_db()
|
|
232
|
+
assert incident.status == IncidentStatus.CLOSED
|
|
233
|
+
assert incident.closure_reason == ClosureReason.CANCELLED
|
|
234
|
+
assert incident.closure_reference == "INC-42"
|
|
235
|
+
|
|
236
|
+
# Ack should clear modal stack
|
|
237
|
+
ack.assert_called_once_with(response_action="clear")
|