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