Peter’s Collaboration E-mails(公開承認ワークフロー管理)

WordPress

投稿された記事を承認工程を経て公開したい時に使えるプラグイン

Peter’s Collaboration E-mails
日本語名:公開承認ワークフロー管理

動作確認

WordPress3.3.1

インストール方法

プラグイン新規追加画面にて「Peter’s Collaboration E-mails」で検索。
結果一覧からPeter’s Collaboration E-mailsをインストールして終了です。

簡単な使用方法

※設定メニューに「公開承認ワークフロー」が追加されています。

既存ルールのままの使い方を説明します。
承認者はwordpress設置時の管理者のみとなっています。もし承認者を追加したい場合は、標準承認者の欄で簡単に追加できます。
承認工程を経たいユーザーの設定ですが、ユーザーの権限を「寄稿者」にします。
※「投稿者」では承認申請はされず、すぐに公開されるので注意。

これだけで設定は終了です。
寄稿者から投稿された記事は承認者が投稿画面で公開するまではサイトには表示されません。

【承認者が公開する方法】
1.クイック編集
投稿一覧でクイック編集をクリックすると色々と設定できますが、その中に「ステータス」があり、承認前は「レビュー待ち」となっています。これを「公開済み」にして更新すれば終了です。
※公開済みにした後でもステータスは変更可能です。もう一度レビュー待ちに戻す事も可能です。

2.投稿の編集
右サイドにある「公開」欄に「ステータス」があります。
こちらも1のクイック編集と同じ?かと思いきや、「レビュー待ち」と「下書き」しかありません。
こちらはステータスはいじらずにそのまま「公開」ボタンを押下すれば公開されます。
※こちらも公開後にもう一度レビュー待ちに戻すことが可能です。その場合はステータスを編集してください。

Perl開発環境を構築する

Eclipse

EPICはEclipse上でPerlの開発をサポートするプラグインで、以下の機能があり
ます。

  • リアルタイム文法チェック
  • コードアシスト
  • perldocサポート
  • ソースコード整形
  • テンプレート
  • Perlデバッガ

http://e-p-i-c.sourceforge.net/

インストール

プラグインは下記URLからダウンロードできます。
EPIC0.5.x系はEclipse3.1系用の安定バージョンです。Eclipse3.2以降を使って
いてEclipse3.1との互換性が不要な場合は、EPIC0.6.x系が推奨されています。

  • バージョン 0.5.x

http://e-p-i-c.sf.net/updates

  • バージョン 0.6.x

http://e-p-i-c.sf.net/updates/testing

Windowsの場合、PerlインタプリタとしてActive PerlかCygwinのPerlが必要に
なります。以下、Active Perlを使用した場合について説明します。

  • Active StateのサイトからActive Perlをダウンロードします。

http://www.activestate.com/Products/activeperl/

  • デバッグ時に変数の値を表示するためにはPadWarkerが必要です。

コマンドラインからインストールします。

 C:\Perl>ppm install PadWalker
 Downloading PadWalker-1.5...done
 Unpacking PadWalker-1.5...done
 Generating HTML for PadWalker-1.5...done
 Updating files in site area...done
   6 files installed
  • EclipseのメニューからWindow→Preference→Perl EPICを選択し、Perl

ExecutableにPerl実行ファイルへのパス(C:\Perl\bin\perl.exe等)を指定
します。

デバッガに関するメモ

Fire Wallや他のアプリケーションの設定によっては、CGIの実行・デバッグが
ブロックされてしまうことがあります。デバッガはポート5000-5004番を使用
します。

Eclipse3.3 + EPIC 0.5.x(安定版)環境では最初の1回目のデバッグは正しく
動きますが、デバッグをいったん終了すると、Eclipseを再起動するまで
デバッグを再開できなくなってしまいます。これはEPIC 0.6.16以降で修正され
たようです。
http://sourceforge.net/forum/forum.php?thread_id=1786869&forum_id=258688

utf-8で構文解析がおかしい

システム全体の文字コードをutf-8にすることで回避できます。
具体的にはeclipse.iniに下記設定を追加します。

 -Dfile.encoding=UTF-8

下記リンク先に詳細情報がありますので参考にどうぞ。

PeriodicalUpdaterを使って時計を作る

Ajax

prototype.jsを使ったサンプルスクリプトです。

刻々と変化する数値や更新される内容などをなるべく定期的(あるいはリアルタイム)にアップデートしたいと思うときはありませんか?
prototype.jsのAjax.PeriodicalUpdaterを使うと、たった数行のコードでそれができてしまうので、サンプルを書いておきます。

ここでは、PHPのプログラムで時刻を表示し、その時刻をAjaxを使用するHTMLファイルで表示するというサンプルです。

用意するのは、下記の2つのファイルです。

time.php…時刻用のプログラム
time_updater.html…時刻を表示させるhtmlファイル(Ajaxはここに書きます)
prototype.jsは事前に取得して(prototype.js)time_updater.htmlが読み込めるように設置しておきます。
PHPが動作する環境も、もちろん必要です。

