MovableTypeプラグインの独自CGIをNginxに対応させる方法
Category:[トラブルシューティング]
Tag:[MovableType, Plugin, TroubleShooting, Workflow]
Permalink
MovableTypeプラグインの独自CGIをNginxに対応させる方法を紹介します。
これはMovable Type Advent Calendar 2023の24日目の記事です。
1.はじめに
以前、Workflowプラグインの独自CGI(mt-preview.cgi)がNginx環境に対応しておらず、アクセスすると「Not Found」というお客様からの申告があり、そのときの対処方法を備忘録で残しておきます。
MTプラグインで独自CGIを実装される方は、変更後または追加部分のみ参照されればよいかと思います。
冗長な修正があるかもしれませんが、実際に修正して回復した内容ということでそのまま掲載しておきます。
2.対処方法
まず。独自CGIの下記の1行を修正。
変更前
use MT::Bootstrap App => 'Workflow::App';
変更後
use MT::Bootstrap App => 'MT::App::Workflow';
config.yamlに"key"を追加。
key: Workflow
プラグインアプリケーション(独自CGI)の定義を丸々追加。ここでは、
- handler
- script
- cgi_path
の3項目を定義します。
applications:
workflow:
handler: MT::App::Workflow
script: '$Workflow::MT::App::Workflow::script_name'
cgi_path: >
sub {
my $path = MT->config->CGIPath;
$path =~ s!/$!!;
$path =~ s!^https?://[^/]*!!;
$path .= '/plugins/Workflow';
return $path;
}
エラーが発生した状態のCGI(Workflow.pm)はMT::App::CMSを継承していたのを、MT::Appを継承するように変更。
変更前
use base qw( MT::App::CMS );
変更後
use base qw( MT::App );
それに伴い、lib/Workflow/App.pm → lib/MT/App/Workflow.pm に移動。
移動したWorkflow.pm に、idとscript_nameを追加。
sub id {'workflow'}
sub script_name {'mt-preview.cgi'}
修正前はinit_requestしかなかったので、initを追加し、旧init_requestのadd_methodsをinitに移動。
変更前(抜粋)
sub init_request {
my $app = shift;
$app->SUPER::init_request(@_);
$app->add_methods( preview => \&preview );
$app->{ default_mode } = 'main';
$app->{ requires_login } = 0;
}
変更後(抜粋)
sub init {
my $app = shift;
$app->SUPER::init(@_);
$app->add_methods( preview => \&preview );
$app->{ default_mode } = 'main';
$app;
}
sub init_request {
my $app = shift;
$app->SUPER::init_request(@_);
$app->{requires_login} = 0;
}
これで独自CGIがNginxで動作するようになりました。
メール送信で「smtp-source: fatal: connect: Connection refused」となる場合の対処
メール送信で「smtp-source: fatal: connect: Connection refused」となる場合の対処方法を紹介します。
1.問題点
以前、「さくらのVPSに送信メールサーバを設定する方法」で紹介した、メールサーバからメールがとばなくなりました。
具体的には、テストメールを送信すると、下記のように「Connection refused」となります。
# smtp-source -v -f "" -t "hoge@xxx.so-net.ne.jp" 127.0.0.1:25
smtp-source: name_mask: all
smtp-source: fatal: connect: Connection refused
ということで、メール送信で「smtp-source: fatal: connect: Connection refused」となる場合の対処方法を紹介します。
2.原因
単純に、何かの拍子にサービスが停止してしまっただけのようです。
netstatで確認したところ、25番ポートも開いていないようでした。
# netstat -ant
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:3306 0.0.0.0:* LISTEN
:
tcp 0 0 :::80 :::* LISTEN
tcp 0 0 :::22 :::* LISTEN
ということで、サービス起動で解消しました。
# service postfix start
Starting postfix: [ OK ]
25番ポートも開きました。
# netstat -ant
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:25 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:3306 0.0.0.0:* LISTEN
:
tcp 0 0 :::80 :::* LISTEN
tcp 0 0 :::22 :::* LISTEN
tcp 0 0 :::25 :::* LISTEN
ちなみにサービスを起動したところ、サービス停止で滞留していたメールが一斉に送信されたようです。
MovableTypeのDataAPIでコンテンツデータをモーダル表示させる方法
MovableTypeのDataAPIでコンテンツデータをモーダル表示させる方法を紹介します。
1.サンプル
下記のテンプレートをコピーしてインデックステンプレートとして再構築してください。
サンプルでは、デフォルトの「Site Page」コンテンツデータの一覧を表示して、リンクをクリックすると取得したデータ(JSON)をモーダル表示させます。
ユーザー、Webサービスパスワード、クライアントID、サイトID、コンテンツタイプIDは適宜書き換えてください。
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.13.2/themes/smoothness/jquery-ui.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.13.2/jquery-ui.min.js"></script>
<script src="<$mt:StaticWebPath$>data-api/v4/js/mt-data-api.min.js"></script>
<mt:Contents content_type="Site Page">
<mt:ContentsHeader><dl></mt:ContentsHeader>
<dt><$mt:ContentLabel$></dt>
<dd><mt:ContentField content_field="Title"><a href="javascript:void(0);" class="mtlink" data-id="<mt:ContentID>"><$mt:ContentFieldValue$></a></mt:ContentField></dd>
<mt:ContentsFooter></dl></mt:ContentsFooter>
</mt:Contents>
<div id="main" style="display:none;">
<p id="hoge"></p>
</div>
<script>
$(function() {
var accessToken;
$.ajax({
url: "<$mt:CGIPath$><$mt:DataAPIScript$>/v<$mt:DataAPIVersion$>/authentication",
type: "POST",
dataType: "json",
data: {
'username': 'ユーザー名',
'password': 'ユーザーのWebサービスパスワード',
'clientId': '任意のID'
}
}).done(function(data){
accessToken = "MTAuth accessToken=" + data.accessToken;
});
$(".mtlink").click(function(){
$('#hoge').text('');
var content_data_id = $(this).data('id');
$("#main").dialog({
open: function(event, ui) {
// コンテンツデータ取得
$.ajax({
url: "<$mt:CGIPath$><$mt:DataAPIScript$>/v<$mt:DataAPIVersion$>/sites/1/contentTypes/1/data/" + content_data_id,
type: "GET",
dataType: "json",
headers: {
'X-MT-Authorization': accessToken
}
}).done(function(data){
$('#hoge').text(JSON.stringify(data));
});
},
modal:true, //モーダル表示
title:"テスト", //タイトル
width: 900,
height: 500,
});
});
});
</script>
2.解説
必要なライブラリを引き込みます。
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.13.2/themes/smoothness/jquery-ui.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.13.2/jquery-ui.min.js"></script>
<script src="<$mt:StaticWebPath$>data-api/v4/js/mt-data-api.min.js"></script>
コンテンツデータの一覧を表示します。data-id属性にコンテンツデータIDを設定。リンクはページ遷移しないようにしておきます。
<mt:Contents content_type="Site Page">
<mt:ContentsHeader><dl></mt:ContentsHeader>
<dt><$mt:ContentLabel$></dt>
<dd><mt:ContentField content_field="Title"><a href="javascript:void(0);" class="mtlink" data-id="<mt:ContentID>"><$mt:ContentFieldValue$></a></mt:ContentField></dd>
<mt:ContentsFooter></dl></mt:ContentsFooter>
</mt:Contents>
モーダルとなるエリアです。
<div id="main" style="display:none;">
<p id="hoge"></p>
</div>
ページ読み込み時にアクセストークンを取得・保持します。
var accessToken;
$.ajax({
url: "<$mt:CGIPath$><$mt:DataAPIScript$>/v<$mt:DataAPIVersion$>/authentication",
type: "POST",
dataType: "json",
data: {
'username': 'ユーザー名',
'password': 'ユーザーのWebサービスパスワード',
'clientId': '任意のID'
}
}).done(function(data){
accessToken = "MTAuth accessToken=" + data.accessToken;
});
リンククリックで前回のモーダル表示の内容をクリアし、コンテンツデータIDを取得します。
$(".mtlink").click(function(){
$('#hoge').text('');
var content_data_id = $(this).data('id');
dialogでモーダル表示を実行し、openイベントを使って、モーダルが開いたタイミングでDataAPIを起動してコンテンツデータを取得します。
$("#main").dialog({
open: function(event, ui) {
// コンテンツデータ取得
$.ajax({
url: "<$mt:CGIPath$><$mt:DataAPIScript$>/v<$mt:DataAPIVersion$>/sites/1/contentTypes/1/data/" + content_data_id,
type: "GET",
dataType: "json",
headers: {
'X-MT-Authorization': accessToken
}
}).done(function(data){
$('#hoge').text(JSON.stringify(data));
});
},
modal:true, //モーダル表示
title:"テスト", //タイトル
width: 900,
height: 500,
});