From f3beff6dbac957c4864d1ba56fd6cb6ffb31b0bb Mon Sep 17 00:00:00 2001 From: reethu2703 Date: Sat, 4 Oct 2025 21:59:20 +0530 Subject: [PATCH] Add MERGED directory with slack_poster.py and requirements --- MERGED/README.md | 69 +++++++++++++ MERGED/requirements.txt | 2 + MERGED/slack_poster.py | 218 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 289 insertions(+) create mode 100644 MERGED/README.md create mode 100644 MERGED/requirements.txt create mode 100644 MERGED/slack_poster.py diff --git a/MERGED/README.md b/MERGED/README.md new file mode 100644 index 0000000..3ac8aeb --- /dev/null +++ b/MERGED/README.md @@ -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 --channel --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`) diff --git a/MERGED/requirements.txt b/MERGED/requirements.txt new file mode 100644 index 0000000..2b0f9eb --- /dev/null +++ b/MERGED/requirements.txt @@ -0,0 +1,2 @@ +slack_sdk>=3.21.0 +requests>=2.28.0 diff --git a/MERGED/slack_poster.py b/MERGED/slack_poster.py new file mode 100644 index 0000000..92b5cf0 --- /dev/null +++ b/MERGED/slack_poster.py @@ -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()