--- /dev/null
+package Newslash::Plugin::Topics;
+use Mojo::Base 'Mojolicious::Plugin';
+
+use Newslash::Util::TextFormatter;
+
+=encoding utf8
+
+=head1 NAME
+
+Newslash::Plugin::NewslashHelper - Newslash helpers plugin
+
+=head1 SYNOPSIS
+
+ # Mojolicious
+ $app->plugin('Newslash::Plugin::NewslashHelpers');
+
+=head1 DESCRIPTION
+
+L<Newslash::Plugin::NewslashHelpers> is collection of helpers for L<Newslash>.
+
+
+=head1 METHODS
+
+=head2 register
+
+ $plugin->register(Mojolicious->new);
+
+Register helpers in L<Mojolicious> application.
+
+=cut
+
+sub register {
+ my ($self, $app, $conf) = @_;
+ $self->{app} = $app;
+
+ for my $k (qw[boxes format_timestamp page_type content_type site_config
+ declare insert_code
+ the_path
+ get_timestamp_by_id
+ tidy_html clean_html escape_html format_htmltext escape_plaintext strip_by_mode
+ get_authors
+ ]) {
+ $app->helper($k => $self->can("_$k"))
+ }
+}
+
+=head1 HELPERS
+
+L<Mojolicious::Plugin::NewslashHelpers> implements the following helpers.
+
+=head2 tidy_html($html)
+
+ tidy HTML, then returns result.
+
+=cut
+
+sub _tidy_html {
+ my ($c, $html) = @_;
+ return Newslash::Util::TextFormatter::tidy_html($html);
+}
+
+=head2 escape_html($html)
+
+ escape HTML, then returns result.
+
+=cut
+
+sub _escape_html {
+ my ($c, $html) = @_;
+ my $allowed = $c->app->config->{Editor}->{allowed_tags};
+ return Newslash::Util::TextFormatter::escape_html($allowed, $html);
+}
+
+=head2 clean_html($html, $type)
+
+ escape and tidy HTML, then returns result.
+
+=cut
+
+sub _clean_html {
+ my ($c, $html) = @_;
+ my $allowed = $c->app->config->{Editor}->{allowed_tags};
+ return Newslash::Util::TextFormatter::clean_html($allowed, $html);
+}
+
+=head2 escape_plaintext($text)
+
+ escape plaintext, then returns result.
+
+=cut
+
+sub _escape_plaintext {
+ my ($c, $text) = @_;
+ return Newslash::Util::TextFormatter::escape_plaintext($text);
+}
+
+=head2 format_htmltext($text)
+
+ format html/text, then returns result.
+
+=cut
+
+sub _format_htmltext {
+ my ($c, $text, $type) = @_;
+ my $allowed;
+
+ if ($type eq "title") {
+ return Newslash::Util::TextFormatter::escape_plaintext($text);
+ }
+ elsif ($type eq "story") {
+ return Newslash::Util::TextFormatter::tidy_html($text);
+ }
+ elsif ($type eq "comment") {
+ $allowed = $c->app->config->{Editor}->{allowed_tags};
+ }
+ elsif ($type eq "journal") {
+ $allowed = $c->app->config->{Editor}->{allowed_tags};
+ }
+ elsif ($type eq "submission") {
+ $allowed = $c->app->config->{Editor}->{allowed_tags};
+ }
+ else {
+ $c->app->log->warn("NewslashHelper::_format_htmltext: invalid type - '$type'");
+ $allowed = $c->app->config->{Editor}->{allowed_tags};
+ }
+ return Newslash::Util::TextFormatter::escape_html($allowed, $text);
+}
+
+=head2 strip_by_mode($html, $post_type)
+
+ strip HTML, then returns result.
+
+=cut
+
+sub _strip_by_mode {
+ my ($c, $html, $post_type) = @_;
+ my $allowed = $c->app->config->{Editor}->{allowed_tags};
+ return Newslash::Util::TextFormatter::strip_by_mode($html, $post_type, $allowed);
+}
+
+=head2 the_path()
+
+ returns current path
+
+=cut
+
+sub _the_path {
+ my ($c, $html, $post_type) = @_;
+ return $c->req->url->to_abs->path;
+}
+
+=head2 get_timestamp_by_id($content_type, $id)
+
+ get given content's timestamp
+
+=cut
+
+sub _get_timestamp_by_id {
+ my ($c, $content_type, $id) = @_;
+}
+
+=head2 get_authors()
+
+ get authors
+
+=cut
+
+sub _get_authors {
+ my ($c) = @_;
+ my $users = $c->model('users');
+ my $authors = $users->select(author => { gt => 0 });
+ return $authors;
+}
+
+
+######################################################################
+#
+
+use constant MARKERS => qw(begin_footer);
+my $marker_contents = {};
+
+sub _insert_code {
+ my ($c, $marker, $content) = @_;
+ if(!$marker_contents->{$marker}) {
+ $marker_contents->{$marker} = [];
+ }
+ push @{$marker_contents->{$marker}}, $content;
+}
+
+sub _declare {
+ my ($c, $name) = @_;
+ my $contents = $marker_contents->{$name} || [];
+
+ return join("\n", @$contents);
+}
+
+
+sub _generate_site_config {
+ my $c = shift;
+ my $epoch = $c->stash('epoch');
+
+ my $reasons = $c->model('moderations')->reasons;
+ my $topics = $c->model('topics')->select;
+ my @topic_texts = map { $_->{textname} } @$topics;
+
+ my $mod_reasons = {};
+ for my $k (keys %$reasons) {
+ $mod_reasons->{$k} = $reasons->{$k}->{name};
+ }
+
+ # my $keywords = {};
+ # for my $topic (@$topics) {
+ # my $lc_keyword = lc($topic->{keyword});
+ # my $lc_textname = lc($topic->{textname});
+ # $keywords->{$lc_keyword} = {keyword => $topic->{keyword},
+ # textname => $topic->{textname},
+ # image => $topic->{image}};
+ # if ($lc_keyword ne $lc_textname) {
+ # $keywords->{$lc_textname} = $keywords->{$lc_keyword};
+ # }
+ # }
+
+ my $value = {
+ modReasons => $mod_reasons,
+ siteInfo => { topic_icon_base_url => $c->config->{Site}->{topic_icon_base_url} },
+ #topics => $keywords,
+ topics => \@topic_texts,
+ editorConfig => $c->config->{Editor},
+ acl2Types => {},
+ };
+
+ return $value;
+}
+
+
+sub _site_config {
+ my $c = shift;
+
+ my $epoch = $c->epoch->get;
+ my $cache_key = "siteconfig";
+ my $config = { memory_expire => 300, # 5 minutes
+ kbs_expire => 86400 }; # 1 day
+
+ my $value = $c->ccache->get($cache_key, $epoch);
+ if (!defined $value) {
+ $value = _generate_site_config($c);
+ $c->ccache->set($cache_key, $epoch, $value);
+ }
+ my $json = to_json($value);
+ return "var siteConfig = $json;";
+}
+
+sub _page_type {
+ my $c = shift;
+ if ($c->stash("page")) {
+ return $c->stash("page")->{type};
+ }
+
+ my $cls = ref($c);
+ if ($cls =~ /^Newslash::Web::Controller::/) {
+ $cls =~ s/^Newslash::Web::Controller:://;
+ $cls = decamelize($cls);
+ return $cls;
+ }
+ return;
+}
+
+sub _content_type {
+ my $c = shift;
+ if ($c->stash("page")) {
+ return $c->stash("page")->{content_type};
+ }
+ return;
+}
+
+=head2 boxes
+
+ [% helpers.boxes() %]
+
+Fetch box contents for current user and returns them.
+
+=cut
+
+sub _boxes {
+ my $c = shift;
+ my $user = $c->stash("user");
+
+ my $value = $c->ccache->get("user-boxes", $user->{uid});
+ if (!defined $value) {
+ $value = _get_sidebar_item($c);
+ $c->ccache->set("user-boxes", $user->{uid}, $value);
+ }
+ return $value;
+}
+
+sub _get_sidebar_item {
+ my $c = shift;
+
+ my $users = $c->model('users');
+ my $user = $c->stash("user");
+ my $user_boxes = $users->sidebar->get_sidebar_contents(uid => $user->{uid});
+
+ my $items = [];
+ my $tt = Template->new();
+
+ for my $box (@$user_boxes) {
+ #$c->app->log->debug("load box $box->{name}");
+ my $q_params = {};
+ if ($box->{query_params}) {
+ $q_params = from_json($box->{query_params});
+ }
+ else {
+ if (!$box->{type} || $box->{type} ne "custom") {
+ push @$items, { type => $box->{type}, name => $box->{name}, contents => $box->{template} };
+ next;
+ }
+ }
+ if (!$q_params) {
+ $c->app->log->warn("Sidebar: invalid query_params in $box->{name}");
+ next;
+ }
+ $q_params->{limit} = $box->{limit} || 20;
+
+ # regularize query parameters
+ my @keys = sort { $a cmp $b } keys %$q_params;
+ my @params;
+ for my $k (@keys) {
+ push @params, $k;
+ push @params, $q_params->{$k};
+ }
+
+ my $rs;
+ if ($box->{type} eq "custom") {
+ my $custom_boxes = $c->app->custom_boxes;
+ if ($custom_boxes) {
+ push @params, "_user";
+ push @params, $user;
+ $rs = $custom_boxes->query($box->{model}, $c, @params);
+ }
+ }
+ else {
+ my $model = $c->ccache->model($box->{model});
+ $rs = $model->select(@params);
+ }
+
+ my $result = '';
+ my $template = $box->{template};
+ next if !$rs || !$template;
+
+ if ($tt->process(\$template, {items => $rs}, \$result)) {
+ push @$items, { type => $box->{type}, name => $box->{name}, contents => $result };
+ }
+ }
+ return $items;
+
+}
+
+=head2 format_timestamp
+
+ $c->format_timestamp(user => $user, epoch => $epoch, format => "user")
+ $c->format_timestamp(datetime => $dt, format => "simple")
+ $c->format_timestamp(user => $user, mysql => $mysql_timestamp_string, format => "datetime");
+
+Return formated string.
+
+=cut
+
+sub _format_timestamp {
+ my $c = shift;
+ my $params = {};
+ my $user = $params->{user} || $c->stash('user');
+
+ if (!ref($_[0])) {
+ $params = {@_};
+ } else {
+ $params = shift;
+ }
+
+ my $offset_sec = 0;
+ if ($user && $user->{config}->{ui}->{offset_sec}) {
+ $offset_sec = $user->{config}->{ui}->{offset_sec};
+ }
+
+ my $format = $params->{format} || ($params->{user} ? "user" : "simple");
+
+ my $dt;
+ if ($params->{from_epoch}) {
+ $dt = DateTime->from_epoch(epoch => $params->{from_epoch});
+ } elsif ($params->{datetime}) {
+ $dt = $params->{datetime}
+ } elsif ($params->{mysql}) {
+ $dt = DateTime::Format::MySQL->parse_datetime($params->{mysql});
+ } elsif ($params->{now}) {
+ $dt = DateTime->now();
+ $format = $params->{now};
+ } else {
+ return;
+ }
+
+ if ($offset_sec) {
+ $dt->add(seconds => $offset_sec);
+ }
+
+ if ($format eq "simple") {
+ return $dt->strftime('%Y-%m-%d %H:%M:%S');
+ }
+ elsif ($format eq "iso8601") {
+ return $dt->strftime('%Y-%m-%dT%H:%M:%S+00:00');
+ }
+ elsif ($format eq "user" && $user) {
+ return $dt->strftime($user->{config}->{ui}->{time_format});
+ }
+ elsif ($format eq "ja") {
+ $dt->set_time_zone('UTC');
+ $dt->set_time_zone('Asia/Tokyo');
+ return $dt->strftime('%Y年%m月%e日 %k時%M分');
+ }
+ elsif ($format eq "datetime") {
+ return $dt;
+ }
+
+ return;
+}
+
+1;
+
+=head1 SEE ALSO
+
+L<Mojolicious>, L<Mojolicious::Guides>, L<http://mojolicious.org>.
+
+=cut