taskpad.jp みたいなのを Catalyst で作ってみる

| 0 Comments | 1 TrackBack

taskpadcheckpad など、いろいろ便利だと思います。やりたいことを追加して、できたかどうか評価することが簡単にできるのです。便利なサイトであることは確かです。しかし、サイトを利用するには、まず回線がつながっている必要があります。また、恥ずかしいことも書くかもしれないので、自分の手元にデータはおいておきたいと思います。

そこで、似たようなツールを Catalyst で作ってみることにしました。 認証部分には、Catalyst で Authentication (以下、例とします)で紹介されている Authenticate モジュールを使うことにしました。あと、どうでもいいですが、プロジェクトの名前としては、MyTask としました。

そして作る前の準備を進めます。手元の chroot な debian testing 環境(壊しても問題ない環境)に、必要なモジュールを apt-get で入れていると、いつのまにか perl 周りが unstable になっていて、ちょっと恐怖を感じました。Catalyst::Plugin::Authenticate::CDBI Catalyst::Plugin::Session::FastMmap に関しては、snapshot から持ってきました。

できたものについては、 こちらに置いておきます

データベースの設計

まずは、データベースの設計です。 ユーザの定義に関しては、例をそのまま使っています。

CREATE TABLE users (
  uid      int PRIMARY KEY NOT NULL auto_increment,
  username varchar(100),
  password varchar(100)
);
INSERT INTO users VALUES(1, 'wore', 'wore-dayo-wore');

そして、TODO 項目に関してですが、以下のようになっています。

CREATE TABLE things (
  # TODO の id
  tid      int PRIMARY KEY NOT NULL auto_increment,
  # ユーザの id
  uid      int,
  # TODO の本文
  body     text,
  # 0: 未評価, 1:達成, 2:未達成
  isdone   int,
  # 追加時刻
  added    int,
  # 期限 (追加時刻 + 指定時間)
  deadline int,
  # 実際終了時間
  finished int
);

これらを一つのファイルにまとめて

$ catalyst.pl MyTask
$ cd MyTask
$ mysqladmin -u root --password= create mytask
$ mysql -u mytask --password= mytask < mytask.sql
$ script/mytask_create.pl model CDBI CDBI DBI:mysql:mytask mytask

とかやっていきます。

初期設定と認証まわり

まずは、lib/MyTask.pm を編集していきます。

package MyTask;
use strict;
use Catalyst qw/-Debug Session::FastMmap Authenticate::CDBI Static/;
our $VERSION = '0.01';

MyTask->config(
     name => 'MyTask',
     root => '/home/wore/public_html/MyTask/root',
     # テンプレート
     templates => {
         index => 'templates/index.tt',
     },
     session => {
         expires => 60 * 60 * 24 * 14,
         rewrite => 0,
         storage => '/home/wore/public_html/MyTask/session',
     },
     authenticate => {
         cdbi => {
             class    => 'MyTask::M::CDBI::Users',
             username => 'username',
             passowrd => 'password'
         },
     },
);
MyTask->setup;

login do_login logout に関しては、例をそのまま使ったので、省きます。

コントローラ部分

コントローラ部分を例と同じように別ファイルにして作っていきます。

$ script/mytask_create.pl controller Home

ここで、実際の処理を行う lib/MyTask/Home.pm を編集していきます。 begin 関数については、例をそのまま使いました。

次に作るのが、通常の表示を行う部分です。ここで表示に Template-Toolkit(TT) を使うので、以下のようにします。

$ script/mytask_create.pl view TT TT

コントローラ部分 - 通常画面

処理の流れとしては、

  1. 認証しているデータをもとに、ユーザの id (uid) を取ってきます。
  2. その id を用いて、ユーザに関する項目を新しい順に持ってきます。
  3. TT に渡します。(テンプレートは、lib/MyTask.pm で定義済。ここでは、root/templates/index.tt を編集)

となります。

sub default : Private {
    my ( $self, $c ) = @_;

    my $uid = MyTask::M::CDBI::Users->retrieve(
        "username" => $c->session->{user}
    ) or die "no user";
    $c->stash->{things}= MyTask::M::CDBI::Things->retrieve_from_sql
        (qq(uid = $uid ORDER BY tid DESC));
    $c->stash->{cur} = time();
    $c->stash->{username} = $c->session->{user} . "[id:" . $uid . "]";
    $c->stash->{template} = MyTask->config->{templates}->{index};
    $c->res->headers->content_type('text/html; charset=euc-jp');
    $c->forward('MyTask::V::TT');
}

