Twitch連携 管理UI(Django)

2025/08/20 - 2025/09/05 / 設計 / 実装 / 運用

Twitch連携 管理UI(Django)

概要

Twitchログイン(django-allauth)で認証されたスタッフのみが利用できる, DiscordロールDMの一括配布ツールである.
Bot(py-cord + FastAPI)の管理APIと連携し, メッセージテンプレート {user} の置換や未知プレースホルダの事前エラーを備える.

  • 目的:運営が非技術者でも安全かつ簡単にロール対象へ告知DMを送れるようにする
  • 効果:案内や告知の即時配布, 誤送信と設定ミスの抑制, 添付ファイル付き配信の省力化

現状

  • 状態:基本機能は実装済み, ローカルで連携動作を確認.
  • 連携:Django(webadmin) と Bot(py-cord + FastAPI) の管理API連携は確認済み. Authorization: Bearer による保護を実装.
  • 送信:送信ジョブの投入からBotによるDM送信まで確認. 0.3秒間隔で順次送信, DM拒否はログ化.
  • 制約:添付は8MBまで, テンプレは {user} のみ対応, 未知の {...} はフォームとAPIで事前エラー.
  • 前提venv/token.jsonadmin_api_tokenbot_admin_api_base を設定. 未設定時は http://127.0.0.1:8000 を利用し, UIのサーバー/ロール選択は空になる.
  • 配置nginx.conf に本番ドメインとHTTPSのリバースプロキシ設定を用意. 公開では /admin/ をブロックし, アプリは 127.0.0.1:8000127.0.0.1:8001 にプロキシ.
  • 未実装:送信進捗の可視化や再送制御の管理UI.

主要機能

  • 認証:Twitchログイン(django-allauth)
    • 許可Twitchログイン名はスタッフ(is_staff)へ自動昇格
  • 権限is_staff のみアクセス可能(非スタッフは 403)
  • 送信:指定ロールの全メンバーへDM一括送信
    • 添付ファイル対応(最大 8MB, Discord DM 制限に準拠)
    • テンプレ置換:メッセージ中の {user} を各メンバーの表示名へ置換
    • バリデーション:未対応の {...} が含まれていれば送信前にエラー
  • 連携:Bot 管理API(Bearer 認証)からサーバー/ロール一覧を取得

画面フロー

1) Twitch でログイン
2) 管理トップから「ロールDM送信」を開く
3) サーバーとロール, メッセージ, (任意で)添付ファイルを指定
4) 送信ボタンでキュー投入(Bot 側が順次送信・ログ記録)

ヒント: {user} は各メンバーの表示名に置換される. 未対応の {...} が含まれるとフォームでエラーになる.

Bot 管理API連携

  • 認証Authorization: Bearer <ADMIN_API_TOKEN>
  • エンドポイント
    • GET /guilds … 参加中サーバー一覧
    • GET /roles?guild_id=<id> … 指定サーバーのロール一覧
    • POST /send_role_dm … ロールDM送信ジョブをキュー投入
  • エラーハンドリング
    • メッセージ中に未知の {...} が含まれていれば 400 を返却
    • 送信処理はBot側で0.3秒間隔で順次DM. 失敗(DM閉鎖等)はログに記録

送信リクエスト例

curl -X POST http://127.0.0.1:8000/send_role_dm \
    -H "Authorization: Bearer <ADMIN_API_TOKEN>" \
    -H "Content-Type: application/json" \
    -d '{
        "guild_id": 123456789012345678,
        "role_id": 987654321098765432,
        "message": "こんにちは {user} さん!最新情報です. ",
        "file_url": "https://example.com/uploads/info.png"
    }'

セキュリティ

  • Web:Twitchログイン+スタッフ昇格(許可ログイン名のみ)で画面アクセスを制限
  • API:Bot 側は Bearer トークンで保護し, Web からのみ正規リクエスト
  • 入力:メッセージのテンプレ置換は {user} のみ許可, 未知 {…} は送信前にブロック
  • 送信:ファイルはDjangoで受領後に公開URLを生成, BotがDLしてDMに添付

セットアップ / 実行

  • 事前:Bot(py-cord + FastAPI)がローカル :8000 で稼働
  • 設定
    • venv/token.json に admin_api_token と bot_admin_api_base を記載(未設定時は http://127.0.0.1:8000 を利用)
    • 許可Twitchログイン名は環境変数 ALLOWED_TWITCH_LOGINS(カンマ区切り)または token.json の twitch_login/twitch_name 読み取りにより自動昇格
  • インストール
    pip install -r requirements.txt
    
  • 起動
    cd webadmin
    python manage.py migrate
    python manage.py runserver 127.0.0.1:8001
    
  • Bot 管理API 設定venv/token.jsonadmin_api_token, bot_admin_api_base を設定. 既定の接続先は http://127.0.0.1:8000.
  • Twitch クレデンシャルvenv/token.json または環境変数 TWITCH_CLIENT_ID, TWITCH_CLIENT_SECRET を使用. allauth へ自動反映.
  • スタッフ昇格ALLOWED_TWITCH_LOGINS に含まれる Twitch ログインでのサインインで is_staff を自動付与.
  • 送信仕様{user} は送信時に表示名へ置換. 未知プレースホルダは 400 を返す. 添付は 8MB まで.
  • 保存場所:添付は MEDIA_ROOT/uploads に保存し, file_urlfile_path を Bot へ引き渡す.
  • 運用補助python manage.py bootstrap_inbox で DB テーブルを初期化. python manage.py bootstrap_twitch_app で SocialApp を作成.
%%{init: { "flowchart": { "htmlLabels": true, "useMaxWidth": true, "nodeSpacing": 35, "rankSpacing": 45 }, "themeVariables": { "fontFamily": "Noto Sans JP, Meiryo, Arial, sans-serif", "fontSize": "20px" } }}%% flowchart LR Staff["Staff(User)"] --> UI["Django /broadcast"] UI -->|GET /guilds| GAPI["Bot Admin API /guilds"] GAPI --> UI UI -->|GET /roles?guild_id| RAPI["Bot Admin API
/roles"] RAPI --> UI UI -->|POST /send_role_dm| PAPI["Bot Admin API
/send_role_dm"] PAPI --> BOT["Bot(py-cord)
queue"] BOT --> LOOP["notify_role_members
0.3s interval"] LOOP --> DM["DM to Role Members"] subgraph Uploads UI --> SAVE["Save attachment
to MEDIA uploads"] SAVE -->|file_url + file_path| PAPI end


%%{init: { "flowchart": { "htmlLabels": true, "useMaxWidth": true, "nodeSpacing": 35, "rankSpacing": 45 }, "themeVariables": { "fontFamily": "Noto Sans JP, Meiryo, Arial, sans-serif", "fontSize": "20px" } }}%% flowchart LR U["User"] --> ALLAUTH["allauth
Twitch login"] ALLAUTH --> CB["Callback"] CB --> SIG["user_logged_in
signal"] SIG --> CK["Check
ALLOWED_TWITCH_LOGINS"] CK -->|allowed| STAFF["set is_staff = True"] CK -->|not allowed| NOOP["no change"]

実装ハイライト

  • 認証/権限:django-allauth + ログイン時シグナルで is_staff を昇格
  • 連携:requests で Bot 管理APIへ(Bearer付与, タイムアウトとエラーハンドリング)
  • UX:サーバー/ロールの動的選択, 未対応 {…} の即時バリデーション, ヒント表示
  • 保守性:設定値は基本 venv/token.json から集約読込

関連