Skip to content

Instantly share code, notes, and snippets.

@aerith
Created November 26, 2010 01:37
Show Gist options
  • Save aerith/716169 to your computer and use it in GitHub Desktop.
Save aerith/716169 to your computer and use it in GitHub Desktop.
動作確認ほとんどしてない。
#!/usr/bin/perl
package MyApp::Model;
use DBIx::Skinny connect_info => +{
dsn => 'dbi:SQLite:db/memo.sqlite',
};
1;
package MyApp::Model::Schema;
use DateTime;
use DateTime::Format::Strptime;
use DateTime::Format::MySQL;
use DBIx::Skinny::Schema;
my $timezone = 'Asia/Tokyo';
install_table pages => schema {
pk 'id';
columns qw/id name body created_at updated_at/;
trigger pre_insert => callback {
my ($class, $args) = @_;
$args->{created_at} = DateTime->now(time_zone => $timezone);
};
trigger pre_update => callback {
my ($class, $args) = @_;
$args->{updated_at} = DateTime->now(time_zone => $timezone);
};
install_utf8_columns qw/name body/;
install_inflate_rule '^.+_at$' => callback {
inflate {
my $value = shift;
my $strptime = DateTime::Format::Strptime->new(
pattern => '%Y-%m-%d %H:%M:%S',
timezone => $timezone,
);
my $datetime = $strptime->parse_datetime($value);
DateTime->from_object(object => $datetime);
};
deflate {
my $value = shift;
DateTime::Format::MySQL->format_datetime($value);
};
};
};
1;
package MyApp::Model::Page::File;
use strict;
use warnings;
sub new {
my $class = shift;
my %data = @_;
bless \%data, $class;
}
sub name { $_[0]->{name} if exists $_[0]->{name} }
sub body { $_[0]->{body} if exists $_[0]->{body} }
1;
package MyApp::Module::List::File;
sub execute_get {
my $controller = shift;
my $pages = [];
my $format = 'data/*.txt';
my @files = glob $format;
foreach (@files) {
m{.+/([^/\.]+)(?:\..*?)$};
my $page = MyApp::Model::Page::File->new(name => $1, body => '');
push @$pages, $page;
}
$controller->stash('pages', $pages);
$controller->render('index');
}
1;
package MyApp::Module::List::Data;
sub execute_get {
my $controller = shift;
my $sql = qq/select * from pages where name <> 'index' order by created_at desc;/;
my @pages = MyApp::Model->search_by_sql($sql);
$controller->stash('pages', \@pages);
$controller->render('index');
}
1;
package main;
use strict;
use warnings;
use utf8;
# for modules
if (exists $ENV{PERLBREW_PATH}) {
my @paths = split /:/, $ENV{PERLBREW_PATH};
if (scalar @paths) {
use lib @paths;
}
}
use UNIVERSAL::require;
use UNIVERSAL::can;
use Mojolicious::Lite;
use Text::Markdown;
use Text::Textile;
use URI::Escape;
# 静的データの保存ディレクトリ
our $BASEPATH = 'data';
# 編集用パスワード
our $PASSWORD = '';
# セキュリティ用シークレットシード
app->secret('');
app->helper(uri_escape_utf8 => sub {
shift;
URI::Escape::uri_escape_utf8($_[0]);
});
app->helper(markdown => sub {
shift;
Text::Markdown->new->markdown($_[0]);
});
app->helper(textile => sub {
shift;
Text::Textile->new->process($_[0]);
});
get '/' => sub {
my $controller = shift;
my $page = MyApp::Model->single(pages => {name => 'index'});
unless (defined $page) {
my @pages = MyApp::Model->search('pages');
$controller->stash('pages', \@pages);
return $controller->render('index');
}
$controller->stash('page', $page);
$controller->render('page');
};
get '/:name' => sub {
my $controller = shift;
my $name = $controller->param('name');
my $page = ();
my $path = sprintf '%s/%s.txt', $BASEPATH, $name;
if ( -f $path && -r _ ) {
my $body = do { open my $fh, '<', $path; binmode $fh, ":encoding(utf8)"; local $/; <$fh> };
$page = MyApp::Model::Page::File->new(name => $name, body => $body);
} else {
$page = MyApp::Model->single(pages => {name => $name});
}
$controller->redirect_to(sprintf '/edit/%s', URI::Escape::uri_escape_utf8($name)) unless defined $page;
$controller->stash('page', $page);
$controller->render('page');
};
get '/edit/:name' => sub {
my $controller = shift;
my $name = $controller->param('name');
unless (defined $name && length $name > 0) {
return $controller->render(template => 'error', status => 500, message => 'what page do you want to edit?');
}
my $path = sprintf '%s/%s.txt', $BASEPATH, $name;
if ( -f $path && -r _ ) {
$controller->redirect_to(sprintf '/%s', URI::Escape::uri_escape_utf8($name));
}
my $page = MyApp::Model->single(pages => {name => $name});
$controller->stash('page', $page) if defined $page;
$controller->render('edit');
};
post '/update' => sub {
my $controller = shift;
my $password = $controller->param('password');
unless (defined $password && length $password > 0) {
return $controller->render(template => 'error', status => 500, message => 'must input your password.');
}
if (Digest::MD5::md5_hex($password) ne $PASSWORD) {
return $controller->render(template => 'error', status => 500, message => 'password you\'ve entered does not match');
}
my $name = $controller->param('name');
unless (defined $name && length $name > 0) {
return $controller->render(template => 'error', status => 500, message => 'what page do you want to edit?');
}
my $page = MyApp::Model->single(pages => {name => $name});
if (defined $page) {
MyApp::Model->update(pages => {body => $controller->param('body')} => {name => $name});
} else {
MyApp::Model->insert(pages => {
name => $name,
body => $controller->param('body')
});
}
$controller->redirect_to(sprintf '/%s', URI::Escape::uri_escape_utf8($name));
};
any '/(*path)' => sub {
my $controller = $_[0];
my @path = split '/', $controller->param('path');
unless (@path && scalar grep { /.+/ } @path > 1) {
return $controller->render(template => 'not_found', status => 404);
}
my $sub_name = join '::', map { ucfirst } @path;
my $module = sprintf 'MyApp::Module::%s', $sub_name;
my $method = sprintf 'execute_%s', lc $controller->req->method;
eval {
$module->use;
}; if ($@) {
# require YAML::Syck; return $controller->render(text => YAML::Syck::Dump([$@, $sub_name, $module, $method]));
return $controller->render(template => 'not_found', status => 404);
}
my $handler = $module->can($method);
unless (defined $handler && ref $handler) {
# require YAML::Syck; return $controller->render(text => YAML::Syck::Dump([$sub_name, $module, $method]));
return $controller->render(template => 'not_found', status => 404);
}
$handler->(@_);
};
shagadelic;
__DATA__
@@ favicon.ico
-
@@ stylesheets/memo.css
#contents {
width: 800px;
margin: 0 auto 200px auto;
}
#contents p {
font-size: 94%;
line-height: 1.8;
}
#contents pre.code {
overflow: scroll;
background: #f1f1f1;
border: 1px solid #cccccc;
margin: 1.2em;
padding: 1.5em;
}
#contents a.screenshot {
display: block;
text-align: center;
margin: 15px 0 10px 0;
}
#contents a.screenshot img {
width: 80%;
border: 1px solid #666666;
}
@@ layouts/contents.html.ep
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title><%= $title %></title>
<link href="/stylesheets/memo.css" media="screen" rel="stylesheet" type="text/css" />
<meta content="width=320, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport" />
</head>
<body>
<div id="contents">
<%= content %>
</div>
</body>
</html>
@@ index.html.ep
% layout 'contents', title => 'Page List';
<h1>Page List</h1>
<ul>
<% foreach my $page (@$pages) { %>
<li><a href="/<%= uri_escape_utf8 $page->name =%>"><%= $page->name %></a></li>
<% } %>
</ul>
@@ page.html.ep
% layout 'contents', title => stash('name');
<% if (ref stash('page')) { %>
<%= b(textile stash('page')->body)->encode('utf-8') =%>
<% } %>
@@ edit.html.ep
% layout 'contents', title => stash('title');
<h1><%= stash('name') %> の編集</h1>
<form method="post" action="/update">
<input type="hidden" id="name" name="name" value="<%= stash('name') %>">
<div><textarea id="body" name="body" cols="80" rows="30"><% if (ref stash('page')) { %><%= stash('page')->body %><% } %></textarea></div>
<div><input type="password" id="password" name="password" /></div>
<div><input type="submit" value="Save" ></div>
</form>
@@ error.html.ep
% layout 'contents', title => 'Error';
<% if (defined $message && length $message > 0) { %>
<p><%= $message %></p>
<% } else { %>
<p>Error</p>
<% } %>
@@ not_found.html.ep
% layout 'contents', title => 'Not Found';
<p>Not Found</p>
@@ exception.html.ep
% layout 'contents', title => 'Internal Server Error';
<p>Internal Server Error</p>
@@ db/install.sql
create table pages (
id integer primary key not null,
name varchar(255) not null,
body text,
created_at datetime,
updated_at datetime
);
create index name_idx_1 ON pages (name);
@@ script/start.sh
#!/bin/bash
BASEPATH=./
STARMAN=`which starman`
PIDFILE=${BASEPATH}/tmp/memo.pid
APPFILE=${BASEPATH}/app.psgi
APPHOST=127.0.0.1
APPPORT=5050
exec 2>&1
cd $BASEPATH || exit 1
case $1 in
start)
COMMAND="${STARMAN} -MFindBin --daemonize --host ${APPHOST} --port ${APPPORT} --pid ${PIDFILE} --app ${APPFILE}"
if [[ -x $STARMAN ]]; then
echo "Server started. You can reload or stop with this script."
`$COMMAND`
else
echo "Server could not be started."
exit 1;
fi
;;
stop)
if [[ -s $PIDFILE ]]; then
PID=`cat $PIDFILE`
kill -9 $PID;
rm -f $PIDFILE;
exit 0;
fi
exit 1;
;;
reload)
if [[ -s $PIDFILE ]]; then
PID=`cat $PIDFILE`
echo "command: kill -HUP ${PID}"
kill -HUP $PID;
exit 0;
fi
exit 1;
;;
*)
echo "Usage: server.sh {start|stop|reload}"
exit 0;
;;
esac
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment