Webhook 通知(送信)の改修案
プリザンターの通知には汎用の「HttpClient」種別があり、任意の URL に HTTP リクエストを送れます。ただし本文の組み立て方や認証の設定に制約があり、主要な SaaS の Webhook にそのまま送るには不便です。このページは、現行の HttpClient 通知の仕組みを確認したうえで、本体の標準機能ではない Webhook 通知種別を追加する改修案をまとめます。
HttpClient 通知の設定手順は Teams 通知・Asana タスク連携 を参照してください。
現行の HttpClient 通知(1.5.8.1)
通知種別とトリガー
通知種別は Mail(1)〜 LineWorks(10)で、HttpClient は 9 です(Notification.cs)。通知は次の操作で送られ、操作前・操作後の状態がビューの条件に合うか(BeforeCondition / AfterCondition と Expression)、指定した列が変わったか(MonitorChangesColumns)で絞れます(Notification.cs)。
| プロパティ | タイミング |
|---|---|
AfterCreate | 作成後 |
AfterUpdate | 更新後 |
AfterDelete | 削除後 |
AfterCopy | コピー後 |
AfterBulkUpdate | 一括更新後 |
AfterBulkDelete | 一括削除後 |
AfterImport | インポート後 |
リマインダーの種別には HttpClient がありません(Mail〜InCircle と LineWorks の 9 種。Reminder.cs)。
送信処理
| 項目 | 1.5.8.1 の動作 |
|---|---|
| 有効化 | Notification.json の HttpClient が true のときだけ送る。既定は false(Notification.cs、Notification.json) |
| メソッド | Get / Post / Put / Delete。未設定なら Post(HttpClient.cs) |
| エンコード | 画面で選べるのは Notification.json の HttpClientEncodings(既定 utf-8 / shift_jis / euc-jp。NotificationUtilities.cs) |
| Content-Type | 既定 application/json(Notification.cs) |
| ヘッダ | Headers に JSON の辞書で書く(例: {"Authorization":"Bearer xxx"})。送信時にデシリアライズしてリクエストヘッダに足す |
| 非同期 | 設定値の解釈(エンコード・ヘッダ・メソッド)だけ同期で行い、送信は Task.Run に投げる(HttpClient.cs) |
| 失敗時 | 例外を SysLogs に記録するだけ。再試行はしない |
| 接続 | 静的な System.Net.Http.HttpClient を 1 つ共有し、応答が 2xx 以外なら EnsureSuccessStatusCode で例外(NotificationHttpClient.cs)。タイムアウトは個別に設定しておらず、.NET の HttpClient の既定値のまま |
| トークン欄 | 通知の「トークン」欄を使う種別は ChatWork・Line・LineGroup・InCircle だけで、HttpClient は対象外(NotificationUtilities.cs) |
本文の組み立て
本文は NoticeBody が書式を改行で分割し、1 行ずつ処理して作ります(ResultModel.cs)。
- 各行を前後の空白を除いてから、列の書式(
{"Name":"[Title]"}のようなNotificationColumnFormatの JSON)として読む - 列が特定できた行は、その列の値(更新時は変更前後)に置き換える
- 列が特定できない行は、
{Url}・{LoginId}・{UserName}・{MailAddress}の 4 つだけを置換して、そのまま出力する(ResultModel.cs)
既定の書式は {Url}、通知対象の各列の書式行、{UserName}<{MailAddress}> を改行でつないだものです(Notification.cs)。
このため、次のことができません。
- 列の値は「行単位」で差し込まれるので、JSON の文字列の途中(
"text": "… [Title] …")に埋め込めない [Title]のようなプレースホルダは、列の書式行以外では置換されない- 差し込んだ値は JSON 用にエスケープされない
サーバースクリプトから送る場合
サーバースクリプトの notifications.New() が返すオブジェクトは MethodType・Encoding・MediaType・Headers を持たないため(ServerScriptModelNotificationModel.cs)、HttpClient 種別は使えません(詳しくは サーバースクリプトから生成 AI を使う)。サーバースクリプトからは httpClient を直接使います。httpClient は Get / Post / Put / Patch / Delete を持ち、タイムアウトは Script.json の ServerScriptHttpClientTimeOut(既定 100000 ミリ秒)です(ServerScriptModelHttpClient.cs、Script.cs)。
主要 SaaS の Webhook 仕様
各サービスの仕様は調査時点のものです。
| サービス | URL | Content-Type | 認証 | 最小のペイロード |
|---|---|---|---|---|
| Slack Incoming Webhooks | https://hooks.slack.com/services/... | application/json | URL に秘密値を含む | {"text":"…"}。リッチ表示は blocks 配列 |
| Teams(Workflows / Power Automate) | Power Automate が発行する URL | application/json | URL に SAS 署名 | 任意の JSON(フロー側でカードに変換) |
| Discord | https://discord.com/api/webhooks/{id}/{token} | application/json | URL に秘密値を含む | {"content":"…"} または embeds 配列 |
| Google Chat | https://chat.googleapis.com/v1/spaces/{space}/messages?key=…&token=… | application/json | URL にキー・トークン | {"text":"…"} |
| Datadog Events API | https://api.datadoghq.com/api/v1/events | application/json | DD-API-KEY ヘッダ | {"title":"…","text":"…"} |
| PagerDuty Events API v2 | https://events.pagerduty.com/v2/enqueue | application/json | 本文の routing_key | event_action と payload |
| 認証方式 | 例 | 現行の HttpClient 通知 |
|---|---|---|
| URL に秘密値を含む | Slack、Discord、Google Chat、Teams | URL に書けば送れる |
| Bearer トークン | 各種 API | Headers に手書きすれば送れる |
| 独自名の API キーヘッダ | Datadog | 同上 |
| 本文に秘密値 | PagerDuty | 1 行の JSON に直接書けば送れる |
| Basic 認証 | 社内ツール | Headers に Base64 を手書き |
| HMAC 署名 | 受信側で署名を検証するサービス | 本文から毎回計算する必要があり、対応できない |
改修案: Webhook 通知種別を追加する
既存の HttpClient 通知の設定項目を増やす案(影響は小さいが本文の制約が残る)と、新しい種別を追加する案を比べ、新しい種別 Webhook を追加する案を推奨します。用途と設定項目が違うので、画面と処理を分けたほうが既存の設定に影響しません。
変更箇所
| ファイル | 変更内容 |
|---|---|
Libraries/Settings/Notification.cs | Types に Webhook = 11 を追加。認証方式・トークン・Basic 認証のユーザー名とパスワード・本文テンプレートの項目を追加し、Send に Webhook の分岐を追加 |
Libraries/Settings/NotificationUtilities.cs | 種別一覧に Webhook を追加(パラメータで有効なときだけ) |
Models/Sites/SiteUtilities.cs | 通知の設定画面に認証方式の選択と、複数行の本文テンプレート欄を追加 |
ParameterAccessor/Parts/Notification.cs・App_Data/Parameters/Notification.json | Webhook の有効・無効(既定 false) |
App_Data/Displays/ | 表示文字列 Webhook などを追加 |
public enum WebhookAuthTypes : int
{
None = 0, // URL に秘密値を含む
BearerToken = 1, // Authorization: Bearer {token}
BasicAuth = 2, // Authorization: Basic {base64(user:pass)}
CustomHeader = 3 // 既存の Headers(JSON の辞書)をそのまま使う
}
private Dictionary<string, string> BuildAuthHeaders()
{
var headers = Headers?.Deserialize<Dictionary<string, string>>()
?? new Dictionary<string, string>();
switch (WebhookAuthType)
{
case WebhookAuthTypes.BearerToken:
headers["Authorization"] = $"Bearer {WebhookAuthToken}";
break;
case WebhookAuthTypes.BasicAuth:
var credentials = Convert.ToBase64String(
System.Text.Encoding.UTF8.GetBytes($"{WebhookAuthUsername}:{WebhookAuthPassword}"));
headers["Authorization"] = $"Basic {credentials}";
break;
}
return headers;
}本文テンプレート
NoticeBody の行単位の処理は使わず、テンプレート文字列全体に対して置換します。
[列名]はss.IncludedColumns(template)で列を取り出し、表示値に置き換える(既存のReplacedDisplayValuesと同じ考え方。ResultModel.cs){Url}・{UserName}などのコンテキスト変数も置き換える- 値は JSON 文字列としてエスケープしてから埋め込む
- テンプレートが空なら、従来の
NoticeBodyの結果を送る
図を読み込み中…
設定例
| 送信先 | 認証方式 | ヘッダ | 本文テンプレート |
|---|---|---|---|
| Slack | なし | ― | {"text": "[Title] が更新されました\n{Url}"} |
| Datadog | カスタムヘッダ | {"DD-API-KEY": "xxxxx"} | {"title": "[Title]", "text": "[Body]", "alert_type": "info"} |
| PagerDuty | なし | ― | {"routing_key": "xxxxx", "event_action": "trigger", "payload": {"summary": "[Title]", "severity": "info", "source": "Pleasanter"}} |
優先順位
Webhook種別の追加(列挙値・パラメータ・画面)- 本文テンプレートと複数行の入力欄
- 認証方式の選択(Bearer / Basic / カスタムヘッダ)
HMAC 署名は難度が高いため、この改修の対象外とします。
ほかに望まれる改善
外部のフロー基盤(iPaaS 連携の実現可能性)の起点として使う場合は、次の改善も効きます。
| 項目 | 現状 | 改善案 |
|---|---|---|
| 再試行 | なし(送りっぱなし) | 指数バックオフで再試行する |
| 送信ログ | 失敗時に SysLogs へ例外を記録するだけ | 成否と応答コードを履歴に残す |
| 署名 | なし | HMAC-SHA256 の署名ヘッダを付ける |
| 流量制限 | なし | 宛先 URL ごとに制限する |
| タイムアウト | 個別設定なし | 通知ごとに設定する |
| 失敗したペイロード | 残らない | 保存して再送できるようにする |