--- /dev/null
+package App::EzPz::Web;
+
+use Module::Runtime qw(use_module);
+use App::EzPz::UserStore;
+use HTML::Zoom;
+use Web::Simple;
+
+has users => (is => 'lazy');
+
+sub _build_users {
+ my ($self) = @_;
+ my $config = $self->config;
+ return App::EzPz::UserStore->new(
+ htpasswd_file => $config->{htpasswd_file},
+ ($config->{ezmlm_bindir}
+ ? (ezmlm_config => {
+ bindir => $config->{ezmlm_bindir},
+ list_base_dir => $config->{list_base_dir},
+ })
+ : ())
+ );
+}
+
+sub default_config {
+ (
+ htpasswd_file => 'test-config/htpasswd',
+ ezmlm_bindir => 'test-ezmlm/bin',
+ list_base_dir => 'test-lists',
+ )
+}
+
+sub dispatch_request {
+ my ($self) = @_;
+ my $users = $self->users;
+ my $current_user;
+ sub () {
+ return if $_[PSGI_ENV]->{REMOTE_USER};
+ return use_module('Plack::Middleware::Auth::Basic')->new(
+ authenticator => sub { $users->check_password(@_) }
+ )
+ },
+ sub () {
+ $current_user = $users->get(my $name = $_[PSGI_ENV]->{REMOTE_USER});
+ return [
+ 401, [ 'Content-type' => 'text/plain' ], [ "No such user $name" ]
+ ] unless $current_user;
+ return;
+ },
+ sub (/) {
+ $self->_render_front_page($current_user);
+ },
+ sub (/list/*/...) {
+ my $list = $current_user->get_list($_[1]);
+ return unless $list;
+ sub (/) {
+ $self->_list_dispatchers($list),
+ sub () { $self->_render_list_page($list) };
+ },
+ sub (/deny/|/allow/|/mod/|/digest/) {
+ sub (/*/) {
+ my $sublist = $list->${\$_[1]};
+ $self->_list_dispatchers($sublist),
+ sub () { $self->_render_sublist_page($sublist) };
+ },
+ },
+ }
+}
+
+sub _list_dispatchers {
+ my ($self, $list) = @_;
+ sub (POST) {
+ sub (%add=) {
+ $list->add_member($_[1]);
+ return;
+ },
+ sub (%remove=) {
+ $list->remove_member($_[1]);
+ return;
+ },
+ }
+}
+
+sub _zoom_for {
+ my ($self, $name) = @_;
+ my $my_file = __FILE__;
+ $my_file =~ s/\.pm//;
+ return HTML::Zoom->from_file("${my_file}/_templates/${name}.html");
+}
+
+sub _render_page {
+ my ($self, $name, $code) = @_;
+ return [
+ 200, [ 'Content-type' => 'text/html' ],
+ [ $self->_zoom_for($name)->${\sub { local $_ = $_[0]; &$code }}->to_html ]
+ ];
+}
+
+sub _render_front_page {
+ my ($self, $user) = @_;
+ return $self->_render_page(index => sub {
+ $_->replace_content('.user-name',$user->username)
+ ->repeat('.list', [
+ map {
+ my $name = $_;
+ sub {
+ $_->select('.list-link')
+ ->replace_content($name)
+ ->then
+ ->set_attribute(href => "/list/${name}/");
+ }
+ } $user->list_names
+ ]);
+ });
+}
+
+sub _render_list_page {
+ my ($self, $list) = @_;
+ $self->_render_listcore_page(
+ $list, [
+ map [ ucfirst($_)." list", "${_}/" ], qw(allow deny mod digest)
+ ]
+ );
+}
+
+sub _render_sublist_page {
+ my ($self, $list) = @_;
+ $self->_render_listcore_page(
+ $list, [ [ "Back to list", "../" ] ],
+ );
+}
+
+sub _render_listcore_page {
+ my ($self, $list, $links) = @_;
+ $self->_render_page(list => sub {
+ $_->replace_content('.list-name', $list->name)
+ ->repeat('.list-link', [
+ map {
+ my ($name, $href) = @$_;
+ sub {
+ $_->select('.list-link-anchor')
+ ->replace_content($name)
+ ->then
+ ->set_attribute(href => $href);
+ }
+ } @$links
+ ])
+ ->repeat('.list-member', [
+ map {
+ my $email = $_;
+ sub {
+ $_->replace_content('.list-member-name', $email)
+ ->set_attribute('.list-member-remove', value => $email);
+ }
+ } $list->members
+ ]);
+ });
+}
+
+__PACKAGE__->run_if_script;