diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2017-08-25 16:12:21 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2017-08-25 16:52:55 +0200 |
commit | 74eb0aab7c69281dac351a47d15522957ee0cfdd (patch) | |
tree | 84438d114e7a4825724b95630c5311100a1bf3b2 | |
parent | 211ebaa02706d4355469aba33f3eab4e6f771efc (diff) | |
download | savane-gray-74eb0aab7c69281dac351a47d15522957ee0cfdd.tar.gz savane-gray-74eb0aab7c69281dac351a47d15522957ee0cfdd.tar.bz2 |
More work on spam checking.
* frontend/php/include/html.php (html_nextprev): Fix operation
when $varpref is passed.
* frontend/php/include/spam.php: Style fixes.
* frontend/php/siteadmin/spamlist.php: Fix pagination.
Print meaningful references in the "incrimnated content"
list, instead of mere "here". List resume first, if it is
marked as spam.
* lib/Savane/DB.pm (db_insert): New function.
* lib/Savane/Trackers.pm (GetTrackersContentAsMail): Fix
email formatting issues.
* db/mysql/table_user.structure (resume_spamscore): New column.
* update/gray/new_tables.pl: New file.
* update/gray/user.sql: New file.
* backend/accounts/sv_usrck: New file. Spamcheck items submitted
by a user or users.
-rwxr-xr-x | backend/accounts/sv_usrck | 585 | ||||
-rw-r--r-- | db/mysql/table_user.structure | 1 | ||||
-rw-r--r-- | frontend/php/include/html.php | 46 | ||||
-rw-r--r-- | frontend/php/include/spam.php | 67 | ||||
-rw-r--r-- | frontend/php/siteadmin/spamlist.php | 251 | ||||
-rw-r--r-- | lib/Savane/DB.pm | 18 | ||||
-rw-r--r-- | lib/Savane/Trackers.pm | 62 | ||||
-rw-r--r-- | update/gray/new_tables.pl | 40 | ||||
-rw-r--r-- | update/gray/user.sql | 1 |
9 files changed, 864 insertions, 207 deletions
diff --git a/backend/accounts/sv_usrck b/backend/accounts/sv_usrck new file mode 100755 index 0000000..d295508 --- /dev/null +++ b/backend/accounts/sv_usrck @@ -0,0 +1,585 @@ +#! /usr/bin/perl +# Copyright (C) 2015-2017 Sergey Poznyakoff <gray@gnu.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +use strict; +use Savane; +use Savane::DB; +use Savane::Backend; +use Savane::Trackers; +use Mail::SpamAssassin::Client; +use Data::Dumper; +use File::Temp qw(tempfile); +use Time::ParseDate; +use Data::Dumper; + +use constant TYPE_SPAM => 0; +use constant TYPE_HAM => 1; +use constant TYPE_FORGET => 2; + +my $spamc; +my $repfd; +my $report_detail; +my $min_score = 5; +my $quiet; +my $learn; +my $assume_status; +my $since; +my $sort; +my $update_spamscore; +my $reporter_uid = 101; # FIXME + +my %all_trackers = map { $_ => 1 } TrackerNames(); +my $enable_resume; +my @enable_trackers; + +my $sys_spamc_socketpath = GetConf('backend.sv_spamchecker.socket'); +my $sys_spamc_host = GetConf('backend.sv_spamchecker.host'); +my $sys_spamc_port = GetConf('backend.sv_spamchecker.port'); +my $sys_spamc_timeout = GetConf('backend.sv_spamchecker.timeout'); +my $sys_spamc_username = GetConf('backend.sv_spamchecker.user'); +my $sys_https_host = GetConf('core.domain'); + +sub userlist_collect { + my @userlist; + my $cond; + + if ($#_ == -1) { + $cond = "user.status='A' AND user_group.group_id IS NULL"; + } else { + if ($#_ == 0) { + $cond = "user.user_name=?"; + } else { + $cond = "user.user_name IN (" . join(',', ('?') x (@_)) . ')'; + } + } + if ($since) { + $cond .= qq{ AND user.add_date >= $since}; + } + + my $order = ''; + if ($sort) { + $order = 'ORDER BY user_name'; + } + + db_foreach(sub { push @userlist, $_[0] }, + qq{ +SELECT distinct user.user_id AS user_id, + user.user_name AS user_name, + user.realname AS realname, + user.people_resume AS resume, + user.people_view_skills AS view_skills, + user.add_date AS date, + cache.isspam AS cache_isspam +FROM user +LEFT JOIN user_group ON user_group.user_id=user.user_id +LEFT JOIN trackers_spamcheck_cache cache + ON cache.item_id = user.user_id + AND cache.artifact = 'resume' +WHERE $cond +$order + }, + @_); + return @userlist; +} + +# sub check_cache { +# my ($ref, $ctr) = @_; +# if (defined($ref->{cache_isspam})) { +# } +# } + +sub spam_check { + my ($msg, $ctr, $tracker, $id) = @_; + my $result; + + $ctr->{total}++; + if (defined($assume_status)) { + return { isspam => $assume_status == TYPE_SPAM ? 'True' : 'False' }; + } + + if (defined($report_detail)) { + $result = $spamc->_filter($msg, $report_detail); + } else { + $result = $spamc->process($msg); + } + + push @{$ctr->{detail}}, + { tracker => $tracker, item_id => $id, msg => $msg, + result => $result } + if $repfd; + + $ctr->{sum} += $result->{score}; + if ($result->{isspam} eq 'True') { + ++$ctr->{spam}; + } else { + ++$ctr->{ham}; + } + return $result; +} + +sub update_trackers_spamscore { + my ($newscore, $tracker, $user_id, $bug_id, $comment_id) = @_; + # Feed the spamscore table +# db_delete('trackers_spamscore', +# artifact => $tracker, +# item_id => $ref->{bug_id}, +# comment_id => $ref->{comment_id}); + db_modify(q{ +DELETE FROM trackers_spamscore +WHERE artifact=? AND item_id=? AND comment_id=? AND affected_user_id=? +}, + $tracker, $bug_id, $comment_id, $user_id); + db_insert('trackers_spamscore', + score => $newscore, + affected_user_id => $user_id, + reporter_user_id => $reporter_uid, + artifact => $tracker, + item_id => $bug_id, + comment_id => $comment_id); + + my $spam = $newscore > 4 ? 'Y' : 'N'; + db_modify(qq{ +INSERT INTO trackers_spamcheck_cache (artifact, item_id, comment_id, isspam) +VALUES (?, ?, ?, ?) +ON DUPLICATE KEY UPDATE isspam=? + }, $tracker, $bug_id, $comment_id, $spam, $spam); +} + +sub check_tracker_comment { + my ($tracker, $ref, $ctr, $user, $cb) = @_; + # FIXME: cache + my $msg = GetTrackersContentAsMail($user->{user_id}, + $ref->{ip}, + $tracker, + $ref->{bug_id}, + $ref->{comment_id}, + $ref->{date}, + $ref->{summary}, + $ref->{details}); + my $res = spam_check($msg, $ctr, $tracker, $ref->{bug_id}); + + &{$cb} ($msg, $res, $user->{user_name}, "$tracker $ref->{bug_id}") + if (ref($cb) eq 'CODE'); + + if ($update_spamscore) { + my $newscore = savane_adjust_spamscore($ref->{spamscore}, + $res->{score}); + my ($q,$id); + if ($ref->{comment_id} > 0) { + $q = qq{UPDATE ${tracker}_history SET spamscore=? WHERE bug_history_id=?}; + $id = $ref->{comment_id}; + } else { + $q = qq{UPDATE $tracker SET spamscore=? WHERE bug_id=?}; + $id = $ref->{bug_id}; + } + db_modify($q, $newscore, $id); + update_trackers_spamscore($newscore, $tracker, + $user->{user_id}, + $ref->{bug_id}, $ref->{comment_id}); + } +} + +sub general_tracker_check { + my ($tracker,$uref,$ctr,$cb) = @_; + my $uid = $uref->{user_id}; + + db_foreach(sub { + my $ref = shift; + $ref->{comment_id} = 0; + check_tracker_comment($tracker, $ref, $ctr, $uref, $cb); + }, + qq{ +SELECT tracker.bug_id AS bug_id, + tracker.summary AS summary, + tracker.details AS details, + tracker.date AS date, + tracker.ip AS ip, + tracker.spamscore AS spamscore, + cache.isspam AS cache_isspam +FROM $tracker tracker +LEFT JOIN trackers_spamcheck_cache cache + ON tracker.bug_id = cache.item_id + AND cache.artifact = ? +WHERE tracker.submitted_by=? +ORDER BY t.date + }, $tracker, $uid); + + db_foreach(sub { + my $ref = shift; + check_tracker_comment($tracker, $ref, $ctr, $uref, $cb); + }, + qq{ +SELECT h.bug_history_id AS comment_id, + h.bug_id AS bug_id, + h.old_value AS details, + h.ip AS ip, + h.date AS date, + h.spamscore AS spamscore, + t.summary AS summary, + cache.isspam AS isspam +FROM ${tracker}_history h, $tracker t +LEFT JOIN trackers_spamcheck_cache cache + ON h.bug_id = cache.item_id + AND cache.artifact = ? +WHERE field_name='details' AND mod_by=? AND t.bug_id=h.bug_id +ORDER BY date}, + $tracker, $uid); + +} + +sub resume_check { + return unless $enable_resume; + # FIXME: cache + my $msg = GetTrackersContentAsMail($uref->{user_id}, + '127.0.0.1', + 'resume', + $uref->{user_id}, # bug_id + '0', # comment_id + $uref->{date}, + 'Resume', + $uref->{resume}); + my $res = spam_check($msg, $ctr, 'resume', 0); + &{$cb} ($msg, $res, $uref->{user_name}, 'Resume') if (ref($cb) eq 'CODE'); + + if ($update_spamscore) { + my $newscore = savane_adjust_spamscore(0, $res->{score}); + db_modify(q{UPDATE user SET resume_spamscore=? WHERE user_id=?}, + $newscore, $uref->{user_id}); + update_trackers_spamscore($newscore, 'resume', + $uref->{user_id}, 0, 0); + } +} + +sub result_is_spam { + my $result = shift; + if (defined($min_score)) { + return $result->{score} >= $min_score; + } else { + return $result->{isspam} eq 'True'; + } +} + +sub report_uid { + my ($usr, $ctr) = @_; + print $repfd "* $usr->{user_name}: $ctr->{status}\n"; + print $repfd "total=$ctr->{total}\n"; + print $repfd "score=$ctr->{score}\n"; + print $repfd "spam=$ctr->{spam} / $ctr->{ham}\n"; + + return unless defined $ctr->{detail}; + + my $tracker; + foreach my $detail (@{$ctr->{detail}}) { + print $repfd "\n"; + + my $result = $detail->{result}; + + if ($tracker ne $detail->{tracker}) { + $tracker = $detail->{tracker}; + print $repfd "\n** $tracker\n"; + } + + my $stat = $result->{isspam} eq 'True'; + print $repfd "\n*** $detail->{item_id}: $stat (score $result->{score})\n"; + my $print_msg; + + if (exists($result->{message})) { + $result->{message} =~ s/.*^(Content analysis details:)/$1/sm; + print $repfd "$result->{message}\n\n"; + $print_msg = 1 if $report_detail; + } else { + $print_msg = 1; + } + if ($print_msg) { + $detail->{msg} =~ s/\r//g; + $detail->{msg} =~ s/^\*/\\*/; + print $repfd "$detail->{msg}\n"; + } + } + print $repfd "\n\f\n"; +} + +sub parsetime { + my $s = shift; + my $t = 0; + if ($s =~ /^\d+$/) { + $t = $s; + } else { + my @keyord = ('Y', 'M', 'd', 'h', 'm', 's'); + my %timetrans = ('Y' => 365*86400, + 'M' => 31*86400, + 'd' => 86400, + 'h' => 3600, + 'm' => 60, + 's' => 1); + for (my $set = join('', @keyord); + $set ne '' && $s =~ /(\d+)\s*([$set])\s*(.*)/; + $set = join('', @keyord)) { + while (shift(@keyord) ne $2) {} + $t += $1 * $timetrans{$2}; + $s = $3; + } + abend(EX_USAGE, "time specification error near $s") unless $s eq ''; + } + return $t; +} + +# #### +my $file; +my $report; +my %d2cmd = ( 1 => 'SYMBOLS', + symbols => 'SYMBOLS', + 2 => 'REPORT', + full => 'REPORT' ); + +my %opts = ("report|r" => \$report, + "detail|D=s" => sub { + if ($_[1] ne '0') { + my $s = lc $_[1]; + abend(EX_USAGE, "unknown detail level") + unless defined $d2cmd{$s}; + $report_detail = $d2cmd{$s}; + } + $report = 1; + }, + "output|o=s" => \$file, + "quiet|q" => \$quiet, + "score|s=f" => \$min_score, + "learn|l" => \$learn, + "update-spamscore" => \$update_spamscore, + "assume-status=s" => sub { + $assume_status = learntype($_[1]); + abend(EX_USAGE, "unrecognized status") + unless (defined($assume_status) && $assume_status != TYPE_FORGET); + }, + "resume" => \$enable_resume, + "no-resume" => sub { $enable_resume = 0 }, + "trackers=s" => sub { + foreach my $name (split /,/, $_[1]) { + push @enable_trackers, $name; + } + }, + "no-trackers:s" => sub { + if ($_[1] eq '') { + %all_trackers = (); + } else { + foreach my $name (split /,/, $_[1]) { + delete $all_trackers{$name}; + } + } + }, + "since:s" => sub { $since = parsedate($_[1]) }, + "sort" => \$sort + ); +backend_setup(descr => "Check active users", + cron => GetConf('backend.sv_usrck.cron')||1, # FIXME + options => \%opts); + +if (defined($assume_status)) { + abend(EX_USAGE, "--assume-status is valid only with --learn") + unless defined $learn; + abend(EX_USAGE, "--update-spamscore is not valid with --assume-status") + if $update_spamscore; +} + +$enable_resume = 1 unless defined $enable_resume; +@enable_trackers = sort keys %all_trackers + unless @enable_trackers; + +my %spamc_options; + +if (defined $sys_spamc_socketpath) { + $spamc_options{socketpath} = $sys_spamc_socketpath; +} elsif (defined $sys_spamc_port) { + $spamc_options{port} = $sys_spamc_port; + $spamc_options{host} = + defined($sys_spamc_host) ? $sys_spamc_host : 'localhost'; +} +$spamc_options{timeout} = $sys_spamc_timeout; +$spamc_options{username} = $sys_spamc_username; + +$spamc = new Mail::SpamAssassin::Client(\%spamc_options); +abend(EX_UNAVAILABLE, "can't connect to spamd") unless $spamc->ping(); + +if ($report) { + if (defined($file)) { + open($repfd, '>', $file) or + abend(EX_CANTCREAT, "can't create file $file"); + } else { + open($repfd, '>&', STDOUT); + ++$quiet; + } +} + +my $now = time(); + +# $s = savane_adjust_spamscore($input, $score); +# Adjusts Savane spamscore $input in accordance with the newly computed +# SpamAssassin $score. +sub savane_adjust_spamscore { + my ($spam_score, $sa_score) = @_; + my $newscore; + + if ($sa_score <= 0) { + $newscore = $spam_score - 8; + } elsif ($sa_score > 0.0 && $sa_score <= 2.0) { + $newscore = $spam_score - 5; + } elsif ($sa_score > 2.0 && $sa_score <= 3.0) { + $newscore = $spam_score - 4; + } elsif ($sa_score > 3.0 && $sa_score <= 5.0) { + $newscore = $spam_score - 3; + } elsif ($sa_score > 5.0 && $sa_score <= 7.0) { + $newscore = $spam_score - 2; + } elsif ($sa_score > 7.0 && $sa_score <= 9.0) { + $newscore = $spam_score - 1; + } else { + $newscore = $sa_score; + } + return $newscore < 0 ? 0 : int($newscore + 0.5); +} + +sub check_user { + my $uref = shift; + + my %ctr; + + $ctr{total} = $ctr{spam} = $ctr{ham} = 0; + if ($uref->{view_skills}) { + debug("$uref->{user_name}: checking resume"); + resume_check($uref, \%ctr); + } + + for my $t (@enable_trackers) { + debug("$uref->{user_name}: checking $t"); + general_tracker_check($t, $uref, \%ctr); + } + my $s = "$uref->{user_name} ($uref->{realname}): total=$ctr{total}"; + if ($ctr{total}) { + $ctr{score} = $ctr{sum} / $ctr{total}; + $ctr{status} = ($ctr{score} >= $min_score) ? 'SPAM' : 'OK'; + $s .= " avg score=$ctr{score}; spam=$ctr{spam}; ham=$ctr{ham}"; + } else { + $ctr{score} = 0.0; + $ctr{status} = 'OK'; + } + debug($s); + + print "$uref->{user_name} ($uref->{realname}): $ctr{status}\n" + unless $quiet; + report_uid($uref, \%ctr) if $report; + db_modify(q{UPDATE user SET spamscore=? WHERE user_id=?}, + savane_adjust_spamscore(8, $ctr{score}), $uref->{user_id}) + if $update_spamscore; +} + +sub line_count { + my $s = shift; + return 0 if $s eq ''; + my $count = 1; + $count++ while $s =~ m/$/g; + return $count; +} + +sub learntype { + my $s = uc shift; + my %t = ( + S => TYPE_SPAM, + SPAM => TYPE_SPAM, + H => TYPE_HAM, + HAM => TYPE_HAM. + F => TYPE_FORGET, + FORGET => TYPE_FORGET + ); + return $t{$s} if exists $t{$s}; + return undef; +} + +sub edit { + my $filename = shift; + my $editor = $ENV{'VISUAL'} || $ENV{'EDITOR'} || 'vi'; + system("$editor $filename"); + if ($? == -1) { + die "failed to execute $editor: $!"; + } elsif ($? & 127) { + die "$editor died with signal " . ($? & 127) . ' '. + (($? & 128) ? 'with' : 'without') . + ' coredump'; + } elsif ($? >> 8) { + die "$editor exited with code " . ($? >> 8); + } +} + +sub inspect { + my ($input, $result, $user, $what) = @_; + my ($learntype, $type); + + my ($fh, $filename) = tempfile(); + + $type = $result->{isspam} eq 'True' ? TYPE_SPAM : TYPE_HAM; + + print $fh "Status: ".($type == TYPE_SPAM ? "S" : "H")."\n"; + print $fh "User: $user\n"; + print $fh "Item: $what\n"; + print $fh "\n"; + print $fh $input; + close $fh; + + edit($filename); + + open(my $fh, '<', $filename) or + abend(EX_NOINPUT, "can't read temp file $filename: $!"); + while (<$fh>) { + chomp; + if (/^Status:\s*(.)/) { + $learntype = learntype($1); + last; + } + last if (/^\s*$/); + } + close $fh; + unlink $filename; + + if (defined($learntype) + && (defined($assume_status) || $learntype != $type)) { + print "Learned $learntype\n"; + my $res = $spamc->learn($input, $learntype); + abend(EX_UNAVAILABLE, $spamc->{resp_msg}) unless defined $res; + print "RES $res\n"; + } +} + +sub learn_user { + my $uref = shift; + print "Inspecting user ".$uref->{user_name}. "\n"; + my %ctr; + + if ($uref->{view_skills}) { + resume_check($uref, \%ctr, \&inspect); + } + + for my $t (@enable_trackers) { + debug("$uref->{user_name}: checking $t"); + general_tracker_check($t, $uref, \%ctr, \&inspect); + } +} + +my $action = defined($learn) ? \&learn_user : \&check_user; + +foreach my $uref (userlist_collect @ARGV) { + &{$action}($uref); +} + +backend_done; diff --git a/db/mysql/table_user.structure b/db/mysql/table_user.structure index 2d6f7d8..ad62d1b 100644 --- a/db/mysql/table_user.structure +++ b/db/mysql/table_user.structure @@ -33,6 +33,7 @@ CREATE TABLE `user` ( `email_new` text, `people_view_skills` int(11) NOT NULL DEFAULT '0', `people_resume` text NOT NULL, + `resume_spamscore` int(2) NOT NULL DEFAULT '0', `timezone` varchar(64) DEFAULT 'GMT', `theme` varchar(15) DEFAULT '', `email_hide` varchar(3) DEFAULT '0', diff --git a/frontend/php/include/html.php b/frontend/php/include/html.php index 12b15e4..40f79a4 100644 --- a/frontend/php/include/html.php +++ b/frontend/php/include/html.php @@ -235,39 +235,43 @@ function html_splitpage ($how) function html_nextprev ($search_url, $rows, $rows_returned, $varprefix=false) { - global $offset, $max_rows; - if (!$varprefix) - { $varprefix = ''; } + $varprefix = ''; else - { $varprefix .= '_'; } + $varprefix .= '_'; + $var_offset = $varprefix . 'offset'; + $var_max_rows = $varprefix . 'max_rows'; + $var_results = $varprefix . 'results'; + + global ${$var_offset}, ${$var_max_rows}; + $l_offset = ${$var_offset}; + $l_max_rows = ${$var_max_rows}; - if (($rows_returned > $rows) || ($offset != 0)) + if (($rows_returned > $rows) || ($l_offset != 0)) { print "\n<br /><h5 class=\"nextprev\">\n"; - if ($offset != 0) - { - print '<a href="'.$search_url.'&'.$varprefix.'offset='.($offset-$rows).'&'.$varprefix.'max_rows='.$max_rows.'#'.$varprefix.'results">'; - print '<img src="'.$GLOBALS['sys_home'].'images/'.SV_THEME.'.theme/arrows/previous.png" border="0" alt="'._("Previous Results").'" />'._("Previous Results").'</a>'; - - } + if ($l_offset != 0) + { + print '<a href="'.$search_url.'&'.$var_offset.'='.($l_offset-$rows).'&'.$var_max_rows.'='.$l_max_rows.'#'.$var_results.'">'; + print '<img src="'.$GLOBALS['sys_home'].'images/'.SV_THEME.'.theme/arrows/previous.png" border="0" alt="'._("Previous Results").'" />'._("Previous Results").'</a>'; + } else - { - print '<img src="'.$GLOBALS['sys_home'].'images/'.SV_THEME.'.theme/arrows/previousgrey.png" border="0" alt="'._("Previous Results").'" /><em>'._("Previous Results").'</em>'; - } + { + print '<img src="'.$GLOBALS['sys_home'].'images/'.SV_THEME.'.theme/arrows/previousgrey.png" border="0" alt="'._("Previous Results").'" /><em>'._("Previous Results").'</em>'; + } print " "; if ($rows_returned > $rows) - { - print '<a href="'.$search_url.'&'.$varprefix.'offset='.($offset+$rows).'&'.$varprefix.'max_rows='.$max_rows.'#'.$varprefix.'results">'; - print _("Next Results").' <img src="'.$GLOBALS['sys_home'].'images/'.SV_THEME.'.theme/arrows/next.png" border="0" alt="'._("Next Results").'" /></a>'; - } + { + print '<a href="'.$search_url.'&'.$var_offset.'='.($l_offset+$rows).'&'.$var_max_rows.'='.$l_max_rows.'#'.$var_results.'">'; + print _("Next Results").' <img src="'.$GLOBALS['sys_home'].'images/'.SV_THEME.'.theme/arrows/next.png" border="0" alt="'._("Next Results").'" /></a>'; + } else - { - print '<em>'._("Next Results").'</em> <img src="'.$GLOBALS['sys_home'].'images/'.SV_THEME.'.theme/arrows/nextgrey.png" border="0" alt="'._("Next Results").'" />'; - } + { + print '<em>'._("Next Results").'</em> <img src="'.$GLOBALS['sys_home'].'images/'.SV_THEME.'.theme/arrows/nextgrey.png" border="0" alt="'._("Next Results").'" />'; + } print "</h5>\n"; } diff --git a/frontend/php/include/spam.php b/frontend/php/include/spam.php index efe1744..d7103c2 100644 --- a/frontend/php/include/spam.php +++ b/frontend/php/include/spam.php @@ -24,20 +24,20 @@ if (!empty($GLOBALS['sys_spamcheck_spamassassin'])) { if ($GLOBALS['sys_spamcheck_spamassassin'] == 1) - { $GLOBALS['sys_spamcheck_spamassassin'] = "anonymous"; } + $GLOBALS['sys_spamcheck_spamassassin'] = "anonymous"; elseif ($GLOBALS['sys_spamcheck_spamassassin'] == 2) - { $GLOBALS['sys_spamcheck_spamassassin'] = "all"; } + $GLOBALS['sys_spamcheck_spamassassin'] = "all"; } $GLOBALS['int_probablyspam'] = false; $GLOBALS['int_delayspamcheck_comment_id'] = false; -# Function to mark a spam. This assume that checks on whether the user +# Function to mark a spam. This assumes that checks on whether the user # has proper rights have been made already. function spam_flag ($item_id, $comment_id, $score, $group_id, $reporter_user_id=0) { if (!$reporter_user_id) - { $reporter_user_id = user_getid(); } + $reporter_user_id = user_getid(); # Check if the reported havent flagged the incriminated comment already $result = db_execute("SELECT id FROM trackers_spamscore WHERE item_id=? @@ -101,7 +101,7 @@ function spam_flag ($item_id, $comment_id, $score, $group_id, $reporter_user_id= # for anonymous post. We fill the database only for real users with positive # scores if ($affected_user_id == 100 && $newscore == $score) - { $newscore += 3; } + $newscore += 3; # Update the item spamscore fields if ($comment_id) @@ -115,23 +115,23 @@ function spam_flag ($item_id, $comment_id, $score, $group_id, $reporter_user_id= { # Get the current summary $summary = db_result(db_execute("SELECT summary FROM ".ARTIFACT." WHERE bug_id=?", - array($item_id)), - 0, 'summary'); + array($item_id)), + 0, 'summary'); $discussion_lock = array(); if ($newscore > 4) - { - if (strpos($summary, '[SPAM]') === FALSE) - $summary = '[SPAM] '.$summary; - $discussion_lock = array('discussion_lock' => 1); - } + { + if (strpos($summary, '[SPAM]') === FALSE) + $summary = '[SPAM] '.$summary; + $discussion_lock = array('discussion_lock' => 1); + } db_autoexecute(ARTIFACT, - array_merge(array('spamscore' => $newscore, - 'summary' => $summary), - $discussion_lock), - DB_AUTOQUERY_UPDATE, - 'bug_id=?', - array($item_id)); + array_merge(array('spamscore' => $newscore, + 'summary' => $summary), + $discussion_lock), + DB_AUTOQUERY_UPDATE, + 'bug_id=?', + array($item_id)); } fb(sprintf(_("Flagged (+%s, total spamscore: %s)"), $score, $newscore)); @@ -139,7 +139,7 @@ function spam_flag ($item_id, $comment_id, $score, $group_id, $reporter_user_id= # If the total spamscore is superior to 4, the content is supposedly # confirmed spam, then increment the user spamscore if ($newscore < 5) - { return true; } + return true; # If the affected_user_id is anonymous, end here, obviously we cannot # change any personal spamscore @@ -154,7 +154,7 @@ function spam_flag ($item_id, $comment_id, $score, $group_id, $reporter_user_id= # (we do not want a single user being able to increment by more than one # another user spamscore) if (spam_get_user_score($affected_user_id, $reporter_user_id) > 1) - { return true; } + return true; # If the reporter is not member of the project that owns the item, # not increment user spamscore @@ -169,7 +169,7 @@ function spam_flag ($item_id, $comment_id, $score, $group_id, $reporter_user_id= # Update the user spamscore field db_execute("UPDATE user SET spamscore=? WHERE user_id=?", - array($userscore, $affected_user_id)); + array($userscore, $affected_user_id)); # No feedback about this last part, one user spamscore is the kind of info # that belongs to site admins territory. @@ -195,43 +195,42 @@ function spam_unflag ($item_id, $comment_id, $tracker, $group_id) { db_execute("UPDATE ".$tracker."_history SET spamscore=0 WHERE bug_history_id=? AND field_name='details' AND bug_id=?", - array($comment_id, $item_id)); + array($comment_id, $item_id)); } else { db_execute("UPDATE $tracker SET spamscore=0 WHERE bug_id=? AND group_id=?", - array($item_id, $group_id)); + array($item_id, $group_id)); } } - # Return the total score of a user function spam_get_user_score ($user_id=0, $set_by_user_id=0) { if (!$user_id) - { $user_id = user_getid(); } + $user_id = user_getid(); # Anonymous get always a score of 3 (requires two users to succesfully # mark as spam something, only one project member) if ($user_id == 100) - { return 3; } + return 3; $set_by_user_id_sql = ''; $set_by_user_id_params = array(); - if ($set_by_user_id) { - $set_by_user_id_sql = " AND reporter_user_id=?"; - $set_by_user_id_params = array($set_by_user_id); - } + if ($set_by_user_id) + { + $set_by_user_id_sql = " AND reporter_user_id=?"; + $set_by_user_id_params = array($set_by_user_id); + } # We cannot do a count because it does not allow us to use GROUP BY $userscore = 0; - $result = db_execute("SELECT score FROM trackers_spamscore WHERE affected_user_id=? $set_by_user_id_sql GROUP BY reporter_user_id", array_merge(array($user_id), $set_by_user_id_params)); + $result = db_execute("SELECT score FROM trackers_spamscore WHERE affected_user_id=? $set_by_user_id_sql GROUP BY reporter_user_id", + array_merge(array($user_id), $set_by_user_id_params)); while ($entry = db_fetch_array($result)) - { - $userscore++; - } + $userscore++; return $userscore; } diff --git a/frontend/php/siteadmin/spamlist.php b/frontend/php/siteadmin/spamlist.php index 4d31766..454ac91 100644 --- a/frontend/php/siteadmin/spamlist.php +++ b/frontend/php/siteadmin/spamlist.php @@ -19,7 +19,6 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. - require_once('../include/init.php'); register_globals_off(); @@ -27,42 +26,42 @@ session_require(array('group'=>'1','admin_flags'=>'A')); ###### See if we were asked to perform anything extract(sane_import('get', array('ban_user_id', 'wash_user_id', 'wash_ip', - 'max_rows', 'offset'))); + 'users_max_rows', 'users_offset', + 'ip_max_rows', 'ip_offset'))); if ($ban_user_id) -{ - if (!user_exists($ban_user_id)) - { fb(_("User not found"), 1); } - else - { + { + if (!user_exists($ban_user_id)) + fb(_("User not found"), 1); + else user_delete($ban_user_id); - } -} + } if ($wash_user_id) -{ - if (!user_exists($wash_user_id)) - { fb(_("User not found"), 1); } - else - { - # Update the user spamscore field - db_execute("UPDATE user SET spamscore='0' WHERE user_id=?", array($wash_user_id)); - - # Previous comment flagged as spam will stay as such. - # We just changed the affected user id that it wont affect this guy - # any more. - # We assume that message flagged as spam really were. - # (we may change that in the future, depending on user experience) - db_execute("UPDATE trackers_spamscore SET affected_user_id='100' WHERE affected_user_id=?", - array($wash_user_id)); + { + if (!user_exists($wash_user_id)) + { fb(_("User not found"), 1); } + else + { + # Update the user spamscore field + db_execute("UPDATE user SET spamscore='0' WHERE user_id=?", + array($wash_user_id)); + + # Previous comment flagged as spam will stay as such. + # We just changed the affected user id that it wont affect this guy + # any more. + # We assume that message flagged as spam really were. + # (we may change that in the future, depending on user experience) + db_execute("UPDATE trackers_spamscore SET affected_user_id='100' WHERE affected_user_id=?", + array($wash_user_id)); - } + } } if ($wash_ip) -{ - db_execute("DELETE FROM trackers_spamban WHERE ip=?", array($wash_ip)); -} + { + db_execute("DELETE FROM trackers_spamban WHERE ip=?", array($wash_ip)); + } @@ -80,121 +79,135 @@ $title_arr[]=_("Wash score"); $title_arr[]=_("Incriminated content"); $title_arr[]=_("Flagged by"); -if (!isset($max_rows)) -{ $max_rows = 50; } +if (!isset($users_max_rows)) + $users_max_rows = 50; else -{ $max_rows = intval($max_rows); } + $users_max_rows = intval($users_max_rows); -if (!isset($offset)) -{ $offset = 0; } +if (!isset($users_offset)) + $users_offset = 0; else -{ $offset = intval($offset); } + $users_offset = intval($users_offset); -$result = db_execute("SELECT user_name,realname,user_id,spamscore FROM user WHERE status='A' AND spamscore > 0 ORDER BY spamscore DESC LIMIT ?,?", array($offset,($max_rows+1))); +$result = db_execute("SELECT user_name,realname,user_id,spamscore FROM user WHERE status='A' AND spamscore > 0 ORDER BY spamscore DESC LIMIT ?,?", array($users_offset,($users_max_rows+1))); if (!db_numrows($result)) -{ - print '<p>'._("No suspects found").'</p>'; -} + { + print '<p>'._("No suspects found").'</p>'; + } else -{ - print html_build_list_table_top($title_arr); + { + print html_build_list_table_top($title_arr); - $i = 0; - while ($entry = db_fetch_array($result)) - { - $i++; - - # the sql was artificially asked to search more result than the number - # we print. If $i > $max, it means that there were more results than - # the max, we wont print these more, but below we will add next/prev - # links - if ($i > $max_rows) - { break; } - - $res_score = db_execute("SELECT trackers_spamscore.artifact,trackers_spamscore.item_id,trackers_spamscore.comment_id,user.user_name FROM trackers_spamscore,user WHERE trackers_spamscore.affected_user_id=? AND user.user_id=trackers_spamscore.reporter_user_id LIMIT 50", array($entry['user_id'])); - $flagged_by = ''; - $incriminated_content = ''; - $seen_before = array(); - while ($entry_score = db_fetch_array($res_score)) - { - if (!isset($seen_before[$entry_score['user_name']])) - { - $flagged_by .= utils_user_link($entry_score['user_name']).', '; - $seen_before[$entry_score['user_name']] = true; - } + $i = 0; + while ($entry = db_fetch_array($result)) + { + $i++; + + # the sql was artificially asked to search more result than the number + # we print. If $i > $max, it means that there were more results than + # the max, we wont print these more, but below we will add next/prev + # links + if ($i > $users_max_rows) + break; + + $res_score = db_execute("SELECT trackers_spamscore.artifact,trackers_spamscore.item_id,trackers_spamscore.comment_id,user.user_name FROM trackers_spamscore,user WHERE trackers_spamscore.affected_user_id=? AND user.user_id=trackers_spamscore.reporter_user_id LIMIT 50", array($entry['user_id'])); + $flagged_by = ''; + $incriminated_content = ''; + $seen_before = array(); + while ($entry_score = db_fetch_array($res_score)) + { + if (!isset($seen_before[$entry_score['user_name']])) + { + $flagged_by .= utils_user_link($entry_score['user_name']).', '; + $seen_before[$entry_score['user_ |