izuemon commited on
Commit
c821a11
·
verified ·
1 Parent(s): 9a91893

Update join.py

Browse files
Files changed (1) hide show
  1. join.py +78 -161
join.py CHANGED
@@ -1,201 +1,118 @@
1
  #!/usr/bin/env python3
2
  # -*- coding: utf-8 -*-
3
 
4
- """
5
- 10秒ごとに指定のグループのメッセージを取得し、
6
- 各メッセージ内の log / logs の action == "join" を検出。
7
- その join が発生したメッセージの createdAt より新しい (createdAt が大きい)
8
- personId == 599642 のメッセージがなければ歓迎メッセージを送信し、
9
- join を起こした人を指定のグループへ invite POST する。
10
- """
11
-
12
  import os
13
  import time
14
- import json
15
  import requests
16
- from typing import List, Dict, Any, Optional, Set
17
 
18
- # --- 設定 ---
19
  X_ACCOUNT = os.getenv("dmsendertoken")
20
  if not X_ACCOUNT:
21
  raise RuntimeError("環境変数 dmsendertoken が設定されていません。")
22
 
23
- GROUP_ID_TO_WATCH = 463667
24
- PARAMS = {"sortOrder": "desc", "limit": 34, "logFolded": "false"}
25
- BASE_GET = "https://desk-api.channel.io/desk/channels/200605/groups/{group_id}/messages"
26
- BASE_POST = "https://desk-api.channel.io/desk/channels/200605/groups/{group_id}/messages"
27
- INVITE_ENDPOINT_TEMPLATE = "https://desk-api.channel.io/desk/channels/200605/groups/{invite_group_id}/invite?managerIds={manager_id}"
28
 
29
- HEADERS_GET = {
30
- "accept": "application/json",
31
- "accept-language": "ja",
32
- "x-account": X_ACCOUNT,
33
- }
34
- HEADERS_POST = {
35
  "accept": "application/json",
36
  "accept-language": "ja",
37
  "content-type": "application/json",
38
  "x-account": X_ACCOUNT,
39
  }
40
 
41
- TARGET_PERSON_ID = "604730" # チェック対象の personId(文字列比較)
42
- INVITE_GROUP_IDS = [463667]
43
-
44
- WELCOME_MESSAGE_TEXT = "こんにちは。ITRSAにようこそ。自動でいくつかの部屋に招待しています。"
45
-
46
- # --- ヘルパー ---
47
-
48
 
49
- def fetch_messages(group_id: int) -> List[Dict[str, Any]]:
50
- url = BASE_GET.format(group_id=group_id)
51
- r = requests.get(url, headers=HEADERS_GET, params=PARAMS, timeout=20)
52
  r.raise_for_status()
53
- data = r.json()
54
- msgs = data.get("messages", [])
55
- if not isinstance(msgs, list):
56
- return []
57
- return msgs
58
 
59
-
60
- def send_welcome_message(group_id: int, text: str) -> None:
61
- url = BASE_POST.format(group_id=group_id)
62
  payload = {
63
  "requestId": f"desk-web-{int(time.time() * 1000)}",
64
- "blocks": [{"type": "text", "value": text}],
65
  }
66
- r = requests.post(url, headers=HEADERS_POST, json=payload, timeout=30)
67
  r.raise_for_status()
68
-
69
-
70
- def post_invite(invite_group_id: int, manager_id: str) -> None:
71
- url = INVITE_ENDPOINT_TEMPLATE.format(invite_group_id=invite_group_id, manager_id=manager_id)
72
- # API に特別な body が必要ならここに入れるが、指定がなかったので空 JSON を送る
73
- r = requests.post(url, headers=HEADERS_POST, json={}, timeout=20)
 
 
 
 
74
  r.raise_for_status()
 
75
 
 
 
 
76
 
