Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #1310 Add admin.conversations.bulk{Archive|Delete|Move} API method support #1311

Merged
merged 3 commits into from
Dec 9, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 32 additions & 23 deletions .github/maintainers_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,30 +54,35 @@ work for this project again in the future, `cd` into this project directory and
run `source env_3.9.6/bin/activate` again.

The last step is to install this project's dependencies and run all unit tests; to do so, you can run

```bash
$ ./scripts/run_validation.sh
```

Also check out [how
we configure GitHub Actions to install dependencies for this project for use in
our continuous integration](https://github.com/slackapi/python-slack-sdk/blob/v3.17.0/.github/workflows/ci-build.yml#L28-L32).

## Tasks

### Testing (Unit Tests)

When you make changes to this SDK, please write unit tests verifying if the changes work as you expected. You can easily run all the tests and formatting/linter with the below scripts.

Run all the unit tests, code formatter, and code analyzer:

```bash
$ ./scripts/run_validation.sh
```

Run all the unit tests (no formatter nor code analyzer):

```bash
$ ./scripts/run_unit_tests.sh
```

Run a specific unit test:

```bash
$ ./scripts/run_unit_tests.sh tests/web/test_web_client.py
```
Expand All @@ -89,11 +94,13 @@ You can rely on GitHub Actions builds for running the tests on a variety of Pyth
This project also has integration tests that verify the SDK works with the Slack API platform. As a preparation, you need to set [the required env variables](https://github.com/slackapi/python-slack-sdk/blob/main/integration_tests/env_variable_names.py) properly. You don't need to setup all of them if you just want to run some of the tests. Commonly, `SLACK_SDK_TEST_BOT_TOKEN` and `SLACK_SDK_TEST_USER_TOKEN` are used for running `WebClient` tests.

Run all integration tests:

```bash
$ ./scripts/run_integration_tests.sh
```

Run a specific integration test:

```bash
$ ./scripts/run_integration_tests.sh integration_tests/web/test_async_web_client.py
```
Expand All @@ -104,12 +111,14 @@ The documentation is generated from the source and templates in the `docs-src` d
gets committed to the repo in `docs` and also published to a GitHub Pages website.

You can generate and preview the **SDK document pages** by running

```bash
$ ./scripts/docs.sh
$ open docs/index.html
```

Similarly you can generate and preview the **API documents for `slack_sdk` package modules** by running

```bash
$ ./scripts/generate_api_docs.sh
```
Expand All @@ -118,46 +127,46 @@ $ ./scripts/generate_api_docs.sh

1. Create the commit for the release:

- Bump the version number in adherence to [Semantic Versioning](http://semver.org/) in `slack_sdk/version.py`.
- Build the docs with `./scripts/docs.sh` and then `./scripts/generate_api_docs.sh`.
- Create a branch for the release with `git checkout -b v2.5.0`
- Make a commit that includes the new version number: `git commit -m 'version 2.5.0'`.
- Open a PR and merge after receiving at least one approval from other maintainers.
- Create a git tag for the release. For example `git tag v2.5.0`.
- Push the tag up to github with `git push origin --tags`
- Bump the version number in adherence to [Semantic Versioning](http://semver.org/) in `slack_sdk/version.py`.
- Build the docs with `./scripts/docs.sh` and then `./scripts/generate_api_docs.sh`.
- Create a branch for the release with `git checkout -b v2.5.0`
- Make a commit that includes the new version number: `git commit -m 'version 2.5.0'`.
- Open a PR and merge after receiving at least one approval from other maintainers.
- Create a git tag for the release. For example `git tag v2.5.0`.
- Push the tag up to github with `git push origin --tags`

2. Distribute the release

- Use the latest stable Python runtime
- `python -m venv env`
- `python setup.py upload`
- Create a GitHub Release. You will select the commit with updated version number (e.g. `version 2.5.0`) to associate with the tag, and name the tag after this version (e.g. `v2.5.0`). This will also serve as a Changelog for the project. Add a description of changes to the Release. Mention Issue and PR #'s and @-mention contributors.
- Use the latest stable Python runtime
- `python -m venv env`
- `python setup.py upload`
- Create a GitHub Release. You will select the commit with updated version number (e.g. `version 2.5.0`) to associate with the tag, and name the tag after this version (e.g. `v2.5.0`). This will also serve as a Changelog for the project. Add a description of changes to the Release. Mention Issue and PR #'s and @-mention contributors.

```markdown
Refer to [v{version} milestone](https://github.com/slackapi/python-slack-sdk/milestone/{TODO}?closed=1) to know the complete list of the issues resolved by this release.
```markdown
Refer to [v{version} milestone](https://github.com/slackapi/python-slack-sdk/milestone/{TODO}?closed=1) to know the complete list of the issues resolved by this release.

**Updates**
**Updates**

1. [WebClient] #111 Make an awesome change - Thanks @SlackHQ
1. [RTMClient] #222 Make an awesome change - Thanks @SlackAPI
1. [WebClient] #111 Make an awesome change - Thanks @SlackHQ
2. [RTMClient] #222 Make an awesome change - Thanks @SlackAPI

**All Changes**
**All Changes**

https://github.com/slackapi/python-slack-sdk/compare/{the previous release version tag}...{the release version tag}
```
https://github.com/slackapi/python-slack-sdk/compare/{the previous release version tag}...{the release version tag}
```

3. (Slack Internal) Communicate the release internally

- Include a link to the GitHub release
- Include a link to the GitHub release

4. Make announcements

- #slack-api in dev4slack.slack.com
- #lang-python in community.slack.com
- #slack-api in dev4slack.slack.com
- #lang-python in community.slack.com

5. (Slack Internal) Tweet by @SlackAPI

- Not necessary for patch updates, might be needed for minor updates, definitely needed for major updates. Include a link to the GitHub release
- Not necessary for patch updates, might be needed for minor updates, definitely needed for major updates. Include a link to the GitHub release

## Workflow

Expand Down
1 change: 1 addition & 0 deletions integration_tests/env_variable_names.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
SLACK_SDK_TEST_GRID_IDP_USERGROUP_ID = "SLACK_SDK_TEST_GRID_IDP_USERGROUP_ID"
SLACK_SDK_TEST_GRID_IDP_USERGROUP_ID_2 = "SLACK_SDK_TEST_GRID_IDP_USERGROUP_ID_2"
SLACK_SDK_TEST_GRID_TEAM_ID = "SLACK_SDK_TEST_GRID_TEAM_ID"
SLACK_SDK_TEST_GRID_TEAM_ID_2 = "SLACK_SDK_TEST_GRID_TEAM_ID_2"
SLACK_SDK_TEST_GRID_USER_ID = "SLACK_SDK_TEST_GRID_USER_ID"
# The following user must be a full member, who is not a primary owner
SLACK_SDK_TEST_GRID_USER_ID_ADMIN_AUTH = "SLACK_SDK_TEST_GRID_USER_ID_ADMIN_AUTH"
Expand Down
102 changes: 102 additions & 0 deletions integration_tests/web/test_admin_conversations_bulk.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import asyncio
import logging
import os
import time
import unittest

from integration_tests.env_variable_names import (
SLACK_SDK_TEST_GRID_ORG_ADMIN_USER_TOKEN,
SLACK_SDK_TEST_GRID_IDP_USERGROUP_ID,
SLACK_SDK_TEST_GRID_TEAM_ID_2,
SLACK_SDK_TEST_GRID_TEAM_ID,
SLACK_SDK_TEST_GRID_USER_ID,
)
from integration_tests.helpers import async_test
from slack_sdk.web import WebClient
from slack_sdk.web.async_client import AsyncWebClient


class TestWebClient(unittest.TestCase):
"""Runs integration tests with real Slack API"""

# TODO: admin_conversations_disconnectShared - not_allowed_token_type
# TODO: admin_conversations_ekm_listOriginalConnectedChannelInfo - enable the feature

def setUp(self):
self.logger = logging.getLogger(__name__)
self.org_admin_token = os.environ[SLACK_SDK_TEST_GRID_ORG_ADMIN_USER_TOKEN]
self.sync_client: WebClient = WebClient(token=self.org_admin_token)
self.async_client: AsyncWebClient = AsyncWebClient(token=self.org_admin_token)

self.team_id = os.environ[SLACK_SDK_TEST_GRID_TEAM_ID]
self.team_id_2 = os.environ[SLACK_SDK_TEST_GRID_TEAM_ID_2]
self.idp_group_id = os.environ[SLACK_SDK_TEST_GRID_IDP_USERGROUP_ID]
self.user_id = os.environ[SLACK_SDK_TEST_GRID_USER_ID]
self.channel_name = f"test-channel-{int(round(time.time() * 1000))}"
self.channel_rename = f"test-channel-renamed-{int(round(time.time() * 1000))}"

def tearDown(self):
pass

def test_sync(self):
client = self.sync_client

conv_creation = client.admin_conversations_create(
is_private=False,
name=self.channel_name,
team_id=self.team_id,
)
self.assertIsNotNone(conv_creation)
created_channel_id = conv_creation.data["channel_id"]

self.assertIsNotNone(
client.admin_conversations_bulkMove(
channel_ids=[created_channel_id],
target_team_id=self.team_id_2,
)
)

self.assertIsNotNone(
client.admin_conversations_bulkArchive(
channel_ids=[created_channel_id],
)
)

self.assertIsNotNone(
client.admin_conversations_bulkDelete(
channel_ids=[created_channel_id],
)
)

@async_test
async def test_async(self):
# await asyncio.sleep(seconds) are included to avoid rate limiting errors

client = self.async_client

conv_creation = await client.admin_conversations_create(
is_private=False,
name=self.channel_name,
team_id=self.team_id,
)
self.assertIsNotNone(conv_creation)
created_channel_id = conv_creation.data["channel_id"]

self.assertIsNotNone(
await client.admin_conversations_bulkMove(
channel_ids=[created_channel_id],
target_team_id=self.team_id_2,
)
)

self.assertIsNotNone(
await client.admin_conversations_bulkArchive(
channel_ids=[created_channel_id],
)
)

self.assertIsNotNone(
await client.admin_conversations_bulkDelete(
channel_ids=[created_channel_id],
)
)
42 changes: 42 additions & 0 deletions slack_sdk/web/async_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -803,6 +803,48 @@ async def admin_conversations_setCustomRetention(
kwargs.update({"channel_id": channel_id, "duration_days": duration_days})
return await self.api_call("admin.conversations.setCustomRetention", params=kwargs)

async def admin_conversations_bulkArchive(
self,
*,
channel_ids: Union[Sequence[str], str],
**kwargs,
) -> AsyncSlackResponse:
"""Archive public or private channels in bulk.
https://api.slack.com/methods/admin.conversations.bulkArchive
"""
kwargs.update({"channel_ids": ",".join(channel_ids) if isinstance(channel_ids, (list, tuple)) else channel_ids})
return await self.api_call("admin.conversations.bulkArchive", params=kwargs)

async def admin_conversations_bulkDelete(
self,
*,
channel_ids: Union[Sequence[str], str],
**kwargs,
) -> AsyncSlackResponse:
"""Delete public or private channels in bulk.
https://slack.com/api/admin.conversations.bulkDelete
"""
kwargs.update({"channel_ids": ",".join(channel_ids) if isinstance(channel_ids, (list, tuple)) else channel_ids})
return await self.api_call("admin.conversations.bulkDelete", params=kwargs)

async def admin_conversations_bulkMove(
self,
*,
channel_ids: Union[Sequence[str], str],
target_team_id: str,
**kwargs,
) -> AsyncSlackResponse:
"""Move public or private channels in bulk.
https://api.slack.com/methods/admin.conversations.bulkMove
"""
kwargs.update(
{
"target_team_id": target_team_id,
"channel_ids": ",".join(channel_ids) if isinstance(channel_ids, (list, tuple)) else channel_ids,
}
)
return await self.api_call("admin.conversations.bulkMove", params=kwargs)

async def admin_emoji_add(
self,
*,
Expand Down
42 changes: 42 additions & 0 deletions slack_sdk/web/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -794,6 +794,48 @@ def admin_conversations_setCustomRetention(
kwargs.update({"channel_id": channel_id, "duration_days": duration_days})
return self.api_call("admin.conversations.setCustomRetention", params=kwargs)

def admin_conversations_bulkArchive(
self,
*,
channel_ids: Union[Sequence[str], str],
**kwargs,
) -> SlackResponse:
"""Archive public or private channels in bulk.
https://api.slack.com/methods/admin.conversations.bulkArchive
"""
kwargs.update({"channel_ids": ",".join(channel_ids) if isinstance(channel_ids, (list, tuple)) else channel_ids})
return self.api_call("admin.conversations.bulkArchive", params=kwargs)

def admin_conversations_bulkDelete(
self,
*,
channel_ids: Union[Sequence[str], str],
**kwargs,
) -> SlackResponse:
"""Delete public or private channels in bulk.
https://slack.com/api/admin.conversations.bulkDelete
"""
kwargs.update({"channel_ids": ",".join(channel_ids) if isinstance(channel_ids, (list, tuple)) else channel_ids})
return self.api_call("admin.conversations.bulkDelete", params=kwargs)

def admin_conversations_bulkMove(
self,
*,
channel_ids: Union[Sequence[str], str],
target_team_id: str,
**kwargs,
) -> SlackResponse:
"""Move public or private channels in bulk.
https://api.slack.com/methods/admin.conversations.bulkMove
"""
kwargs.update(
{
"target_team_id": target_team_id,
"channel_ids": ",".join(channel_ids) if isinstance(channel_ids, (list, tuple)) else channel_ids,
}
)
return self.api_call("admin.conversations.bulkMove", params=kwargs)

def admin_emoji_add(
self,
*,
Expand Down
42 changes: 42 additions & 0 deletions slack_sdk/web/legacy_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -805,6 +805,48 @@ def admin_conversations_setCustomRetention(
kwargs.update({"channel_id": channel_id, "duration_days": duration_days})
return self.api_call("admin.conversations.setCustomRetention", params=kwargs)

def admin_conversations_bulkArchive(
self,
*,
channel_ids: Union[Sequence[str], str],
**kwargs,
) -> Union[Future, SlackResponse]:
"""Archive public or private channels in bulk.
https://api.slack.com/methods/admin.conversations.bulkArchive
"""
kwargs.update({"channel_ids": ",".join(channel_ids) if isinstance(channel_ids, (list, tuple)) else channel_ids})
return self.api_call("admin.conversations.bulkArchive", params=kwargs)

def admin_conversations_bulkDelete(
self,
*,
channel_ids: Union[Sequence[str], str],
**kwargs,
) -> Union[Future, SlackResponse]:
"""Delete public or private channels in bulk.
https://slack.com/api/admin.conversations.bulkDelete
"""
kwargs.update({"channel_ids": ",".join(channel_ids) if isinstance(channel_ids, (list, tuple)) else channel_ids})
return self.api_call("admin.conversations.bulkDelete", params=kwargs)

def admin_conversations_bulkMove(
self,
*,
channel_ids: Union[Sequence[str], str],
target_team_id: str,
**kwargs,
) -> Union[Future, SlackResponse]:
"""Move public or private channels in bulk.
https://api.slack.com/methods/admin.conversations.bulkMove
"""
kwargs.update(
{
"target_team_id": target_team_id,
"channel_ids": ",".join(channel_ids) if isinstance(channel_ids, (list, tuple)) else channel_ids,
}
)
return self.api_call("admin.conversations.bulkMove", params=kwargs)

def admin_emoji_add(
self,
*,
Expand Down
Loading