OSDN Git Service

Plugin::PostFilter: implement experimental and basic functions
authorhylom <hylom@users.sourceforge.jp>
Wed, 9 Jan 2019 10:39:45 +0000 (19:39 +0900)
committerhylom <hylom@users.sourceforge.jp>
Wed, 9 Jan 2019 10:39:45 +0000 (19:39 +0900)
src/newslash_web/lib/Newslash/Plugin/PostFilter.pm [new file with mode: 0644]
src/newslash_web/lib/Newslash/Web.pm

diff --git a/src/newslash_web/lib/Newslash/Plugin/PostFilter.pm b/src/newslash_web/lib/Newslash/Plugin/PostFilter.pm
new file mode 100644 (file)
index 0000000..b8f4f63
--- /dev/null
@@ -0,0 +1,142 @@
+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
index 022bf93..818d0fa 100644 (file)
@@ -187,6 +187,9 @@ sub startup {
     # ReCaptcha control
     $app->plugin('Newslash::Plugin::ReCaptcha');
 
+    # Post Filter
+    $app->plugin('Newslash::Plugin::PostFilter');
+
     # set canocal (for test.srad.jp)
     $app->plugin('Newslash::Plugin::Canonical');