コントローラ部分 - フォーム入力

次は、フォームから入力された項目の追加部分です。

処理の流れとしては、

  1. フォームから来たデータが正しいかどうかチェックします。
  2. 認証しているデータをもとに、ユーザの id (uid) を取ってきます。
  3. 現在時間とともにデータベースに追加します。
  4. 通常画面にリダイレクトしておしまいです。

となります。

sub add : Global {
    my ($self, $c) = @_;
    my $times = $c->req->param('time');
    my $thing = $c->req->param('thing');
    if ($times < 1 or length($thing) == 0) {
        $c->res->redirect('/');
        return;
    }

    my $uid = MyTask::M::CDBI::Users->retrieve(
        "username" => $c->session->{user}
    ) or die "no user";

    my $t = time();
    my $map = MyTask::M::CDBI::Things->create({
        uid => $uid,
        body => $thing,
        isdone => 0,
        added => $t,
        deadline => ($t + ($times * 60)),
        finished => 0
    }) or die "create";
    $c->res->redirect('/home');
}

コントローラ部分 - 評価

今度は、実行中の TODO の達成、未達成に関する処理です。

  1. 認証しているデータをもとに、ユーザの id (uid) を取ってきます。
  2. 項目が存在しているかチェックします。
  3. 達成・未達成のフラグ、終了時間について更新します。
  4. 通常画面にリダイレクトしておしまいです。

となります。

sub finish : Regex('^finish-(yes|no)-(\d+)$') {
    my ($self, $c) = @_;

    my $uid = MyTask::M::CDBI::Users->retrieve(
        "username" => $c->session->{user}
    ) or die "no user";

    my $rel = MyTask::M::CDBI::Things->search(
         uid => $uid,
         tid => $c->req->snippets->[1]
    );

    if (!$rel) {
        $c->res->headers->content_type('text/html; charset=euc-jp');
        $c->res->output("no such item " . $c->req->snippets->[1]
                        . " for user " . $c->session->{user}
                        . "<br><a href=/home>click here to return</a>"
                        );
        return;
    }

    my $rel = MyTask::M::CDBI::Things->retrieve
        ($c->req->snippets->[1]);

    my $flag = 0;
    if ($c->req->snippets->[0] eq "yes") {
        $flag = 1;
    } elsif ($c->req->snippets->[0] eq "no") {
        $flag = 2;
    }
    $rel->isdone($flag);
    my $t = time();
    $rel->finished($t);
    $rel->update;
    $c->res->redirect('/');
}

コントローラ部分 - 全消去

全消去部分を作ります。

  1. 認証しているデータをもとに、ユーザの id (uid) を取ってきます。
  2. ユーザのデータを全部消しておしまいです。

となります。

sub clear : Global {
    my ($self, $c) = @_;
    my $uid = MyTask::M::CDBI::Users->retrieve(
        "username" => $c->session->{user}
    ) or die "no user";
    MyTask::M::CDBI::Things->search(uid => $uid)->delete_all;
    $c->res->redirect('/home');
}

静的ファイルを使う準備

このほかに、画面表示時に画像などを使うことを考えて、その準備をします。 root/static というディレクトリを掘って、そこにファイルをおけば、httpd 経由で /static/ ディレクトリ以下よりとれます。

$ script/mytask_create.pl controller Static

sub default : Path('/static') {
    my ( $self, $c ) = @_;

    # Optional, allow the browser to cache the content
    $c->res->headers->header( 'Cache-Control' => 'max-age=86400' );

    $c->serve_static; # from Catalyst::Plugin::Static
}

以上記事に書いてきたコード、および、その他のファイルについては、 こちらに置いてあります

これまで書いてきたコードは、

$ script/mytask_server.pl

としてテスト用サーバを起動し、ポート 3000 番をアクセスすれば実際に使うことができます。

オブジェクト指向Perlマスターコース―オブジェクト指向の概念とPerlによる実装方法
ダミアン コンウェイ Damian Conway 山根ドキュメンテーション
ピアソンエデュケーション (2001/02)
売り上げランキング: 54,766

Leave a comment