それぞれの内容を下記のようにします。

 例:time.php PHPプログラムで時刻を表示させる
 <?php
 $now=date('r');
 print $now;
 ?>
 例:time_updater.html…上記のphpプログラムから時刻を受け取って表示する
 
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>
 <script type="text/javascript" src="prototype.js"></script>
 <script>
 var myAjax=new Ajax.PeriodicalUpdater(
   'time','time.php',

{
method:’get’,
frequency: 1,

        decay: 2,

}
);

 </script>
 </head>
 <body>
 <div id="time"> </div>
 </body>
 </html>

time_updater.htmlを実行すると、時刻が刻々と変化するようになりましたか?

time_updater.html内のAjax.PeriodicalUpdaterの引数の意味を書いておきます。

‘time’ …

とあるように、html内のどこに書き込むか
‘time.php’ …どのファイルを取得するか

method:’get’…どの方法で取得するか
frequency: 1 …どのような頻度で更新するか 単位は秒です。つまり、ここでは1秒ごとに内容が更新されます。
decay: 2 …上記のfrequencyで更新がされますが、内容が変わらなくっても毎秒更新してたらサーバーへかかる負荷とか大変だよね?!というわけで、このパラメーターの登場です。
GETしにいき、更新がなければ、次はこのdecayで指定した値をかけた秒数後に見に行くのです。
と説明しても分かりにくいと思うので、例をあげます。
このサンプルでは時間を表示するので、毎秒変わってしまうので、別のサンプルを考えます。
たとえば、登録してある商品内容などを定期的に更新するなどの場合、しばらくは変わりませんよね。
PeriodicalUpdaterが取得するファイルを取得しにいき、その応答内容が変わらない場合、
1秒×2 =2秒後
に次は見に行きます。また内容が変わらなければ、
2秒×2 =4秒後
に次に見に行きます。

この2、という数字がdecayで指定する数字です。

内容が変わっていれば、貯められた数字(4秒後)などはリセットされ、最初の1秒からカウントが始まります。

細かくは、
http://www.prototypejs.org/api/ajax/periodicalUpdater
で見てください。

ちなみに、IEでは上記だけではアップデートがされません。
下記のサイトに解決方法がありますので、参考にしてみてください。
http://phpspot.org/blog/archives/2006/12/prototypejsajax.html

Percona-Toolkitのonline-schema-changeを利用して無停止でALTER TABLEする

MySQL

MySQL5.6からは無停止でALTER TABLEできるオンラインDDLが実装されましたが、いくつかある制約に引っかかって利用できませんでした。

Percoana Toolkitのpt-online-schema-changeを使うと、オンラインDDLの制限に引っかかる場合や
MySQL5.5以前でも無停止でALTER TABLEできます。

  • インストール(CentOSの場合)
 yum install perl-TermReadKey
 wget https://www.percona.com/downloads/percona-toolkit/2.2.17/RPM/percona-toolkit-2.2.17-1.noarch.rpm
 rpm -ivh percona-toolkit-2.2.17-1.noarch.rpm
  • 動作確認
 pt-online-schema-change --dry-run --set-vars="sql_log_bin=0" --alter "ENGINE=InnoDB"  -h=localhost,D=database_name,t=table_name

上記コマンドの–dry-runを–executeに置き換えるとスキーマ変更が実行されます。

  • 仕組み
  1. + スキーマ変更対象テーブルをコピーして作業テーブルを作成
  2. + 元テーブルにINSERT/UPDATE/DELETEトリガーを追加して元テーブルの変更が作業テーブルにも反映されるようにする
  3. + 作業テーブルにALTER TABLEを適用する
  4. + RENAMEで元テーブルと作業テーブルをいれかえる
  5. + 元テーブルとトリガーを削除して完了
  • 注意事項
  • – 作業テーブルをコピーして作るので、CPUやDisk I/O負荷が高い。
  • – ALTER対象テーブルをコピーして作業テーブルが作成されるので、ストレージに余裕が必要
  • – 普通にALTER TABLEするより時間がかかる
  • – 普通に実行するとレプリケーション遅延が発生する

参考
http://d.hatena.ne.jp/fat47/20140418/1397811745
http://d.hatena.ne.jp/fat47/20140421/1398049276

PendingIntentとAlarmManagerについて検証してみる

Android

使ってみないとよくわからない機能の一つがPendingIntentですよね。
今回は、アラームなどでよく利用するPendingIntentで、忘れてしまったことやちょっとわかりにくいことが個人的にあったので、記録しておきます。