77
- def extract_join_person_ids_from_message(msg: Dict[str, Any]) -> List[str]:
78
- """
79
- メッセージ内の log / logs を調べ、action == "join" のエントリから personId を取り出す。
80
- log エントリ自体に personId がある場合はそれを使い、なければメッセージの personId を使う。
81
- 戻り値は文字列の personId のリスト(重複はこの段階では除去しない)。
82
- """
83
- person_ids = []
84
- # 支持されているキー名を両方確認
85
- log_lists = []
86
- for key in ("log", "logs"):
87
- if key in msg and isinstance(msg[key], list):
88
- log_lists.append(msg[key])
89
-
90
- # もし log/ logs が無ければ return empty
91
- if not log_lists:
92
- return []
93
-
94
- for logs in log_lists:
95
- for entry in logs:
96
- if not isinstance(entry, dict):
97
- continue
98
- action = entry.get("action")
99
- if action != "join":
100
- continue
101
- pid = entry.get("personId") or msg.get("personId")
102
- if pid is not None:
103
- person_ids.append(str(pid))
104
- return person_ids
105
-
106
-
107
- def any_person599642_after(created_at: int, messages: List[Dict[str, Any]]) -> bool:
108
- """
109
- messages の中に createdAt が created_at より大きく、かつ personId == TARGET_PERSON_ID のものがあれば True
110
- """
111
- for m in messages:
112
- try:
113
- ca = int(m.get("createdAt") or 0)
114
- except Exception:
115
- ca = 0
116
- if ca > created_at and str(m.get("personId", "")) == TARGET_PERSON_ID:
117
- return True
118
- return False
119
-
120
-
121
- def process_once(messages: List[Dict[str, Any]]) -> None:
122
- """
123
- 1 回分のメッセージ群を処理する。
124
- - 各 message の log(s) 内で action == "join" を探す
125
- - そのメッセージの createdAt 以降に personId == 599642 のメッセージが無ければ招待処理
126
- - 同じ manager_id への招待は一回の処理実行内で重複しないようにする
127
- - 歓迎メッセージはその条件で招待を行う最初のケースで一度だけ送る
128
- """
129
- if not messages:
130
- return
131
 
132
- invited_manager_ids: Set[str] = set()
133
- welcome_sent = False
 
 
 
 
134
 
135
- # messages は API から降順 (新しい順) で来るはずだが、安全のためそのまま扱う。
136
  for msg in messages:
137
- try:
138
- created_at = int(msg.get("createdAt") or 0)
139
- except Exception:
140
- created_at = 0
141
 
142
- join_person_ids = extract_join_person_ids_from_message(msg)
143
- if not join_person_ids:
144
  continue
145
 
146
- # この join が起きたメッセージ以降に personId==599642 のメッセージがあるか確認
147
- if any_person599642_after(created_at, messages):
148
- # あるならこの join はスキップ(歓迎メッセージが既にある/今後来る想定のため)
149
- continue
150
 
151
- # 招待対象 personId を集める(同一処理内で重複しないよう set で管理)
152
- for manager_id in join_person_ids:
153
- if manager_id in invited_manager_ids:
154
- continue
155
- # まず歓迎メッセージ(まだ送っていなければ)
156
- if not welcome_sent:
157
- try:
158
- send_welcome_message(GROUP_ID_TO_WATCH, WELCOME_MESSAGE_TEXT)
159
- print(f"[INFO] Sent welcome message to group {GROUP_ID_TO_WATCH}")
160
- except Exception as e:
161
- print(f"[ERROR] Failed to send welcome message: {e}")
162
- # 歓迎送信失敗しても続行して招待は試みる
163
- welcome_sent = True
164
-
165
- # 各 invite グループへ POST
166
- for invite_gid in INVITE_GROUP_IDS:
167
- try:
168
- post_invite(invite_gid, manager_id)
169
- print(f"[INFO] Invited manager {manager_id} to group {invite_gid}")
170
- except Exception as e:
171
- print(f"[ERROR] Failed to invite manager {manager_id} to group {invite_gid}: {e}")
172
-
173
- invited_manager_ids.add(manager_id)
174
-
175
- if invited_manager_ids:
176
- print(f"[INFO] Invited manager ids in this cycle: {', '.join(sorted(invited_manager_ids))}")
177
- else:
178
- print("[INFO] No join events required inviting in this cycle.")
179
-
180
-
181
- def main_loop():
182
- print("[INFO] Bot 起動。10秒ごとにチェックします。")
183
- while True:
184
- try:
185
- messages = fetch_messages(GROUP_ID_TO_WATCH)
186
- except Exception as e:
187
- print(f"[ERROR] メッセージ取得に失敗しました: {e}")
188
- # エラーでも sleep して再試行
189
- time.sleep(10)
190
- continue
191
 
192
- try:
193
- process_once(messages)
194
- except Exception as e:
195
- print(f"[ERROR] 処理中に例外が発生しました: {e}")
 
 
 
 
 
196
 
197
- time.sleep(10)
 
 
 
198
 
 
 
 
 
 
 
 
 
 
 
 
 
199
 
200
  if __name__ == "__main__":
201
- main_loop()
 
1
  #!/usr/bin/env python3
