407 lines
13 KiB
PHP
407 lines
13 KiB
PHP
<?php
|
|
/**
|
|
* <pre>
|
|
* Invision Power Services
|
|
* IP.Board v3.1.4
|
|
* Facilitates reputation plugins
|
|
* Last Updated: $Date: 2010-09-29 20:23:38 -0400 (Wed, 29 Sep 2010) $
|
|
* </pre>
|
|
*
|
|
* @author Joshua Williams <josh@invisionpower.com>
|
|
* @package IP.Board
|
|
* @copyright (c) 2001 - 2009 Invision Power Services, Inc.
|
|
* @license http://www.invisionpower.com/community/board/license.html
|
|
* @link http://www.invisionpower.com
|
|
* @since Wednesday 14th May 2008 14:00
|
|
*/
|
|
|
|
class classReputationCache
|
|
{
|
|
/**
|
|
* Variable that determines if the reputation system is activated
|
|
*
|
|
* @access public
|
|
* @var boolean
|
|
*/
|
|
public $rep_system_on;
|
|
|
|
/**
|
|
* Error string
|
|
*
|
|
* @access public
|
|
* @var string
|
|
*/
|
|
public $error_message;
|
|
|
|
/**
|
|
* CONSTRUCTOR
|
|
*
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public function __construct()
|
|
{
|
|
$this->rep_system_on = ipsRegistry::$settings['reputation_enabled'];
|
|
}
|
|
|
|
/**
|
|
* Retuns an array for use in a join statement
|
|
*
|
|
* @access public
|
|
* @param string $type Type of content, ex; Post
|
|
* @param integer $type_id ID of the type, ex: pid
|
|
* @param string [$app] App for this content, by default the current application
|
|
* @return array
|
|
*/
|
|
public function getTotalRatingJoin( $type, $type_id, $app='' )
|
|
{
|
|
/* Online? */
|
|
if( ! $this->rep_system_on )
|
|
{
|
|
return array();
|
|
}
|
|
|
|
/* INIT */
|
|
$app = ( $app ) ? $app : ipsRegistry::$current_application;
|
|
|
|
/* Return the join array */
|
|
return array(
|
|
'select' => 'rep_cache.rep_points',
|
|
'from' => array( 'reputation_cache' => 'rep_cache' ),
|
|
'where' => "rep_cache.app='{$app}' AND rep_cache.type='{$type}' AND rep_cache.type_id={$type_id}",
|
|
'type' => 'left',
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Retuns an array for use in a join statement
|
|
*
|
|
* @access public
|
|
* @param string $type Type of content, ex; Post
|
|
* @param integer $type_id ID of the type, ex: pid
|
|
* @param string [$app] App for this content, by default the current application
|
|
* @return array
|
|
*/
|
|
public function getUserHasRatedJoin( $type, $type_id, $app='' )
|
|
{
|
|
/* Online? */
|
|
if( ! $this->rep_system_on )
|
|
{
|
|
return array();
|
|
}
|
|
|
|
/* INIT */
|
|
$app = ( $app ) ? $app : ipsRegistry::$current_application;
|
|
|
|
/* Return the join array */
|
|
return array(
|
|
'select' => 'rep_index.rep_rating as has_given_rep',
|
|
'from' => array( 'reputation_index' => 'rep_index' ),
|
|
'where' => "rep_index.app='{$app}' AND
|
|
rep_index.type='{$type}' AND
|
|
rep_index.type_id={$type_id} AND
|
|
rep_index.member_id=" . ipsRegistry::member()->getProperty( 'member_id' ),
|
|
'type' => 'left',
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Adds a rating to the index and updates caches
|
|
*
|
|
* @access public
|
|
* @param string $type Type of content, ex; Post
|
|
* @param integer $type_id ID of the type, ex: pid
|
|
* @param integer $rating Either 1 or -1
|
|
* @param string $message Message associated with this rating
|
|
* @param integer $member_id Id of the owner of the content being rated
|
|
* @param string [$app] App for this content, by default the current application
|
|
* @return bool
|
|
*/
|
|
public function addRate( $type, $type_id, $rating, $message='', $member_id=0, $app='' )
|
|
{
|
|
ipsRegistry::instance()->getClass('class_localization')->loadLanguageFile( array( 'public_global' ), 'core' );
|
|
|
|
/* Online? */
|
|
if( ! $this->rep_system_on )
|
|
{
|
|
$this->error_message = ipsRegistry::instance()->getClass( 'class_localization' )->words['reputation_offline'];
|
|
return false;
|
|
}
|
|
|
|
/* INIT */
|
|
$app = ( $app ) ? $app : ipsRegistry::$current_application;
|
|
$rating = intval( $rating );
|
|
|
|
if( ! ipsRegistry::member()->getProperty( 'member_id' ) )
|
|
{
|
|
$this->error_message = ipsRegistry::instance()->getClass( 'class_localization' )->words['reputation_guest'];
|
|
return false;
|
|
}
|
|
|
|
if( $rating != -1 && $rating != 1 )
|
|
{
|
|
$this->error_message = ipsRegistry::instance()->getClass( 'class_localization' )->words['reputation_invalid'];
|
|
return false;
|
|
}
|
|
|
|
/* Check the point types */
|
|
if( $rating == -1 && ipsRegistry::$settings['reputation_point_types'] == 'positive' )
|
|
{
|
|
$this->error_message = ipsRegistry::instance()->getClass( 'class_localization' )->words['reputation_invalid'];
|
|
return false;
|
|
}
|
|
|
|
if( $rating == 1 && ipsRegistry::$settings['reputation_point_types'] == 'negative' )
|
|
{
|
|
$this->error_message = ipsRegistry::instance()->getClass( 'class_localization' )->words['reputation_invalid'];
|
|
return false;
|
|
}
|
|
|
|
/* Day Cutoff */
|
|
$day_cutoff = time() - 86400;
|
|
|
|
/* Check Max Positive Votes */
|
|
if( $rating == 1 )
|
|
{
|
|
if( intval( ipsRegistry::member()->getProperty( 'g_rep_max_positive' ) ) === 0 )
|
|
{
|
|
$this->error_message = ipsRegistry::instance()->getClass( 'class_localization' )->words['reputation_quota_pos'];
|
|
return false;
|
|
}
|
|
|
|
$total = ipsRegistry::DB()->buildAndFetch( array(
|
|
'select' => 'count(*) as votes',
|
|
'from' => 'reputation_index',
|
|
'where' => 'member_id=' . ipsRegistry::member()->getProperty( 'member_id' ) . ' AND rep_rating=1 AND rep_date > ' . $day_cutoff
|
|
) );
|
|
|
|
if( $total['votes'] >= ipsRegistry::member()->getProperty( 'g_rep_max_positive' ) )
|
|
{
|
|
$this->error_message = ipsRegistry::instance()->getClass( 'class_localization' )->words['reputation_quota_pos'];
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/* Check Max Negative Votes */
|
|
if( $rating == -1 )
|
|
{
|
|
if( intval( ipsRegistry::member()->getProperty( 'g_rep_max_negative' ) ) === 0 )
|
|
{
|
|
$this->error_message = ipsRegistry::instance()->getClass( 'class_localization' )->words['reputation_quota_neg'];
|
|
return false;
|
|
}
|
|
|
|
$total = ipsRegistry::DB()->buildAndFetch( array(
|
|
'select' => 'count(*) as votes',
|
|
'from' => 'reputation_index',
|
|
'where' => 'member_id=' . ipsRegistry::member()->getProperty( 'member_id' ) . ' AND rep_rating=-1 AND rep_date > ' . $day_cutoff
|
|
) );
|
|
|
|
if( $total['votes'] >= ipsRegistry::member()->getProperty( 'g_rep_max_negative' ) )
|
|
{
|
|
$this->error_message = ipsRegistry::instance()->getClass( 'class_localization' )->words['reputation_quota_neg'];
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/* If no member id was passted in, we have to query it using the config file */
|
|
if( ! $member_id )
|
|
{
|
|
/* Reputation Config */
|
|
if( file_exists( IPSLib::getAppDir( $app ) . '/extensions/reputation.php' ) )
|
|
{
|
|
$rep_author_config = array();
|
|
require( IPSLib::getAppDir( $app ) . '/extensions/reputation.php' );
|
|
}
|
|
else
|
|
{
|
|
$this->error_message = ipsRegistry::instance()->getClass( 'class_localization' )->words['reputation_config'];
|
|
return false;
|
|
}
|
|
|
|
if( ! $rep_author_config[$type]['column'] || ! $rep_author_config[$type]['table'] )
|
|
{
|
|
$this->error_message = ipsRegistry::instance()->getClass( 'class_localization' )->words['reputation_config'];
|
|
return false;
|
|
}
|
|
|
|
/* Query the content author */
|
|
$content_author = ipsRegistry::DB()->buildAndFetch( array(
|
|
'select' => "{$rep_author_config[$type]['column']} as id",
|
|
'from' => $rep_author_config[$type]['table'],
|
|
'where' => "{$type}={$type_id}"
|
|
) );
|
|
|
|
$member_id = $content_author['id'];
|
|
}
|
|
|
|
if( ! ipsRegistry::$settings['reputation_can_self_vote'] && $member_id == ipsRegistry::member()->getProperty( 'member_id' ) )
|
|
{
|
|
$this->error_message = ipsRegistry::instance()->getClass( 'class_localization' )->words['reputation_yourown'];
|
|
return false;
|
|
}
|
|
|
|
/* Query the member group */
|
|
if( ipsRegistry::$settings['reputation_protected_groups'] )
|
|
{
|
|
$member_group = ipsRegistry::DB()->buildAndFetch( array( 'select' => 'member_group_id', 'from' => 'members', 'where' => "member_id={$member_id}" ) );
|
|
|
|
if( in_array( $member_group['member_group_id'], explode( ',', ipsRegistry::$settings['reputation_protected_groups'] ) ) )
|
|
{
|
|
$this->error_message = ipsRegistry::instance()->getClass( 'class_localization' )->words['reputation_protected'];
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/* Build the insert array */
|
|
$db_insert = array(
|
|
'member_id' => ipsRegistry::member()->getProperty( 'member_id' ),
|
|
'app' => $app,
|
|
'type' => $type,
|
|
'type_id' => $type_id,
|
|
'rep_date' => time(),
|
|
'rep_msg' => $message,
|
|
'rep_rating' => $rating,
|
|
);
|
|
|
|
/* Check for existing rating */
|
|
$current_rating = ipsRegistry::DB()->buildAndFetch( array(
|
|
'select' => '*',
|
|
'from' => 'reputation_index',
|
|
'where' => "app='{$app}' AND type='{$type}' AND type_id={$type_id} AND member_id=".ipsRegistry::member()->getProperty( 'member_id' ),
|
|
) );
|
|
|
|
/* Insert */
|
|
if( $current_rating )
|
|
{
|
|
//ipsRegistry::DB()->update( 'reputation_index', $db_insert, "app='{$app}' AND type='{$type}' AND type_id={$type_id} AND member_id=".ipsRegistry::member()->getProperty( 'member_id' ) );
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
ipsRegistry::DB()->insert( 'reputation_index', $db_insert );
|
|
}
|
|
|
|
/* Update type cache */
|
|
$this->_updateTypeCache( $app, $type, $type_id, $rating, $current_rating );
|
|
|
|
/* Get authors current rep */
|
|
$author_points = ipsRegistry::DB()->buildAndFetch( array(
|
|
'select' => 'pp_reputation_points',
|
|
'from' => 'profile_portal',
|
|
'where' => "pp_member_id={$member_id}"
|
|
) );
|
|
|
|
/* Figure out new rep */
|
|
if( $current_rating['rep_rating'] == -1 )
|
|
{
|
|
$author_points['pp_reputation_points'] += 1;
|
|
}
|
|
else if( $current_rating['rep_rating'] == 1 )
|
|
{
|
|
$author_points['pp_reputation_points'] -= 1;
|
|
}
|
|
$author_points['pp_reputation_points'] += $rating;
|
|
|
|
ipsRegistry::DB()->update( 'profile_portal', array( 'pp_reputation_points' => $author_points['pp_reputation_points'] ), "pp_member_id={$member_id}" );
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Returns an array of reputation information based on the points passed in
|
|
*
|
|
* @access public
|
|
* @param integer $points Number of points to base the repuation information on
|
|
* @return array 'text' and 'image'
|
|
*/
|
|
public function getReputation( $points )
|
|
{
|
|
/* INIT */
|
|
$cache = ipsRegistry::cache()->getCache( 'reputation_levels' );
|
|
$cache = is_array( $cache ) && count( $cache ) ? $cache : array();
|
|
$points = intval( $points );
|
|
|
|
if( count($cache) AND is_array($cache) )
|
|
{
|
|
foreach( $cache as $k => $r )
|
|
{
|
|
if( $r['level_points'] == 0 )
|
|
{
|
|
if( $points >= 0 && $points < intval( $cache[ $k -1 ]['level_points'] ) )
|
|
{
|
|
return array( 'text' => $r['level_title'], 'image' => $r['level_image'] ? ipsRegistry::$settings['public_dir'] . 'style_extra/reputation_icons/' . $r['level_image'] : '' );
|
|
}
|
|
else if( $points <= 0 && $points > intval( $cache[ $k + 1 ]['level_points'] ) )
|
|
{
|
|
return array( 'text' => $r['level_title'], 'image' => $r['level_image'] ? ipsRegistry::$settings['public_dir'] . 'style_extra/reputation_icons/' . $r['level_image'] : '' );
|
|
}
|
|
else if( $points == 0 )
|
|
{
|
|
return array( 'text' => $r['level_title'], 'image' => $r['level_image'] ? ipsRegistry::$settings['public_dir'] . 'style_extra/reputation_icons/' . $r['level_image'] : '' );
|
|
}
|
|
}
|
|
else if( $r['level_points'] > 0 )
|
|
{
|
|
if( $points >= intval( $r['level_points'] ) )
|
|
{
|
|
return array( 'text' => $r['level_title'], 'image' => $r['level_image'] ? ipsRegistry::$settings['public_dir'] . 'style_extra/reputation_icons/' . $r['level_image'] : '' );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( $points <= intval( $r['level_points'] ) && $points > intval( $cache[ $k + 1 ]['level_points'] ) )
|
|
{
|
|
return array( 'text' => $r['level_title'], 'image' => $r['level_image'] ? ipsRegistry::$settings['public_dir'] . 'style_extra/reputation_icons/' . $r['level_image'] : '' );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Return the lowest rep, if we're still here */
|
|
$r = array_pop( $cache );
|
|
return array( 'text' => $r['level_title'], 'image' => $r['level_image'] ? ipsRegistry::$settings['public_dir'] . 'style_extra/reputation_icons/' . $r['level_image'] : '' );
|
|
}
|
|
|
|
/**
|
|
* Handles updating and creating new caches
|
|
*
|
|
* @access private
|
|
* @param string $app App for this content
|
|
* @param string $type Type of content, ex; Post
|
|
* @param integer $type_id ID of the type, ex: pid
|
|
* @param integer $rating Either 1 or -1
|
|
* @param array $old_record If this is a revote, then this array contains the previous vote
|
|
* @return void
|
|
*/
|
|
private function _updateTypeCache( $app, $type, $type_id, $rating, $old_record )
|
|
{
|
|
/* Update type cache */
|
|
$type_cache = ipsRegistry::DB()->buildAndFetch( array(
|
|
'select' => '*',
|
|
'from' => 'reputation_cache',
|
|
'where' => "app='{$app}' AND type='$type' AND type_id='$type_id'",
|
|
) );
|
|
|
|
/* Update cache */
|
|
if( $type_cache )
|
|
{
|
|
/* Previous rating? */
|
|
if( $old_record['rep_rating'] == -1 )
|
|
{
|
|
$type_cache['rep_points'] += 1;
|
|
}
|
|
else if( $old_record['rep_rating'] == 1 )
|
|
{
|
|
$type_cache['rep_points'] -= 1;
|
|
}
|
|
|
|
ipsRegistry::DB()->update( 'reputation_cache', array( 'rep_points' => $type_cache['rep_points'] + $rating ), "app='{$app}' AND type='$type' AND type_id='$type_id'" );
|
|
}
|
|
/* Insert Cache */
|
|
else
|
|
{
|
|
ipsRegistry::DB()->insert( 'reputation_cache', array( 'app' => $app, 'type' => $type, 'type_id' => $type_id, 'rep_points' => $rating ) );
|
|
}
|
|
}
|
|
} |