Henry Lyne (henrylyne) wrote in changelog,
Henry Lyne
henrylyne
changelog

[livejournal] r15761: Add page to review AntiSpam verdicts and...

Committer: henrylyne
Add page to review AntiSpam verdicts and send feedback to AntiSpam server.

U   trunk/cgi-bin/LJ/AntiSpam.pm
A   trunk/htdocs/admin/antispam.bml
Modified: trunk/cgi-bin/LJ/AntiSpam.pm
===================================================================
--- trunk/cgi-bin/LJ/AntiSpam.pm	2009-10-07 09:10:12 UTC (rev 15760)
+++ trunk/cgi-bin/LJ/AntiSpam.pm	2009-10-07 15:53:40 UTC (rev 15761)
@@ -6,6 +6,7 @@
 
 package LJ::AntiSpam;
 use strict;
+use Net::Akismet::TPAS;
 use Carp qw/ croak cluck /;
 
 my @cols = qw( itemid type posterid journalid eventtime poster_ip email user_agent uniq spam confidence );
@@ -70,6 +71,7 @@
 sub load_recent {
     my $class = shift;
     my $reviewed = shift || 0;
+    my $limit = shift || 50;
 
     my $hours = 3600 * 24; # 24 hours
 
@@ -78,16 +80,17 @@
 
     my $sth;
     my $ago = LJ::mysql_time(time() - $hours, 1);
-    my $sortby = "ORDER BY eventtime";
+    my $xsql = "ORDER BY eventtime DESC";
+    $xsql .= " LIMIT $limit";
 
     # Retrieve all antispam
     if ($reviewed) {
-        $sth = $dbh->prepare("SELECT * FROM antispam WHERE eventtime > ? $sortby");
+        $sth = $dbh->prepare("SELECT * FROM antispam WHERE eventtime > ? $xsql");
 
     # Retrieve all anitspam not yet reviewed
     } else {
         $sth = $dbh->prepare("SELECT * FROM antispam WHERE eventtime > ? " .
-                             "AND review IS NULL $sortby");
+                             "AND review IS NULL $xsql");
     }
     $sth->execute($ago);
     die $dbh->errstr if $dbh->err;
@@ -141,15 +144,16 @@
         my $dbh = LJ::get_db_writer()
             or die "unable to contact global db master to load category";
 
-        $dbh->do("UPDATE antispam SET $key=? WHERE itemid=? AND type=?",
-                 undef, $val, $self->{itemid}, $self->{type});
+        $dbh->do("UPDATE antispam SET $key=? WHERE journalid=? AND itemid=? " .
+                 "AND type=?", undef, $val, $self->{journalid},
+                 $self->{itemid}, $self->{type});
         die $dbh->errstr if $dbh->err;
 
         return $self->{$key} = $val;
     }
 
     # getter case
-    $self->preload_rows unless $self->{_loaded_row};
+    $self->load_row unless $self->{_loaded_row};
 
     return $self->{$key};
 }
@@ -166,8 +170,90 @@
 sub spam        { shift->_get_set('spam')       }
 sub confidence  { shift->_get_set('confidence') }
 sub review      { shift->_get_set('review')     }
+sub set_review  { shift->_get_set('review' => $_[0]) }
 
 
 sub column_list { return @cols }
 
