diff --git a/Pipfile b/Pipfile index b793317b08..0109d013d6 100644 --- a/Pipfile +++ b/Pipfile @@ -28,7 +28,7 @@ opencv-python = "==4.8.1.78" pyperclip = "==1.8.2" click = "==8.1.7" psycopg2-binary = "==2.9.9" -slackeventsapi = "==3.0.1" +slack-bolt = "==1.18.1" slack-sdk = "==3.26.1" gitpython = "==3.1.40" pandas = "==2.1.4" @@ -37,7 +37,7 @@ openai = "==1.3.8" "discord.py" = "==2.3.2" "misskey.py" = "==4.1.0" websockets = "==12.0" -flask = "==2.3.3" +flask = "==3.0.0" markupsafe = "==2.1.3" numpy = "==1.26.2" diff --git a/Pipfile.lock b/Pipfile.lock index f46bb0500f..cc5e88bb17 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "a1198994962f3704ae819ff406123e171326eb639d65c9a41e8ca593660fa900" + "sha256": "f5935604ae745b5116edf82106ab53f7eb8eea4fd6eb672fb428fcbc3e0918ab" }, "pipfile-spec": 6, "requires": { @@ -122,6 +122,14 @@ "markers": "python_version >= '3.8'", "version": "==4.1.0" }, + "async-timeout": { + "hashes": [ + "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f", + "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028" + ], + "markers": "python_version < '3.11'", + "version": "==4.0.3" + }, "attrs": { "hashes": [ "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04", @@ -326,14 +334,22 @@ "markers": "python_version >= '3.6'", "version": "==1.8.0" }, + "exceptiongroup": { + "hashes": [ + "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14", + "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68" + ], + "markers": "python_version < '3.11'", + "version": "==1.2.0" + }, "flask": { "hashes": [ - "sha256:09c347a92aa7ff4a8e7f3206795f30d826654baf38b873d0744cd571ca609efc", - "sha256:f69fcd559dc907ed196ab9df0e48471709175e696d6e698dd4dbe940f96ce66b" + "sha256:21128f47e4e3b9d597a3e8521a329bf56909b690fcc3fa3e477725aa81367638", + "sha256:cfadcdb638b609361d29ec22360d6070a77d7463dcb3ab08d2c2f2f168845f58" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==2.3.3" + "version": "==3.0.0" }, "fonttools": { "hashes": [ @@ -1178,14 +1194,6 @@ "markers": "python_version >= '3.7'", "version": "==2.14.5" }, - "pyee": { - "hashes": [ - "sha256:5d346a7d0f861a4b2e6c47960295bd895f816725b27d656181947346be98d7c1", - "sha256:b53af98f6990c810edd9b56b87791021a8f54fd13db4edd1142438d44ba2263f" - ], - "markers": "python_version >= '3.8'", - "version": "==11.1.0" - }, "pyparsing": { "hashes": [ "sha256:32c7c0b711493c72ff18a981d24f28aaf9c1fb7ed5e9667c9e84e3db623bdbfb", @@ -1250,6 +1258,15 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.16.0" }, + "slack-bolt": { + "hashes": [ + "sha256:2509e5bb43898a593667bf37965057a9b9a41008b29628e3b57a6136b650b90e", + "sha256:694f84a81ba1c4c428ba7daa01d599d3e9fba7a54ad10c11008aa22573b23ff0" + ], + "index": "pypi", + "markers": "python_version >= '3.6'", + "version": "==1.18.1" + }, "slack-sdk": { "hashes": [ "sha256:d1600211eaa37c71a5f92daf4404074c3e6b3f5359a37c93c818b39d88ab4ca0", @@ -1259,15 +1276,6 @@ "markers": "python_full_version >= '3.6.0'", "version": "==3.26.1" }, - "slackeventsapi": { - "hashes": [ - "sha256:24f8e843a60118b08368161105bae8a998801202f85782239d48f8635e2ead58", - "sha256:b3b075917743a83288cb92a7cbde35f181cdecddc4392b9ab1c9ed9f001ffe2c" - ], - "index": "pypi", - "markers": "python_version >= '3.6'", - "version": "==3.0.1" - }, "smmap": { "hashes": [ "sha256:dceeb6c0028fdb6734471eb07c0cd2aae706ccaecab45965ee83f11c8d3b1f62", @@ -1286,7 +1294,7 @@ }, "sudden-death": { "git": "https://github.com/dev-hato/sudden-death", - "ref": "d94e1f91d5729cd34cbbb489a05d1fd04884c371" + "ref": "73a0c4233d544af2863fdf283380288dec74297d" }, "tqdm": { "hashes": [ @@ -1704,7 +1712,7 @@ "sha256:76b122c08ef4ce2eedcd4d1abd8e641114bfc6c2867f49f3c41facf65bf19f5e", "sha256:cc1c8b182eb3013e24bd475ff2e9295af86c1a38eb1aff128dac8962a9ce3c03" ], - "markers": "python_version >= '3.11'", + "markers": "python_version < '3.11'", "version": "==0.3.7" }, "distlib": { @@ -1714,6 +1722,14 @@ ], "version": "==0.3.7" }, + "exceptiongroup": { + "hashes": [ + "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14", + "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68" + ], + "markers": "python_version < '3.11'", + "version": "==1.2.0" + }, "filelock": { "hashes": [ "sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e", @@ -2197,6 +2213,14 @@ "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==0.10.2" }, + "tomli": { + "hashes": [ + "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", + "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f" + ], + "markers": "python_version < '3.11'", + "version": "==2.0.1" + }, "tomlkit": { "hashes": [ "sha256:75baf5012d06501f07bee5bf8e801b9f343e7aac5a92581f20f80ce632e6b5a4", diff --git a/library/clientclass.py b/library/clientclass.py index 804acaf376..317800fb62 100644 --- a/library/clientclass.py +++ b/library/clientclass.py @@ -9,8 +9,6 @@ import discord from slack_sdk import WebClient -import slackbot_settings as conf - class BaseClient(metaclass=ABCMeta): """ @@ -52,8 +50,8 @@ class SlackClient(BaseClient): Slackを操作するClient """ - def __init__(self, channel, send_user): - self.client = WebClient(token=conf.SLACK_API_TOKEN) + def __init__(self, client: WebClient, channel, send_user): + self.client = client self.slack_channel = channel self.send_user = send_user self.send_user_name = self.client.users_info(user=send_user)["user"]["name"] @@ -64,8 +62,8 @@ def post(self, message): def upload(self, file, filename): """ファイルを投稿する""" - self.client.files_upload( - channels=self.slack_channel, file=file, filename=filename + self.client.files_upload_v2( + channel=self.slack_channel, file=file, filename=filename ) def get_send_user(self): diff --git a/plugins/analyze.py b/plugins/analyze.py index 0415549b5d..230e31eabf 100644 --- a/plugins/analyze.py +++ b/plugins/analyze.py @@ -3,12 +3,19 @@ """ from functools import partial -from typing import Callable +from typing import Callable, List -from library.clientclass import BaseClient +from library.clientclass import BaseClient, SlackClient from plugins import hato +def analyze_slack_message(messages: List[dict]) -> Callable[[SlackClient], None]: + """Slackコマンド解析""" + + message = "".join([m["text"] for m in messages if "text" in m]).strip() + return analyze_message(message) + + def analyze_message(message: str) -> Callable[[BaseClient], None]: """コマンド解析""" diff --git a/renovate.json b/renovate.json index dee312c44f..ce0e09de55 100644 --- a/renovate.json +++ b/renovate.json @@ -3,12 +3,6 @@ "github>dev-hato/renovate-config" ], "packageRules": [ - { - "matchPackageNames": [ - "flask" - ], - "allowedVersions": "<3.0.0" - }, { "matchPackageNames": [ "postgres" diff --git a/run.py b/run.py index 8c4c8d4c39..1a182b65f3 100644 --- a/run.py +++ b/run.py @@ -10,15 +10,15 @@ import sys import time from concurrent.futures import ThreadPoolExecutor -from typing import Callable, List import discord +import slack_bolt import websockets from flask import Flask, jsonify, request from markupsafe import escape from misskey import Misskey from requests.exceptions import ReadTimeout -from slackeventsapi import SlackEventAdapter +from slack_bolt.adapter.flask import SlackRequestHandler import slackbot_settings as conf from library.clientclass import ( @@ -32,9 +32,10 @@ app = Flask(__name__) -slack_events_adapter = SlackEventAdapter( - signing_secret=conf.SLACK_SIGNING_SECRET, endpoint="/slack/events", server=app +slack_app = slack_bolt.App( + token=conf.SLACK_API_TOKEN, signing_secret=conf.SLACK_SIGNING_SECRET ) +slack_handler = SlackRequestHandler(slack_app) def __init__(): @@ -50,25 +51,14 @@ def __init__(): ) -def analyze_slack_message(messages: List[dict]) -> Callable[[SlackClient], None]: - """Slackコマンド解析""" +@slack_app.event("app_mention") +def on_app_mention(body): + channel = body["event"]["channel"] + blocks = body["event"]["blocks"] + authed_users = body["authed_users"] + client_msg_id = body["event"]["client_msg_id"] - message = "".join([m["text"] for m in messages if "text" in m]).strip() - return analyze.analyze_message(message) - - -@slack_events_adapter.on("app_mention") -def on_app_mention(event_data): - """ - appにメンションが送られたらここが呼ばれる - """ - - channel = event_data["event"]["channel"] - blocks = event_data["event"]["blocks"] - authed_users = event_data["authed_users"] - client_msg_id = event_data["event"]["client_msg_id"] - - print(f"event_data: {event_data}") + print(f"body: {body}") print(f"channel: {channel}") print(f"blocks: {blocks}") print(f"authed_users: {authed_users}") @@ -109,13 +99,25 @@ def on_app_mention(event_data): and block_element_elements[0]["user_id"] in authed_users ): tpe.submit( - analyze_slack_message(block_element_elements[1:]), + analyze.analyze_slack_message( + block_element_elements[1:] + ), SlackClient( - channel, block_element_elements[0]["user_id"] + slack_app.client, + channel, + block_element_elements[0]["user_id"], ), ) +@app.route("/slack/events", methods=["POST"]) +def slack_events(): + """ + appにメンションが送られたらここが呼ばれる + """ + return slack_handler.handle(request) + + @app.route("/", methods=["GET", "POST"]) def http_app(): """ @@ -132,7 +134,7 @@ def http_app(): msg = request.json["message"] channel = request.json["channel"] user = request.json["user"] - client = SlackClient(channel, user) + client = SlackClient(slack_app.client, channel, user) client.post(f"コマンド: {msg}") analyze.analyze_message(msg)(client) return "success" diff --git a/tests/plugins/test_analyze.py b/tests/plugins/test_analyze.py index 4440bcafef..8c78c76dd0 100644 --- a/tests/plugins/test_analyze.py +++ b/tests/plugins/test_analyze.py @@ -5,10 +5,42 @@ import unittest from plugins import hato -from plugins.analyze import analyze_message +from plugins.analyze import analyze_message, analyze_slack_message from tests.plugins import TestClient +class TestAnalyzeSlackMessage(unittest.TestCase): + """ + Slackコマンドを正しく解析できるかテストする + """ + + def test_telephone_link(self): + """電話番号のリンクを含むコマンドを正しく解析できる""" + client1 = TestClient() + messages = [ + {"type": "text", "text": ">< "}, + {"type": "link", "url": "tel:09012345678", "text": "09012345678"}, + ] + analyze_slack_message(messages)(client1) + client2 = TestClient() + # pylint: disable=E1121 + hato.totuzensi(client2, "09012345678") + self.assertEqual(client1.get_post_message(), client2.get_post_message()) + + def test_code(self): + """コードを含むコマンドを正しく解析できる""" + client1 = TestClient() + messages = [ + {"type": "text", "text": ">< "}, + {"type": "text", "text": "09012345678", "style": {"code": True}}, + ] + analyze_slack_message(messages)(client1) + client2 = TestClient() + # pylint: disable=E1121 + hato.totuzensi(client2, "09012345678") + self.assertEqual(client1.get_post_message(), client2.get_post_message()) + + class TestAnaryzeMessage(unittest.TestCase): """ コマンドを正しく解析できるかテストする diff --git a/tests/test_run.py b/tests/test_run.py index 872bbdab38..a85a4404a7 100644 --- a/tests/test_run.py +++ b/tests/test_run.py @@ -1,41 +1,3 @@ """ run.pyのテスト """ - -import unittest - -from plugins import hato -from run import analyze_slack_message -from tests.plugins import TestClient - - -class TestAnalyzeSlackMessage(unittest.TestCase): - """ - Slackコマンドを正しく解析できるかテストする - """ - - def test_telephone_link(self): - """電話番号のリンクを含むコマンドを正しく解析できる""" - client1 = TestClient() - messages = [ - {"type": "text", "text": ">< "}, - {"type": "link", "url": "tel:09012345678", "text": "09012345678"}, - ] - analyze_slack_message(messages)(client1) - client2 = TestClient() - # pylint: disable=E1121 - hato.totuzensi(client2, "09012345678") - self.assertEqual(client1.get_post_message(), client2.get_post_message()) - - def test_code(self): - """コードを含むコマンドを正しく解析できる""" - client1 = TestClient() - messages = [ - {"type": "text", "text": ">< "}, - {"type": "text", "text": "09012345678", "style": {"code": True}}, - ] - analyze_slack_message(messages)(client1) - client2 = TestClient() - # pylint: disable=E1121 - hato.totuzensi(client2, "09012345678") - self.assertEqual(client1.get_post_message(), client2.get_post_message())