Skip to content
This repository was archived by the owner on Jan 16, 2026. It is now read-only.
Open
Show file tree
Hide file tree
Changes from 2 commits
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
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
- An [OAuth token](https://api.slack.com/docs/oauth) from a [Slack app](https://api.slack.com/slack-apps) on your workspace that has the following permission scopes:
- `channels:history`
- `channels:read`
- `channels:write`
- `chat:write:bot`
- `chat:write:user`
- `channels:manage`
- `channels:join`
- `chat:write`
- `chat:write.customize`
- `chat:write.public`

## Example Usages

Expand Down
82 changes: 59 additions & 23 deletions slack_autoarchive.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def slack_api_http(
""" Helper function to query the slack api and handle errors and rate limit. """
# pylint: disable=no-member
uri = 'https://slack.com/api/' + api_endpoint
payload['token'] = self.settings.get('slack_token')
headers = {'Authorization': 'Bearer ' + self.settings.get('slack_token')}
try:
# Force request to take at least 1 second. Slack docs state:
# > In general we allow applications that integrate with Slack to send
Expand All @@ -78,16 +78,28 @@ def slack_api_http(
time.sleep(retry_delay)

if method == 'POST':
response = requests.post(uri, data=payload)
response = requests.post(uri, json=payload, headers=headers)
else:
response = requests.get(uri, params=payload)
response = requests.get(uri, params=payload, headers=headers)

if response.status_code == requests.codes.ok and 'error' in response.json(
) and response.json()['error'] == 'not_authed':
self.logger.error(
'Need to setup auth. eg, SLACK_TOKEN=<secret token> python slack-autoarchive.py'
)
sys.exit(1)
):
if response.json()['error'] == 'not_authed':
self.logger.error(
'Need to setup auth. eg, SLACK_TOKEN=<secret token> python slack-autoarchive.py'
)
sys.exit(1)
elif response.json()['error'] == 'not_in_channel':
self.logger.error(
'Need to add bot to channel described by ' + str(payload)
)
self.join_channel(payload['channel'])
return response.json()
Comment thread
shamarashid marked this conversation as resolved.
Outdated
else:
self.logger.error(
response.json()['error']
)
sys.exit(1)
elif response.status_code == requests.codes.ok and response.json(
)['ok']:
return response.json()
Expand All @@ -100,20 +112,44 @@ def slack_api_http(
raise Exception(error_msg)
return None

def join_channel(self, channel_id):
api_endpoint = 'conversations.join'
info_payload = {'channel': channel_id}
channel_info = self.slack_api_http(api_endpoint=api_endpoint,
payload=info_payload,
method='POST')
self.logger.info('Joined channel ' + channel_id)

def get_all_channels(self):
""" Get a list of all non-archived channels from slack channels.list. """
payload = {'exclude_archived': 1}
api_endpoint = 'channels.list'
channels = self.slack_api_http(api_endpoint=api_endpoint,
payload=payload)['channels']
payload = {'exclude_archived':1, 'limit':100}
api_endpoint = 'conversations.list'

flag_first_page = True
flag_last_page = False
next_cursor = ''
all_channels = []
for channel in channels:
all_channels.append({
'id': channel['id'],
'name': channel['name'],
'created': channel['created'],
'num_members': channel['num_members']
})
while not flag_last_page:
if not flag_first_page:
payload['cursor'] = next_cursor
api_response = self.slack_api_http(api_endpoint=api_endpoint, payload=payload)
if flag_first_page:
flag_first_page = False

channels = api_response['channels']
self.logger.info('%s channel(s) retrieved' % str(len(channels)))
for channel in channels:
all_channels.append({
'id': channel['id'],
'name': channel['name'],
'created': channel['created'],
'num_members': channel['num_members']
})

next_cursor = api_response['response_metadata'].get('next_cursor')
if not next_cursor:
flag_last_page = True

return all_channels

def get_last_message_timestamp(self, channel_history, too_old_datetime):
Expand Down Expand Up @@ -144,7 +180,7 @@ def is_channel_disused(self, channel, too_old_datetime):
""" Return True or False depending on if a channel is "active" or not. """
num_members = channel['num_members']
payload = {'inclusive': 0, 'oldest': 0, 'count': 50}
api_endpoint = 'channels.history'
api_endpoint = 'conversations.history'

payload['channel'] = channel['id']
channel_history = self.slack_api_http(api_endpoint=api_endpoint,
Expand All @@ -165,7 +201,7 @@ def is_channel_whitelisted(self, channel, white_listed_channels):
# self.settings.get('skip_channel_str')
# if the channel purpose contains the string self.settings.get('skip_channel_str'), we'll skip it.
info_payload = {'channel': channel['id']}
channel_info = self.slack_api_http(api_endpoint='channels.info',
channel_info = self.slack_api_http(api_endpoint='conversations.info',
payload=info_payload,
method='GET')
channel_purpose = channel_info['channel']['purpose']['value']
Expand Down Expand Up @@ -197,15 +233,15 @@ def send_channel_message(self, channel_id, message):

def archive_channel(self, channel, alert):
""" Archive a channel, and send alert to slack admins. """
api_endpoint = 'channels.archive'
api_endpoint = 'conversations.archive'
stdout_message = 'Archiving channel... %s' % channel['name']
self.logger.info(stdout_message)

if not self.settings.get('dry_run'):
channel_message = alert.format(self.settings.get('days_inactive'))
self.send_channel_message(channel['id'], channel_message)
payload = {'channel': channel['id']}
self.slack_api_http(api_endpoint=api_endpoint, payload=payload)
self.slack_api_http(api_endpoint=api_endpoint, payload=payload, method='POST')
self.logger.info(stdout_message)

def send_admin_report(self, channels):
Expand Down