--- /dev/null
+package Newslash::Plugin::PostFilter;
+use Mojo::Base 'Mojolicious::Plugin';
+use Mojo::JSON qw(decode_json);
+use Mojo::JSON::Pointer;
+use Data::Dumper;
+use List::Util qw(any);
+
+sub register {
+ my ($self, $app, $conf) = @_;
+
+ # set default config value
+ my $cnf = $app->config->{PostFilter} ||= {};
+ $cnf->{enable} = 0 if !$cnf->{enable};
+
+ my $filters = [
+ { id => "foobarhogehoge",
+ name => "foobarhogehoge",
+ message => "filter test",
+ regexp => "foobarhogehoge",
+ ratio => 1,
+ threshold => 0,
+ limit => 0,
+ pathes => ['^\/api\/v1\/comment$', ],
+ fields => ["/title", "/comment"],
+ },
+ ];
+
+ $app->hook(around_action => sub {
+ my ($next, $c, $action, $last) = @_;
+ return $next->() if $c->req->method ne 'POST';
+
+ my $config = $c->config->{PostFilter} || {};
+ return $next->() if !$config->{enable};
+
+ # calculation score
+ my $score = 0.0;
+ my $post_data;
+
+ if ($c->req->headers->content_type =~ m/^.*\/json(\s*|;.*)$/) {
+ # request body is JSON
+ $post_data = $c->req->json;
+ }
+
+ my $reason = "";
+ my $max_score = 0.0;
+ if ($post_data) {
+ $app->log->debug(Dumper $post_data);
+ my $pointer = Mojo::JSON::Pointer->new($post_data);
+ for my $filter (@$filters) {
+ # check request path
+ next if !any { eval {$c->url_for =~ m/$_/;} } @{$filter->{pathes}};
+
+ # check for each field
+ my $match_count = 0;
+ for my $field (@{$filter->{fields}}) {
+ if ($pointer->contains($field)) {
+ my $val = $pointer->get($field);
+ my @matches = eval {$val =~ $filter->{regexp}};
+ if ($@) {
+ $app->log->warn("Plugin::PostFilter: invalid regexp: $filter->{regexp}. filter ID: $filter->{id}");
+ }
+ $match_count += @matches;
+ }
+ }
+
+ # ceiling by limit
+ if ($filter->{limit} > 0 && $match_count > $filter->{limit}) {
+ $match_count = $filter->{limit};
+ }
+
+ # calculate score
+ if ($match_count > $filter->{threshold}) {
+ my $this_score = ($match_count - $filter->{threshold}) * $filter->{ratio};
+ $score += $this_score;
+ if ($this_score > $max_score) {
+ $reason = $filter->{message};
+ }
+ }
+ }
+ }
+
+ if ($score >= 1.0) {
+ # do filtering
+ my $url = $c->url_for();
+ $c->app->log->debug("post is filtered by PostFilter. URL: $url");
+ $c->render(json => { error => 1, reason => "post_is_filtered", message => $reason });
+ $c->rendered(400);
+ return;
+ }
+ return $next->();
+ });
+
+}
+
+1;
+
+=encoding utf8
+
+=head1 NAME
+
+Newslash::Plugin::PostFilter - Contents filter plugin
+
+=head1 SYNOPSIS
+
+ # Mojolicious
+ $app->plugin('Newslash::Plugin::PostFilter');
+
+=head1 DESCRIPTION
+
+L<Newslash::Plugin::PostFilters> is collection of helpers for L<Newslash>.
+
+
+=head1 HELPERS
+
+L<Mojolicious::Plugin::PostFilters> implements the following helpers.
+
+=head2 boxes
+
+ [% helpers.boxes() %]
+
+Fetch box contents for current user and returns them.
+
+=head2 format_timestamp
+
+ $c->format_timestamp(user => $user, epoch => $epoch, format => "user")
+ $c->format_timestamp(datetime => $dt, format => "simple")
+
+Return formated string.
+
+=head1 METHODS
+
+=head2 register
+
+ $plugin->register(Mojolicious->new);
+
+Register helpers in L<Mojolicious> application.
+
+=head1 SEE ALSO
+
+L<Mojolicious>, L<Mojolicious::Guides>, L<http://mojolicious.org>.
+
+=cut