ページゲート(開く前の確認・合い言葉)の標準機能化
サイトを開いたときに注意事項への同意や合い言葉の入力を求め、通過したら一定時間は聞かない「ページゲート」を、テーブルの管理から設定できる本体の機能にする設計メモです。本体の標準機能ではありません。
拡張スクリプト・拡張スタイル・拡張 SQL だけで作る方法は サイトを開くときに確認ゲートを表示する にあります。すぐに使うならこちらです。
要件
| 要件 | 内容 |
|---|---|
| 同意 | 注意事項を表示し、「理解した」にチェックしないと先へ進めない |
| 合い言葉 | 決められた合い言葉を入力しないと中身を見られない |
| スキップ | 一度通過したら一定時間(例: 4 時間)は聞かない |
| サイト単位 | 特定のサイトだけに設定できる |
| GUI | テーブルの管理から設定できる |
拡張機能で作る方式との違い
| 方式 | 手段 | 合い言葉 | スキップ状態 | 回避のしやすさ |
|---|---|---|---|---|
| スクリプトだけ | スクリプトに合い言葉を書き、localStorage で期限を持つ | ブラウザから見える | ブラウザごと・利用者が書き換えられる | JavaScript を止めれば通れる |
| 拡張 SQL で照合(レシピ) | 合い言葉をサーバー側で照合する | 見えない | 同上 | 同上 |
| 本体の機能にする(このページ) | サーバーが通過状態を持ち、未通過なら中身を出さない | 見えない | ユーザー単位でサーバーに持つ | 画面の出力をサーバーで止めれば回避できない |
サーバースクリプトの「画面表示の前」で context.Redirect() を使って確認ページへ飛ばす方法もありますが(ServerScriptModelContext.cs)、確認ページをプリザンター内に作ると、そのページでもまた同じスクリプトが動くため作りにくくなります。
全体の流れ
図を読み込み中…
改修箇所
1. SiteSettings にプロパティを足す
public bool? PageGateEnabled; // 有効
public string PageGateMessage; // 注意事項
public bool? PageGateRequireAgreement; // 同意を必須にする
public bool? PageGateRequirePassphrase; // 合い言葉を必須にする
public string PageGatePassphrase; // 合い言葉
public int? PageGateSkipMinutes; // スキップする時間(分)サイト設定は JSON で保存されるので、public フィールドを足せば保存対象になります。画面から受け取るために Set メソッドの switch にも同じ名前の case を足します。そのまま持つと合い言葉はサイト設定の JSON に平文で残るので、ハッシュにして持つかどうかも決めておきます。
2. テーブルの管理に設定タブを足す
SiteUtilities.cs のタブ一覧に #PageGateSettingsEditor を足し、既存の FieldCheckBox・FieldTextBox・FieldMarkDown で入力欄を作ります。
テーブルの管理
└── ページゲート(新しいタブ)
├── [x] ページゲートを有効にする
├── [x] 同意を必須にする
├── 注意事項: [Markdown]
├── [x] 合い言葉を必須にする
├── 合い言葉: [パスワード入力]
└── スキップする時間(分): [240]表示名は App_Data/Displays/ に JSON を足し、CodeDefiner で Displays のメソッドを生成します。
3. ゲートのオーバーレイを出力する
全画面共通のダイアログ置き場 TemplateDialogs(HtmlTemplates.cs)に、ゲートの HTML を出すメソッドを足します。通過記録が期限内なら何も出しません。
ゲートは閉じるボタンや Esc で閉じられては困るので、jQuery UI Dialog や <ui-modal> ではなく、position: fixed の div を全画面に重ねる形がテーマの世代に関係なく扱いやすくなります。
オーバーレイを重ねるだけでは HTML の中身は送られてしまうので、回避できないようにするには、未通過のときは一覧や編集画面の本体(#MainForm の中身)をサーバー側で出力しない形にします。
4. 通過用のエンドポイント
同意と合い言葉を受け取り、サーバーで照合して、通過記録を期限付きで保存するアクションを足します。
[HttpPost]
public ActionResult SubmitPageGate(long id)
{
// 1. ss.PageGateEnabled を確認
// 2. 同意(PageGateRequireAgreement)と合い言葉(PageGatePassphrase)を照合
// 3. 期限 = 現在 + PageGateSkipMinutes をセッションに保存
// 4. 成功・失敗を JSON で返す
}5. スキップ状態をセッションに持つ
ユーザー単位で持つと、別のブラウザや端末からでもスキップが効きます。Sessions API の SavePerUser と同じく、セッション ID の代わりに "@" + UserId をキーにして保存します(SessionUtilities.cs)。
| 項目 | 値 |
|---|---|
| SessionGuid | @{UserId} |
| Key | PageGate_{SiteId} など |
| Value | 期限(ISO 8601) |
SessionUtilities を使うときの注意点です(1.5.8.1)。
SetのuserArea: trueは、それだけではキーを@{UserId}にしません。sessionGuidに"@" + context.UserIdを明示して渡します(SessionUtilities.cs)。userArea: trueの値は、Redis を使う設定でも RDB のSessionsテーブルに保存されます(SessionUtilities.cs)。SetUserAreaはキーの先頭にUser_を付けます(SessionUtilities.cs)。- リクエストごとに読み込まれる
context.UserSessionData(@{UserId}の値)は、sessionsコントローラー以外ではUserAreaの値を含みません(Context.cs、SessionUtilities.cs)。userArea: trueで保存した通過記録をゲートの判定で読むときは、SessionUtilities.Get(includeUserArea: true, sessionGuid: "@" + context.UserId)のように明示して読みます。
6. ブラウザ側のスクリプト
通過ボタンで Ajax を送り、成功ならオーバーレイを外して中身を表示し、失敗ならエラーを表示するだけの小さなスクリプトを足します(generals/ に新しいファイルを作り、index.ts から読み込む)。
改修するファイル
| ファイル | 内容 | 種類 |
|---|---|---|
Libraries/Settings/SiteSettings.cs | ゲートのプロパティと Set | 修正 |
Models/Sites/SiteUtilities.cs | 設定タブと入力欄 | 修正 |
Libraries/HtmlParts/HtmlTemplates.cs | TemplateDialogs からゲートを出す | 修正 |
Libraries/HtmlParts/HtmlPageGate.cs | ゲートの HTML | 新規 |
Controllers/ItemsController.cs | 通過用のアクション | 修正 |
App_Data/Displays/PageGate*.json | 表示名・エラーメッセージ | 新規(CodeDefiner で生成) |
Implem.PleasanterFrontend/wwwroot/src/scripts/generals/ | 通過ボタンのスクリプト | 新規 |
API とサーバースクリプト
ゲートは画面を開く操作に対するもので、API とサーバースクリプトからのアクセスには掛けません。API は自動処理が前提で、対話的な確認に向きません。API の利用は API キーとアクセス権限で制御します。