2
  # -*- coding: utf-8 -*-
3
 
 
 
 
 
 
 
 
 
4
  import os
5
  import time
 
6
  import requests
7
+ from typing import List, Dict, Any, Set
8
 
9
+ # ===== 設定 =====
10
  X_ACCOUNT = os.getenv("dmsendertoken")
11
  if not X_ACCOUNT:
12
  raise RuntimeError("環境変数 dmsendertoken が設定されていません。")
13
 
14
+ BASE_MESSAGES = "https://desk-api.channel.io/desk/channels/200605/groups/463667/messages"
15
+ INVITE_GROUPS = [519217, 536194, 534868]
 
 
 
16
 
17
+ WELCOME_TEXT = "こんにちは。ITRSAにようこそ。自動でいくつかの部屋に招待しています。"
18
+
19
+ CHECK_INTERVAL = 10
20
+ BOT_PERSON_ID = "599642"
21
+
22
+ HEADERS = {
23
  "accept": "application/json",
24
  "accept-language": "ja",
25
  "content-type": "application/json",
26
  "x-account": X_ACCOUNT,
27
  }
28
 
29
+ PARAMS = {
30
+ "sortOrder": "desc",
31
+ "limit": 34,
32
+ "logFolded": "false",
33
+ }
 
 
34
 
35
+ # ===== API ユーティリティ =====
36
+ def get_messages() -> List[Dict[str, Any]]:
37
+ r = requests.get(BASE_MESSAGES, headers=HEADERS, params=PARAMS, timeout=20)
38
  r.raise_for_status()
39
+ return r.json().get("messages", [])
 
 
 
 
40
 
41
+ def post_welcome_message() -> None:
 
 
42
  payload = {
43
  "requestId": f"desk-web-{int(time.time() * 1000)}",
44
+ "blocks": [{"type": "text", "value": WELCOME_TEXT}],
45
  }
46
+ r = requests.post(BASE_MESSAGES, headers=HEADERS, json=payload, timeout=20)
47
  r.raise_for_status()
48
+ print("[INFO] 歓迎メッセージを送信しました")
49
+
50
+ def invite_to_group(group_id: int, manager_id: str) -> None:
51
+ url = f"https://desk-api.channel.io/desk/channels/200605/groups/{group_id}/invite"
52
+ r = requests.post(
53
+ url,
54
+ headers=HEADERS,
55
+ params={"managerIds": manager_id},
56
+ timeout=20,
57
+ )
58
  r.raise_for_status()
59
+ print(f"[INFO] group {group_id} に personId={manager_id} を招待")
60
 
61
+ # ===== メイン処理 =====
62
+ def process():
63
+ messages = get_messages()
64
 
65
+ # 新しい順で処理されている前提
66
+ join_candidates: List[Dict[str, Any]] = []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
 
68
+ # 599642 の最新発言時刻
69
+ latest_bot_created_at = None
70
+ for m in messages:
71
+ if str(m.get("personId")) == BOT_PERSON_ID:
72
+ latest_bot_created_at = int(m.get("createdAt") or 0)
73
+ break
74
 
 
75
  for msg in messages:
76
+ created_at = int(msg.get("createdAt") or 0)
 
 
 
77
 
78
+ # bot発言より古い join は対象外
79
+ if latest_bot_created_at and created_at <= latest_bot_created_at:
80
  continue
81
 
82
+ log = msg.get("log") or {}
83
+ if log.get("action") == "join":
84
+ join_candidates.append(msg)
 
85
 
86
+ if not join_candidates:
87
+ return
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
 
89
+ # join した personId を重複なしで集める
90
+ join_person_ids: Set[str] = {
91
+ str(m.get("personId"))
92
+ for m in join_candidates
93
+ if m.get("personId")
94
+ }
95
+
96
+ if not join_person_ids:
97
+ return
98
 
99
+ # === 招待 ===
100
+ for pid in join_person_ids:
101
+ for gid in INVITE_GROUPS:
102
+ invite_to_group(gid, pid)
103
 
104
+ # === 歓迎メッセージ��1回のみ) ===
105
+ post_welcome_message()
106
+
107
+ # ===== ループ =====
108
+ def main():
109
+ print("[INFO] Join監視Bot 起動")
110
+ while True:
111
+ try:
112
+ process()
113
+ except Exception as e:
114
+ print(f"[ERROR] 処理中に例外: {e}")
115
+ time.sleep(CHECK_INTERVAL)
116
 
117
  if __name__ == "__main__":
118
+ main()