2022-06-03 08:09:47 -06:00
|
|
|
from unittest.mock import patch
|
|
|
|
|
|
|
|
|
|
import pytest
|
|
|
|
|
from django.conf import settings
|
|
|
|
|
from django.urls import reverse
|
|
|
|
|
from rest_framework import status
|
|
|
|
|
from rest_framework.response import Response
|
|
|
|
|
from rest_framework.test import APIClient
|
|
|
|
|
|
2022-11-29 09:41:56 +01:00
|
|
|
from apps.api.permissions import LegacyAccessControlRole
|
2023-09-07 09:42:30 +01:00
|
|
|
from apps.schedules.models import OnCallScheduleWeb
|
2024-11-04 15:49:22 -05:00
|
|
|
from apps.slack.tasks import (
|
|
|
|
|
clean_slack_channel_leftovers,
|
|
|
|
|
clean_slack_integration_leftovers,
|
|
|
|
|
unpopulate_slack_user_identities,
|
|
|
|
|
)
|
2023-09-07 09:42:30 +01:00
|
|
|
from apps.user_management.models import User
|
2022-06-03 08:09:47 -06:00
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.django_db
|
|
|
|
|
@pytest.mark.parametrize(
|
|
|
|
|
"role,expected_status",
|
|
|
|
|
[
|
2022-11-29 09:41:56 +01:00
|
|
|
(LegacyAccessControlRole.ADMIN, status.HTTP_200_OK),
|
|
|
|
|
(LegacyAccessControlRole.EDITOR, status.HTTP_403_FORBIDDEN),
|
|
|
|
|
(LegacyAccessControlRole.VIEWER, status.HTTP_403_FORBIDDEN),
|
2023-10-19 14:39:08 -03:00
|
|
|
(LegacyAccessControlRole.NONE, status.HTTP_403_FORBIDDEN),
|
2022-06-03 08:09:47 -06:00
|
|
|
],
|
|
|
|
|
)
|
|
|
|
|
def test_reset_slack_integration_permissions(
|
2022-11-29 09:41:56 +01:00
|
|
|
make_organization_and_user_with_plugin_token, load_slack_urls, make_user_auth_headers, role, expected_status
|
2022-06-03 08:09:47 -06:00
|
|
|
):
|
|
|
|
|
settings.FEATURE_SLACK_INTEGRATION_ENABLED = True
|
|
|
|
|
|
2022-11-29 09:41:56 +01:00
|
|
|
_, user, token = make_organization_and_user_with_plugin_token(role=role)
|
2022-06-03 08:09:47 -06:00
|
|
|
client = APIClient()
|
|
|
|
|
|
|
|
|
|
url = reverse("reset-slack")
|
|
|
|
|
with patch("apps.slack.views.ResetSlackView.post", return_value=Response(status=status.HTTP_200_OK)):
|
|
|
|
|
response = client.post(url, format="json", **make_user_auth_headers(user, token))
|
|
|
|
|
|
|
|
|
|
assert response.status_code == expected_status
|
2023-09-07 09:42:30 +01:00
|
|
|
|
|
|
|
|
|
2024-11-04 15:49:22 -05:00
|
|
|
@pytest.mark.django_db
|
|
|
|
|
def test_clean_slack_channel_leftovers(
|
|
|
|
|
make_slack_team_identity,
|
|
|
|
|
make_slack_channel,
|
|
|
|
|
make_organization,
|
|
|
|
|
make_alert_receive_channel,
|
|
|
|
|
make_channel_filter,
|
|
|
|
|
make_slack_user_group,
|
|
|
|
|
make_schedule,
|
|
|
|
|
):
|
|
|
|
|
slack_team_identity = make_slack_team_identity()
|
|
|
|
|
slack_channel = make_slack_channel(slack_team_identity)
|
|
|
|
|
organization = make_organization(slack_team_identity=slack_team_identity, default_slack_channel=slack_channel)
|
|
|
|
|
|
|
|
|
|
# create channel filter with Slack channel
|
|
|
|
|
alert_receive_channel = make_alert_receive_channel(organization)
|
|
|
|
|
channel_filter = make_channel_filter(alert_receive_channel, slack_channel=slack_channel)
|
|
|
|
|
|
|
|
|
|
# create schedule with Slack channel and user group
|
|
|
|
|
user_group = make_slack_user_group(slack_team_identity)
|
|
|
|
|
schedule = make_schedule(
|
|
|
|
|
organization,
|
|
|
|
|
schedule_class=OnCallScheduleWeb,
|
|
|
|
|
slack_channel=slack_channel,
|
|
|
|
|
user_group=user_group,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
assert channel_filter.slack_channel == slack_channel
|
|
|
|
|
assert schedule.slack_channel == slack_channel
|
|
|
|
|
assert schedule.user_group == user_group
|
|
|
|
|
assert organization.default_slack_channel_slack_id == slack_channel.slack_id
|
|
|
|
|
|
|
|
|
|
# clean Slack channel leftovers
|
|
|
|
|
clean_slack_channel_leftovers(slack_team_identity.pk, slack_channel.slack_id)
|
|
|
|
|
channel_filter.refresh_from_db()
|
|
|
|
|
schedule.refresh_from_db()
|
|
|
|
|
organization.refresh_from_db()
|
|
|
|
|
|
|
|
|
|
# check that references to Slack objects are removed
|
|
|
|
|
assert channel_filter.slack_channel is None
|
|
|
|
|
assert organization.default_slack_channel is None
|
|
|
|
|
|
|
|
|
|
# NOTE: user groups shouldn't be updated for schedules, only the channel
|
|
|
|
|
assert schedule.slack_channel is None
|
|
|
|
|
assert schedule.user_group == user_group
|
|
|
|
|
|
|
|
|
|
|
2023-09-07 09:42:30 +01:00
|
|
|
@pytest.mark.django_db
|
|
|
|
|
def test_clean_slack_integration_leftovers(
|
2024-11-04 13:34:06 -05:00
|
|
|
make_slack_team_identity,
|
|
|
|
|
make_slack_channel,
|
|
|
|
|
make_organization,
|
2023-09-07 09:42:30 +01:00
|
|
|
make_alert_receive_channel,
|
|
|
|
|
make_channel_filter,
|
|
|
|
|
make_slack_user_group,
|
|
|
|
|
make_schedule,
|
|
|
|
|
):
|
2024-11-04 13:34:06 -05:00
|
|
|
slack_team_identity = make_slack_team_identity()
|
|
|
|
|
slack_channel = make_slack_channel(slack_team_identity)
|
|
|
|
|
organization = make_organization(slack_team_identity=slack_team_identity, default_slack_channel=slack_channel)
|
2023-09-07 09:42:30 +01:00
|
|
|
|
|
|
|
|
# create channel filter with Slack channel
|
|
|
|
|
alert_receive_channel = make_alert_receive_channel(organization)
|
2024-11-04 13:34:06 -05:00
|
|
|
channel_filter = make_channel_filter(alert_receive_channel, slack_channel=slack_channel)
|
2023-09-07 09:42:30 +01:00
|
|
|
|
|
|
|
|
# create schedule with Slack channel and user group
|
|
|
|
|
user_group = make_slack_user_group(slack_team_identity)
|
2024-11-04 15:49:22 -05:00
|
|
|
schedule = make_schedule(
|
|
|
|
|
organization,
|
|
|
|
|
schedule_class=OnCallScheduleWeb,
|
|
|
|
|
slack_channel=slack_channel,
|
|
|
|
|
user_group=user_group,
|
|
|
|
|
)
|
2023-09-07 09:42:30 +01:00
|
|
|
|
2024-11-04 15:49:22 -05:00
|
|
|
assert channel_filter.slack_channel == slack_channel
|
|
|
|
|
assert schedule.slack_channel == slack_channel
|
|
|
|
|
assert schedule.user_group == user_group
|
2024-11-04 13:34:06 -05:00
|
|
|
|
2023-09-07 09:42:30 +01:00
|
|
|
# clean Slack integration leftovers
|
|
|
|
|
clean_slack_integration_leftovers(organization.pk)
|
|
|
|
|
channel_filter.refresh_from_db()
|
|
|
|
|
schedule.refresh_from_db()
|
|
|
|
|
|
|
|
|
|
# check that references to Slack objects are removed
|
2024-11-04 13:34:06 -05:00
|
|
|
assert channel_filter.slack_channel is None
|
2024-11-04 15:49:22 -05:00
|
|
|
assert schedule.slack_channel is None
|
2023-09-07 09:42:30 +01:00
|
|
|
assert schedule.user_group is None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.django_db
|
|
|
|
|
def test_unpopulate_slack_user_identities(
|
feat: convert `organization.general_log_channel_id` to `organization.default_slack_channel` (#5191)
# What this PR does
Related to https://github.com/grafana/oncall-private/issues/2947
Right now `general_log_channel_id` is just a string value representing
the Slack Channel ID (ex. `C043HQ70QMB`). This PR migrates this instead
to be a foreign key relationship on the `slack_slackchannel` table and
updates all references to `general_log_channel_id`.
Tested migrations locally:
```bash
Operations to perform:
Apply all migrations: [redacted secret grafana-admin-creds:admin-user], alerts, auth, auth_token, base, contenttypes, email, exotel, fcm_django, google, heartbeat, labels, mobile_app, oss_installation, phone_notifications, schedules, sessions, slack, social_django, telegram, twilioapp, user_management, webhooks, zvonok
Running migrations:
Applying user_management.0024_organization_general_log_slack_channel... OK
source=engine:app google_trace_id=none logger=apps.user_management.migrations.0025_auto_20241017_1919 Starting migration to populate general_log_slack_channel field.
source=engine:app google_trace_id=none logger=apps.user_management.migrations.0025_auto_20241017_1919 Total organizations to process: 1
source=engine:app google_trace_id=none logger=apps.user_management.migrations.0025_auto_20241017_1919 Organization 1 updated with SlackChannel 2 (slack_id: C043LL6RTS7).
source=engine:app google_trace_id=none logger=apps.user_management.migrations.0025_auto_20241017_1919 Finished migration. Total organizations processed: 1. Organizations updated: 1. Missing SlackChannels: 0.
Applying user_management.0025_auto_20241017_1919... OK
```
## Future incoming PRs
- Drop `Organization.general_log_channel_id` column
- Migrate `ChannelFilter.slack_channel_id` and
`ResolutionNoteSlackMessage.slack_channel_id` to use foreign key
relationships
## Checklist
- [x] Unit, integration, and e2e (if applicable) tests updated
- [x] Documentation added (or `pr:no public docs` PR label added if not
required)
- [x] Added the relevant release notes label (see labels prefixed w/
`release:`). These labels dictate how your PR will
show up in the autogenerated release notes.
2024-11-01 06:41:38 +01:00
|
|
|
make_slack_team_identity,
|
|
|
|
|
make_slack_channel,
|
|
|
|
|
make_organization,
|
|
|
|
|
make_user_for_organization,
|
|
|
|
|
make_user_with_slack_user_identity,
|
2023-09-07 09:42:30 +01:00
|
|
|
):
|
|
|
|
|
# create organization and user with Slack connected
|
feat: convert `organization.general_log_channel_id` to `organization.default_slack_channel` (#5191)
# What this PR does
Related to https://github.com/grafana/oncall-private/issues/2947
Right now `general_log_channel_id` is just a string value representing
the Slack Channel ID (ex. `C043HQ70QMB`). This PR migrates this instead
to be a foreign key relationship on the `slack_slackchannel` table and
updates all references to `general_log_channel_id`.
Tested migrations locally:
```bash
Operations to perform:
Apply all migrations: [redacted secret grafana-admin-creds:admin-user], alerts, auth, auth_token, base, contenttypes, email, exotel, fcm_django, google, heartbeat, labels, mobile_app, oss_installation, phone_notifications, schedules, sessions, slack, social_django, telegram, twilioapp, user_management, webhooks, zvonok
Running migrations:
Applying user_management.0024_organization_general_log_slack_channel... OK
source=engine:app google_trace_id=none logger=apps.user_management.migrations.0025_auto_20241017_1919 Starting migration to populate general_log_slack_channel field.
source=engine:app google_trace_id=none logger=apps.user_management.migrations.0025_auto_20241017_1919 Total organizations to process: 1
source=engine:app google_trace_id=none logger=apps.user_management.migrations.0025_auto_20241017_1919 Organization 1 updated with SlackChannel 2 (slack_id: C043LL6RTS7).
source=engine:app google_trace_id=none logger=apps.user_management.migrations.0025_auto_20241017_1919 Finished migration. Total organizations processed: 1. Organizations updated: 1. Missing SlackChannels: 0.
Applying user_management.0025_auto_20241017_1919... OK
```
## Future incoming PRs
- Drop `Organization.general_log_channel_id` column
- Migrate `ChannelFilter.slack_channel_id` and
`ResolutionNoteSlackMessage.slack_channel_id` to use foreign key
relationships
## Checklist
- [x] Unit, integration, and e2e (if applicable) tests updated
- [x] Documentation added (or `pr:no public docs` PR label added if not
required)
- [x] Added the relevant release notes label (see labels prefixed w/
`release:`). These labels dictate how your PR will
show up in the autogenerated release notes.
2024-11-01 06:41:38 +01:00
|
|
|
slack_team_identity = make_slack_team_identity()
|
|
|
|
|
slack_channel = make_slack_channel(slack_team_identity)
|
|
|
|
|
organization = make_organization(slack_team_identity=slack_team_identity, default_slack_channel=slack_channel)
|
|
|
|
|
user = make_user_for_organization(organization)
|
|
|
|
|
|
|
|
|
|
assert organization.default_slack_channel_slack_id is not None
|
2023-09-07 09:42:30 +01:00
|
|
|
|
|
|
|
|
# create & delete user with Slack connected
|
|
|
|
|
deleted_user, _ = make_user_with_slack_user_identity(slack_team_identity, organization)
|
|
|
|
|
User.objects.filter(pk=deleted_user.pk).delete()
|
|
|
|
|
|
|
|
|
|
# unpopulate Slack user identities
|
|
|
|
|
unpopulate_slack_user_identities(organization.pk, force=True)
|
|
|
|
|
user.refresh_from_db()
|
|
|
|
|
deleted_user.refresh_from_db()
|
|
|
|
|
organization.refresh_from_db()
|
|
|
|
|
|
|
|
|
|
# check that references to Slack user identities are removed
|
|
|
|
|
assert user.slack_user_identity is None
|
|
|
|
|
assert deleted_user.slack_user_identity is None
|
|
|
|
|
|
|
|
|
|
# check that Slack specific info is reset for organization
|
|
|
|
|
assert organization.slack_team_identity is None
|
feat: convert `organization.general_log_channel_id` to `organization.default_slack_channel` (#5191)
# What this PR does
Related to https://github.com/grafana/oncall-private/issues/2947
Right now `general_log_channel_id` is just a string value representing
the Slack Channel ID (ex. `C043HQ70QMB`). This PR migrates this instead
to be a foreign key relationship on the `slack_slackchannel` table and
updates all references to `general_log_channel_id`.
Tested migrations locally:
```bash
Operations to perform:
Apply all migrations: [redacted secret grafana-admin-creds:admin-user], alerts, auth, auth_token, base, contenttypes, email, exotel, fcm_django, google, heartbeat, labels, mobile_app, oss_installation, phone_notifications, schedules, sessions, slack, social_django, telegram, twilioapp, user_management, webhooks, zvonok
Running migrations:
Applying user_management.0024_organization_general_log_slack_channel... OK
source=engine:app google_trace_id=none logger=apps.user_management.migrations.0025_auto_20241017_1919 Starting migration to populate general_log_slack_channel field.
source=engine:app google_trace_id=none logger=apps.user_management.migrations.0025_auto_20241017_1919 Total organizations to process: 1
source=engine:app google_trace_id=none logger=apps.user_management.migrations.0025_auto_20241017_1919 Organization 1 updated with SlackChannel 2 (slack_id: C043LL6RTS7).
source=engine:app google_trace_id=none logger=apps.user_management.migrations.0025_auto_20241017_1919 Finished migration. Total organizations processed: 1. Organizations updated: 1. Missing SlackChannels: 0.
Applying user_management.0025_auto_20241017_1919... OK
```
## Future incoming PRs
- Drop `Organization.general_log_channel_id` column
- Migrate `ChannelFilter.slack_channel_id` and
`ResolutionNoteSlackMessage.slack_channel_id` to use foreign key
relationships
## Checklist
- [x] Unit, integration, and e2e (if applicable) tests updated
- [x] Documentation added (or `pr:no public docs` PR label added if not
required)
- [x] Added the relevant release notes label (see labels prefixed w/
`release:`). These labels dictate how your PR will
show up in the autogenerated release notes.
2024-11-01 06:41:38 +01:00
|
|
|
assert organization.default_slack_channel_slack_id is None
|
2024-11-04 13:34:06 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.django_db
|
|
|
|
|
def test_delete_slack_channel_and_cascade_deletes(
|
|
|
|
|
make_slack_team_identity,
|
|
|
|
|
make_slack_channel,
|
|
|
|
|
make_organization,
|
|
|
|
|
make_alert_receive_channel,
|
|
|
|
|
make_channel_filter,
|
2024-11-04 15:49:22 -05:00
|
|
|
make_schedule,
|
2024-11-04 13:34:06 -05:00
|
|
|
):
|
|
|
|
|
slack_team_identity = make_slack_team_identity()
|
|
|
|
|
slack_channel = make_slack_channel(slack_team_identity)
|
|
|
|
|
organization = make_organization(slack_team_identity=slack_team_identity, default_slack_channel=slack_channel)
|
|
|
|
|
|
|
|
|
|
alert_receive_channel = make_alert_receive_channel(organization)
|
|
|
|
|
channel_filter = make_channel_filter(alert_receive_channel, slack_channel=slack_channel)
|
2024-11-04 15:49:22 -05:00
|
|
|
schedule = make_schedule(organization, schedule_class=OnCallScheduleWeb, slack_channel=slack_channel)
|
2024-11-04 13:34:06 -05:00
|
|
|
|
|
|
|
|
assert channel_filter.slack_channel == slack_channel
|
2024-11-04 15:49:22 -05:00
|
|
|
assert schedule.slack_channel == slack_channel
|
2024-11-04 13:34:06 -05:00
|
|
|
|
|
|
|
|
slack_channel.delete()
|
|
|
|
|
channel_filter.refresh_from_db()
|
2024-11-04 15:49:22 -05:00
|
|
|
schedule.refresh_from_db()
|
2024-11-04 13:34:06 -05:00
|
|
|
|
|
|
|
|
assert channel_filter.slack_channel is None
|
2024-11-04 15:49:22 -05:00
|
|
|
assert schedule.slack_channel is None
|