+# Set review as 'T' for True.
+sub mark_reviewed {
+    my $class = shift;
+    my @recs = @_;
+
+    foreach my $rec (@recs) {
+        my $as = LJ::AntiSpam->new(journalid => $rec->{journalid},
+                                   itemid => $rec->{itemid},
+                                   type => $rec->{type} );
+        $as->set_review('T');
+    }
+}
+
+sub mark_false_neg {
+    my $class = shift;
+    return $class->_mark_false_do("false_neg", @_);
+}
+
+sub mark_false_pos {
+    my $class = shift;
+    return $class->_mark_false_do("false_pos", @_);
+}
+
+sub _mark_false_do {
+    my $class = shift;
+    my $sign = shift;
+    my @recs = @_;
+
+    foreach my $rec (@recs) {
+        my $as = LJ::AntiSpam->new(journalid => $rec->{journalid},
+                                   itemid => $rec->{itemid},
+                                   type => $rec->{type} );
+        my $ju = LJ::load_userid($as->journalid);
+        my $poster = LJ::load_userid($as->posterid);
+        my $content;
+
+        if ($as->type eq 'E') {
+            my $entry = LJ::Entry->new($ju, jitemid => $as->itemid);
+            $content = $entry->event_html;
+        } elsif ($as->type eq 'C') {
+            #TODO support comments also
+        }
+
+        my $tpas = LJ::AntiSpam->tpas($as->posterid, LJ::journal_base($ju) . "/");
+
+        if ($sign eq 'false_neg' && !$as->spam) {
+            my $feedback = $tpas->spam(
+                            USER_IP                 => $as->poster_ip,
+                            COMMENT_USER_AGENT      => $as->user_agent,
+                            COMMENT_CONTENT         => $content,
+                            COMMENT_AUTHOR          => $poster->user,
+                            COMMENT_AUTHOR_EMAIL    => $as->email,
+                           ) or die "Failed to get response from antispam server.\n";
+        } elsif ($sign eq 'false_pos' && $as->spam) {
+            my $feedback = $tpas->spam(
+                            USER_IP                 => $as->poster_ip,
+                            COMMENT_USER_AGENT      => $as->user_agent,
+                            COMMENT_CONTENT         => $content,
+                            COMMENT_AUTHOR          => $poster->user,
+                            COMMENT_AUTHOR_EMAIL    => $as->email,
+                           ) or die "Failed to get response from antispam server.\n";
+        }
+        $as->set_review('F');
+    }
+}
+
+
+sub tpas {
+    my $class = shift;
+    my $uid = shift;
+    my $url = shift;
+
+    my $tpas = Net::Akismet::TPAS->new(
+                KEY => $LJ::TPAS_KEY->($uid),
+                URL => $url,
+                SERVER => $LJ::TPAS_SERVER,
+               ) or die "Key verification failure!";
+
+    return $tpas;
+}
+
 1;