次のようなサンプルコードを用意します。

 //AlarmTestActivity.java
 public class AlarmTestActivity extends Activity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_aram_test);
 
        String type = "ON";
        PendingIntent alarmSender = getPendingIntent(4, type);
 
        // アラーム時間設定
        Calendar cal = Calendar.getInstance();
 
        // 設定した時刻をカレンダーに設定
        cal.set(Calendar.HOUR_OF_DAY, 12);
        cal.set(Calendar.MINUTE, 02);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
 
 
        AlarmManager am = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), alarmSender);
        } else {
            am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), alarmSender);
        }
 
 
        // アラーム時間設定 2
        Calendar cal2 = Calendar.getInstance();
 
        // 設定した時刻をカレンダーに設定
        cal2.set(Calendar.HOUR_OF_DAY, 12);
        cal2.set(Calendar.MINUTE, 05);
        cal2.set(Calendar.SECOND, 0);
        cal2.set(Calendar.MILLISECOND, 0);
 
       /* SimpleDateFormat df2 = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
        Date alarm_day2 = cal2.getTime();
        String alarmDate2 = df2.format(alarm_day2);
        Log.d("AramTestActivity", alarmDate2);*/
 
        AlarmManager am2 = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            am2.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, cal2.getTimeInMillis(), alarmSender);
        } else {
            am2.set(AlarmManager.RTC_WAKEUP, cal2.getTimeInMillis(), alarmSender);
        }
 
 
    }
 
 
     public PendingIntent getPendingIntent(int i, String type) {
 
        Intent intent = new Intent(this, AlarmReceiver.class);
        intent.putExtra("type", type);
 
        // アラーム時に起動するアプリケーションを登録
        PendingIntent pendingIntent = null;
        if (type.equals("ON")) {
 
            pendingIntent = PendingIntent.getBroadcast(this,
                    10000 + i,
                    intent, PendingIntent.FLAG_UPDATE_CURRENT);
 
        } 
 
        return pendingIntent;
    }
 
 }
 //AlarmReceiver.java
 public class AlarmReceiver extends BroadcastReceiver {
 
    private final static String TAG = "AlarmReceiver"; 
    
    @Override
    public void onReceive(Context context, Intent i) {
 
        try {
            
            Bundle extras = i.getExtras();
            String type = extras.getString("type");
            Log.d(TAG, "AlarmReceiver起動");
            
            if(type != null){
             
                Intent intent = null;
                if(type.equals("ON")){
     
                    intent = new Intent(context, LocationUpdateAlwaysService.class);
    
                }
            
            }
            
        } catch (Exception e) {
            
            Log.d(TAG, "エラー" + e);
        
        }
 
    }
 
 }

12時2分と12時5分にAlarmReceiverが動作しそうですが、しません。
この場合は、5分のやつだけ動作します。
時間を逆にしてみたらどうでしょうか。
先に5分のやつ、次に2分のやつに順序を変更してみます。

       PendingIntent alarmSender = getPendingIntent(4, type);
 
        // アラーム時間設定
        Calendar cal = Calendar.getInstance();
 
        // 設定した時刻をカレンダーに設定
        cal.set(Calendar.HOUR_OF_DAY, 12);
        cal.set(Calendar.MINUTE, 05);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
 
        AlarmManager am = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), alarmSender);
        } else {
            am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), alarmSender);
        }
 
       // PendingIntent alarmSender2 = getPendingIntent(4, type);
 
        // アラーム時間設定
        Calendar cal2 = Calendar.getInstance();
 
        // 設定した時刻をカレンダーに設定
        cal2.set(Calendar.HOUR_OF_DAY, 12);
        cal2.set(Calendar.MINUTE, 02);
        cal2.set(Calendar.SECOND, 0);
        cal2.set(Calendar.MILLISECOND, 0);
 
        AlarmManager am2 = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            am2.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, cal2.getTimeInMillis(), alarmSender);
        } else {
            am2.set(AlarmManager.RTC_WAKEUP, cal2.getTimeInMillis(), alarmSender);
        }

この場合は、2分のやつだけ動作します。

PendingIntentのフラグに

 PendingIntent.FLAG_ONE_SHOT

を設定しても、動作は同じです。
上書き設定された方が動作するわけですね。

       String type = "ON";
        PendingIntent alarmSender = getPendingIntent(4, type);
 
        // アラーム時間設定
        Calendar cal = Calendar.getInstance();
 
        // 設定した時刻をカレンダーに設定
        cal.set(Calendar.HOUR_OF_DAY, 12);
        cal.set(Calendar.MINUTE, 05);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
 
        AlarmManager am = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), alarmSender);
        } else {
            am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), alarmSender);
        }
 
        //これが新しいPendingIntent
        PendingIntent alarmSender2 = getPendingIntent(4, type);
 
        Calendar cal2 = Calendar.getInstance();
 
        // 設定した時刻をカレンダーに設定
        cal2.set(Calendar.HOUR_OF_DAY, 12);
        cal2.set(Calendar.MINUTE, 02);
        cal2.set(Calendar.SECOND, 0);
        cal2.set(Calendar.MILLISECOND, 0);
 
        AlarmManager am2 = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            am2.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, cal2.getTimeInMillis(), alarmSender2);
        } else {
            am2.set(AlarmManager.RTC_WAKEUP, cal2.getTimeInMillis(), alarmSender);
        } 

2番目のアラームは、違うPendingIntentを作成してみます。
PendingIntent alarmSender と PendingIntent alarmSender2 があります。
ただし、リクエストコードは4で一緒です。
これも、2分のものしか動作しません。
同じリクエストコードだと、上書きされちゃうんですね。

リクエストコードを変更します。

 PendingIntent alarmSender2 = getPendingIntent(5, type);

今度は2分のアラームも5分のアラームも動作します。