2010-10-25 18:44:28 -05:00
"""
Karma - handle karma ( + + and - - ) tracking
Copyright ( C ) 2010 Brian S . Stephan
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 of the License , 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 / > .
"""
2010-10-23 22:52:15 -05:00
2012-07-27 02:18:01 -05:00
from math import floor
2010-10-23 22:52:15 -05:00
import re
2012-07-27 02:18:01 -05:00
import MySQLdb as mdb
2010-10-23 22:52:15 -05:00
from Module import Module
2010-10-24 09:37:43 -05:00
__author__ = " Mike Bloy <mike@bloy.org> "
__date__ = " $Oct 23, 2010 11:12:33 AM$ "
2010-10-23 22:52:15 -05:00
class Karma ( Module ) :
2012-12-19 21:06:53 -06:00
def __init__ ( self , irc , config ) :
2010-10-23 22:52:15 -05:00
"""
Upon creation , determine the save file location
"""
2012-12-19 21:06:53 -06:00
Module . __init__ ( self , irc , config )
2010-10-23 22:52:15 -05:00
2012-09-13 12:16:25 -05:00
pattern = " (?: \ ((.+?) \ )|( \ S+)) "
2010-11-23 21:45:47 -06:00
karmapattern = pattern + ' ( \ + \ +|--| \ +-|- \ +) ' + ' ( \ s+|$) '
2011-01-07 20:37:24 -06:00
querypattern = ' ^!rank \ s+(.*) '
2011-01-20 14:50:51 -06:00
reportpattern = ' ^!karma \ s+report \ s+(highest|lowest|positive|negative|top) '
2011-01-07 20:37:24 -06:00
statpattern = ' ^!karma \ s+stat \ s+(.*) '
2010-10-23 22:52:15 -05:00
self . karmare = re . compile ( karmapattern )
self . queryre = re . compile ( querypattern )
2010-11-23 22:05:03 -06:00
self . reportre = re . compile ( reportpattern )
self . statre = re . compile ( statpattern )
2010-10-23 22:52:15 -05:00
2010-10-27 17:59:01 -05:00
def db_init ( self ) :
2010-10-24 13:05:16 -05:00
# need to init the database if karma tables don't already exist
version = self . db_module_registered ( self . __class__ . __name__ )
if ( version == None ) :
# have to create the database tables
2012-07-27 02:18:01 -05:00
db = self . get_db ( )
2010-10-24 13:05:16 -05:00
try :
2012-07-27 02:18:01 -05:00
version = 1
cur = db . cursor ( mdb . cursors . DictCursor )
cur . execute ( '''
2010-10-24 13:05:16 -05:00
CREATE TABLE karma_log (
2012-07-27 02:18:01 -05:00
id SERIAL ,
karma_key VARCHAR ( 128 ) NOT NULL ,
2010-10-24 13:05:16 -05:00
delta INTEGER NOT NULL ,
2012-07-27 02:18:01 -05:00
who VARCHAR ( 64 ) NOT NULL ,
userhost VARCHAR ( 256 ) NOT NULL ,
karmatime TIMESTAMP DEFAULT CURRENT_TIMESTAMP
2012-07-27 14:57:41 -05:00
) ENGINE = InnoDB CHARACTER SET utf8 COLLATE utf8_bin
2012-07-27 02:18:01 -05:00
''' )
cur . execute ( ' CREATE INDEX karma_log_key_ix ON karma_log (karma_key) ' )
cur . execute ( ' CREATE INDEX karma_log_who_ix ON karma_log (who) ' )
cur . execute ( '''
2010-10-24 13:05:16 -05:00
CREATE VIEW karma_values AS
2012-07-27 02:18:01 -05:00
SELECT karma_key , SUM ( delta ) AS value
2010-10-24 13:05:16 -05:00
FROM karma_log
2012-07-27 02:18:01 -05:00
GROUP BY karma_key ''' )
cur . execute ( '''
2010-11-23 22:05:03 -06:00
CREATE VIEW karma_users AS
SELECT who , COUNT ( NULLIF ( delta , - 1 ) ) AS pos ,
COUNT ( NULLIF ( delta , 1 ) ) AS neg
FROM karma_log GROUP BY who ''' )
2012-07-27 02:18:01 -05:00
db . commit ( )
2011-06-14 21:22:56 -05:00
self . db_register_module_version ( self . __class__ . __name__ , version )
2012-07-27 02:18:01 -05:00
except mdb . Error as e :
db . rollback ( )
self . log . error ( " database error trying to create tables " )
self . log . exception ( e )
2011-06-14 21:22:56 -05:00
raise
2012-07-27 02:18:01 -05:00
finally : cur . close ( )
2010-12-01 10:58:04 -06:00
2011-01-07 23:09:07 -06:00
def do ( self , connection , event , nick , userhost , what , admin_unlocked ) :
2010-10-24 09:36:15 -05:00
""" look for karma strings at the start of messages """
2010-10-25 18:37:30 -05:00
2012-09-13 12:28:03 -05:00
# don't return anything, do this attempt regardless
2010-10-29 13:08:48 -05:00
if ( self . karmare . search ( what ) ) :
2012-09-13 12:28:03 -05:00
self . handle_karma_change ( connection , nick , userhost , what )
if ( self . queryre . search ( what ) ) :
2012-12-19 20:51:35 -06:00
return self . irc . reply ( event , self . handle_karma_query ( connection , nick , userhost , what ) )
2010-11-25 11:41:12 -06:00
elif ( self . statre . search ( what ) ) :
2012-12-19 20:51:35 -06:00
return self . irc . reply ( event , self . handle_stat_query ( connection , nick , userhost , what ) )
2010-11-25 12:59:15 -06:00
elif ( self . reportre . search ( what ) ) :
2012-12-19 20:51:35 -06:00
return self . irc . reply ( event , self . handle_report_query ( connection , nick , userhost , what ) )
2010-12-01 10:58:04 -06:00
2011-01-07 23:09:07 -06:00
def handle_karma_change ( self , connection , nick , userhost , what ) :
2010-10-24 09:36:15 -05:00
"""
handle the karma change and storage .
"""
2012-09-13 12:16:25 -05:00
if self . karmare . search ( what ) :
matches = self . karmare . findall ( what )
for match in matches :
key = match [ 0 ] if match [ 0 ] else match [ 1 ]
value = match [ 2 ]
if ( value == ' ++ ' ) :
self . karma_modify ( key , 1 , nick , userhost )
elif ( value == ' -- ' ) :
self . karma_modify ( key , - 1 , nick , userhost )
elif ( value == ' +- ' ) :
self . karma_modify ( key , 1 , nick , userhost )
self . karma_modify ( key , - 1 , nick , userhost )
elif ( value == ' -+ ' ) :
self . karma_modify ( key , - 1 , nick , userhost )
self . karma_modify ( key , 1 , nick , userhost )
2010-11-19 09:26:49 -06:00
2010-12-08 22:05:46 -06:00
def karma_modify ( self , key , value , nick , userhost ) :
2010-11-19 09:26:49 -06:00
"""
Go out to the database and update the karma value .
"""
2010-10-24 09:36:15 -05:00
2012-07-27 02:18:01 -05:00
db = self . get_db ( )
2010-10-24 09:36:15 -05:00
try :
2012-07-27 02:18:01 -05:00
cur = db . cursor ( mdb . cursors . DictCursor )
2010-10-24 13:05:16 -05:00
sql = '''
2012-07-27 02:18:01 -05:00
INSERT INTO karma_log ( karma_key , delta , who , userhost )
VALUES ( % s , % s , % s , % s )
2010-10-24 13:05:16 -05:00
'''
2012-07-27 16:34:57 -05:00
cur . execute ( sql , ( key . lower ( ) , value , nick , userhost ) )
2012-07-27 02:18:01 -05:00
db . commit ( )
except mdb . Error as e :
db . rollback ( )
self . log . error ( " database error modifying karma " )
self . log . exception ( e )
raise
finally : cur . close ( )
2010-11-25 12:59:15 -06:00
2011-01-07 23:09:07 -06:00
def handle_report_query ( self , connection , nick , userhost , what ) :
2010-11-25 12:59:15 -06:00
match = self . reportre . search ( what )
report = match . group ( 1 )
message = ' {nick} : the desired report is not yet implemented ' . format ( nick = nick )
query = None
header = None
if ( report == ' highest ' ) :
2012-07-27 02:18:01 -05:00
query = ' SELECT karma_key AS who, value FROM karma_values ORDER BY value DESC LIMIT 5 '
2010-11-25 12:59:15 -06:00
header = ' Top 5 karma recipients: '
elif ( report == ' lowest ' ) :
2012-07-27 02:18:01 -05:00
query = ' SELECT karma_key AS who, value FROM karma_values ORDER BY value ASC LIMIT 5 '
2010-11-25 12:59:15 -06:00
header = ' Bottom 5 karma recipients: '
elif ( report == ' positive ' ) :
2012-07-27 02:18:01 -05:00
query = ' SELECT who, pos AS value FROM karma_users ORDER BY pos DESC LIMIT 5 '
2010-11-25 13:05:23 -06:00
header = ' Top 5 Optimists: '
2010-11-25 12:59:15 -06:00
elif ( report == ' negative ' ) :
2012-07-27 02:18:01 -05:00
query = ' SELECT who, neg AS value FROM karma_users ORDER BY neg DESC LIMIT 5 '
2010-12-08 22:15:26 -06:00
header = ' Top 5 Pessimists: '
2011-01-20 10:08:20 -06:00
elif ( report == ' top ' ) :
2012-07-27 02:18:01 -05:00
query = ' SELECT who, pos+neg AS value FROM karma_users ORDER BY value DESC LIMIT 5 '
2011-01-20 10:08:20 -06:00
header = ' Top 5 Total Karma Givers: '
2010-11-25 12:59:15 -06:00
if ( query != None ) :
2012-07-27 02:18:01 -05:00
db = self . get_db ( )
2010-11-25 12:59:15 -06:00
list = [ ]
try :
2012-07-27 02:18:01 -05:00
cur = db . cursor ( mdb . cursors . DictCursor )
cur . execute ( query )
result = cur . fetchone ( )
2010-11-25 12:59:15 -06:00
while ( result != None ) :
2012-07-27 02:18:01 -05:00
list . append ( " {key} ( {value} ) " . format ( key = result [ ' who ' ] , value = result [ ' value ' ] ) )
result = cur . fetchone ( )
2010-11-25 12:59:15 -06:00
list = ' , ' . join ( list )
message = ' {header} {list} ' . format ( header = header , list = list )
2012-07-27 02:18:01 -05:00
except mdb . Error as e :
self . log . error ( " database error during report query " )
self . log . exception ( e )
raise
finally : cur . close ( )
2011-01-07 23:09:07 -06:00
return message
2010-11-25 12:59:15 -06:00
2011-01-07 23:09:07 -06:00
def handle_stat_query ( self , connection , nick , userhost , what ) :
2010-11-25 11:41:12 -06:00
match = self . statre . search ( what )
statnick = match . group ( 1 )
2012-07-27 02:18:01 -05:00
db = self . get_db ( )
2010-11-25 11:41:12 -06:00
reply = ' {nick} : {statnick} has never given karma ' . format ( nick = nick , statnick = statnick )
try :
2012-07-27 02:18:01 -05:00
cur = db . cursor ( mdb . cursors . DictCursor )
2010-11-25 11:41:12 -06:00
query = '''
SELECT pos , neg
FROM karma_users
WHERE who = : who
'''
2012-07-27 02:18:01 -05:00
cur . execute ( query , { ' who ' : statnick } )
value = cur . fetchone ( )
2010-11-25 11:41:12 -06:00
if ( value != None ) :
pos = value [ 0 ]
neg = value [ 1 ]
total = pos + neg ;
reply = ' {nick} : {statnick} has given {pos} postive karma and {neg} negative karma, for a total of {total} karma ' . format ( nick = nick , statnick = statnick , pos = pos , neg = neg , total = total )
2012-07-27 02:18:01 -05:00
except mdb . Error as e :
self . log . error ( " database error during handle stat query " )
self . log . exception ( e )
raise
finally : cur . close ( )
2010-11-25 11:41:12 -06:00
2011-01-07 23:09:07 -06:00
return reply
2010-10-24 09:36:15 -05:00
2011-01-07 23:09:07 -06:00
def handle_karma_query ( self , connection , nick , userhost , what ) :
2010-10-29 13:08:48 -05:00
match = self . queryre . search ( what )
2010-10-24 09:36:15 -05:00
key = match . group ( 1 )
2012-07-27 02:18:01 -05:00
db = self . get_db ( )
2010-10-24 13:05:16 -05:00
reply = ' {nick} : {key} has no karma ' . format ( nick = nick , key = key )
2010-10-24 09:36:15 -05:00
try :
2012-07-27 02:18:01 -05:00
cur = db . cursor ( mdb . cursors . DictCursor )
2010-10-24 13:05:16 -05:00
query = '''
SELECT value
FROM karma_values
2012-07-27 02:18:01 -05:00
WHERE karma_key = % s
2010-10-24 13:05:16 -05:00
'''
2012-07-27 16:34:57 -05:00
cur . execute ( query , ( key . lower ( ) , ) )
2012-07-27 02:18:01 -05:00
value = cur . fetchone ( )
2010-10-24 14:48:26 -05:00
2010-10-24 13:05:16 -05:00
if ( value != None ) :
2010-10-24 14:48:26 -05:00
query = '''
2012-07-27 02:18:01 -05:00
SELECT count ( * ) FROM karma_values WHERE value > % s
2010-10-24 14:48:26 -05:00
'''
2012-07-27 02:18:01 -05:00
cur . execute ( query , ( value [ ' value ' ] , ) )
rank = cur . fetchone ( )
rank = rank [ ' count(*) ' ] + 1 ;
reply = ' {0:s} : {1:s} has {2:d} points of karma (rank {3:d} ) ' . format (
nick , key , int ( floor ( value [ ' value ' ] ) ) , rank )
except mdb . Error as e :
self . log . error ( " database error during handle karma query " )
self . log . exception ( e )
raise
finally : cur . close ( )
2010-10-24 09:36:15 -05:00
2011-01-07 23:09:07 -06:00
return reply
2010-10-23 22:52:15 -05:00
if __name__ == " __main__ " :
print " Hello World "
2010-11-19 09:20:48 -06:00
# vi:tabstop=4:expandtab:autoindent