2004年10月14日

エントリー保存時にインデックスをリビルドしない

前のエントリーに引き続き、次々エントリーを編集したいときの話。
次々エントリーを編集していくときは、一つ保存するたびにいちいちインデックスをリビルドされると時間とCPUの無駄。なのでリビルド権限のないユーザーを作って試してみたが、エントリー保存の際は権限がなくてもリビルドしてしまう。そこでlib/MT.pmを読んでみると、コード中のコメントに、エントリの依存関係を考慮するのは大変だから前後のエントリーとインデックスは決め打ちでまとめてリビルドしちゃうよーんとか書いてある。一応 BuildDependencies というフラグがあるので、これを利用して他のファイルをリビルドしないように変更する。

lib/MT/App/CMS.pm 2320行目

$app->rebuild_entry( Entry => $entry, BuildDependencies => 1 ) or return;
if ($perms->can_rebuild) { $app->rebuild_entry( Entry => $entry, BuildDependencies => 1 ) or return; } else { $app->rebuild_entry( Entry => $entry, BuildDependencies => 0 ) or return; }
に変更。

これでリビルド権限のないユーザーで入って編集しているときはエントリー自身以外のファイルはリビルドされなくなった。リビルドしたいときは権限を持ったユーザーで入り直してリビルドする。

追記
しかし考えてみるとエントリー自身のリビルドも無駄。エントリーのタイトルなどを変更した場合はIndividual Archiveをまとめてリビルドしないと前後のエントリーの<MTEntryPrevious>や<MTEntryNext>に表示されるタイトルが古いままになってしまう。Individual Archiveをまとめてリビルドすれば編集したエントリー自身も当然リビルドされるので、二重にリビルドすることになる。

そもそも権限がなくてもリビルドされるようになっているのは、そうじゃないと普通は不便だからだが、ここにあげているような状況の場合は逆に厳密に権限に従うのが理に適っている。
というわけで結局上記の変更は破棄して以下のようにした。

lib/MT/App/CMS.pm 1747行目

if ($obj->status == MT::Entry::RELEASE() || $status_old eq MT::Entry::RELEASE()) {
if ( ($obj->status == MT::Entry::RELEASE() || $status_old eq MT::Entry::RELEASE() ) && $perms->can_rebuild) {
に変更。

エントリー編集画面内にプレビュー表示

大量のエントリーを次々に編集するときなど、プレビューを見ながら作業したいことがある。
そこで以下のようにしてみた。

lib/MT/App/CMS.pm 509行目

$param{can_view_log} = $app->{author}->can_view_log; } elsif ($type eq 'category') {
$param{can_view_log} = $app->{author}->can_view_log; require MT::Builder; require MT::Template::Context; require MT::Blog; my $blog = MT::Blog->load($blog_id); my $ctx = MT::Template::Context->new; $ctx->stash('entry', $obj); $ctx->stash('blog', $blog); my $build = MT::Builder->new; my $preview_code = <<'HTML'; <p><b><$MTEntryTitle$></b></p> <$MTEntryBody$> <$MTEntryMore$> HTML my $tokens = $build->compile($ctx, $preview_code) or return $app->error($app->translate( "Parse error: [_1]", $build->errstr)); defined(my $html = $build->build($ctx, $tokens)) or return $app->error($app->translate( "Build error: [_1]", $build->errstr)); $param{preview_body} = $html; } elsif ($type eq 'category') {
に変更。そして tmpl/cms/edit_entry.tmpl の好きなところに<TMPL_VAR NAME=PREVIEW_BODY>を追加。つまりEntry編集画面のテンプレートにプレビュー画面と同じ変数が渡るようにして、それを表示するようにした。

コメントスパム対策その2

しばらくログを取ってみたら、スパムの多くがRefererを送って来ていないようなので、jm@foo: コメントスパム対策に加えて、以下のようにしてみた。

lib/MT/App/Comments.pm 161-162行目の

} my $comment = MT::Comment->new;
} require MT::ConfigMgr; my $cfg = MT::ConfigMgr->instance; my $archive_url = $blog->archive_url; my $comment_cgi = $cfg->CGIPath . 'mt-comments.cgi'; my $refer = $ENV{'HTTP_REFERER'} || 'No referer'; unless ($refer =~ /^($archive_url|$comment_cgi)/) { $app->log("Invalid referer ($refer), $user_ip"); return $app->handle_error('リファラ(<a target="_blank" href="http://service1.symantec.com/SUPPORT/INTER/nisjapanesekb.nsf/jp_docid/20031024163125947?Open&src=&docid=20021020160209947&nsf=support%5CINTER%5Cnisjapanesekb.nsf&view=jp_docid&dtype=&prod=&ver=&osv=&osv_lvl=">参考</a>)が無効です'); } my $comment = MT::Comment->new;
に変更。こちらはベイジアンフィルタの場合と違い、コメントを保存する前に弾いている。 はじめ、
return $app->handle_error($app->translate('Invalid referer'));
として、ja.pmを使って日本語メッセージを表示しようと思ったのだが、なぜか日本語に変換されないので、コード中に直書き。そういえば'Name and email address are required. 'も日本語化されていない。なぜだろう?