forked from GNUsocial/gnu-social
		
	
		
			
				
	
	
		
			452 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			452 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| /**
 | |
|  * Phergie
 | |
|  *
 | |
|  * PHP version 5
 | |
|  *
 | |
|  * LICENSE
 | |
|  *
 | |
|  * This source file is subject to the new BSD license that is bundled
 | |
|  * with this package in the file LICENSE.
 | |
|  * It is also available through the world-wide-web at this URL:
 | |
|  * http://phergie.org/license
 | |
|  *
 | |
|  * @category  Phergie
 | |
|  * @package   Phergie_Plugin_Karma
 | |
|  * @author    Phergie Development Team <team@phergie.org>
 | |
|  * @copyright 2008-2010 Phergie Development Team (http://phergie.org)
 | |
|  * @license   http://phergie.org/license New BSD License
 | |
|  * @link      http://pear.phergie.org/package/Phergie_Plugin_Karma
 | |
|  */
 | |
| 
 | |
| /**
 | |
|  * Handles requests for incrementation or decrementation of a maintained list
 | |
|  * of counters for specified terms.
 | |
|  *
 | |
|  * @category Phergie
 | |
|  * @package  Phergie_Plugin_Karma
 | |
|  * @author   Phergie Development Team <team@phergie.org>
 | |
|  * @license  http://phergie.org/license New BSD License
 | |
|  * @link     http://pear.phergie.org/package/Phergie_Plugin_Karma
 | |
|  * @uses     extension PDO
 | |
|  * @uses     extension pdo_sqlite
 | |
|  * @uses     Phergie_Plugin_Command pear.phergie.org
 | |
|  */
 | |
| class Phergie_Plugin_Karma extends Phergie_Plugin_Abstract
 | |
