Skip to content

Instantly share code, notes, and snippets.

@jawbs
Created February 25, 2012 23:26
Show Gist options
  • Save jawbs/bac2da6d69b841eec92a to your computer and use it in GitHub Desktop.
Save jawbs/bac2da6d69b841eec92a to your computer and use it in GitHub Desktop.
ACF Score v1.1
#!/usr/bin/perl
use strict;
use warnings;
use utf8;
use Database qw(return_row_array return_all_arrayref execute);
use Getopt::Long qw(GetOptions);
use IO::AtomicFile ();
use JSON qw(to_json);
our $VERSION = 1.1;
my $days = 60;
my $weights = {
'w' => .45, # posts count
'x' => .55, # thanks received count
'y' => .92, # posts count + thanks received count
'z' => .08 # thanks sent
};
&main( $days, $weights );
sub main {
my ( $days, $weights ) = @_;
my $json_file;
GetOptions( "json-file=s" => \$json_file );
my $cutoff_time = &get_cutoff_time( $days );
my $users = &get_users( $days, $cutoff_time );
&calculate_base_scores( $users, $weights );
&calculate_thanks_received_bonus_counts( $users, $weights );
&calculate_acf_scores( $users, $weights );
my $current_time = time;
&save_acf_scores_to_db( $users );
&set_last_updated_to_current_time( $current_time );
&save_acf_scores_data_to_json_file( $users, $current_time, $json_file ) if $json_file;
}
sub set_last_updated_to_current_time {
my $current_time = shift;
execute( q|REPLACE INTO phpbb_acf_scores (acf_score_id, acf_score_last_updated) VALUES (1,?)|, $current_time );
}
sub get_cutoff_time {
my $days = shift;
my ( $cutoff_time ) = return_row_array( q|SELECT UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL ? DAY))|, $days );
return $cutoff_time;
}
sub save_acf_scores_data_to_json_file {
my ( $users, $current_time, $json_file ) = @_;
my $json = &users_to_json( $users, $current_time );
my $FH = IO::AtomicFile->open( $json_file, "w" ) or die "unable to open '$json_file': $!";
print $FH &json_file_header_comment(), q|var usersACFScoreData = JSON.parse('|, $json, q|');|;
$FH->close() or die "couldn't install atomic file '$json_file': $!";
}
sub users_to_json {
my ( $users, $current_time ) = @_;
my $data_for_json = {
'LastUpdated' => $current_time,
'Version' => $VERSION,
'Users' => []
};
foreach my $user ( values %$users ) {
push( @{$data_for_json->{'Users'}},
{
'Username' => $user->{'username'},
'Posts' => int $user->{'posts'},
'Days' => int $user->{'days'},
'ThanksSent' => int $user->{'thanks_sent_count'},
'ThanksReceived' => int $user->{'thanks_received_count'},
'BaseScore' => 0 + $user->{'base_score'},
'ACFScore' => 0 + $user->{'acf_score'},
'ThanksReceivedBonus' => 0 + $user->{'thanks_received_bonus_count'}
}
);
}
return to_json( $data_for_json, {'utf8' => 1} );
}
sub save_acf_scores_to_db {
my $users = shift;
execute( q|UPDATE phpbb_users SET user_temp_acf_score = 0| );
map{ execute( q|UPDATE phpbb_users SET user_temp_acf_score = ? WHERE user_id = ?|, $_->{'acf_score'}, $_->{'user_id'} ) } values %$users;
execute( q|UPDATE phpbb_users SET user_acf_score = user_temp_acf_score| );
}
sub get_users {
my ( $days, $cutoff_time ) = @_;
my $users = {};
my $users_data = return_all_arrayref(q|SELECT
phpbb_users.user_id,
phpbb_users.username,
IF(DATEDIFF(NOW(),FROM_UNIXTIME(phpbb_users.user_regdate)) < ?, DATEDIFF(NOW(),FROM_UNIXTIME(phpbb_users.user_regdate)) + 1, ?) AS 'days',
COUNT(DISTINCT phpbb_posts.post_id) AS 'posts'
FROM
phpbb_users
INNER JOIN phpbb_posts ON (phpbb_posts.poster_id = phpbb_users.user_id AND phpbb_posts.post_time >= ?)
WHERE
phpbb_users.user_rank != 14
GROUP BY
phpbb_users.user_id|, $days, $days, $cutoff_time );
foreach my $row ( @$users_data ) {
my $user = {
'user_id' => $row->[0],
'username' => $row->[1],
'days' => $row->[2],
'posts' => $row->[3],
'thanks_received' => &get_thanks_received( $row->[0], $cutoff_time ),
'thanks_sent_count' => &get_thanks_sent_count( $row->[0], $cutoff_time ),
'thanks_received_bonus_count' => 0
};
$user->{'thanks_received_count'} = scalar( @{$user->{'thanks_received'}} );
$users->{$user->{'user_id'}} = $user;
}
return $users;
}
sub calculate_thanks_received_bonus_counts {
my ( $users, $weights ) = @_;
foreach my $user ( values %$users ) {
foreach my $thanks_user_id ( @{$user->{'thanks_received'}} ) {
next unless defined $users->{$thanks_user_id};
$user->{'thanks_received_bonus_count'} += $users->{$thanks_user_id}->{'base_score'} * $weights->{'z'};
}
$user->{'thanks_received_bonus_count'} = sprintf( "%.04f", $user->{'thanks_received_bonus_count'} );
}
}
sub calculate_score {
my ( $user, $weights ) = @_;
my $score = $user->{'posts'} * $weights->{'w'} * $weights->{'y'};
$score += ( $user->{'thanks_received_count'} + $user->{'thanks_received_bonus_count'} ) * $weights->{'x'} * $weights->{'y'};
$score += $user->{'thanks_sent_count'} * $weights->{'z'};
return $score / $user->{'days'};
}
sub calculate_base_scores {
my ( $users, $weights ) = @_;
map{ $_->{'base_score'} = sprintf( "%.05f", &calculate_score( $_, $weights ) ) } values %$users;
}
sub calculate_acf_scores {
my ( $users, $weights ) = @_;
map{ $_->{'acf_score'} = sprintf( "%.02f", &calculate_score( $_, $weights ) * 1000 ) } values %$users;
}
sub get_thanks_received {
my ( $user_id, $cutoff_time ) = @_;
my $data = return_all_arrayref( q|SELECT
thanks_received.user_id
FROM
phpbb_thanks thanks_received
WHERE
thanks_received.poster_id = ?
AND
thanks_received.thanks_time >= ?|, $user_id, $cutoff_time );
my @thanks = map{ $_->[0] } @$data;
return \@thanks;
}
sub get_thanks_sent_count {
my ( $user_id, $cutoff_time ) = @_;
my ( $thanks_count ) = return_row_array( q|SELECT
COUNT(thanks_sent.post_id)
FROM
phpbb_thanks thanks_sent
WHERE
thanks_sent.user_id = ?
AND
thanks_sent.thanks_time >= ?|, $user_id, $cutoff_time );
return $thanks_count;
}
sub json_file_header_comment {
return <<EOF
/*
ACF Scores Data v$VERSION
http://www.ambercutie.com/forums/viewtopic.php?t=7011
Please don't do anything serious with this data. It's just for fun. You do like fun, right?
*/
EOF
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment