import os
import json
import logging
from slack_bolt import App
from slack_bolt.adapter.flask import SlackRequestHandler
from flask import Flask, request, jsonify
from dotenv import load_dotenv
os.environ.pop("SLACK_SIGNING_SECRET", None)
os.environ.pop("SLACK_BOT_TOKEN", None)
load_dotenv() # Reload .env values
# Configure logging
logging.basicConfig(level=logging.INFO)
# Initialize your Flask application and Slack app
app = App(token=os.environ['SLACK_BOT_TOKEN'], signing_secret=os.environ['SLACK_SIGNING_SECRET'])
flask_app = Flask(__name__)
handler = SlackRequestHandler(app)
# List of admin user IDs
ADMIN_USER_IDS = ["user"] # Replace with actual admin user IDs
# Dictionary to store polls with votes
polls = {}
# Function to send a message with buttons for the poll
def send_poll_message(channel_id, question, button1_text, button2_text, poll_id):
button_elements = [
{"type": "button", "text": {"type": "plain_text", "text": button1_text},
"action_id": "button_1_click", "value": poll_id},
{"type": "button", "text": {"type": "plain_text", "text": button2_text},
"action_id": "button_2_click", "value": poll_id}
]
app.client.chat_postMessage(channel=channel_id, text=question, blocks=[
{"type": "section", "text": {"type": "mrkdwn", "text": question}},
{"type": "actions", "elements": button_elements}
])
# Endpoint to receive the slash command to start a poll
@flask_app.route("/send_poll", methods=["POST"])
def send_poll_endpoint():
data = request.form
channel_id = data.get("channel_id")
user_id = data.get("user_id") # Get the user ID of the person who initiated the poll
text = data.get("text").strip().split('|')
if len(text) != 3:
return jsonify({"response_type": "ephemeral", "text": "Correct format: `/send_poll | | `"}), 200
question, button1_text, button2_text = map(str.strip, text)
poll_id = str(len(polls) + 1)
polls[poll_id] = {
"question": question,
"button1_text": button1_text,
"button2_text": button2_text,
"button1_votes": [],
"button2_votes": []
}
send_poll_message(channel_id, question, button1_text, button2_text, poll_id)
# Send poll ID only to admins
if user_id in ADMIN_USER_IDS:
return jsonify({"response_type": "ephemeral", "text": f"Poll initiated! Your poll ID is: {poll_id}"}), 200
return jsonify({"response_type": "ephemeral", "text": "Poll initiated!"}), 200
# Endpoint to receive the slash command for poll results
@flask_app.route("/poll_results", methods=["POST"])
def poll_results_command():
data = request.form
user_id = data.get("user_id") # Get the user ID who initiated the command
text = data.get("text").strip() # Get the poll ID from the command text
# Check if the user is an admin
if user_id not in ADMIN_USER_IDS:
return jsonify({"response_type": "ephemeral", "text": "Sorry, this command is restricted to admins only."}), 200
if not text:
return jsonify({"response_type": "ephemeral", "text": "Please provide a poll ID. Usage: `/poll_results
`"}), 200
poll_id = text
# Check if the poll_id exists
if poll_id not in polls:
return jsonify({"response_type": "ephemeral", "text": "Poll ID not found!"}), 404
poll = polls[poll_id]
# Format voter IDs into @user format
button1_voters = [f"" for user in poll['button1_votes']]
button2_voters = [f"" for user in poll['button2_votes']]
results_message = (
f"*Poll Question:* {poll['question']}\n"
f"*Votes for {poll['button1_text']}:* {len(poll['button1_votes'])}\n"
f"*Voters for {poll['button1_text']}:* {', '.join(button1_voters) if button1_voters else 'No votes yet'}\n"
f"*Votes for {poll['button2_text']}:* {len(poll['button2_votes'])}\n"
f"*Voters for {poll['button2_text']}:* {', '.join(button2_voters) if button2_voters else 'No votes yet'}\n"
)
return jsonify({"response_type": "ephemeral", "text": results_message}), 200
# Endpoint to receive interactions from Slack
@flask_app.route("/slack/actions", methods=["POST"])
def slack_actions():
raw_body = request.get_data(as_text=True)
logging.info("Received raw request body: %s", raw_body)
content_type = request.headers.get('Content-Type')
logging.info("Received interaction with Content-Type: %s", content_type)
if content_type == 'application/x-www-form-urlencoded':
payload = request.form.get('payload')
if payload:
payload_data = json.loads(payload)
logging.info("Processing interaction: %s", payload_data)
return handler.handle(request)
elif content_type == 'application/json':
return handler.handle(request)
return jsonify({"error": "Unsupported Media Type"}), 415
# Handle button clicks for option 1
@app.action("button_1_click")
def handle_button_click_1(ack, body):
ack()
logging.info("Button 1 clicked: %s", body)
poll_id = body['actions'][0]['value']
user_id = body['user']['id']
# Check if the user has already voted
if user_id in polls[poll_id]["button1_votes"] or user_id in polls[poll_id]["button2_votes"]:
app.client.chat_postMessage(channel=user_id, text="You have already voted in this poll!")
else:
# Append user vote if not already voted
polls[poll_id]["button1_votes"].append(user_id)
app.client.chat_postMessage(channel=user_id, text="Thank you for voting for " + polls[poll_id]["button1_text"] + "!")
# Handle button clicks for option 2
@app.action("button_2_click")
def handle_button_click_2(ack, body):
ack()
logging.info("Button 2 clicked: %s", body)
poll_id = body['actions'][0]['value']
user_id = body['user']['id']
# Check if the user has already voted
if user_id in polls[poll_id]["button1_votes"] or user_id in polls[poll_id]["button2_votes"]:
app.client.chat_postMessage(channel=user_id, text="You have already voted in this poll!")
else:
# Append user vote if not already voted
polls[poll_id]["button2_votes"].append(user_id)
app.client.chat_postMessage(channel=user_id, text="Thank you for voting for " + polls[poll_id]["button2_text"] + "!")
# Starting the Flask server
if __name__ == "__main__":
flask_app.run(port=3000)
Проблема 404 при нажатии кнопок после отправки сообщения с помощью двух кнопок в этом приложении. в ngrok он работает правильно, без ошибок, но в Gunicorn от vultr он возвращает ошибку 404.
этот код, который я поставил, работает правильно в моих тестах с ngrok, но в тот момент, когда я перемещаю его в vultr и запустите его с помощью Gunicorn, кнопки возвращают ошибки (404). Я пробовал пройти через это с помощью чатгпт, но его решения принесли мне только разные коды ошибок, такие как 415 или keyError 1. Я не могу понять, как это будет работать в ngrok, а не на моем реальном сервере. ? Я новичок в этом, и это моя первая попытка развернуть что-то на сервере, но для пояснения я сделал следующее: запустил сервер vultr, установил nginx и запустил certbot в домене, заменил маршруты конфигурации слабых приложений для интерактивности и слэш-команды с адреса ngrok на адрес моего домена (также пробовал прямой IP-адрес от vultr, но тоже безуспешно) и запуск приложения с помощью Gunicorn. очень надеюсь, что кто-нибудь поможет мне пролить свет на то, что я делаю неправильно. большое спасибо!
[code]import os import json import logging from slack_bolt import App from slack_bolt.adapter.flask import SlackRequestHandler from flask import Flask, request, jsonify from dotenv import load_dotenv
# Endpoint to receive the slash command to start a poll @flask_app.route("/send_poll", methods=["POST"]) def send_poll_endpoint(): data = request.form channel_id = data.get("channel_id") user_id = data.get("user_id") # Get the user ID of the person who initiated the poll text = data.get("text").strip().split('|')
# Send poll ID only to admins if user_id in ADMIN_USER_IDS: return jsonify({"response_type": "ephemeral", "text": f"Poll initiated! Your poll ID is: {poll_id}"}), 200
# Endpoint to receive the slash command for poll results @flask_app.route("/poll_results", methods=["POST"]) def poll_results_command(): data = request.form user_id = data.get("user_id") # Get the user ID who initiated the command text = data.get("text").strip() # Get the poll ID from the command text
# Check if the user is an admin if user_id not in ADMIN_USER_IDS: return jsonify({"response_type": "ephemeral", "text": "Sorry, this command is restricted to admins only."}), 200
if not text: return jsonify({"response_type": "ephemeral", "text": "Please provide a poll ID. Usage: `/poll_results `"}), 200
poll_id = text
# Check if the poll_id exists if poll_id not in polls: return jsonify({"response_type": "ephemeral", "text": "Poll ID not found!"}), 404
poll = polls[poll_id]
# Format voter IDs into @user format button1_voters = [f"" for user in poll['button1_votes']] button2_voters = [f"" for user in poll['button2_votes']]
results_message = ( f"*Poll Question:* {poll['question']}\n" f"*Votes for {poll['button1_text']}:* {len(poll['button1_votes'])}\n" f"*Voters for {poll['button1_text']}:* {', '.join(button1_voters) if button1_voters else 'No votes yet'}\n" f"*Votes for {poll['button2_text']}:* {len(poll['button2_votes'])}\n" f"*Voters for {poll['button2_text']}:* {', '.join(button2_voters) if button2_voters else 'No votes yet'}\n" )
# Check if the user has already voted if user_id in polls[poll_id]["button1_votes"] or user_id in polls[poll_id]["button2_votes"]: app.client.chat_postMessage(channel=user_id, text="You have already voted in this poll!") else: # Append user vote if not already voted polls[poll_id]["button1_votes"].append(user_id) app.client.chat_postMessage(channel=user_id, text="Thank you for voting for " + polls[poll_id]["button1_text"] + "!")
# Check if the user has already voted if user_id in polls[poll_id]["button1_votes"] or user_id in polls[poll_id]["button2_votes"]: app.client.chat_postMessage(channel=user_id, text="You have already voted in this poll!") else: # Append user vote if not already voted polls[poll_id]["button2_votes"].append(user_id) app.client.chat_postMessage(channel=user_id, text="Thank you for voting for " + polls[poll_id]["button2_text"] + "!")
# Starting the Flask server if __name__ == "__main__": flask_app.run(port=3000) [/code] Проблема 404 при нажатии кнопок после отправки сообщения с помощью двух кнопок в этом приложении. в ngrok он работает правильно, без ошибок, но в Gunicorn от vultr он возвращает ошибку 404. этот код, который я поставил, работает правильно в моих тестах с ngrok, но в тот момент, когда я перемещаю его в vultr и запустите его с помощью Gunicorn, кнопки возвращают ошибки (404). Я пробовал пройти через это с помощью чатгпт, но его решения принесли мне только разные коды ошибок, такие как 415 или keyError 1. Я не могу понять, как это будет работать в ngrok, а не на моем реальном сервере. ? Я новичок в этом, и это моя первая попытка развернуть что-то на сервере, но для пояснения я сделал следующее: запустил сервер vultr, установил nginx и запустил certbot в домене, заменил маршруты конфигурации слабых приложений для интерактивности и слэш-команды с адреса ngrok на адрес моего домена (также пробовал прямой IP-адрес от vultr, но тоже безуспешно) и запуск приложения с помощью Gunicorn. очень надеюсь, что кто-нибудь поможет мне пролить свет на то, что я делаю неправильно. большое спасибо! 🙏