| {
 | |
|     /**
 | |
|      * SQLite object
 | |
|      *
 | |
|      * @var resource
 | |
|      */
 | |
|     protected $db = null;
 | |
| 
 | |
|     /**
 | |
|      * Prepared statement to add a new karma record
 | |
|      *
 | |
|      * @var PDOStatement
 | |
|      */
 | |
|     protected $insertKarma;
 | |
| 
 | |
|     /**
 | |
|      * Prepared statement to update an existing karma record
 | |
|      *
 | |
|      * @var PDOStatement
 | |
|      */
 | |
|     protected $updateKarma;
 | |
| 
 | |
|     /**
 | |
|      * Retrieves an existing karma record
 | |
|      *
 | |
|      * @var PDOStatement
 | |
|      */
 | |
|     protected $fetchKarma;
 | |
| 
 | |
|     /**
 | |
|      * Retrieves an existing fixed karma record
 | |
|      *
 | |
|      * @var PDOStatement
 | |
|      */
 | |
|     protected $fetchFixedKarma;
 | |
| 
 | |
|     /**
 | |
|      * Retrieves a positive answer for a karma comparison
 | |
|      *
 | |
|      * @var PDOStatement
 | |
|      */
 | |
|     protected $fetchPositiveAnswer;
 | |
| 
 | |
|     /**
 | |
|      * Retrieves a negative answer for a karma comparison
 | |
|      *
 | |
|      * @var PDOStatement
 | |
|      */
 | |
|     protected $fetchNegativeAnswer;
 | |
| 
 | |
|     /**
 | |
|      * Check for dependencies and initializes a database connection and
 | |
|      * prepared statements.
 | |
|      *
 | |
|      * @return void
 | |
|      */
 | |
|     public function onLoad()
 | |
|     {
 | |
|         $plugins = $this->getPluginHandler();
 | |
|         $plugins->getPlugin('Command');
 | |
|         $this->getDb();
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Initializes prepared statements used by the plugin.
 | |
|      *
 | |
|      * @return void
 | |
|      */
 | |
|     protected function initializePreparedStatements()
 | |
|     {
 | |
|         $this->fetchKarma = $this->db->prepare('
 | |
|             SELECT karma
 | |
|             FROM karmas
 | |
|             WHERE term = :term
 | |
|             LIMIT 1
 | |
|         ');
 | |
| 
 | |
|         $this->insertKarma = $this->db->prepare('
 | |
|             INSERT INTO karmas (term, karma)
 | |
|             VALUES (:term, :karma)
 | |
|         ');
 | |
| 
 | |
|         $this->updateKarma = $this->db->prepare('
 | |
|             UPDATE karmas
 | |
|             SET karma = :karma
 | |
|             WHERE term = :term
 | |
|         ');
 | |
| 
 | |
|         $this->fetchFixedKarma = $this->db->prepare('
 | |
|             SELECT karma
 | |
|             FROM fixed_karmas
 | |
|             WHERE term = :term
 | |
|             LIMIT 1
 | |
|         ');
 | |
| 
 | |
|         $this->fetchPositiveAnswer = $this->db->prepare('
 | |
|             SELECT answer
 | |
|             FROM positive_answers
 | |
|             ORDER BY RANDOM()
 | |
|             LIMIT 1
 | |
|         ');
 | |
| 
 | |
|         $this->fetchNegativeAnswer = $this->db->prepare('
 | |
|             SELECT answer
 | |
|             FROM negative_answers
 | |
|             ORDER BY RANDOM()
 | |
|             LIMIT 1
 | |
|         ');
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Returns a connection to the plugin database, initializing one if none
 | |
|      * is explicitly set.
 | |
|      *
 | |
|      * @return PDO Database connection
 | |
|      */
 | |
|     public function getDb()
 | |
|     {
 | |
|         if (empty($this->db)) {
 | |
|             $this->db = new PDO('sqlite:' . dirname(__FILE__) . '/Karma/karma.db');
 | |
|             $this->initializePreparedStatements();
 | |
|         }
 | |
|         return $this->db;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Sets the connection to the plugin database, mainly intended for unit
 | |
|      * testing.
 | |
|      *
 | |
|      * @param PDO $db Database connection
 | |
|      *
 | |
|      * @return Phergie_Plugin_Karma Provides a fluent interface
 | |
|      */
 | |
|     public function setDb(PDO $db)
 | |
|     {
 | |
|         $this->db = $db;
 | |
|         $this->initializePreparedStatements();
 | |
|         return $this;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Get the canonical form of a given term.
 | |
|      *
 | |
|      * In the canonical form all sequences of whitespace
 | |
|      * are replaced by a single space and all characters
 | |
|      * are lowercased.
 | |
|      *
 | |
|      * @param string $term Term for which a canonical form is required
 | |
|      *
 | |
|      * @return string Canonical term
 | |
|      */
 | |
|     protected function getCanonicalTerm($term)
 | |
|     {
 | |
|         $canonicalTerm = strtolower(preg_replace('|\s+|', ' ', trim($term, '()')));
 | |
|         switch ($canonicalTerm) {
 | |
|             case 'me':
 | |
|                 $canonicalTerm = strtolower($this->event->getNick());
 | |
|                 break;
 | |
|             case 'all':
 | |
|             case '*':
 | |
|             case 'everything':
 | |
|                 $canonicalTerm = 'everything';
 | |
|                 break;
 | |
|         }
 | |
|         return $canonicalTerm;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Intercepts a message and processes any contained recognized commands.
 | |
|      *
 | |
|      * @return void
 | |
|      */
 | |
|     public function onPrivmsg()
 | |
|     {
 | |
|         $message = $this->getEvent()->getText();
 | |
| 
 | |
|         $termPattern = '\S+?|\([^<>]+?\)+';
 | |
|         $actionPattern = '(?P<action>\+\+|--)';
 | |
| 
 | |
|         $modifyPattern = <<<REGEX
 | |
| 		{^
 | |
| 		(?J) # allow overwriting capture names
 | |
| 		\s*  # ignore leading whitespace
 | |
| 
 | |
| 		(?:  # start with ++ or -- before the term
 | |
|             $actionPattern
 | |
|             (?P<term>$termPattern)
 | |
| 		|   # follow the term with ++ or --
 | |
|             (?P<term>$termPattern)
 | |
| 			$actionPattern # allow no whitespace between the term and the action
 | |
| 		)
 | |
| 		$}ix
 | |
| REGEX;
 | |
| 
 | |
|         $versusPattern = <<<REGEX
 | |
|         {^
 | |
|         	(?P<term0>$termPattern)
 | |
|         		\s+(?P<method><|>)\s+
 | |
|         	(?P<term1>$termPattern)$#
 | |
|         $}ix
 | |
| REGEX;
 | |
| 
 | |
|         $match = null;
 | |
| 
 | |
|         if (preg_match($modifyPattern, $message, $match)) {
 | |
|             $action = $match['action'];
 | |
|             $term = $this->getCanonicalTerm($match['term']);
 | |
|             $this->modifyKarma($term, $action);
 | |
|         } elseif (preg_match($versusPattern, $message, $match)) {
 | |
|             $term0 = trim($match['term0']);
 | |
|             $term1 = trim($match['term1']);
 | |
|             $method = $match['method'];
 | |
|             $this->compareKarma($term0, $term1, $method);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Get the karma rating for a given term.
 | |
|      *
 | |
|      * @param string $term Term for which the karma rating needs to be
 | |
|      *        retrieved
 | |
|      *
 | |
|      * @return void
 | |
|      */
 | |
|     public function onCommandKarma($term)
 | |
|     {
 | |
|         $source = $this->getEvent()->getSource();
 | |
|         $nick = $this->getEvent()->getNick();
 | |
| 
 | |
|         $canonicalTerm = $this->getCanonicalTerm($term);
 | |
| 
 | |
|         $fixedKarma = $this->fetchFixedKarma($canonicalTerm);
 | |
|         if ($fixedKarma) {
 | |
|             $message = $nick . ': ' . $term . ' ' . $fixedKarma;
 | |
|             $this->doPrivmsg($source, $message);
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         $karma = $this->fetchKarma($canonicalTerm);
 | |
| 
 | |
|         $message = $nick . ': ';
 | |
| 
 | |
|         if ($term == 'me') {
 | |
|             $message .= 'You have';
 | |
|         } else {
 | |
|             $message .= $term . ' has';
 | |
|         }
 | |
| 
 | |
|         $message .= ' ';
 | |
| 
 | |
|         if ($karma) {
 | |
|             $message .= 'karma of ' . $karma;
 | |
|         } else {
 | |
|             $message .= 'neutral karma';
 | |
|         }
 | |
| 
 | |
|         $message .= '.';
 | |
| 
 | |
|         $this->doPrivmsg($source, $message);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Resets the karma for a term to 0.
 | |
|      *
 | |
|      * @param string $term Term for which to reset the karma rating
 | |
|      *
 | |
|      * @return void
 | |
|      */
 | |
|     public function onCommandReincarnate($term)
 | |
|     {
 | |
|         $data = array(
 | |
|             ':term' => $term,
 | |
|             ':karma' => 0
 | |
|         );
 | |
|         $this->updateKarma->execute($data);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Compares the karma between two terms. Optionally increases/decreases
 | |
|      * the karma of either term.
 | |
|      *
 | |
|      * @param string $term0  First term
 | |
|      * @param string $term1  Second term
 | |
|      * @param string $method Comparison method (< or >)
 | |
|      *
 | |
|      * @return void
 | |
|      */
 | |
|     protected function compareKarma($term0, $term1, $method)
 | |
|     {
 | |
|         $event = $this->getEvent();
 | |
|         $nick = $event->getNick();
 | |
|         $source = $event->getSource();
 | |
| 
 | |
|         $canonicalTerm0 = $this->getCanonicalTerm($term0);
 | |
|         $canonicalTerm1 = $this->getCanonicalTerm($term1);
 | |
| 
 | |
|         $fixedKarma0 = $this->fetchFixedKarma($canonicalTerm0);
 | |
|         $fixedKarma1 = $this->fetchFixedKarma($canonicalTerm1);
 | |
| 
 | |
|         if ($fixedKarma0 || $fixedKarma1) {
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         if ($canonicalTerm0 == 'everything') {
 | |
|             $change = $method == '<' ? '++' : '--';
 | |
|             $karma0 = 0;
 | |
|             $karma1 = $this->modifyKarma($canonicalTerm1, $change);
 | |
|         } elseif ($canonicalTerm1 == 'everything') {
 | |
|             $change = $method == '<' ? '--' : '++';
 | |
|             $karma0 = $this->modifyKarma($canonicalTerm0, $change);
 | |
|             $karma1 = 0;
 | |
|         } else {
 | |
|             $karma0 = $this->fetchKarma($canonicalTerm0);
 | |
|             $karma1 = $this->fetchKarma($canonicalTerm1);
 | |
|         }
 | |
| 
 | |
|         // Combining the first and second branches here causes an odd
 | |
|         // single-line lapse in code coverage, but the lapse disappears if
 | |
|         // they're separated
 | |
|         if ($method == '<' && $karma0 < $karma1) {
 | |
|             $replies = $this->fetchPositiveAnswer;
 | |
|         } elseif ($method == '>' && $karma0 > $karma1) {
 | |
|             $replies = $this->fetchPositiveAnswer;
 | |
|         } else {
 | |
|             $replies = $this->fetchNegativeAnswer;
 | |
|         }
 | |
|         $replies->execute();
 | |
|         $reply = $replies->fetchColumn();
 | |
| 
 | |
|         if (max($karma0, $karma1) == $karma1) {
 | |
|             list($canonicalTerm0, $canonicalTerm1) =
 | |
|                 array($canonicalTerm1, $canonicalTerm0);
 | |
|         }
 | |
| 
 | |
|         $message = str_replace(
 | |
|             array('%owner%','%owned%'),
 | |
|             array($canonicalTerm0, $canonicalTerm1),
 | |
|             $reply
 | |
|         );
 | |
| 
 | |
|         $this->doPrivmsg($source, $message);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Modifes a term's karma.
 | |
|      *
 | |
|      * @param string $term   Term to modify
 | |
|      * @param string $action Karma action (either ++ or --)
 | |
|      *
 | |
|      * @return int Modified karma rating
 | |
|      */
 | |
|     protected function modifyKarma($term, $action)
 | |
|     {
 | |
|         $karma = $this->fetchKarma($term);
 | |
|         if ($karma !== false) {
 | |
|             $statement = $this->updateKarma;
 | |
|         } else {
 | |
|             $statement = $this->insertKarma;
 | |
|         }
 | |
| 
 | |
|         $karma += ($action == '++') ? 1 : -1;
 | |
| 
 | |
|         $args = array(
 | |
|             ':term'  => $term,
 | |
|             ':karma' => $karma
 | |
|         );
 | |
|         $statement->execute($args);
 | |
| 
 | |
|         return $karma;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Returns the karma rating for a specified term for which the karma
 | |
|      * rating can be modified.
 | |
|      *
 | |
|      * @param string $term Term for which to fetch the corresponding karma
 | |
|      *        rating
 | |
|      *
 | |
|      * @return integer|boolean Integer value denoting the term's karma or
 | |
|      *         FALSE if there is the specified term has no associated karma
 | |
|      *         rating
 | |
|      */
 | |
|     protected function fetchKarma($term)
 | |
|     {
 | |
|         $this->fetchKarma->execute(array(':term' => $term));
 | |
|         $result = $this->fetchKarma->fetch(PDO::FETCH_ASSOC);
 | |
| 
 | |
|         if ($result === false) {
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         return (int) $result['karma'];
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Returns a phrase describing the karma rating for a specified term for
 | |
|      * which the karma rating is fixed.
 | |
|      *
 | |
|      * @param string $term Term for which to fetch the corresponding karma
 | |
|      *        rating
 | |
|      *
 | |
|      * @return string Phrase describing the karma rating, which may be append
 | |
|      *         to the term to form a complete response
 | |
|      */
 | |
|     protected function fetchFixedKarma($term)
 | |
|     {
 | |
|         $this->fetchFixedKarma->execute(array(':term' => $term));
 | |
|         $result = $this->fetchFixedKarma->fetch(PDO::FETCH_ASSOC);
 | |
| 
 | |
|         if ($result === false) {
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         return $result['karma'];
 | |
|     }
 | |
| }
 |