|
55 | 55 | from apps.slack.slack_client import SlackClientWithErrorHandling
|
56 | 56 | from apps.slack.slack_client.exceptions import SlackAPIException, SlackAPITokenException
|
57 | 57 | from apps.slack.tasks import clean_slack_integration_leftovers, unpopulate_slack_user_identities
|
| 58 | +from apps.user_management.models import Organization |
58 | 59 | from common.insight_log import ChatOpsEvent, ChatOpsTypePlug, write_chatops_insight_log
|
59 | 60 | from common.oncall_gateway import delete_slack_connector
|
60 | 61 |
|
@@ -285,6 +286,19 @@ def post(self, request):
|
285 | 286 | # Open pop-up to inform user why OnCall bot doesn't work if any action was triggered
|
286 | 287 | self._open_warning_window_if_needed(payload, slack_team_identity, warning_text)
|
287 | 288 | return Response(status=200)
|
| 289 | + elif organization is None: |
| 290 | + # see this GitHub issue for more context on how this situation can arise |
| 291 | + # https://github.com/grafana/oncall-private/issues/1836 |
| 292 | + warning_text = ( |
| 293 | + "OnCall is not able to process this action because one of the following scenarios: \n" |
| 294 | + "1. The Slack chatops integration was disconnected from the instance that the Alert Group belongs " |
| 295 | + "to, BUT the Slack workspace is still connected to another instance as well. In this case, simply log " |
| 296 | + "in to the OnCall web interface and re-install the Slack Integration with this workspace again.\n" |
| 297 | + "2. (Less likely) The Grafana instance belonging to this Alert Group was deleted. In this case the Alert Group is orphaned and cannot be acted upon." |
| 298 | + ) |
| 299 | + # Open pop-up to inform user why OnCall bot doesn't work if any action was triggered |
| 300 | + self._open_warning_window_if_needed(payload, slack_team_identity, warning_text) |
| 301 | + return Response(status=200) |
288 | 302 | elif not slack_user_identity.users.exists():
|
289 | 303 | # Means that slack_user_identity doesn't have any connected user
|
290 | 304 | # Open pop-up to inform user why OnCall bot doesn't work if any action was triggered
|
@@ -420,76 +434,81 @@ def _get_organization_from_payload(self, payload, slack_team_identity):
|
420 | 434 | channel_id = None
|
421 | 435 | organization = None
|
422 | 436 |
|
423 |
| - # view submission or actions in view |
424 |
| - if "view" in payload: |
425 |
| - organization_id = None |
426 |
| - private_metadata = payload["view"].get("private_metadata") |
427 |
| - # steps with private_metadata in which we know organization before open view |
428 |
| - if private_metadata and "organization_id" in private_metadata: |
429 |
| - organization_id = json.loads(private_metadata).get("organization_id") |
430 |
| - # steps with organization selection in view (e.g. slash commands) |
431 |
| - elif SELECT_ORGANIZATION_AND_ROUTE_BLOCK_ID in payload["view"].get("state", {}).get("values", {}): |
432 |
| - payload_values = payload["view"]["state"]["values"] |
433 |
| - selected_value = payload_values[SELECT_ORGANIZATION_AND_ROUTE_BLOCK_ID][ |
434 |
| - SELECT_ORGANIZATION_AND_ROUTE_BLOCK_ID |
435 |
| - ]["selected_option"]["value"] |
436 |
| - organization_id = int(selected_value.split("-")[0]) |
437 |
| - if organization_id: |
438 |
| - organization = slack_team_identity.organizations.get(pk=organization_id) |
439 |
| - return organization |
440 |
| - # buttons and actions |
441 |
| - elif payload.get("type") in [ |
442 |
| - PAYLOAD_TYPE_BLOCK_ACTIONS, |
443 |
| - PAYLOAD_TYPE_INTERACTIVE_MESSAGE, |
444 |
| - PAYLOAD_TYPE_MESSAGE_ACTION, |
445 |
| - ]: |
446 |
| - # for cases when we put organization_id into action value (e.g. public suggestion) |
447 |
| - if ( |
448 |
| - payload.get("actions") |
449 |
| - and payload["actions"][0].get("value", {}) |
450 |
| - and "organization_id" in payload["actions"][0]["value"] |
451 |
| - ): |
452 |
| - organization_id = int(json.loads(payload["actions"][0]["value"])["organization_id"]) |
453 |
| - organization = slack_team_identity.organizations.get(pk=organization_id) |
454 |
| - return organization |
455 |
| - |
456 |
| - channel_id = payload["channel"]["id"] |
457 |
| - if "message" in payload: |
458 |
| - message_ts = payload["message"].get("thread_ts") or payload["message"]["ts"] |
459 |
| - # for interactive message |
460 |
| - elif "message_ts" in payload: |
461 |
| - message_ts = payload["message_ts"] |
462 |
| - else: |
463 |
| - return |
464 |
| - # events |
465 |
| - elif payload.get("type") == PAYLOAD_TYPE_EVENT_CALLBACK: |
466 |
| - if "channel" in payload["event"]: # events without channel: user_change, events with subteam, etc. |
467 |
| - channel_id = payload["event"]["channel"] |
468 |
| - |
469 |
| - if "message" in payload["event"]: |
470 |
| - message_ts = payload["event"]["message"].get("thread_ts") or payload["event"]["message"]["ts"] |
471 |
| - elif "thread_ts" in payload["event"]: |
472 |
| - message_ts = payload["event"]["thread_ts"] |
473 |
| - else: |
474 |
| - return |
| 437 | + try: |
| 438 | + # view submission or actions in view |
| 439 | + if "view" in payload: |
| 440 | + organization_id = None |
| 441 | + private_metadata = payload["view"].get("private_metadata") |
| 442 | + # steps with private_metadata in which we know organization before open view |
| 443 | + if private_metadata and "organization_id" in private_metadata: |
| 444 | + organization_id = json.loads(private_metadata).get("organization_id") |
| 445 | + # steps with organization selection in view (e.g. slash commands) |
| 446 | + elif SELECT_ORGANIZATION_AND_ROUTE_BLOCK_ID in payload["view"].get("state", {}).get("values", {}): |
| 447 | + payload_values = payload["view"]["state"]["values"] |
| 448 | + selected_value = payload_values[SELECT_ORGANIZATION_AND_ROUTE_BLOCK_ID][ |
| 449 | + SELECT_ORGANIZATION_AND_ROUTE_BLOCK_ID |
| 450 | + ]["selected_option"]["value"] |
| 451 | + organization_id = int(selected_value.split("-")[0]) |
| 452 | + if organization_id: |
| 453 | + organization = slack_team_identity.organizations.get(pk=organization_id) |
| 454 | + return organization |
| 455 | + # buttons and actions |
| 456 | + elif payload.get("type") in [ |
| 457 | + PAYLOAD_TYPE_BLOCK_ACTIONS, |
| 458 | + PAYLOAD_TYPE_INTERACTIVE_MESSAGE, |
| 459 | + PAYLOAD_TYPE_MESSAGE_ACTION, |
| 460 | + ]: |
| 461 | + # for cases when we put organization_id into action value (e.g. public suggestion) |
| 462 | + if ( |
| 463 | + payload.get("actions") |
| 464 | + and payload["actions"][0].get("value", {}) |
| 465 | + and "organization_id" in payload["actions"][0]["value"] |
| 466 | + ): |
| 467 | + organization_id = int(json.loads(payload["actions"][0]["value"])["organization_id"]) |
| 468 | + organization = slack_team_identity.organizations.get(pk=organization_id) |
| 469 | + return organization |
| 470 | + |
| 471 | + channel_id = payload["channel"]["id"] |
| 472 | + if "message" in payload: |
| 473 | + message_ts = payload["message"].get("thread_ts") or payload["message"]["ts"] |
| 474 | + # for interactive message |
| 475 | + elif "message_ts" in payload: |
| 476 | + message_ts = payload["message_ts"] |
| 477 | + else: |
| 478 | + return |
| 479 | + # events |
| 480 | + elif payload.get("type") == PAYLOAD_TYPE_EVENT_CALLBACK: |
| 481 | + if "channel" in payload["event"]: # events without channel: user_change, events with subteam, etc. |
| 482 | + channel_id = payload["event"]["channel"] |
| 483 | + |
| 484 | + if "message" in payload["event"]: |
| 485 | + message_ts = payload["event"]["message"].get("thread_ts") or payload["event"]["message"]["ts"] |
| 486 | + elif "thread_ts" in payload["event"]: |
| 487 | + message_ts = payload["event"]["thread_ts"] |
| 488 | + else: |
| 489 | + return |
475 | 490 |
|
476 |
| - if not (message_ts and channel_id): |
477 |
| - return |
| 491 | + if not (message_ts and channel_id): |
| 492 | + return |
478 | 493 |
|
479 |
| - try: |
480 |
| - slack_message = SlackMessage.objects.get( |
481 |
| - slack_id=message_ts, |
482 |
| - _slack_team_identity=slack_team_identity, |
483 |
| - channel_id=channel_id, |
484 |
| - ) |
485 |
| - except SlackMessage.DoesNotExist: |
486 |
| - pass |
487 |
| - else: |
488 |
| - alert_group = slack_message.get_alert_group() |
489 |
| - if alert_group: |
490 |
| - organization = alert_group.channel.organization |
491 |
| - return organization |
492 |
| - return organization |
| 494 | + try: |
| 495 | + slack_message = SlackMessage.objects.get( |
| 496 | + slack_id=message_ts, |
| 497 | + _slack_team_identity=slack_team_identity, |
| 498 | + channel_id=channel_id, |
| 499 | + ) |
| 500 | + except SlackMessage.DoesNotExist: |
| 501 | + pass |
| 502 | + else: |
| 503 | + alert_group = slack_message.get_alert_group() |
| 504 | + if alert_group: |
| 505 | + organization = alert_group.channel.organization |
| 506 | + return organization |
| 507 | + return organization |
| 508 | + except Organization.DoesNotExist: |
| 509 | + # see this GitHub issue for more context on how this situation can arise |
| 510 | + # https://github.com/grafana/oncall-private/issues/1836 |
| 511 | + return None |
493 | 512 |
|
494 | 513 | def _open_warning_window_if_needed(self, payload, slack_team_identity, warning_text) -> None:
|
495 | 514 | if payload.get("trigger_id") is not None:
|
|
0 commit comments