Add MERGED directory with slack_poster.py and requirements
This commit is contained in:
parent
7aaa812df5
commit
f3beff6dba
69
MERGED/README.md
Normal file
69
MERGED/README.md
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
# Slack Message Poster CLI
|
||||||
|
|
||||||
|
A fast and simple command-line tool for posting messages to Slack channels.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
1. Install dependencies:
|
||||||
|
```bash
|
||||||
|
pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Command Line Arguments
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python slack_poster.py --token <SLACK_TOKEN> --channel <CHANNEL_ID> --message "<MESSAGE>"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Interactive Mode
|
||||||
|
|
||||||
|
If any parameter is missing, the tool will prompt you interactively:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python slack_poster.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Full command line
|
||||||
|
python slack_poster.py -t xoxb-1234567890-1234567890-abcdefghijklmnopqrstuvwx -c C04ABC123 -m "Hello World!"
|
||||||
|
|
||||||
|
# Interactive mode
|
||||||
|
python slack_poster.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## Parameters
|
||||||
|
|
||||||
|
- `--token` or `-t`: Slack Bot/User OAuth token (e.g., xoxb-...)
|
||||||
|
- `--channel` or `-c`: Slack channel ID (e.g., C04ABC123)
|
||||||
|
- `--message` or `-m`: Message text to post
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
The tool handles various error scenarios:
|
||||||
|
- Invalid token
|
||||||
|
- Channel not found
|
||||||
|
- Bot not in channel
|
||||||
|
- Rate limiting
|
||||||
|
- Network issues
|
||||||
|
- Empty messages
|
||||||
|
|
||||||
|
## Getting Slack Credentials
|
||||||
|
|
||||||
|
1. Go to https://api.slack.com/apps
|
||||||
|
2. Create a new app or select existing one
|
||||||
|
3. Go to "OAuth & Permissions"
|
||||||
|
4. Add the `chat:write` scope
|
||||||
|
5. Install the app to your workspace
|
||||||
|
6. Copy the Bot User OAuth Token (starts with `xoxb-`)
|
||||||
|
|
||||||
|
## Channel ID
|
||||||
|
|
||||||
|
To get a channel ID:
|
||||||
|
1. Open Slack in your browser
|
||||||
|
2. Navigate to the channel
|
||||||
|
3. The channel ID is in the URL: `https://app.slack.com/client/T1234567890/C04ABC123`
|
||||||
|
4. Use the part after `/C` (e.g., `C04ABC123`)
|
||||||
2
MERGED/requirements.txt
Normal file
2
MERGED/requirements.txt
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
slack_sdk>=3.21.0
|
||||||
|
requests>=2.28.0
|
||||||
218
MERGED/slack_poster.py
Normal file
218
MERGED/slack_poster.py
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Slack Message Poster CLI Tool
|
||||||
|
|
||||||
|
A command-line tool that posts messages to Slack channels using the Slack Web API.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import sys
|
||||||
|
from datetime import datetime
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
try:
|
||||||
|
from slack_sdk import WebClient
|
||||||
|
from slack_sdk.errors import SlackApiError, SlackClientError
|
||||||
|
except ImportError:
|
||||||
|
print("Error: slack_sdk not installed. Run: pip install slack_sdk")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
class SlackPoster:
|
||||||
|
"""Main class for posting messages to Slack."""
|
||||||
|
|
||||||
|
def __init__(self, token: str):
|
||||||
|
"""Initialize the Slack client with the provided token."""
|
||||||
|
self.client = WebClient(token=token)
|
||||||
|
|
||||||
|
def post_message(self, channel: str, message: str) -> dict:
|
||||||
|
"""
|
||||||
|
Post a message to the specified Slack channel.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
channel: Slack channel ID (e.g., C04ABC123)
|
||||||
|
message: Message text to post
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Response from Slack API
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
SlackApiError: If the API call fails
|
||||||
|
SlackClientError: If there's a client error
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
response = self.client.chat_postMessage(
|
||||||
|
channel=channel,
|
||||||
|
text=message
|
||||||
|
)
|
||||||
|
return response
|
||||||
|
except SlackApiError as e:
|
||||||
|
raise SlackApiError(f"Slack API Error: {e.response['error']}")
|
||||||
|
except SlackClientError as e:
|
||||||
|
raise SlackClientError(f"Slack Client Error: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
def get_user_input(prompt: str, required: bool = True) -> str:
|
||||||
|
"""
|
||||||
|
Get user input with optional validation.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
prompt: The prompt to display to the user
|
||||||
|
required: Whether the input is required
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: User input
|
||||||
|
"""
|
||||||
|
while True:
|
||||||
|
value = input(prompt).strip()
|
||||||
|
if value or not required:
|
||||||
|
return value
|
||||||
|
print("This field is required. Please try again.")
|
||||||
|
|
||||||
|
|
||||||
|
def validate_token(token: str) -> bool:
|
||||||
|
"""
|
||||||
|
Basic validation for Slack token format.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
token: The token to validate
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if token format looks valid
|
||||||
|
"""
|
||||||
|
if not token:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Basic format validation for Slack tokens
|
||||||
|
valid_prefixes = ['xoxb-', 'xoxp-', 'xoxa-', 'xoxr-']
|
||||||
|
return any(token.startswith(prefix) for prefix in valid_prefixes)
|
||||||
|
|
||||||
|
|
||||||
|
def validate_channel(channel: str) -> bool:
|
||||||
|
"""
|
||||||
|
Basic validation for Slack channel ID format.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
channel: The channel ID to validate
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if channel format looks valid
|
||||||
|
"""
|
||||||
|
if not channel:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Slack channel IDs typically start with C, D, or G
|
||||||
|
return channel.startswith(('C', 'D', 'G')) and len(channel) > 1
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Main function to handle CLI arguments and execute the message posting."""
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="Post a message to a Slack channel",
|
||||||
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||||
|
epilog="""
|
||||||
|
Examples:
|
||||||
|
python slack_poster.py -t xoxb-1234567890-1234567890-abcdefghijklmnopqrstuvwx -c C04ABC123 -m "Hello World!"
|
||||||
|
python slack_poster.py --token xoxb-1234567890-1234567890-abcdefghijklmnopqrstuvwx --channel C04ABC123 --message "Hello World!"
|
||||||
|
python slack_poster.py # Interactive mode - will prompt for missing parameters
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
'--token', '-t',
|
||||||
|
type=str,
|
||||||
|
help='Slack Bot/User OAuth token (e.g., xoxb-...)'
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
'--channel', '-c',
|
||||||
|
type=str,
|
||||||
|
help='Slack channel ID (e.g., C04ABC123)'
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
'--message', '-m',
|
||||||
|
type=str,
|
||||||
|
help='Message text to post'
|
||||||
|
)
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
# Get token
|
||||||
|
token = args.token
|
||||||
|
if not token:
|
||||||
|
print("Slack Token not provided. Please enter it interactively:")
|
||||||
|
token = get_user_input("Enter your Slack token: ")
|
||||||
|
|
||||||
|
# Validate token format
|
||||||
|
if not validate_token(token):
|
||||||
|
print("Error: Invalid token format. Slack tokens typically start with 'xoxb-', 'xoxp-', 'xoxa-', or 'xoxr-'")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Get channel
|
||||||
|
channel = args.channel
|
||||||
|
if not channel:
|
||||||
|
print("Channel ID not provided. Please enter it interactively:")
|
||||||
|
channel = get_user_input("Enter Slack channel ID (e.g., C04ABC123): ")
|
||||||
|
|
||||||
|
# Validate channel format
|
||||||
|
if not validate_channel(channel):
|
||||||
|
print("Error: Invalid channel format. Channel IDs typically start with 'C', 'D', or 'G'")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Get message
|
||||||
|
message = args.message
|
||||||
|
if not message:
|
||||||
|
print("Message not provided. Please enter it interactively:")
|
||||||
|
message = get_user_input("Enter message text: ")
|
||||||
|
|
||||||
|
# Validate message
|
||||||
|
if not message.strip():
|
||||||
|
print("Error: Message cannot be empty")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Initialize Slack poster and send message
|
||||||
|
try:
|
||||||
|
poster = SlackPoster(token)
|
||||||
|
response = poster.post_message(channel, message)
|
||||||
|
|
||||||
|
# Extract timestamp from response
|
||||||
|
timestamp = response.get('ts', 'unknown')
|
||||||
|
channel_name = response.get('channel', channel)
|
||||||
|
|
||||||
|
# Convert timestamp to readable format
|
||||||
|
try:
|
||||||
|
dt = datetime.fromtimestamp(float(timestamp))
|
||||||
|
formatted_time = dt.strftime('%Y-%m-%d %H:%M:%S UTC')
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
formatted_time = timestamp
|
||||||
|
|
||||||
|
print(f"✅ Success! Message posted to channel {channel_name}")
|
||||||
|
print(f"📅 Timestamp: {formatted_time}")
|
||||||
|
print(f"💬 Message: {message}")
|
||||||
|
|
||||||
|
except SlackApiError as e:
|
||||||
|
error_msg = str(e)
|
||||||
|
if "invalid_auth" in error_msg.lower():
|
||||||
|
print("❌ Error: Invalid token. Please check your Slack token.")
|
||||||
|
elif "channel_not_found" in error_msg.lower():
|
||||||
|
print(f"❌ Error: Channel '{channel}' not found. Please check the channel ID.")
|
||||||
|
elif "not_in_channel" in error_msg.lower():
|
||||||
|
print(f"❌ Error: Bot is not a member of channel '{channel}'. Please add the bot to the channel.")
|
||||||
|
elif "rate_limited" in error_msg.lower():
|
||||||
|
print("❌ Error: Rate limited. Please wait before trying again.")
|
||||||
|
else:
|
||||||
|
print(f"❌ Slack API Error: {error_msg}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
except SlackClientError as e:
|
||||||
|
print(f"❌ Slack Client Error: {e}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Unexpected error: {e}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Loading…
Reference in New Issue
Block a user