Added: trunk/htdocs/admin/antispam.bml
===================================================================
--- trunk/htdocs/admin/antispam.bml	                        (rev 0)
+++ trunk/htdocs/admin/antispam.bml	2009-10-07 15:53:40 UTC (rev 15761)
@@ -0,0 +1,152 @@
+<?page
+title=>Latest AntiSpam Posts
+head<=
+<style>
+ table td { vertical-align: top; }
+ .verdict { font-weight: bold; text-align: center; }
+ .spam0 { background-color: #33ff33; color: #fff; }
+ .spam1 { background-color: #dd0000; color: #000; }
+ </style>
+ <=head
+body<=
+<?_code
+{
+    use strict;
+    use vars qw(%GET %POST $title $headextra @errors @warnings);
+    use Class::Autouse qw(LJ::AntiSpam);
+
+    my $remote = LJ::get_remote();
+
+    return "<?needlogin?>"
+        unless $remote;
+
+    return "You are not allowed to view this page"
+        unless LJ::check_priv($remote, 'supporthelp', 'antispam');
+
+    my $ret;
+
+    if (LJ::did_post()) {
+        push @errors, "Invalid form submission" unless LJ::check_form_auth();
+
+        my @correct; # list of correct verdicts
+        my @false_neg; # list of false negatives for spam
+        my @false_pos; # list of false positives for ham
+        my $changes;
+
+        foreach (grep { /^review_/} keys %POST) {
+            $changes = 1;
+            my $as = $_;
+            $as =~ s/^review_//;
+            my ($spam, $jid, $type, $itemid) = split('-', $as);
+            if ($POST{$_} eq '1') {
+                push @correct,
+                     {journalid => $jid, type => $type, itemid => $itemid};
+            } elsif ($POST{$_} eq '0') {
+                if ($spam) {
+                    push @false_pos, {journalid => $jid, type => $type,
+                                      itemid => $itemid};
+                } else {
+                    push @false_neg, {journalid => $jid, type => $type,
+                                      itemid => $itemid};
+                }
+            }
+        }
+
+warn("correct: " . @correct . "; false_neg: " . @false_neg . "; false_pos: " . @false_pos);
+        LJ::AntiSpam->mark_reviewed(@correct) if (@correct);
+        LJ::AntiSpam->mark_false_neg(@false_neg) if (@false_neg);
+        LJ::AntiSpam->mark_false_pos(@false_pos) if (@false_pos);
+
+        unless (@errors) {
+            if ($changes) {
+                $ret .= "<span class='super notice'>Reviews saved.</span>";
+            } else {
+                $ret .= "<span class='super notice'>No changes.</span>";
+            }
+            $ret .= "<p><a href=''>Review more AntiSpam</a></p>";
+        }
+
+        return $ret;
+    }
+
+    my @posts = LJ::AntiSpam->load_recent;
+    my @cols = LJ::AntiSpam->column_list;
+
+    unless (@posts) {
+        $ret .= "No recent posts to review";
+        return $ret;
+    }
+
+    # Instantiate Entries
+    foreach my $p (@posts) {
+        $p->{entry} = LJ::Entry->new($p->journalid, jitemid => $p->itemid);
+    }
+
+    $ret .= "<form method='POST'>\n";
+    $ret .= LJ::form_auth();
+
+    $ret .= "<table border=1>";
+    foreach my $p (@posts) {
+        $ret .= "<tr><td width='350'>";
+
+        # Left Column
+        # Top of cell indicating result
+        $ret .= "<div class='verdict spam".$p->{spam}."'>";
+        $ret .= $p->{spam} ? "SPAM" : "Yummy Ham";
+        $ret .= "</div>\n";
+
+        foreach my $c (@cols) {
+            $ret .= "<b>$c:</b> " . $p->$c . "<br />";
+        }
+        my $uj = LJ::want_user($p->journalid);
+        my $up = LJ::want_user($p->posterid);
+        my $url = LJ::journal_base($uj) . "/" . $p->{entry}->ditemid . ".html";
+        my $subject = $p->{entry}->subject_raw;
+        my $body = $p->{entry}->event_raw;
+
+        # Middle Column
+        $ret .= "</td><td width=80>";
+        my $asid = $p->spam . "-" . $p->journalid . "-" . $p->type . "-" . $p->itemid;
+        $ret .= "<div><label for='true_$asid'>";
+        $ret .= LJ::html_check({ name => "review_$asid", id => "true_$asid",
+                                 type => 'radio', value => 1, });
+        $ret .= " TRUE";
+        $ret .= "</label></div><br />\n";
+
+        $ret .= "<div><label for='false_$asid'>";
+        $ret .= LJ::html_check({ name => "review_$asid", id => "false_$asid",
+                                 type => 'radio', value => 0, });
+        $ret .= " FALSE";
+        $ret .= "</label></div>\n";
+
+        # Right Column
+        $ret .= "</td><td>";
+
+        $ret .= "<a href=\"$url\">" .
+                $p->{entry}->eventtime_mysql .
+                "</a><br />\n";
+        $ret .= LJ::ljuser($up->{user});
+        if ($up->{userid} != $uj->{userid}) {
+            $ret .= " (in " . LJ::ljuser($uj->{user}, {type => $uj->{journaltype}}) . ")";
+        }
+        $ret .= ":<br />\n";
+
+        $ret .= "<div class='entry'>";
+        LJ::CleanHTML::clean_subject(\$subject);
+        LJ::CleanHTML::clean_event(\$body, {'cuturl' => LJ::item_link($uj, $p->{entry}->{'itemid'}, $p->{entry}->{'anum'})});
+        $ret .= "<h3>$subject</h3>\n" if $subject;
+        $ret .= $body . "</div>";
+        $ret .= "</td></tr>\n";
+    }
+    $ret .= "</table>";
+
+    $ret .= "<p style='text-align: center'>" . LJ::html_submit('submite', 'Submit') . "</p>";
+
+    $ret .= "</form>";
+
+    return $ret;
+}
+_code?>
+
+<=body
+page?>

Subscribe

  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

  • 0 comments