Merge branch 'master' of git://git.assembla.com/fpdb
Conflicts: pyfpdb/DatabaseManager.py pyfpdb/TourneySummary.py setup.py
This commit is contained in:
commit
52ae2e6b1f
|
@ -50,8 +50,8 @@ class Gametype(MappedBase):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_or_create(session, siteId, gametype):
|
def get_or_create(session, siteId, gametype):
|
||||||
map = zip(
|
map = zip(
|
||||||
['type', 'base', 'category', 'limitType', 'smallBlind', 'bigBlind', 'smallBet', 'bigBet'],
|
['type', 'base', 'category', 'limitType', 'smallBlind', 'bigBlind', 'smallBet', 'bigBet', 'currency'],
|
||||||
['type', 'base', 'category', 'limitType', 'sb', 'bb', 'dummy', 'dummy', ])
|
['type', 'base', 'category', 'limitType', 'sb', 'bb', 'dummy', 'dummy', 'currency'])
|
||||||
gametype = dict([(new, gametype.get(old)) for new, old in map ])
|
gametype = dict([(new, gametype.get(old)) for new, old in map ])
|
||||||
|
|
||||||
hilo = "h"
|
hilo = "h"
|
||||||
|
@ -168,8 +168,8 @@ class HandInternal(DerivedStats):
|
||||||
'speed': 'speed',
|
'speed': 'speed',
|
||||||
'maxSeats': 'maxseats',
|
'maxSeats': 'maxseats',
|
||||||
'knockout': 'isKO',
|
'knockout': 'isKO',
|
||||||
'rebuyOrAddon': 'isRebuy',
|
'rebuy': 'isRebuy',
|
||||||
'headsUp': 'isHU',
|
'addOn': 'isAddOn',
|
||||||
'shootout': 'isShootout',
|
'shootout': 'isShootout',
|
||||||
'matrix': 'isMatrix',
|
'matrix': 'isMatrix',
|
||||||
'sng': 'isSNG',
|
'sng': 'isSNG',
|
||||||
|
@ -201,7 +201,7 @@ class HandInternal(DerivedStats):
|
||||||
|
|
||||||
# fetch and update tourney players
|
# fetch and update tourney players
|
||||||
for hp in self.handPlayers:
|
for hp in self.handPlayers:
|
||||||
tp = TourneyPlayer.get_or_create(session, tour.id, hp.playerId)
|
tp = TourneysPlayer.get_or_create(session, tour.id, hp.playerId)
|
||||||
# FIXME: other TourneysPlayers should be added here
|
# FIXME: other TourneysPlayers should be added here
|
||||||
|
|
||||||
session.flush()
|
session.flush()
|
||||||
|
@ -356,18 +356,20 @@ class HandPlayer(MappedBase):
|
||||||
class Site(object):
|
class Site(object):
|
||||||
"""Class reflecting Players db table"""
|
"""Class reflecting Players db table"""
|
||||||
INITIAL_DATA = [
|
INITIAL_DATA = [
|
||||||
(1 , 'Full Tilt Poker','USD'),
|
(1 , 'Full Tilt Poker','FT'),
|
||||||
(2 , 'PokerStars', 'USD'),
|
(2 , 'PokerStars', 'PS'),
|
||||||
(3 , 'Everleaf', 'USD'),
|
(3 , 'Everleaf', 'EV'),
|
||||||
(4 , 'Win2day', 'USD'),
|
(4 , 'Win2day', 'W2'),
|
||||||
(5 , 'OnGame', 'USD'),
|
(5 , 'OnGame', 'OG'),
|
||||||
(6 , 'UltimateBet', 'USD'),
|
(6 , 'UltimateBet', 'UB'),
|
||||||
(7 , 'Betfair', 'USD'),
|
(7 , 'Betfair', 'BF'),
|
||||||
(8 , 'Absolute', 'USD'),
|
(8 , 'Absolute', 'AB'),
|
||||||
(9 , 'PartyPoker', 'USD'),
|
(9 , 'PartyPoker', 'PP'),
|
||||||
(10, 'Partouche', 'EUR'),
|
(10, 'Partouche', 'PA'),
|
||||||
|
(11, 'Carbon', 'CA'),
|
||||||
|
(12, 'PKR', 'PK'),
|
||||||
]
|
]
|
||||||
INITIAL_DATA_KEYS = ('id', 'name', 'currency')
|
INITIAL_DATA_KEYS = ('id', 'name', 'code')
|
||||||
|
|
||||||
INITIAL_DATA_DICTS = [ dict(zip(INITIAL_DATA_KEYS, datum)) for datum in INITIAL_DATA ]
|
INITIAL_DATA_DICTS = [ dict(zip(INITIAL_DATA_KEYS, datum)) for datum in INITIAL_DATA ]
|
||||||
|
|
||||||
|
@ -388,7 +390,7 @@ class Tourney(MappedBase):
|
||||||
|
|
||||||
|
|
||||||
class TourneyType(MappedBase):
|
class TourneyType(MappedBase):
|
||||||
"""Class reflecting TourneysType db table"""
|
"""Class reflecting TourneyType db table"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_or_create(cls, session, **kwargs):
|
def get_or_create(cls, session, **kwargs):
|
||||||
|
@ -396,12 +398,12 @@ class TourneyType(MappedBase):
|
||||||
|
|
||||||
Required kwargs:
|
Required kwargs:
|
||||||
buyin fee speed maxSeats knockout
|
buyin fee speed maxSeats knockout
|
||||||
rebuyOrAddon headsUp shootout matrix sng
|
rebuy addOn shootout matrix sng currency
|
||||||
"""
|
"""
|
||||||
return get_or_create(cls, session, **kwargs)[0]
|
return get_or_create(cls, session, **kwargs)[0]
|
||||||
|
|
||||||
|
|
||||||
class TourneyPlayer(MappedBase):
|
class TourneysPlayer(MappedBase):
|
||||||
"""Class reflecting TourneysPlayers db table"""
|
"""Class reflecting TourneysPlayers db table"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -453,7 +455,7 @@ mapper (Gametype, gametypes_table, properties={
|
||||||
})
|
})
|
||||||
mapper (Player, players_table, properties={
|
mapper (Player, players_table, properties={
|
||||||
'playerHands': relation(HandPlayer, backref='player'),
|
'playerHands': relation(HandPlayer, backref='player'),
|
||||||
'playerTourney': relation(TourneyPlayer, backref='player'),
|
'playerTourney': relation(TourneysPlayer, backref='player'),
|
||||||
})
|
})
|
||||||
mapper (Site, sites_table, properties={
|
mapper (Site, sites_table, properties={
|
||||||
'gametypes': relation(Gametype, backref = 'site'),
|
'gametypes': relation(Gametype, backref = 'site'),
|
||||||
|
@ -471,7 +473,7 @@ mapper (Tourney, tourneys_table)
|
||||||
mapper (TourneyType, tourney_types_table, properties={
|
mapper (TourneyType, tourney_types_table, properties={
|
||||||
'tourneys': relation(Tourney, backref='type'),
|
'tourneys': relation(Tourney, backref='type'),
|
||||||
})
|
})
|
||||||
mapper (TourneyPlayer, tourneys_players_table)
|
mapper (TourneysPlayer, tourneys_players_table)
|
||||||
|
|
||||||
class LambdaKeyDict(defaultdict):
|
class LambdaKeyDict(defaultdict):
|
||||||
"""Operates like defaultdict but passes key argument to the factory function"""
|
"""Operates like defaultdict but passes key argument to the factory function"""
|
||||||
|
|
|
@ -45,6 +45,7 @@ autorates_table = Table('Autorates', metadata,
|
||||||
gametypes_table = Table('Gametypes', metadata,
|
gametypes_table = Table('Gametypes', metadata,
|
||||||
Column('id', SmallInteger, primary_key=True),
|
Column('id', SmallInteger, primary_key=True),
|
||||||
Column('siteId', SmallInteger, ForeignKey("Sites.id"), nullable=False), # SMALLINT
|
Column('siteId', SmallInteger, ForeignKey("Sites.id"), nullable=False), # SMALLINT
|
||||||
|
Column('currency', String(4), nullable=False), # varchar(4) NOT NULL
|
||||||
Column('type', String(4), nullable=False), # char(4) NOT NULL
|
Column('type', String(4), nullable=False), # char(4) NOT NULL
|
||||||
Column('base', String(4), nullable=False), # char(4) NOT NULL
|
Column('base', String(4), nullable=False), # char(4) NOT NULL
|
||||||
Column('category', String(9), nullable=False), # varchar(9) NOT NULL
|
Column('category', String(9), nullable=False), # varchar(9) NOT NULL
|
||||||
|
@ -354,7 +355,7 @@ settings_table = Table('Settings', metadata,
|
||||||
sites_table = Table('Sites', metadata,
|
sites_table = Table('Sites', metadata,
|
||||||
Column('id', SmallInteger, primary_key=True),
|
Column('id', SmallInteger, primary_key=True),
|
||||||
Column('name', String(32), nullable=False), # varchar(32) NOT NULL
|
Column('name', String(32), nullable=False), # varchar(32) NOT NULL
|
||||||
Column('currency', String(3), nullable=False), # char(3) NOT NULL
|
Column('code', String(2), nullable=False), # char(2) NOT NULL
|
||||||
mysql_charset='utf8',
|
mysql_charset='utf8',
|
||||||
mysql_engine='InnoDB',
|
mysql_engine='InnoDB',
|
||||||
)
|
)
|
||||||
|
@ -368,17 +369,11 @@ tourneys_table = Table('Tourneys', metadata,
|
||||||
Column('prizepool', Integer), # INT NOT NULL
|
Column('prizepool', Integer), # INT NOT NULL
|
||||||
Column('tourStartTime', DateTime), # DATETIME NOT NULL
|
Column('tourStartTime', DateTime), # DATETIME NOT NULL
|
||||||
Column('tourEndTime', DateTime), # DATETIME
|
Column('tourEndTime', DateTime), # DATETIME
|
||||||
Column('buyinChips', Integer), # INT
|
|
||||||
Column('tourneyName', String(40)), # varchar(40)
|
Column('tourneyName', String(40)), # varchar(40)
|
||||||
# Mask use : 1=Positionnal Winnings|2=Match1|4=Match2|...|pow(2,n)=Matchn
|
# Mask use : 1=Positionnal Winnings|2=Match1|4=Match2|...|pow(2,n)=Matchn
|
||||||
Column('matrixIdProcessed',SmallInteger, default=0), # TINYINT UNSIGNED DEFAULT 0
|
Column('matrixIdProcessed',SmallInteger, default=0), # TINYINT UNSIGNED DEFAULT 0
|
||||||
Column('rebuyChips', Integer, default=0), # INT DEFAULT 0
|
Column('totalRebuyCount', Integer, default=0), # INT DEFAULT 0
|
||||||
Column('addonChips', Integer, default=0), # INT DEFAULT 0
|
Column('totalAddOnCount', Integer, default=0), # INT DEFAULT 0
|
||||||
Column('rebuyAmount', MoneyColumn, default=0), # INT DEFAULT 0
|
|
||||||
Column('addonAmount', MoneyColumn, default=0), # INT DEFAULT 0
|
|
||||||
Column('totalRebuys', Integer, default=0), # INT DEFAULT 0
|
|
||||||
Column('totalAddons', Integer, default=0), # INT DEFAULT 0
|
|
||||||
Column('koBounty', Integer, default=0), # INT DEFAULT 0
|
|
||||||
Column('comment', Text), # TEXT
|
Column('comment', Text), # TEXT
|
||||||
Column('commentTs', DateTime), # DATETIME
|
Column('commentTs', DateTime), # DATETIME
|
||||||
mysql_charset='utf8',
|
mysql_charset='utf8',
|
||||||
|
@ -390,36 +385,46 @@ Index('siteTourneyNo', tourneys_table.c.siteTourneyNo, tourneys_table.c.tourneyT
|
||||||
tourney_types_table = Table('TourneyTypes', metadata,
|
tourney_types_table = Table('TourneyTypes', metadata,
|
||||||
Column('id', Integer, primary_key=True),
|
Column('id', Integer, primary_key=True),
|
||||||
Column('siteId', SmallInteger, ForeignKey("Sites.id"), nullable=False),
|
Column('siteId', SmallInteger, ForeignKey("Sites.id"), nullable=False),
|
||||||
|
Column('currency', String(4), nullable=False), # varchar(4) NOT NULL
|
||||||
Column('buyin', Integer, nullable=False), # INT NOT NULL
|
Column('buyin', Integer, nullable=False), # INT NOT NULL
|
||||||
Column('fee', Integer, nullable=False, default=0), # INT NOT NULL
|
Column('fee', Integer, nullable=False), # INT NOT NULL
|
||||||
|
Column('buyInChips', Integer, nullable=False), # INT NOT NULL
|
||||||
Column('maxSeats', Boolean, nullable=False, default=-1), # INT NOT NULL DEFAULT -1
|
Column('maxSeats', Boolean, nullable=False, default=-1), # INT NOT NULL DEFAULT -1
|
||||||
|
Column('rebuy', Boolean, nullable=False, default=False), # BOOLEAN NOT NULL DEFAULT False
|
||||||
|
Column('rebuyCost', Integer), # INT
|
||||||
|
Column('rebuyChips', Integer), # INT
|
||||||
|
Column('addOn', Boolean, nullable=False, default=False), # BOOLEAN NOT NULL DEFAULT False
|
||||||
|
Column('addOnCost', Integer), # INT
|
||||||
|
Column('addOnChips', Integer), # INT
|
||||||
Column('knockout', Boolean, nullable=False, default=False), # BOOLEAN NOT NULL DEFAULT False
|
Column('knockout', Boolean, nullable=False, default=False), # BOOLEAN NOT NULL DEFAULT False
|
||||||
Column('rebuyOrAddon', Boolean, nullable=False, default=False), # BOOLEAN NOT NULL DEFAULT False
|
Column('koBounty', Integer), # INT
|
||||||
Column('speed', String(10)), # varchar(10)
|
Column('speed', String(10)), # varchar(10)
|
||||||
Column('headsUp', Boolean, nullable=False, default=False), # BOOLEAN NOT NULL DEFAULT False
|
|
||||||
Column('shootout', Boolean, nullable=False, default=False), # BOOLEAN NOT NULL DEFAULT False
|
Column('shootout', Boolean, nullable=False, default=False), # BOOLEAN NOT NULL DEFAULT False
|
||||||
Column('matrix', Boolean, nullable=False, default=False), # BOOLEAN NOT NULL DEFAULT False
|
Column('matrix', Boolean, nullable=False, default=False), # BOOLEAN NOT NULL DEFAULT False
|
||||||
Column('sng', Boolean, nullable=False, default=False), # BOOLEAN NOT NULL DEFAULT False
|
Column('sng', Boolean, nullable=False, default=False), # BOOLEAN NOT NULL DEFAULT False
|
||||||
|
Column('satellite', Boolean, nullable=False, default=False), # BOOLEAN NOT NULL DEFAULT False
|
||||||
|
Column('doubleOrNothing', Boolean, nullable=False, default=False), # BOOLEAN NOT NULL DEFAULT False
|
||||||
|
Column('guarantee', Integer, nullable=False, default=0), # INT NOT NULL DEFAULT 0
|
||||||
mysql_charset='utf8',
|
mysql_charset='utf8',
|
||||||
mysql_engine='InnoDB',
|
mysql_engine='InnoDB',
|
||||||
)
|
)
|
||||||
Index('tourneyTypes_all',
|
Index('tourneyTypes_all',
|
||||||
tourney_types_table.c.siteId, tourney_types_table.c.buyin, tourney_types_table.c.fee,
|
tourney_types_table.c.siteId, tourney_types_table.c.buyin, tourney_types_table.c.fee,
|
||||||
tourney_types_table.c.maxSeats, tourney_types_table.c.knockout, tourney_types_table.c.rebuyOrAddon,
|
tourney_types_table.c.maxSeats, tourney_types_table.c.knockout, tourney_types_table.c.rebuy,
|
||||||
tourney_types_table.c.speed, tourney_types_table.c.headsUp, tourney_types_table.c.shootout,
|
tourney_types_table.c.addOn, tourney_types_table.c.speed,
|
||||||
tourney_types_table.c.matrix, tourney_types_table.c.sng)
|
tourney_types_table.c.shootout, tourney_types_table.c.matrix, tourney_types_table.c.sng)
|
||||||
|
|
||||||
|
|
||||||
tourneys_players_table = Table('TourneysPlayers', metadata,
|
tourneys_players_table = Table('TourneysPlayers', metadata,
|
||||||
Column('id', BigIntColumn, primary_key=True),
|
Column('id', BigIntColumn, primary_key=True),
|
||||||
Column('tourneyId', Integer, ForeignKey("Tourneys.id"), nullable=False),
|
Column('tourneyId', Integer, ForeignKey("Tourneys.id"), nullable=False),
|
||||||
Column('playerId', Integer, ForeignKey("Players.id"), nullable=False),
|
Column('playerId', Integer, ForeignKey("Players.id"), nullable=False),
|
||||||
Column('payinAmount', Integer), # INT NOT NULL
|
|
||||||
Column('rank', Integer), # INT NOT NULL
|
Column('rank', Integer), # INT NOT NULL
|
||||||
Column('winnings', Integer), # INT NOT NULL
|
Column('winnings', Integer), # INT NOT NULL
|
||||||
Column('nbRebuys', Integer, default=0), # INT DEFAULT 0
|
Column('winningsCurrency', Text), # TEXT
|
||||||
Column('nbAddons', Integer, default=0), # INT DEFAULT 0
|
Column('rebuyCount', Integer, default=0), # INT DEFAULT 0
|
||||||
Column('nbKO', Integer, default=0), # INT DEFAULT 0
|
Column('addOnCount', Integer, default=0), # INT DEFAULT 0
|
||||||
|
Column('koCount', Integer, default=0), # INT DEFAULT 0
|
||||||
Column('comment', Text), # TEXT
|
Column('comment', Text), # TEXT
|
||||||
Column('commentTs', DateTime), # DATETIME
|
Column('commentTs', DateTime), # DATETIME
|
||||||
mysql_charset='utf8',
|
mysql_charset='utf8',
|
||||||
|
|
|
@ -53,7 +53,6 @@ log = logging.getLogger("db")
|
||||||
# FreePokerTools modules
|
# FreePokerTools modules
|
||||||
import SQL
|
import SQL
|
||||||
import Card
|
import Card
|
||||||
import Tourney
|
|
||||||
import Charset
|
import Charset
|
||||||
from Exceptions import *
|
from Exceptions import *
|
||||||
import Configuration
|
import Configuration
|
||||||
|
@ -75,7 +74,7 @@ except ImportError:
|
||||||
use_numpy = False
|
use_numpy = False
|
||||||
|
|
||||||
|
|
||||||
DB_VERSION = 119
|
DB_VERSION = 127
|
||||||
|
|
||||||
|
|
||||||
# Variance created as sqlite has a bunch of undefined aggregate functions.
|
# Variance created as sqlite has a bunch of undefined aggregate functions.
|
||||||
|
@ -1344,29 +1343,30 @@ class Database:
|
||||||
def fillDefaultData(self):
|
def fillDefaultData(self):
|
||||||
c = self.get_cursor()
|
c = self.get_cursor()
|
||||||
c.execute("INSERT INTO Settings (version) VALUES (%s);" % (DB_VERSION))
|
c.execute("INSERT INTO Settings (version) VALUES (%s);" % (DB_VERSION))
|
||||||
c.execute("INSERT INTO Sites (name,currency) VALUES ('Full Tilt Poker', 'USD')")
|
c.execute("INSERT INTO Sites (name,code) VALUES ('Full Tilt Poker', 'FT')")
|
||||||
c.execute("INSERT INTO Sites (name,currency) VALUES ('PokerStars', 'USD')")
|
c.execute("INSERT INTO Sites (name,code) VALUES ('PokerStars', 'PS')")
|
||||||
c.execute("INSERT INTO Sites (name,currency) VALUES ('Everleaf', 'USD')")
|
c.execute("INSERT INTO Sites (name,code) VALUES ('Everleaf', 'EV')")
|
||||||
c.execute("INSERT INTO Sites (name,currency) VALUES ('Win2day', 'USD')")
|
c.execute("INSERT INTO Sites (name,code) VALUES ('Win2day', 'W2')")
|
||||||
c.execute("INSERT INTO Sites (name,currency) VALUES ('OnGame', 'USD')")
|
c.execute("INSERT INTO Sites (name,code) VALUES ('OnGame', 'OG')")
|
||||||
c.execute("INSERT INTO Sites (name,currency) VALUES ('UltimateBet', 'USD')")
|
c.execute("INSERT INTO Sites (name,code) VALUES ('UltimateBet', 'UB')")
|
||||||
c.execute("INSERT INTO Sites (name,currency) VALUES ('Betfair', 'USD')")
|
c.execute("INSERT INTO Sites (name,code) VALUES ('Betfair', 'BF')")
|
||||||
c.execute("INSERT INTO Sites (name,currency) VALUES ('Absolute', 'USD')")
|
c.execute("INSERT INTO Sites (name,code) VALUES ('Absolute', 'AB')")
|
||||||
c.execute("INSERT INTO Sites (name,currency) VALUES ('PartyPoker', 'USD')")
|
c.execute("INSERT INTO Sites (name,code) VALUES ('PartyPoker', 'PP')")
|
||||||
c.execute("INSERT INTO Sites (name,currency) VALUES ('Partouche', 'EUR')")
|
c.execute("INSERT INTO Sites (name,code) VALUES ('Partouche', 'PA')")
|
||||||
c.execute("INSERT INTO Sites (name,currency) VALUES ('Carbon', 'USD')")
|
c.execute("INSERT INTO Sites (name,code) VALUES ('Carbon', 'CA')")
|
||||||
c.execute("INSERT INTO Sites (name,currency) VALUES ('PKR', 'USD')")
|
c.execute("INSERT INTO Sites (name,code) VALUES ('PKR', 'PK')")
|
||||||
if self.backend == self.SQLITE:
|
if self.backend == self.SQLITE:
|
||||||
c.execute("INSERT INTO TourneyTypes (id, siteId, buyin, fee) VALUES (NULL, 1, 0, 0);")
|
c.execute("""INSERT INTO TourneyTypes (id, siteId, currency, buyin, fee, buyInChips, maxSeats, knockout,
|
||||||
|
rebuy, addOn, speed, shootout, matrix)
|
||||||
|
VALUES (NULL, 1, 'USD', 0, 0, 0, 0, 0, 0, 0, NULL, 0, 0);""")
|
||||||
elif self.backend == self.PGSQL:
|
elif self.backend == self.PGSQL:
|
||||||
c.execute("""insert into TourneyTypes(siteId, buyin, fee, maxSeats, knockout
|
c.execute("""insert into TourneyTypes(siteId, currency, buyin, fee, buyInChips, maxSeats, knockout
|
||||||
,rebuyOrAddon, speed, headsUp, shootout, matrix)
|
,rebuy, addOn, speed, shootout, matrix)
|
||||||
values (1, 0, 0, 0, False, False, null, False, False, False);""")
|
values (1, 'USD', 0, 0, 0, 0, False, False, False, null, False, False);""")
|
||||||
elif self.backend == self.MYSQL_INNODB:
|
elif self.backend == self.MYSQL_INNODB:
|
||||||
c.execute("""insert into TourneyTypes(id, siteId, buyin, fee, maxSeats, knockout
|
c.execute("""insert into TourneyTypes(id, siteId, currency, buyin, fee, buyInChips, maxSeats, knockout
|
||||||
,rebuyOrAddon, speed, headsUp, shootout, matrix)
|
,rebuy, addOn, speed, shootout, matrix)
|
||||||
values (DEFAULT, 1, 0, 0, 0, False, False, null, False, False, False);""")
|
values (DEFAULT, 1, 'USD', 0, 0, 0, 0, False, False, False, null, False, False);""")
|
||||||
|
|
||||||
#end def fillDefaultData
|
#end def fillDefaultData
|
||||||
|
|
||||||
def rebuild_indexes(self, start=None):
|
def rebuild_indexes(self, start=None):
|
||||||
|
@ -1374,6 +1374,7 @@ class Database:
|
||||||
self.createAllIndexes()
|
self.createAllIndexes()
|
||||||
self.dropAllForeignKeys()
|
self.dropAllForeignKeys()
|
||||||
self.createAllForeignKeys()
|
self.createAllForeignKeys()
|
||||||
|
#end def rebuild_indexes
|
||||||
|
|
||||||
def rebuild_hudcache(self, h_start=None, v_start=None):
|
def rebuild_hudcache(self, h_start=None, v_start=None):
|
||||||
"""clears hudcache and rebuilds from the individual handsplayers records"""
|
"""clears hudcache and rebuilds from the individual handsplayers records"""
|
||||||
|
@ -1559,6 +1560,7 @@ class Database:
|
||||||
pids[p],
|
pids[p],
|
||||||
pdata[p]['startCash'],
|
pdata[p]['startCash'],
|
||||||
pdata[p]['seatNo'],
|
pdata[p]['seatNo'],
|
||||||
|
pdata[p]['sitout'],
|
||||||
pdata[p]['card1'],
|
pdata[p]['card1'],
|
||||||
pdata[p]['card2'],
|
pdata[p]['card2'],
|
||||||
pdata[p]['card3'],
|
pdata[p]['card3'],
|
||||||
|
@ -1793,8 +1795,9 @@ class Database:
|
||||||
hilo = "s"
|
hilo = "s"
|
||||||
elif game['category'] in ['razz','27_3draw','badugi']:
|
elif game['category'] in ['razz','27_3draw','badugi']:
|
||||||
hilo = "l"
|
hilo = "l"
|
||||||
tmp = self.insertGameTypes( (siteid, game['type'], game['base'], game['category'], game['limitType'], hilo,
|
tmp = self.insertGameTypes( (siteid, 'USD', game['type'], game['base'], game['category'], game['limitType'], hilo,
|
||||||
int(Decimal(game['sb'])*100), int(Decimal(game['bb'])*100), 0, 0) )
|
int(Decimal(game['sb'])*100), int(Decimal(game['bb'])*100), 0, 0) )
|
||||||
|
#FIXME: recognise currency
|
||||||
return tmp[0]
|
return tmp[0]
|
||||||
|
|
||||||
def getSqlPlayerIDs(self, pnames, siteid):
|
def getSqlPlayerIDs(self, pnames, siteid):
|
||||||
|
@ -1929,59 +1932,88 @@ class Database:
|
||||||
print "***Error sending finish: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
|
print "***Error sending finish: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
|
||||||
# end def send_finish_msg():
|
# end def send_finish_msg():
|
||||||
|
|
||||||
def tRecogniseTourneyType(self, tourney):
|
def createOrUpdateTourneyType(self, hand):
|
||||||
log.debug("Database.tRecogniseTourneyType")
|
tourneyTypeId = 1
|
||||||
typeId = 1
|
|
||||||
# Check if Tourney exists, and if so retrieve TTypeId : in that case, check values of the ttype
|
# Check if Tourney exists, and if so retrieve TTypeId : in that case, check values of the ttype
|
||||||
cursor = self.get_cursor()
|
cursor = self.get_cursor()
|
||||||
cursor.execute (self.sql.query['getTourneyTypeIdByTourneyNo'].replace('%s', self.sql.query['placeholder']),
|
cursor.execute (self.sql.query['getTourneyTypeIdByTourneyNo'].replace('%s', self.sql.query['placeholder']),
|
||||||
(tourney.tourNo, tourney.siteId)
|
(hand.tourNo, hand.siteId)
|
||||||
)
|
)
|
||||||
result=cursor.fetchone()
|
result=cursor.fetchone()
|
||||||
|
|
||||||
expectedValues = { 1 : "buyin", 2 : "fee", 4 : "isKO", 5 : "isRebuy", 6 : "speed",
|
expectedValues = { 1 : "buyin", 2 : "fee", 4 : "isKO", 5 : "isRebuy", 6 : "speed",
|
||||||
7 : "isHU", 8 : "isShootout", 9 : "isMatrix" }
|
7 : "isShootout", 8 : "isMatrix" }
|
||||||
typeIdMatch = True
|
tourneyTypeIdMatch = True
|
||||||
|
|
||||||
try:
|
try:
|
||||||
len(result)
|
tourneyTypeId = result[0]
|
||||||
typeId = result[0]
|
log.debug("Tourney found in db with Tourney_Type_ID = %d" % tourneyTypeId)
|
||||||
log.debug("Tourney found in db with Tourney_Type_ID = %d" % typeId)
|
|
||||||
for ev in expectedValues :
|
for ev in expectedValues :
|
||||||
if ( getattr( tourney, expectedValues.get(ev) ) <> result[ev] ):
|
if ( getattr( hand, expectedValues.get(ev) ) <> result[ev] ):
|
||||||
log.debug("TypeId mismatch : wrong %s : Tourney=%s / db=%s" % (expectedValues.get(ev), getattr( tourney, expectedValues.get(ev)), result[ev]) )
|
log.debug("TypeId mismatch : wrong %s : Tourney=%s / db=%s" % (expectedValues.get(ev), getattr( hand, expectedValues.get(ev)), result[ev]) )
|
||||||
typeIdMatch = False
|
tourneyTypeIdMatch = False
|
||||||
#break
|
#break
|
||||||
except:
|
except:
|
||||||
# Tourney not found : a TourneyTypeId has to be found or created for that specific tourney
|
# Tourney not found : a TourneyTypeId has to be found or created for that specific tourney
|
||||||
typeIdMatch = False
|
tourneyTypeIdMatch = False
|
||||||
|
|
||||||
if typeIdMatch == False :
|
if tourneyTypeIdMatch == False :
|
||||||
# Check for an existing TTypeId that matches tourney info (buyin/fee, knockout, rebuy, speed, matrix, shootout)
|
# Check for an existing TTypeId that matches tourney info, if not found create it
|
||||||
# if not found create it
|
|
||||||
log.debug("Searching for a TourneyTypeId matching TourneyType data")
|
|
||||||
cursor.execute (self.sql.query['getTourneyTypeId'].replace('%s', self.sql.query['placeholder']),
|
cursor.execute (self.sql.query['getTourneyTypeId'].replace('%s', self.sql.query['placeholder']),
|
||||||
(tourney.siteId, tourney.buyin, tourney.fee, tourney.isKO,
|
(hand.siteId, hand.buyinCurrency, hand.buyin, hand.fee, hand.isKO,
|
||||||
tourney.isRebuy, tourney.speed, tourney.isHU, tourney.isShootout, tourney.isMatrix)
|
hand.isRebuy, hand.isRebuy, hand.speed, hand.isShootout, hand.isMatrix)
|
||||||
)
|
)
|
||||||
result=cursor.fetchone()
|
result=cursor.fetchone()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
len(result)
|
tourneyTypeId = result[0]
|
||||||
typeId = result[0]
|
|
||||||
log.debug("Existing Tourney Type Id found : %d" % typeId)
|
|
||||||
except TypeError: #this means we need to create a new entry
|
except TypeError: #this means we need to create a new entry
|
||||||
log.debug("Tourney Type Id not found : create one")
|
cursor.execute (self.sql.query['insertTourneyType'].replace('%s', self.sql.query['placeholder']),
|
||||||
cursor.execute (self.sql.query['insertTourneyTypes'].replace('%s', self.sql.query['placeholder']),
|
(hand.siteId, hand.buyinCurrency, hand.buyin, hand.fee, hand.buyInChips,
|
||||||
(tourney.siteId, tourney.buyin, tourney.fee, tourney.isKO, tourney.isRebuy,
|
hand.isKO, hand.isRebuy,
|
||||||
tourney.speed, tourney.isHU, tourney.isShootout, tourney.isMatrix)
|
hand.isAddOn, hand.speed, hand.isShootout, hand.isMatrix)
|
||||||
)
|
)
|
||||||
typeId = self.get_last_insert_id(cursor)
|
tourneyTypeId = self.get_last_insert_id(cursor)
|
||||||
|
return tourneyTypeId
|
||||||
return typeId
|
#end def createOrUpdateTourneyType
|
||||||
#end def tRecogniseTourneyType
|
|
||||||
|
def createOrUpdateTourney(self, hand):
|
||||||
|
cursor = self.get_cursor()
|
||||||
|
cursor.execute (self.sql.query['getTourneyIdByTourneyNo'].replace('%s', self.sql.query['placeholder']),
|
||||||
|
(hand.siteId, hand.tourNo))
|
||||||
|
result=cursor.fetchone()
|
||||||
|
|
||||||
|
if result != None and len(result)==1:
|
||||||
|
tourneyId = result[0]
|
||||||
|
else:
|
||||||
|
cursor.execute (self.sql.query['insertTourney'].replace('%s', self.sql.query['placeholder']),
|
||||||
|
(hand.tourneyTypeId, hand.tourNo, None, None,
|
||||||
|
hand.startTime, None, None, None,
|
||||||
|
None, None))
|
||||||
|
tourneyId = self.get_last_insert_id(cursor)
|
||||||
|
return tourneyId
|
||||||
|
#end def createOrUpdateTourney
|
||||||
|
|
||||||
|
def createOrUpdateTourneysPlayers(self, hand):
|
||||||
|
tourneysPlayersIds=[]
|
||||||
|
for player in hand.players:
|
||||||
|
playerId = hand.dbid_pids[player[1]]
|
||||||
|
|
||||||
|
cursor = self.get_cursor()
|
||||||
|
cursor.execute (self.sql.query['getTourneysPlayersId'].replace('%s', self.sql.query['placeholder']),
|
||||||
|
(hand.tourneyId, playerId))
|
||||||
|
result=cursor.fetchone()
|
||||||
|
|
||||||
|
if result != None and len(result)==1:
|
||||||
|
tourneysPlayersIds.append(result[0])
|
||||||
|
else:
|
||||||
|
cursor.execute (self.sql.query['insertTourneysPlayer'].replace('%s', self.sql.query['placeholder']),
|
||||||
|
(hand.tourneyId, playerId, None, None, None, None, None, None, None, None))
|
||||||
|
tourneysPlayersIds.append(self.get_last_insert_id(cursor))
|
||||||
|
return tourneysPlayersIds
|
||||||
|
#end def createOrUpdateTourneysPlayers
|
||||||
|
#end class Database
|
||||||
|
|
||||||
# Class used to hold all the data needed to write a hand to the db
|
# Class used to hold all the data needed to write a hand to the db
|
||||||
# mainParser() in fpdb_parse_logic.py creates one of these and then passes it to
|
# mainParser() in fpdb_parse_logic.py creates one of these and then passes it to
|
||||||
|
@ -2028,7 +2060,6 @@ class HandToWrite:
|
||||||
self.maxSeats = None
|
self.maxSeats = None
|
||||||
self.tableName = None
|
self.tableName = None
|
||||||
self.seatNos = None
|
self.seatNos = None
|
||||||
self.payin_amounts = None # tourney import was complaining mightily about this missing
|
|
||||||
except:
|
except:
|
||||||
print "htw.init error: " + str(sys.exc_info())
|
print "htw.init error: " + str(sys.exc_info())
|
||||||
raise
|
raise
|
||||||
|
|
|
@ -1,827 +0,0 @@
|
||||||
#!/usr/bin/python2
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
#Copyright 2008-2010 J. Urner
|
|
||||||
#This program is free software: you can redistribute it and/or modify
|
|
||||||
#it under the terms of the GNU Affero General Public License as published by
|
|
||||||
#the Free Software Foundation, version 3 of the License.
|
|
||||||
#
|
|
||||||
#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 Affero General Public License
|
|
||||||
#along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#In the "official" distribution you can find the license in agpl-3.0.txt.
|
|
||||||
|
|
||||||
"""Database manager
|
|
||||||
|
|
||||||
@todo: (gtk) how to validate user input in gtk.Dialog? as soon as the user clicks ok the dialog is dead. we use a while loop as workaround. not nice
|
|
||||||
@todo: (fpdb) we need the application name 'fpdb' from somewhere to put it in dialog titles
|
|
||||||
@todo: (fpdb) config object should be initialized globally and accessible from all modules via Configuration.py
|
|
||||||
|
|
||||||
@todo: (all dialogs) save/restore size and pos
|
|
||||||
|
|
||||||
@todo: (WidgetDatabaseManager) give database status meaningful colors
|
|
||||||
@todo: (WidgetDatabaseManager) implement database purging
|
|
||||||
@todo: (WidgetDatabaseManager) implement database export
|
|
||||||
@todo: (WidgetDatabaseManager) what to do on database doubleclick?
|
|
||||||
@todo: (WidgetDatabaseManager) context menu for database tree
|
|
||||||
@todo: (WidgetDatabaseManager) initializing/validating databases may take a while. how to give feedback?
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
import os
|
|
||||||
import pygtk
|
|
||||||
pygtk.require('2.0')
|
|
||||||
import gtk
|
|
||||||
import gobject
|
|
||||||
|
|
||||||
#*******************************************************************************************************
|
|
||||||
class DatabaseManager(gobject.GObject):
|
|
||||||
DatabaseTypes = {}
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_fpdb(klass, data, defaultDatabaseType=None):
|
|
||||||
|
|
||||||
#NOTE: if no databases are present in config fpdb fails with
|
|
||||||
# Traceback (most recent call last):
|
|
||||||
# File "/home/me2/Scr/Repos/fpdb-mme/pyfpdb/DatabaseManager.py", line 783, in <module>
|
|
||||||
# databaseManager = DatabaseManager.from_fpdb('', defaultDatabaseType=DatabaseTypeSqLite)
|
|
||||||
# File "/home/me2/Scr/Repos/fpdb-mme/pyfpdb/DatabaseManager.py", line 36, in from_fpdb
|
|
||||||
# config = Configuration.Config(file=options.config, dbname=options.dbname)
|
|
||||||
# File "/home/me2/Scr/Repos/fpdb-mme/pyfpdb/Configuration.py", line 436, in __init__
|
|
||||||
# db = self.get_db_parameters()
|
|
||||||
# File "/home/me2/Scr/Repos/fpdb-mme/pyfpdb/Configuration.py", line 583, in get_db_parameters
|
|
||||||
# name = self.db_selected
|
|
||||||
# AttributeError: Config instance has no attribute 'db_selected'
|
|
||||||
import sys
|
|
||||||
import Options
|
|
||||||
import Configuration
|
|
||||||
#NOTE: fpdb should perform this globally
|
|
||||||
(options, argv) = Options.fpdb_options()
|
|
||||||
config = Configuration.Config(file=options.config, dbname=options.dbname)
|
|
||||||
#TODO: handle no database present
|
|
||||||
defaultDatabaseName = config.get_db_parameters().get('db-databaseName', None)
|
|
||||||
#TODO: fpdb stores databases in no particular order. this has to be fixed somehow
|
|
||||||
databases = []
|
|
||||||
for name, fpdbDatabase in config.supported_databases.items():
|
|
||||||
databaseKlass = klass.DatabaseTypes.get(fpdbDatabase.db_server, None)
|
|
||||||
#NOTE: Config does not seem to validate user input, so anything may end up here
|
|
||||||
if databaseKlass is None:
|
|
||||||
raise ValueError('Unknown databasetype: %s' % fpdbDatabase.db_server)
|
|
||||||
|
|
||||||
database = databaseKlass()
|
|
||||||
if database.Type == 'sqlite':
|
|
||||||
database.name = fpdbDatabase.db_name
|
|
||||||
database.file = fpdbDatabase.db_server
|
|
||||||
else:
|
|
||||||
database.name = fpdbDatabase.db_name
|
|
||||||
database.host = fpdbDatabase.db_server
|
|
||||||
#NOTE: fpdbDatabase.db_ip is no is a string
|
|
||||||
database.port = int(fpdbDatabase.db_ip)
|
|
||||||
database.user = fpdbDatabase.db_user
|
|
||||||
database.password = fpdbDatabase.db_pass
|
|
||||||
databases.append(database)
|
|
||||||
|
|
||||||
return klass(databases=databases, defaultDatabaseType=defaultDatabaseType)
|
|
||||||
|
|
||||||
def to_fpdb(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, databases=None, defaultDatabaseType=None):
|
|
||||||
gobject.GObject.__init__(self)
|
|
||||||
|
|
||||||
self._defaultDatabaseType = defaultDatabaseType
|
|
||||||
self._databases = [] if databases is None else list(databases)
|
|
||||||
self._activeDatabase = None
|
|
||||||
def __iter__(self):
|
|
||||||
return iter(self._databases)
|
|
||||||
def set_default_database_type(self, databaseType):
|
|
||||||
self._defaultDatabaseType = defaultDatabaseType
|
|
||||||
def get_default_database_type(self):
|
|
||||||
return self._defaultDatabaseType
|
|
||||||
def database_from_id(self, idDatabase):
|
|
||||||
for database in self._databases:
|
|
||||||
if idDatabase == self.database_id(database):
|
|
||||||
return database
|
|
||||||
def database_id(self, database):
|
|
||||||
return id(database)
|
|
||||||
def add_database(self, database):
|
|
||||||
if database in self._databases:
|
|
||||||
raise ValueError('database already registered')
|
|
||||||
self._databases.append(database)
|
|
||||||
def remove_database(self, database):
|
|
||||||
self._databases.remove(database)
|
|
||||||
|
|
||||||
def activate_database(self, database):
|
|
||||||
if self._activeDatabase is not None:
|
|
||||||
self._activeDatabase.status = self._activeDatabase.StatusInactive
|
|
||||||
#TODO: finalize database
|
|
||||||
self.emit('database-deactivated', self.database_id(self._activeDatabase) )
|
|
||||||
|
|
||||||
database.status = database.StatusActive
|
|
||||||
#TODO: activate database
|
|
||||||
self._activeDatabase = database
|
|
||||||
self.emit('database-activated', self.database_id(database) )
|
|
||||||
|
|
||||||
def active_database(self):
|
|
||||||
return self._activeDatabase
|
|
||||||
|
|
||||||
# register DatabaseManager signals
|
|
||||||
gobject.type_register(DatabaseManager)
|
|
||||||
gobject.signal_new('database-activated', DatabaseManager, gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (int, ))
|
|
||||||
gobject.signal_new('database-deactivated', DatabaseManager, gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (int, ))
|
|
||||||
gobject.signal_new('database-error', DatabaseManager, gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (int, ))
|
|
||||||
|
|
||||||
class DatabaseTypeMeta(type):
|
|
||||||
def __new__(klass, name, bases, kws):
|
|
||||||
newKlass = type.__new__(klass, name, bases, kws)
|
|
||||||
if newKlass.Type is not None:
|
|
||||||
if newKlass.Type in DatabaseManager.DatabaseTypes:
|
|
||||||
raise ValueError('data base type already registered for: %s' % newKlass.Type)
|
|
||||||
DatabaseManager.DatabaseTypes[newKlass.Type] = newKlass
|
|
||||||
return newKlass
|
|
||||||
|
|
||||||
class DatabaseTypeBase(object):
|
|
||||||
__metaclass__ = DatabaseTypeMeta
|
|
||||||
Type = None
|
|
||||||
StatusActive = 'active'
|
|
||||||
StatusInactive = 'inactive'
|
|
||||||
StatusError = 'error' #TODO: not implemented
|
|
||||||
|
|
||||||
#TODO: not happy with returning error string. just being too lazy to impl dozens of error codes for later translation
|
|
||||||
def init_new_database(self):
|
|
||||||
"""initializes a new empty database
|
|
||||||
@return: (str) error if something goes wrong, None otherwise
|
|
||||||
"""
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
def validate_database(self):
|
|
||||||
"""checks if the database is valid
|
|
||||||
@return: (str) error if something goes wrong, None otherwise
|
|
||||||
"""
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
class DatabaseTypePostgres(DatabaseTypeBase):
|
|
||||||
Type = 'postgresql'
|
|
||||||
@classmethod
|
|
||||||
def display_name(klass):
|
|
||||||
return 'Postgres'
|
|
||||||
def __init__(self, name='', host='localhost', port=5432, user='postgres', password='', database='fpdb'):
|
|
||||||
self.name = name
|
|
||||||
self.host = host
|
|
||||||
self.port = port
|
|
||||||
self.user = user
|
|
||||||
self.password = password
|
|
||||||
self.database = database
|
|
||||||
self.status = self.StatusInactive
|
|
||||||
|
|
||||||
#TODO: implement
|
|
||||||
def init_new_database(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
#TODO: implement
|
|
||||||
def validate_database(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
class DatabaseTypeMysql(DatabaseTypeBase):
|
|
||||||
Type = 'mysql'
|
|
||||||
@classmethod
|
|
||||||
def display_name(klass):
|
|
||||||
return 'MySql'
|
|
||||||
def __init__(self, name='', host='localhost', port=3306, user='root', password='', database='fpdb'):
|
|
||||||
self.name = name
|
|
||||||
self.host = host
|
|
||||||
self.port = port
|
|
||||||
self.user = user
|
|
||||||
self.password = password
|
|
||||||
self.database = database
|
|
||||||
self.status = self.StatusInactive
|
|
||||||
|
|
||||||
#TODO: implement
|
|
||||||
def init_new_database(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
#TODO: implement
|
|
||||||
def validate_database(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class DatabaseTypeSqLite(DatabaseTypeBase):
|
|
||||||
Type = 'sqlite'
|
|
||||||
@classmethod
|
|
||||||
def display_name(klass):
|
|
||||||
return 'SqLite'
|
|
||||||
def __init__(self, name='', host='', file='', database='fpdb'):
|
|
||||||
self.name = name
|
|
||||||
self.file = file
|
|
||||||
self.status = self.StatusInactive
|
|
||||||
|
|
||||||
def init_new_database(self):
|
|
||||||
# make shure all attrs are specified
|
|
||||||
if not self.file:
|
|
||||||
return 'no database file specified'
|
|
||||||
# create file if necessary (this will truncate file if it exists)
|
|
||||||
try:
|
|
||||||
open(self.file, 'w').close()
|
|
||||||
except IOError:
|
|
||||||
return 'can not write file'
|
|
||||||
|
|
||||||
#TODO: init tables (...)
|
|
||||||
|
|
||||||
|
|
||||||
def validate_database(self):
|
|
||||||
pass
|
|
||||||
#TODO: check if tables (...) exist
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#TODO: how do we want to handle unsupported database types?
|
|
||||||
# ..uncomment to remove unsupported database types
|
|
||||||
#try: import psycopg2
|
|
||||||
#except ImportError: del DatabaseManager.DatabaseTypes['postgres']
|
|
||||||
#try: import MySQLdb
|
|
||||||
#except ImportError: del DatabaseManager.DatabaseTypes['mysql']
|
|
||||||
#try: import sqlite3
|
|
||||||
#except ImportError: del DatabaseManager.DatabaseTypes['sqlite']
|
|
||||||
|
|
||||||
#***************************************************************************************************************************
|
|
||||||
#TODO: there is no title (on linux), wtf?
|
|
||||||
def DialogError(parent=None, msg=''):
|
|
||||||
dlg = gtk.MessageDialog(
|
|
||||||
parent=parent,
|
|
||||||
flags=gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
|
|
||||||
type=gtk.MESSAGE_ERROR,
|
|
||||||
buttons=gtk.BUTTONS_OK,
|
|
||||||
message_format=msg,
|
|
||||||
)
|
|
||||||
dlg.run()
|
|
||||||
dlg.destroy()
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
#TODO: derrive from gtk.VBox?
|
|
||||||
class WidgetDatabaseProperties(gtk.VBox):
|
|
||||||
|
|
||||||
ModeNew = 0
|
|
||||||
ModeEdit = 1
|
|
||||||
ModeAdd = 2
|
|
||||||
|
|
||||||
class SqLiteFileChooserButton(gtk.HBox):
|
|
||||||
#NOTE: for some weird reason it is impossible to let the user choose a non exiting filename with gtk.FileChooserButton, so impl our own on the fly
|
|
||||||
def __init__(self, widgetDatabaseProperties, parentWidget):
|
|
||||||
gtk.HBox.__init__(self)
|
|
||||||
self.set_homogeneous(False)
|
|
||||||
|
|
||||||
self.parentWidget = parentWidget
|
|
||||||
self.widgetDatabaseProperties = widgetDatabaseProperties
|
|
||||||
self.entry = gtk.Entry()
|
|
||||||
self.button = gtk.Button('...')
|
|
||||||
self.button.connect('clicked', self.on_button_clicked)
|
|
||||||
|
|
||||||
# layout widgets
|
|
||||||
self.pack_start(self.entry, True, True)
|
|
||||||
self.pack_start(self.button, False, False)
|
|
||||||
|
|
||||||
def get_filename(self):
|
|
||||||
return self.entry.get_text()
|
|
||||||
|
|
||||||
def set_filename(self, name):
|
|
||||||
self.entry.set_text(name)
|
|
||||||
|
|
||||||
def on_button_clicked(self, button):
|
|
||||||
if self.widgetDatabaseProperties.mode == WidgetDatabaseProperties.ModeAdd:
|
|
||||||
action = gtk.FILE_CHOOSER_ACTION_OPEN
|
|
||||||
elif self.widgetDatabaseProperties.mode == WidgetDatabaseProperties.ModeNew:
|
|
||||||
action = gtk.FILE_CHOOSER_ACTION_SAVE
|
|
||||||
else:
|
|
||||||
raise ValueError('unsupported dialog mode')
|
|
||||||
dlg = gtk.FileChooserDialog(
|
|
||||||
title='Choose an exiting database file or type in name of a new one',
|
|
||||||
parent=self.parentWidget,
|
|
||||||
action=action,
|
|
||||||
buttons=(
|
|
||||||
gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
|
|
||||||
gtk.STOCK_OK, gtk.RESPONSE_OK,
|
|
||||||
),
|
|
||||||
backend=None
|
|
||||||
)
|
|
||||||
dlg.set_default_response(gtk.RESPONSE_OK)
|
|
||||||
dlg.set_do_overwrite_confirmation(True)
|
|
||||||
if dlg.run() == gtk.RESPONSE_OK:
|
|
||||||
fileName = dlg.get_filename()
|
|
||||||
self.set_filename(fileName)
|
|
||||||
dlg.destroy()
|
|
||||||
|
|
||||||
|
|
||||||
#TODO: bit ugly this thingy. try to find a better way to map database attrs to gtk widgets
|
|
||||||
class FieldWidget(object):
|
|
||||||
def __init__(self, text='', attrDatabase='', widget=None, attrGet=None, attrSet=None, defaultValue=None, canEdit=False, tooltip=''):
|
|
||||||
"""
|
|
||||||
@param canEdit: True if the user can edit the attr in edit mode, False otherwise
|
|
||||||
"""
|
|
||||||
self._label = gtk.Label(text)
|
|
||||||
self._attrDatabase = attrDatabase
|
|
||||||
self._widget = widget
|
|
||||||
self._defaultValue = defaultValue
|
|
||||||
self._attrGetter=None,
|
|
||||||
self._attrGet = attrGet
|
|
||||||
self._attrSet = attrSet
|
|
||||||
self._canEdit = canEdit
|
|
||||||
|
|
||||||
self._label.set_tooltip_text(tooltip)
|
|
||||||
self._widget.set_tooltip_text(tooltip)
|
|
||||||
|
|
||||||
def widget(self):
|
|
||||||
return self._widget
|
|
||||||
def label(self):
|
|
||||||
return self._label
|
|
||||||
def is_sensitive(self, database):
|
|
||||||
return hasattr(database, self._attrDatabase)
|
|
||||||
def can_edit(self):
|
|
||||||
return self._canEdit
|
|
||||||
def set_sensitive(self, flag):
|
|
||||||
self._label.set_sensitive(flag)
|
|
||||||
self._widget.set_sensitive(flag)
|
|
||||||
def value_from_database(self, database):
|
|
||||||
getattr(self._widget, self._attrSet)( getattr(database, self._attrDatabase) )
|
|
||||||
def value_to_database(self, database):
|
|
||||||
setattr(database, self._attrDatabase, getattr(self._widget, self._attrGet)() )
|
|
||||||
def reset_value(self):
|
|
||||||
getattr(self._widget, self._attrSet)(self._defaultValue)
|
|
||||||
|
|
||||||
def __init__(self, databaseManager, database, mode=ModeEdit, parentWidget=None):
|
|
||||||
gtk.VBox.__init__(self)
|
|
||||||
|
|
||||||
self.databaseManager = databaseManager
|
|
||||||
self.database = database
|
|
||||||
self.mode = mode
|
|
||||||
self.parentWidget = parentWidget
|
|
||||||
self.fieldWidgets = (
|
|
||||||
self.FieldWidget(
|
|
||||||
text='Name:',
|
|
||||||
attrDatabase='name',
|
|
||||||
widget=gtk.Entry(),
|
|
||||||
defaultValue='',
|
|
||||||
attrGet='get_text',
|
|
||||||
attrSet='set_text',
|
|
||||||
canEdit=True,
|
|
||||||
tooltip='Any name you like to name the database '
|
|
||||||
),
|
|
||||||
self.FieldWidget(
|
|
||||||
text='File:',
|
|
||||||
attrDatabase='file',
|
|
||||||
widget=self.SqLiteFileChooserButton(self, self.parentWidget),
|
|
||||||
defaultValue='',
|
|
||||||
attrGet='get_filename',
|
|
||||||
attrSet='set_filename',
|
|
||||||
canEdit=False,
|
|
||||||
tooltip='Fully qualified path of the file to hold the database '
|
|
||||||
),
|
|
||||||
self.FieldWidget(
|
|
||||||
text='Host:',
|
|
||||||
attrDatabase='host',
|
|
||||||
widget=gtk.Entry(),
|
|
||||||
defaultValue='',
|
|
||||||
attrGet='get_text',
|
|
||||||
attrSet='set_text',
|
|
||||||
canEdit=False,
|
|
||||||
tooltip='Host the database is located at'
|
|
||||||
),
|
|
||||||
self.FieldWidget(
|
|
||||||
text='Port:',
|
|
||||||
attrDatabase='port',
|
|
||||||
widget=gtk.SpinButton(adjustment=gtk.Adjustment(value=0, lower=0, upper=999999, step_incr=1, page_incr=10) ),
|
|
||||||
defaultValue=0,
|
|
||||||
attrGet='get_value',
|
|
||||||
attrSet='set_value',
|
|
||||||
canEdit=False,
|
|
||||||
tooltip='Port to use to connect to the host'
|
|
||||||
),
|
|
||||||
self.FieldWidget(
|
|
||||||
text='User:',
|
|
||||||
attrDatabase='user',
|
|
||||||
widget=gtk.Entry(),
|
|
||||||
defaultValue='',
|
|
||||||
attrGet='get_text',
|
|
||||||
attrSet='set_text',
|
|
||||||
canEdit=False,
|
|
||||||
tooltip='User name used to login to the host'
|
|
||||||
),
|
|
||||||
self.FieldWidget(
|
|
||||||
text='Pwd:',
|
|
||||||
attrDatabase='password',
|
|
||||||
widget=gtk.Entry(),
|
|
||||||
defaultValue='',
|
|
||||||
attrGet='get_text',
|
|
||||||
attrSet='set_text',
|
|
||||||
canEdit=False,
|
|
||||||
tooltip='Password used to login to the host'
|
|
||||||
),
|
|
||||||
self.FieldWidget(
|
|
||||||
text='Db:',
|
|
||||||
attrDatabase='database',
|
|
||||||
widget=gtk.Entry(),
|
|
||||||
defaultValue='',
|
|
||||||
attrGet='get_text',
|
|
||||||
attrSet='set_text',
|
|
||||||
canEdit=False,
|
|
||||||
tooltip='Name of the database'
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
# setup database type combo
|
|
||||||
self.comboType = gtk.ComboBox()
|
|
||||||
listStore= gtk.ListStore(str, str)
|
|
||||||
self.comboType.set_model(listStore)
|
|
||||||
cell = gtk.CellRendererText()
|
|
||||||
self.comboType.pack_start(cell, True)
|
|
||||||
self.comboType.add_attribute(cell, 'text', 0)
|
|
||||||
self.comboType.connect('changed', self.on_combo_type_changed)
|
|
||||||
|
|
||||||
# fill database type combo with available database klasses. we store (databaseDisplayName, databaseType) in our model for later lookup
|
|
||||||
iCurrentDatabase = 0
|
|
||||||
databaseTypes = [(klass.display_name(), klass.Type) for klass in databaseManager.DatabaseTypes.values()]
|
|
||||||
databaseTypes.sort()
|
|
||||||
for i, (databaseDisplayName, databaseType) in enumerate(databaseTypes):
|
|
||||||
listStore.append( (databaseDisplayName, databaseType) )
|
|
||||||
if databaseType == self.database.Type:
|
|
||||||
iCurrentDatabase = i
|
|
||||||
if self.mode == self.ModeEdit or len(databaseTypes) < 2:
|
|
||||||
self.comboType.set_button_sensitivity(gtk.SENSITIVITY_OFF)
|
|
||||||
|
|
||||||
# init and layout field widgets
|
|
||||||
self.pack_start(self.comboType, False, False, 2)
|
|
||||||
table = gtk.Table(rows=len(self.fieldWidgets) +1, columns=2, homogeneous=False)
|
|
||||||
self.pack_start(table, False, False, 2)
|
|
||||||
for i,fieldWidget in enumerate(self.fieldWidgets):
|
|
||||||
table.attach(fieldWidget.label(), 0, 1, i, i+1, xoptions=gtk.FILL)
|
|
||||||
table.attach(fieldWidget.widget(), 1, 2, i, i+1)
|
|
||||||
|
|
||||||
# init widget
|
|
||||||
self.comboType.set_active(iCurrentDatabase)
|
|
||||||
self._adjust_widgets(self.database)
|
|
||||||
|
|
||||||
def _adjust_widgets(self, database):
|
|
||||||
for fieldWidget in self.fieldWidgets:
|
|
||||||
isSensitive = fieldWidget.is_sensitive(database)
|
|
||||||
if isSensitive:
|
|
||||||
fieldWidget.value_from_database(database)
|
|
||||||
else:
|
|
||||||
fieldWidget.reset_value()
|
|
||||||
if self.mode == self.ModeEdit:
|
|
||||||
isSensitive = isSensitive and fieldWidget.can_edit()
|
|
||||||
fieldWidget.set_sensitive(isSensitive)
|
|
||||||
|
|
||||||
|
|
||||||
def on_combo_type_changed(self, combo):
|
|
||||||
i = self.comboType.get_active()
|
|
||||||
if i < 0:
|
|
||||||
return
|
|
||||||
|
|
||||||
# check if we need to init a new database
|
|
||||||
currentDatabaseType = self.comboType.get_model()[i][1]
|
|
||||||
if currentDatabaseType == self.database.Type:
|
|
||||||
return
|
|
||||||
|
|
||||||
# create new empty database
|
|
||||||
#NOTE: we dont register it in DatabaseManager
|
|
||||||
self.database = self.databaseManager.DatabaseTypes[currentDatabaseType]()
|
|
||||||
self._adjust_widgets(self.database)
|
|
||||||
|
|
||||||
|
|
||||||
def get_database(self):
|
|
||||||
for fieldWidget in self.fieldWidgets:
|
|
||||||
if fieldWidget.is_sensitive(self.database):
|
|
||||||
fieldWidget.value_to_database(self.database)
|
|
||||||
return self.database
|
|
||||||
|
|
||||||
|
|
||||||
class DialogDatabaseProperties(gtk.Dialog):
|
|
||||||
def __init__(self, databaseManager, database, parent=None, mode=WidgetDatabaseProperties.ModeEdit, title=''):
|
|
||||||
gtk.Dialog.__init__(self,
|
|
||||||
title=title,
|
|
||||||
parent=parent,
|
|
||||||
flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
|
|
||||||
buttons=(
|
|
||||||
gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
|
|
||||||
gtk.STOCK_OK, gtk.RESPONSE_ACCEPT,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
self.connect('response', self.on_dialog_response)
|
|
||||||
|
|
||||||
# setup widget
|
|
||||||
self.widgetDatabaseProperties = WidgetDatabaseProperties(databaseManager,database, mode=mode, parentWidget=self)
|
|
||||||
self.vbox.pack_start(self.widgetDatabaseProperties, True, True)
|
|
||||||
self.show_all()
|
|
||||||
|
|
||||||
def get_widget_database_properties(self):
|
|
||||||
return self.widgetDatabaseProperties
|
|
||||||
|
|
||||||
def on_dialog_response(self, dlg, responseId):
|
|
||||||
if responseId == gtk.RESPONSE_REJECT:
|
|
||||||
pass
|
|
||||||
elif responseId == gtk.RESPONSE_ACCEPT:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
#TODO: derrive from gtk.VBox?
|
|
||||||
# ..is there a way to derrive from gtk.Widget or similar? this would make parentWidget kw obsolete
|
|
||||||
class WidgetDatabaseManager(gtk.VBox):
|
|
||||||
"""
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, databaseManager, parentWidget=None):
|
|
||||||
gtk.VBox.__init__(self)
|
|
||||||
|
|
||||||
self.parentWidget = parentWidget
|
|
||||||
self.databaseManager = databaseManager
|
|
||||||
self.databaseManager.connect('database-activated', self.on_database_manager_database_activated)
|
|
||||||
self.databaseManager.connect('database-deactivated', self.on_database_manager_database_deactivated)
|
|
||||||
self.databaseStatusNames = {
|
|
||||||
DatabaseTypeBase.StatusActive: 'Active',
|
|
||||||
DatabaseTypeBase.StatusInactive: 'Inactive',
|
|
||||||
DatabaseTypeBase.StatusError: 'Error',
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#TODO: dono how to make word wrap work as expected
|
|
||||||
self.labelInfo = gtk.Label('database management')
|
|
||||||
self.labelInfo.set_line_wrap(True)
|
|
||||||
self.labelInfo.set_selectable(True)
|
|
||||||
self.labelInfo.set_single_line_mode(False)
|
|
||||||
self.labelInfo.set_alignment(0, 0)
|
|
||||||
|
|
||||||
# database management buttons
|
|
||||||
|
|
||||||
#TODO: bit messy the distinction New/Add/Edit. we'd have to pass three flags to DialogDatabaseProperties
|
|
||||||
# to handle this. maybe drop Edit (is just a Remove + Add), to keep things simple
|
|
||||||
self.buttonDatabaseActivate = gtk.Button("Activate")
|
|
||||||
self.buttonDatabaseActivate.set_tooltip_text('activates the database')
|
|
||||||
self.buttonDatabaseActivate.connect('clicked', self.on_button_database_activate_clicked)
|
|
||||||
self.buttonDatabaseActivate.set_sensitive(False)
|
|
||||||
self.buttonDatabaseNew = gtk.Button("New..")
|
|
||||||
self.buttonDatabaseNew.set_tooltip_text('creates a new database')
|
|
||||||
self.buttonDatabaseNew.connect('clicked', self.on_button_database_new_clicked)
|
|
||||||
self.buttonDatabaseAdd = gtk.Button("Add..")
|
|
||||||
self.buttonDatabaseAdd.set_tooltip_text('adds an existing database')
|
|
||||||
self.buttonDatabaseAdd.connect('clicked', self.on_button_database_add_clicked)
|
|
||||||
self.buttonDatabaseEdit = gtk.Button("Edit..")
|
|
||||||
self.buttonDatabaseEdit.set_tooltip_text('edit database settings')
|
|
||||||
self.buttonDatabaseEdit.connect('clicked', self.on_button_database_edit_clicked)
|
|
||||||
self.buttonDatabaseEdit.set_sensitive(False)
|
|
||||||
self.buttonDatabaseRemove = gtk.Button("Remove")
|
|
||||||
self.buttonDatabaseRemove.set_tooltip_text('removes the database from the list')
|
|
||||||
self.buttonDatabaseRemove.set_sensitive(False)
|
|
||||||
self.buttonDatabaseRemove.connect('clicked', self.on_button_database_remove_clicked)
|
|
||||||
|
|
||||||
#TODO: i dont think we should do any real database management here. maybe drop it
|
|
||||||
#self.buttonDatabaseDelete = gtk.Button("Delete")
|
|
||||||
#self.buttonDatabaseDelete.set_tooltip_text('removes the database from the list and deletes it')
|
|
||||||
#self.buttonDatabaseDelete.set_sensitive(False)
|
|
||||||
|
|
||||||
# init database tree
|
|
||||||
self.treeDatabases = gtk.TreeView()
|
|
||||||
treeDatabaseColumns = ( # name, displayName, dataType
|
|
||||||
('name', 'Name', str),
|
|
||||||
('status', 'Status', str),
|
|
||||||
('type', 'Type', str),
|
|
||||||
('_id', '', int),
|
|
||||||
)
|
|
||||||
self.treeDatabaseColumns = {} # name --> index
|
|
||||||
store = gtk.ListStore( *[i[2] for i in treeDatabaseColumns] )
|
|
||||||
self.treeDatabases.set_model(store)
|
|
||||||
for i, (name, displayName, dataType) in enumerate(treeDatabaseColumns):
|
|
||||||
col = gtk.TreeViewColumn(displayName, gtk.CellRendererText(), text=i)
|
|
||||||
self.treeDatabases.append_column(col)
|
|
||||||
if name.startswith('_'):
|
|
||||||
col.set_visible(False)
|
|
||||||
self.treeDatabaseColumns[name] = i
|
|
||||||
self.treeDatabases.get_selection().connect('changed', self.on_tree_databases_selection_changed)
|
|
||||||
|
|
||||||
# layout widgets
|
|
||||||
vbox = gtk.VBox(self)
|
|
||||||
vbox.pack_start(self.labelInfo, False, False, 2)
|
|
||||||
vbox.pack_start(gtk.HSeparator(), False, False, 2)
|
|
||||||
hbox = gtk.HBox()
|
|
||||||
self.add(hbox)
|
|
||||||
hbox.set_homogeneous(False)
|
|
||||||
vbox = gtk.VBox()
|
|
||||||
hbox.pack_start(vbox, False, False, 2)
|
|
||||||
vbox.pack_start(self.buttonDatabaseActivate, False, False, 2)
|
|
||||||
vbox.pack_start(self.buttonDatabaseNew, False, False, 2)
|
|
||||||
vbox.pack_start(self.buttonDatabaseAdd, False, False, 2)
|
|
||||||
vbox.pack_start(self.buttonDatabaseEdit, False, False, 2)
|
|
||||||
vbox.pack_start(self.buttonDatabaseRemove, False, False, 2)
|
|
||||||
#vbox.pack_start(self.buttonDatabaseDelete, False, False, 2)
|
|
||||||
box = gtk.VBox()
|
|
||||||
vbox.pack_start(box, True, True, 0)
|
|
||||||
|
|
||||||
hbox.pack_start(gtk.VSeparator(), False, False, 2)
|
|
||||||
hbox.pack_end(self.treeDatabases, True, True, 2)
|
|
||||||
|
|
||||||
self.show_all()
|
|
||||||
|
|
||||||
# init widget
|
|
||||||
model = self.treeDatabases.get_model()
|
|
||||||
for database in self.databaseManager:
|
|
||||||
it = model.append()
|
|
||||||
model.set_value(it, self.treeDatabaseColumns['name'], database.name)
|
|
||||||
model.set_value(it, self.treeDatabaseColumns['status'], self.databaseStatusNames[database.status] )
|
|
||||||
model.set_value(it, self.treeDatabaseColumns['type'], database.display_name() )
|
|
||||||
model.set_value(it, self.treeDatabaseColumns['_id'], self.databaseManager.database_id(database))
|
|
||||||
|
|
||||||
|
|
||||||
def on_database_manager_database_activated(self, databaseManager, idDatabase):
|
|
||||||
database = self.databaseManager.database_from_id(idDatabase)
|
|
||||||
model = self.treeDatabases.get_model()
|
|
||||||
for row in iter(model):
|
|
||||||
if row[self.treeDatabaseColumns['_id']] == idDatabase:
|
|
||||||
row[self.treeDatabaseColumns['status']] = self.databaseStatusNames[database.StatusActive]
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
raise ValueError('database not found')
|
|
||||||
|
|
||||||
|
|
||||||
def on_database_manager_database_deactivated(self, databaseManager, idDatabase):
|
|
||||||
database = self.databaseManager.database_from_id(idDatabase)
|
|
||||||
model = self.treeDatabases.get_model()
|
|
||||||
for row in iter(model):
|
|
||||||
if row[self.treeDatabaseColumns['_id']] == idDatabase:
|
|
||||||
row[self.treeDatabaseColumns['status']] = self.databaseStatusNames[database.StatusInactive]
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
raise ValueError('database not found')
|
|
||||||
|
|
||||||
|
|
||||||
def on_button_database_activate_clicked(self, button):
|
|
||||||
selection = self.treeDatabases.get_selection()
|
|
||||||
if selection is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
model, it = selection.get_selected()
|
|
||||||
idDatabase = model.get_value(it, self.treeDatabaseColumns['_id'])
|
|
||||||
database = self.databaseManager.database_from_id(idDatabase)
|
|
||||||
self.databaseManager.activate_database(database)
|
|
||||||
|
|
||||||
|
|
||||||
#TODO: for some reason i have to click OK/Cancel twice to close the dialog
|
|
||||||
def on_button_database_new_clicked(self, button):
|
|
||||||
databaseKlass = self.databaseManager.get_default_database_type()
|
|
||||||
if databaseKlass is None:
|
|
||||||
raise ValueError('no default database type set')
|
|
||||||
database = databaseKlass()
|
|
||||||
|
|
||||||
while True:
|
|
||||||
dlg = DialogDatabaseProperties(
|
|
||||||
self.databaseManager,
|
|
||||||
database,
|
|
||||||
parent=self.parentWidget,
|
|
||||||
mode=WidgetDatabaseProperties.ModeNew,
|
|
||||||
title='New database'
|
|
||||||
)
|
|
||||||
response = dlg.run()
|
|
||||||
if response == gtk.RESPONSE_ACCEPT:
|
|
||||||
database = dlg.get_widget_database_properties().get_database()
|
|
||||||
#TODO: initing may or may not take a while. how to handle?
|
|
||||||
error = database.init_new_database()
|
|
||||||
if error:
|
|
||||||
DialogError(parent=dlg, msg=error)
|
|
||||||
dlg.destroy()
|
|
||||||
continue
|
|
||||||
else:
|
|
||||||
database = None
|
|
||||||
dlg.destroy()
|
|
||||||
break
|
|
||||||
|
|
||||||
|
|
||||||
if database is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
self.databaseManager.add_database(database)
|
|
||||||
model = self.treeDatabases.get_model()
|
|
||||||
it = model.append()
|
|
||||||
model.set_value(it, self.treeDatabaseColumns['name'], database.name)
|
|
||||||
model.set_value(it, self.treeDatabaseColumns['status'], self.databaseStatusNames[database.status] )
|
|
||||||
model.set_value(it, self.treeDatabaseColumns['type'], database.display_name() )
|
|
||||||
model.set_value(it, self.treeDatabaseColumns['_id'], self.databaseManager.database_id(database))
|
|
||||||
|
|
||||||
|
|
||||||
def on_button_database_add_clicked(self, button):
|
|
||||||
databaseKlass = self.databaseManager.get_default_database_type()
|
|
||||||
if databaseKlass is None:
|
|
||||||
raise ValueError('no defult database type set')
|
|
||||||
database = databaseKlass()
|
|
||||||
|
|
||||||
while True:
|
|
||||||
dlg = DialogDatabaseProperties(
|
|
||||||
self.databaseManager,
|
|
||||||
database,
|
|
||||||
parent=self.parentWidget,
|
|
||||||
mode=WidgetDatabaseProperties.ModeAdd,
|
|
||||||
title='Add database'
|
|
||||||
)
|
|
||||||
response = dlg.run()
|
|
||||||
if response == gtk.RESPONSE_ACCEPT:
|
|
||||||
database = dlg.get_widget_database_properties().get_database()
|
|
||||||
#TODO: validating may or may not take a while. how to handle?
|
|
||||||
error = database.validate_database()
|
|
||||||
if error:
|
|
||||||
DialogError(parent=self.parentWidget, msg=error)
|
|
||||||
dlg.destroy()
|
|
||||||
continue
|
|
||||||
else:
|
|
||||||
database = None
|
|
||||||
dlg.destroy()
|
|
||||||
break
|
|
||||||
|
|
||||||
if database is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
self.databaseManager.add_database(database)
|
|
||||||
model = self.treeDatabases.get_model()
|
|
||||||
it = model.append()
|
|
||||||
model.set_value(it, self.treeDatabaseColumns['name'], database.name)
|
|
||||||
model.set_value(it, self.treeDatabaseColumns['status'], self.databaseStatusNames[database.status] )
|
|
||||||
model.set_value(it, self.treeDatabaseColumns['type'], database.display_name() )
|
|
||||||
model.set_value(it, self.treeDatabaseColumns['_id'], self.databaseManager.database_id(database))
|
|
||||||
dlg.destroy()
|
|
||||||
|
|
||||||
def on_button_database_edit_clicked(self, button):
|
|
||||||
selection = self.treeDatabases.get_selection()
|
|
||||||
if selection is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
model, it = selection.get_selected()
|
|
||||||
idDatabase = model.get_value(it, self.treeDatabaseColumns['_id'])
|
|
||||||
database = self.databaseManager.database_from_id(idDatabase)
|
|
||||||
dlg = DialogDatabaseProperties(
|
|
||||||
self.databaseManager,
|
|
||||||
database,
|
|
||||||
parent=self.parentWidget,
|
|
||||||
mode=WidgetDatabaseProperties.ModeEdit,
|
|
||||||
title='Edit database'
|
|
||||||
)
|
|
||||||
response = dlg.run()
|
|
||||||
if response == gtk.RESPONSE_REJECT:
|
|
||||||
pass
|
|
||||||
elif response == gtk.RESPONSE_ACCEPT:
|
|
||||||
database = dlg.get_database()
|
|
||||||
selection = self.treeDatabases.get_selection()
|
|
||||||
if selection is not None:
|
|
||||||
model, it = selection.get_selected()
|
|
||||||
model.set_value(it, self.treeDatabaseColumns['name'], database.name)
|
|
||||||
dlg.destroy()
|
|
||||||
|
|
||||||
|
|
||||||
def on_button_database_remove_clicked(self, button):
|
|
||||||
selection = self.treeDatabases.get_selection()
|
|
||||||
if selection is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
model, it = selection.get_selected()
|
|
||||||
#TODO: finalize database
|
|
||||||
model.remove(it)
|
|
||||||
|
|
||||||
|
|
||||||
def on_tree_databases_selection_changed(self, treeSelection):
|
|
||||||
hasSelection = bool(treeSelection.count_selected_rows())
|
|
||||||
|
|
||||||
# enable/disable selection dependend widgets
|
|
||||||
self.buttonDatabaseActivate.set_sensitive(hasSelection)
|
|
||||||
self.buttonDatabaseEdit.set_sensitive(hasSelection)
|
|
||||||
self.buttonDatabaseRemove.set_sensitive(hasSelection)
|
|
||||||
#self.buttonDatabaseDelete.set_sensitive(hasSelection)
|
|
||||||
|
|
||||||
|
|
||||||
class DialogDatabaseManager(gtk.Dialog):
|
|
||||||
def __init__(self, databaseManager, parent=None):
|
|
||||||
gtk.Dialog.__init__(self,
|
|
||||||
title="Databases",
|
|
||||||
parent=parent,
|
|
||||||
flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
|
|
||||||
buttons=(
|
|
||||||
gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
|
|
||||||
gtk.STOCK_OK, gtk.RESPONSE_ACCEPT,
|
|
||||||
))
|
|
||||||
#self.set_size_request(260, 250)
|
|
||||||
self.widgetDatabaseManager = WidgetDatabaseManager(databaseManager, parentWidget=self)
|
|
||||||
self.vbox.pack_start(self.widgetDatabaseManager, True, True)
|
|
||||||
self.show_all()
|
|
||||||
|
|
||||||
#**************************************************************************************************
|
|
||||||
if __name__ == '__main__':
|
|
||||||
databaseManager = DatabaseManager.from_fpdb('', defaultDatabaseType=DatabaseTypeSqLite)
|
|
||||||
|
|
||||||
#d = DialogDatabaseProperties(
|
|
||||||
# DatabaseManager(defaultDatabaseType=DatabaseTypeSqLite),
|
|
||||||
#database=DatabaseTypePostgres(),
|
|
||||||
# database=None,
|
|
||||||
# )
|
|
||||||
d = DialogDatabaseManager(databaseManager)
|
|
||||||
d.connect("destroy", gtk.main_quit)
|
|
||||||
d.run()
|
|
||||||
#gtk.main()
|
|
|
@ -139,6 +139,7 @@ class DerivedStats():
|
||||||
for player in hand.players:
|
for player in hand.players:
|
||||||
self.handsplayers[player[1]]['seatNo'] = player[0]
|
self.handsplayers[player[1]]['seatNo'] = player[0]
|
||||||
self.handsplayers[player[1]]['startCash'] = int(100 * Decimal(player[2]))
|
self.handsplayers[player[1]]['startCash'] = int(100 * Decimal(player[2]))
|
||||||
|
self.handsplayers[player[1]]['sitout'] = False #TODO: implement actual sitout detection
|
||||||
|
|
||||||
# XXX: enumerate(list, start=x) is python 2.6 syntax; 'start'
|
# XXX: enumerate(list, start=x) is python 2.6 syntax; 'start'
|
||||||
#for i, street in enumerate(hand.actionStreets[2:], start=1):
|
#for i, street in enumerate(hand.actionStreets[2:], start=1):
|
||||||
|
@ -431,6 +432,11 @@ class DerivedStats():
|
||||||
self.handsplayers[player[1]]['street%sAggr' % i] = True
|
self.handsplayers[player[1]]['street%sAggr' % i] = True
|
||||||
else:
|
else:
|
||||||
self.handsplayers[player[1]]['street%sAggr' % i] = False
|
self.handsplayers[player[1]]['street%sAggr' % i] = False
|
||||||
|
|
||||||
|
if len(aggrers)>0 and i>0:
|
||||||
|
for playername in others:
|
||||||
|
self.handsplayers[playername]['otherRaisedStreet%s' % i] = True
|
||||||
|
#print "otherRaised detected on handid "+str(hand.handid)+" for "+playername+" on street "+str(i)
|
||||||
|
|
||||||
if i > 0 and len(aggrers) > 0:
|
if i > 0 and len(aggrers) > 0:
|
||||||
for playername in others:
|
for playername in others:
|
||||||
|
@ -450,8 +456,7 @@ class DerivedStats():
|
||||||
for act in hand.actions[hand.actionStreets[i+1]]:
|
for act in hand.actions[hand.actionStreets[i+1]]:
|
||||||
if act[1] in ('bets'):
|
if act[1] in ('bets'):
|
||||||
self.handsplayers[act[0]]['street%sBets' % i] = 1 + self.handsplayers[act[0]]['street%sBets' % i]
|
self.handsplayers[act[0]]['street%sBets' % i] = 1 + self.handsplayers[act[0]]['street%sBets' % i]
|
||||||
|
|
||||||
|
|
||||||
def folds(self, hand, i):
|
def folds(self, hand, i):
|
||||||
for act in hand.actions[hand.actionStreets[i+1]]:
|
for act in hand.actions[hand.actionStreets[i+1]]:
|
||||||
if act[1] in ('folds'):
|
if act[1] in ('folds'):
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from HandHistoryConverter import *
|
from HandHistoryConverter import *
|
||||||
|
import TourneySummary
|
||||||
|
|
||||||
# Fulltilt HH Format converter
|
# Fulltilt HH Format converter
|
||||||
|
|
||||||
|
@ -66,7 +67,7 @@ class Fulltilt(HandHistoryConverter):
|
||||||
''', re.VERBOSE)
|
''', re.VERBOSE)
|
||||||
re_Button = re.compile('^The button is in seat #(?P<BUTTON>\d+)', re.MULTILINE)
|
re_Button = re.compile('^The button is in seat #(?P<BUTTON>\d+)', re.MULTILINE)
|
||||||
re_PlayerInfo = re.compile('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.{2,15}) \(\$(?P<CASH>[,.0-9]+)\)$', re.MULTILINE)
|
re_PlayerInfo = re.compile('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.{2,15}) \(\$(?P<CASH>[,.0-9]+)\)$', re.MULTILINE)
|
||||||
re_TourneyPlayerInfo = re.compile('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.{2,15}) \(\$?(?P<CASH>[,.0-9]+)\)(, is sitting out)?$', re.MULTILINE)
|
re_TourneysPlayerInfo = re.compile('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.{2,15}) \(\$?(?P<CASH>[,.0-9]+)\)(, is sitting out)?$', re.MULTILINE)
|
||||||
re_Board = re.compile(r"\[(?P<CARDS>.+)\]")
|
re_Board = re.compile(r"\[(?P<CARDS>.+)\]")
|
||||||
|
|
||||||
#static regex for tourney purpose
|
#static regex for tourney purpose
|
||||||
|
@ -87,8 +88,8 @@ class Fulltilt(HandHistoryConverter):
|
||||||
re_TourneyBuyInChips = re.compile("Buy-In Chips: (?P<BUYINCHIPS>\d+)")
|
re_TourneyBuyInChips = re.compile("Buy-In Chips: (?P<BUYINCHIPS>\d+)")
|
||||||
re_TourneyEntries = re.compile("(?P<ENTRIES>\d+) Entries")
|
re_TourneyEntries = re.compile("(?P<ENTRIES>\d+) Entries")
|
||||||
re_TourneyPrizePool = re.compile("Total Prize Pool: (?P<PRIZEPOOL_CURRENCY>\$|)?(?P<PRIZEPOOL>[.,0-9]+)")
|
re_TourneyPrizePool = re.compile("Total Prize Pool: (?P<PRIZEPOOL_CURRENCY>\$|)?(?P<PRIZEPOOL>[.,0-9]+)")
|
||||||
re_TourneyRebuyAmount = re.compile("Rebuy: (?P<REBUY_CURRENCY>\$|)?(?P<REBUY_AMOUNT>[.,0-9]+)")
|
re_TourneyRebuyCost = re.compile("Rebuy: (?P<REBUY_CURRENCY>\$|)?(?P<REBUY_COST>[.,0-9]+)")
|
||||||
re_TourneyAddOnAmount = re.compile("Add-On: (?P<ADDON_CURRENCY>\$|)?(?P<ADDON_AMOUNT>[.,0-9]+)")
|
re_TourneyAddOnCost = re.compile("Add-On: (?P<ADDON_CURRENCY>\$|)?(?P<ADDON_COST>[.,0-9]+)")
|
||||||
re_TourneyRebuyCount = re.compile("performed (?P<REBUY_COUNT>\d+) Rebuy")
|
re_TourneyRebuyCount = re.compile("performed (?P<REBUY_COUNT>\d+) Rebuy")
|
||||||
re_TourneyAddOnCount = re.compile("performed (?P<ADDON_COUNT>\d+) Add-On")
|
re_TourneyAddOnCount = re.compile("performed (?P<ADDON_COUNT>\d+) Add-On")
|
||||||
re_TourneyRebuysTotal = re.compile("Total Rebuys: (?P<REBUY_TOTAL>\d+)")
|
re_TourneyRebuysTotal = re.compile("Total Rebuys: (?P<REBUY_TOTAL>\d+)")
|
||||||
|
@ -96,10 +97,10 @@ class Fulltilt(HandHistoryConverter):
|
||||||
re_TourneyRebuyChips = re.compile("Rebuy Chips: (?P<REBUY_CHIPS>\d+)")
|
re_TourneyRebuyChips = re.compile("Rebuy Chips: (?P<REBUY_CHIPS>\d+)")
|
||||||
re_TourneyAddOnChips = re.compile("Add-On Chips: (?P<ADDON_CHIPS>\d+)")
|
re_TourneyAddOnChips = re.compile("Add-On Chips: (?P<ADDON_CHIPS>\d+)")
|
||||||
re_TourneyKOBounty = re.compile("Knockout Bounty: (?P<KO_BOUNTY_CURRENCY>\$|)?(?P<KO_BOUNTY_AMOUNT>[.,0-9]+)")
|
re_TourneyKOBounty = re.compile("Knockout Bounty: (?P<KO_BOUNTY_CURRENCY>\$|)?(?P<KO_BOUNTY_AMOUNT>[.,0-9]+)")
|
||||||
re_TourneyCountKO = re.compile("received (?P<COUNT_KO>\d+) Knockout Bounty Award(s)?")
|
re_TourneyKoCount = re.compile("received (?P<COUNT_KO>\d+) Knockout Bounty Award(s)?")
|
||||||
re_TourneyTimeInfo = re.compile("Tournament started: (?P<STARTTIME>.*)\nTournament ((?P<IN_PROGRESS>is still in progress)?|(finished:(?P<ENDTIME>.*))?)$")
|
re_TourneyTimeInfo = re.compile("Tournament started: (?P<STARTTIME>.*)\nTournament ((?P<IN_PROGRESS>is still in progress)?|(finished:(?P<ENDTIME>.*))?)$")
|
||||||
|
|
||||||
re_TourneyPlayersSummary = re.compile("^(?P<RANK>(Still Playing|\d+))( - |: )(?P<PNAME>[^\n,]+)(, )?(?P<WINNING_CURRENCY>\$|)?(?P<WINNING>[.\d]+)?", re.MULTILINE)
|
re_TourneysPlayersSummary = re.compile("^(?P<RANK>(Still Playing|\d+))( - |: )(?P<PNAME>[^\n,]+)(, )?(?P<WINNING_CURRENCY>\$|)?(?P<WINNING>[.\d]+)?", re.MULTILINE)
|
||||||
re_TourneyHeroFinishingP = re.compile("(?P<HERO_NAME>.*) finished in (?P<HERO_FINISHING_POS>\d+)(st|nd|rd|th) place")
|
re_TourneyHeroFinishingP = re.compile("(?P<HERO_NAME>.*) finished in (?P<HERO_FINISHING_POS>\d+)(st|nd|rd|th) place")
|
||||||
|
|
||||||
#TODO: See if we need to deal with play money tourney summaries -- Not right now (they shouldn't pass the re_TourneyInfo)
|
#TODO: See if we need to deal with play money tourney summaries -- Not right now (they shouldn't pass the re_TourneyInfo)
|
||||||
|
@ -221,7 +222,14 @@ class Fulltilt(HandHistoryConverter):
|
||||||
else:
|
else:
|
||||||
hand.tourneyComment = n.group('TOURNEY_NAME') # can be None
|
hand.tourneyComment = n.group('TOURNEY_NAME') # can be None
|
||||||
if (n.group('CURRENCY') is not None and n.group('BUYIN') is not None and n.group('FEE') is not None):
|
if (n.group('CURRENCY') is not None and n.group('BUYIN') is not None and n.group('FEE') is not None):
|
||||||
hand.buyin = "%s%s+%s%s" %(n.group('CURRENCY'), n.group('BUYIN'), n.group('CURRENCY'), n.group('FEE'))
|
if n.group('CURRENCY')=="$":
|
||||||
|
hand.buyinCurrency="USD"
|
||||||
|
elif n.group('CURRENCY')==u"€":
|
||||||
|
hand.buyinCurrency="EUR"
|
||||||
|
else:
|
||||||
|
hand.buyinCurrency="NA"
|
||||||
|
hand.buyin = int(100*Decimal(n.group('BUYIN')))
|
||||||
|
hand.fee = int(100*Decimal(n.group('FEE')))
|
||||||
if n.group('TURBO') is not None :
|
if n.group('TURBO') is not None :
|
||||||
hand.speed = "Turbo"
|
hand.speed = "Turbo"
|
||||||
if n.group('SPECIAL') is not None :
|
if n.group('SPECIAL') is not None :
|
||||||
|
@ -231,7 +239,7 @@ class Fulltilt(HandHistoryConverter):
|
||||||
if special == "KO":
|
if special == "KO":
|
||||||
hand.isKO = True
|
hand.isKO = True
|
||||||
if special == "Head's Up":
|
if special == "Head's Up":
|
||||||
hand.isHU = True
|
hand.maxSeats = 2
|
||||||
if re.search("Matrix", special):
|
if re.search("Matrix", special):
|
||||||
hand.isMatrix = True
|
hand.isMatrix = True
|
||||||
if special == "Shootout":
|
if special == "Shootout":
|
||||||
|
@ -264,7 +272,7 @@ class Fulltilt(HandHistoryConverter):
|
||||||
if hand.gametype['type'] == "ring" :
|
if hand.gametype['type'] == "ring" :
|
||||||
m = self.re_PlayerInfo.finditer(pre)
|
m = self.re_PlayerInfo.finditer(pre)
|
||||||
else: #if hand.gametype['type'] == "tour"
|
else: #if hand.gametype['type'] == "tour"
|
||||||
m = self.re_TourneyPlayerInfo.finditer(pre)
|
m = self.re_TourneysPlayerInfo.finditer(pre)
|
||||||
|
|
||||||
for a in m:
|
for a in m:
|
||||||
hand.addPlayer(int(a.group('SEAT')), a.group('PNAME'), a.group('CASH'))
|
hand.addPlayer(int(a.group('SEAT')), a.group('PNAME'), a.group('CASH'))
|
||||||
|
@ -430,10 +438,10 @@ class Fulltilt(HandHistoryConverter):
|
||||||
if m:
|
if m:
|
||||||
# info list should be 2 lines : Tourney infos & Finsihing postions with winnings
|
# info list should be 2 lines : Tourney infos & Finsihing postions with winnings
|
||||||
if (len(summaryInfoList) != 2 ):
|
if (len(summaryInfoList) != 2 ):
|
||||||
log.info("Too many lines (%d) in file '%s' : '%s'" % (len(summaryInfoList), self.in_path, summaryInfoList) )
|
log.info("Too many or too few lines (%d) in file '%s' : '%s'" % (len(summaryInfoList), self.in_path, summaryInfoList) )
|
||||||
self.status = False
|
self.status = False
|
||||||
else:
|
else:
|
||||||
self.tourney = Tourney.Tourney(sitename = self.sitename, gametype = None, summaryText = summaryInfoList, builtFrom = "HHC")
|
self.tourney = TourneySummary.TourneySummary(sitename = self.sitename, gametype = None, summaryText = summaryInfoList, builtFrom = "HHC")
|
||||||
self.status = self.getPlayersPositionsAndWinnings(self.tourney)
|
self.status = self.getPlayersPositionsAndWinnings(self.tourney)
|
||||||
if self.status == True :
|
if self.status == True :
|
||||||
self.status = self.determineTourneyType(self.tourney)
|
self.status = self.determineTourneyType(self.tourney)
|
||||||
|
@ -497,7 +505,6 @@ class Fulltilt(HandHistoryConverter):
|
||||||
if special == "KO":
|
if special == "KO":
|
||||||
tourney.isKO = True
|
tourney.isKO = True
|
||||||
if special == "Heads Up":
|
if special == "Heads Up":
|
||||||
tourney.isHU = True
|
|
||||||
tourney.maxseats = 2
|
tourney.maxseats = 2
|
||||||
if re.search("Matrix", special):
|
if re.search("Matrix", special):
|
||||||
tourney.isMatrix = True
|
tourney.isMatrix = True
|
||||||
|
@ -566,8 +573,8 @@ class Fulltilt(HandHistoryConverter):
|
||||||
dictRegex = { "BUYINCHIPS" : self.re_TourneyBuyInChips,
|
dictRegex = { "BUYINCHIPS" : self.re_TourneyBuyInChips,
|
||||||
"ENTRIES" : self.re_TourneyEntries,
|
"ENTRIES" : self.re_TourneyEntries,
|
||||||
"PRIZEPOOL" : self.re_TourneyPrizePool,
|
"PRIZEPOOL" : self.re_TourneyPrizePool,
|
||||||
"REBUY_AMOUNT" : self.re_TourneyRebuyAmount,
|
"REBUY_COST" : self.re_TourneyRebuyCost,
|
||||||
"ADDON_AMOUNT" : self.re_TourneyAddOnAmount,
|
"ADDON_COST" : self.re_TourneyAddOnCost,
|
||||||
"REBUY_TOTAL" : self.re_TourneyRebuysTotal,
|
"REBUY_TOTAL" : self.re_TourneyRebuysTotal,
|
||||||
"ADDONS_TOTAL" : self.re_TourneyAddOnsTotal,
|
"ADDONS_TOTAL" : self.re_TourneyAddOnsTotal,
|
||||||
"REBUY_CHIPS" : self.re_TourneyRebuyChips,
|
"REBUY_CHIPS" : self.re_TourneyRebuyChips,
|
||||||
|
@ -580,10 +587,10 @@ class Fulltilt(HandHistoryConverter):
|
||||||
dictHolders = { "BUYINCHIPS" : "buyInChips",
|
dictHolders = { "BUYINCHIPS" : "buyInChips",
|
||||||
"ENTRIES" : "entries",
|
"ENTRIES" : "entries",
|
||||||
"PRIZEPOOL" : "prizepool",
|
"PRIZEPOOL" : "prizepool",
|
||||||
"REBUY_AMOUNT" : "rebuyAmount",
|
"REBUY_COST" : "rebuyCost",
|
||||||
"ADDON_AMOUNT" : "addOnAmount",
|
"ADDON_COST" : "addOnCost",
|
||||||
"REBUY_TOTAL" : "totalRebuys",
|
"REBUY_TOTAL" : "totalRebuyCount",
|
||||||
"ADDONS_TOTAL" : "totalAddOns",
|
"ADDONS_TOTAL" : "totalAddOnCount",
|
||||||
"REBUY_CHIPS" : "rebuyChips",
|
"REBUY_CHIPS" : "rebuyChips",
|
||||||
"ADDON_CHIPS" : "addOnChips",
|
"ADDON_CHIPS" : "addOnChips",
|
||||||
"STARTTIME" : "starttime",
|
"STARTTIME" : "starttime",
|
||||||
|
@ -607,42 +614,39 @@ class Fulltilt(HandHistoryConverter):
|
||||||
if m is not None:
|
if m is not None:
|
||||||
mg = m.groupdict()
|
mg = m.groupdict()
|
||||||
if mg['REBUY_COUNT'] is not None :
|
if mg['REBUY_COUNT'] is not None :
|
||||||
tourney.countRebuys.update( { tourney.hero : Decimal(mg['REBUY_COUNT']) } )
|
tourney.rebuyCounts.update( { tourney.hero : Decimal(mg['REBUY_COUNT']) } )
|
||||||
m = self.re_TourneyAddOnCount.search(tourneyText)
|
m = self.re_TourneyAddOnCount.search(tourneyText)
|
||||||
if m is not None:
|
if m is not None:
|
||||||
mg = m.groupdict()
|
mg = m.groupdict()
|
||||||
if mg['ADDON_COUNT'] is not None :
|
if mg['ADDON_COUNT'] is not None :
|
||||||
tourney.countAddOns.update( { tourney.hero : Decimal(mg['ADDON_COUNT']) } )
|
tourney.addOnCounts.update( { tourney.hero : Decimal(mg['ADDON_COUNT']) } )
|
||||||
m = self.re_TourneyCountKO.search(tourneyText)
|
m = self.re_TourneyKoCount.search(tourneyText)
|
||||||
if m is not None:
|
if m is not None:
|
||||||
mg = m.groupdict()
|
mg = m.groupdict()
|
||||||
if mg['COUNT_KO'] is not None :
|
if mg['COUNT_KO'] is not None :
|
||||||
tourney.countKO.update( { tourney.hero : Decimal(mg['COUNT_KO']) } )
|
tourney.koCounts.update( { tourney.hero : Decimal(mg['COUNT_KO']) } )
|
||||||
|
|
||||||
# Deal with money amounts
|
# Deal with money amounts
|
||||||
tourney.koBounty = 100*Decimal(re.sub(u',', u'', "%s" % tourney.koBounty))
|
tourney.koBounty = 100*Decimal(re.sub(u',', u'', "%s" % tourney.koBounty))
|
||||||
tourney.prizepool = 100*Decimal(re.sub(u',', u'', "%s" % tourney.prizepool))
|
tourney.prizepool = 100*Decimal(re.sub(u',', u'', "%s" % tourney.prizepool))
|
||||||
tourney.rebuyAmount = 100*Decimal(re.sub(u',', u'', "%s" % tourney.rebuyAmount))
|
tourney.rebuyCost = 100*Decimal(re.sub(u',', u'', "%s" % tourney.rebuyCost))
|
||||||
tourney.addOnAmount = 100*Decimal(re.sub(u',', u'', "%s" % tourney.addOnAmount))
|
tourney.addOnCost = 100*Decimal(re.sub(u',', u'', "%s" % tourney.addOnCost))
|
||||||
|
|
||||||
# Calculate payin amounts and update winnings -- not possible to take into account nb of rebuys, addons or Knockouts for other players than hero on FTP
|
# Calculate payin amounts and update winnings -- not possible to take into account nb of rebuys, addons or Knockouts for other players than hero on FTP
|
||||||
for p in tourney.players :
|
for p in tourney.players :
|
||||||
tourney.payinAmounts[p] = tourney.buyin + tourney.fee + (tourney.rebuyAmount * tourney.countRebuys[p]) + (tourney.addOnAmount * tourney.countAddOns[p])
|
|
||||||
#print " player %s : payinAmount = %d" %( p, tourney.payinAmounts[p])
|
|
||||||
if tourney.isKO :
|
if tourney.isKO :
|
||||||
#tourney.incrementPlayerWinnings(tourney.players[p], Decimal(tourney.koBounty)*Decimal(tourney.countKO[p]))
|
#tourney.incrementPlayerWinnings(tourney.players[p], Decimal(tourney.koBounty)*Decimal(tourney.koCounts[p]))
|
||||||
tourney.winnings[p] += Decimal(tourney.koBounty)*Decimal(tourney.countKO[p])
|
tourney.winnings[p] += Decimal(tourney.koBounty)*Decimal(tourney.koCounts[p])
|
||||||
#print "player %s : winnings %d" % (p, tourney.winnings[p])
|
#print "player %s : winnings %d" % (p, tourney.winnings[p])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#print mg
|
#print mg
|
||||||
return True
|
return True
|
||||||
|
#end def determineTourneyType
|
||||||
|
|
||||||
def getPlayersPositionsAndWinnings(self, tourney):
|
def getPlayersPositionsAndWinnings(self, tourney):
|
||||||
playersText = tourney.summaryText[1]
|
playersText = tourney.summaryText[1]
|
||||||
#print "Examine : '%s'" %(playersText)
|
#print "Examine : '%s'" %(playersText)
|
||||||
m = self.re_TourneyPlayersSummary.finditer(playersText)
|
m = self.re_TourneysPlayersSummary.finditer(playersText)
|
||||||
|
|
||||||
for a in m:
|
for a in m:
|
||||||
if a.group('PNAME') is not None and a.group('RANK') is not None:
|
if a.group('PNAME') is not None and a.group('RANK') is not None:
|
||||||
|
@ -656,7 +660,7 @@ class Fulltilt(HandHistoryConverter):
|
||||||
else:
|
else:
|
||||||
winnings = "0"
|
winnings = "0"
|
||||||
|
|
||||||
tourney.addPlayer(rank, a.group('PNAME'), winnings, 0, 0, 0, 0)
|
tourney.addPlayer(rank, a.group('PNAME'), winnings, "USD", 0, 0, 0) #TODO: make it store actual winnings currency
|
||||||
else:
|
else:
|
||||||
print "FullTilt: Player finishing stats unreadable : %s" % a
|
print "FullTilt: Player finishing stats unreadable : %s" % a
|
||||||
|
|
||||||
|
@ -666,10 +670,10 @@ class Fulltilt(HandHistoryConverter):
|
||||||
heroName = n.group('HERO_NAME')
|
heroName = n.group('HERO_NAME')
|
||||||
tourney.hero = heroName
|
tourney.hero = heroName
|
||||||
# Is this really useful ?
|
# Is this really useful ?
|
||||||
if heroName not in tourney.finishPositions:
|
if heroName not in tourney.ranks:
|
||||||
print "FullTilt:", heroName, "not found in tourney.finishPositions ..."
|
print "FullTilt:", heroName, "not found in tourney.ranks ..."
|
||||||
elif (tourney.finishPositions[heroName] != Decimal(n.group('HERO_FINISHING_POS'))):
|
elif (tourney.ranks[heroName] != Decimal(n.group('HERO_FINISHING_POS'))):
|
||||||
print "FullTilt: Bad parsing : finish position incoherent : %s / %s" % (tourney.finishPositions[heroName], n.group('HERO_FINISHING_POS'))
|
print "FullTilt: Bad parsing : finish position incoherent : %s / %s" % (tourney.ranks[heroName], n.group('HERO_FINISHING_POS'))
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ import Configuration
|
||||||
from Exceptions import *
|
from Exceptions import *
|
||||||
import DerivedStats
|
import DerivedStats
|
||||||
import Card
|
import Card
|
||||||
|
import Tourney
|
||||||
|
|
||||||
class Hand(object):
|
class Hand(object):
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ class Hand(object):
|
||||||
self.siteId = self.SITEIDS[sitename]
|
self.siteId = self.SITEIDS[sitename]
|
||||||
self.stats = DerivedStats.DerivedStats(self)
|
self.stats = DerivedStats.DerivedStats(self)
|
||||||
self.gametype = gametype
|
self.gametype = gametype
|
||||||
self.starttime = 0
|
self.startTime = 0
|
||||||
self.handText = handText
|
self.handText = handText
|
||||||
self.handid = 0
|
self.handid = 0
|
||||||
self.cancelled = False
|
self.cancelled = False
|
||||||
|
@ -69,16 +69,21 @@ class Hand(object):
|
||||||
self.maxseats = None
|
self.maxseats = None
|
||||||
self.counted_seats = 0
|
self.counted_seats = 0
|
||||||
self.buttonpos = 0
|
self.buttonpos = 0
|
||||||
|
|
||||||
|
#tourney stuff
|
||||||
self.tourNo = None
|
self.tourNo = None
|
||||||
|
self.tourneyId = None
|
||||||
|
self.tourneyTypeId = None
|
||||||
self.buyin = None
|
self.buyin = None
|
||||||
|
self.buyinCurrency = None
|
||||||
|
self.buyInChips = None
|
||||||
self.fee = None # the Database code is looking for this one .. ?
|
self.fee = None # the Database code is looking for this one .. ?
|
||||||
self.level = None
|
self.level = None
|
||||||
self.mixed = None
|
self.mixed = None
|
||||||
# Some attributes for hand from a tourney
|
|
||||||
self.speed = "Normal"
|
self.speed = "Normal"
|
||||||
self.isRebuy = False
|
self.isRebuy = False
|
||||||
|
self.isAddOn = False
|
||||||
self.isKO = False
|
self.isKO = False
|
||||||
self.isHU = False
|
|
||||||
self.isMatrix = False
|
self.isMatrix = False
|
||||||
self.isShootout = False
|
self.isShootout = False
|
||||||
self.tourneyComment = None
|
self.tourneyComment = None
|
||||||
|
@ -86,7 +91,8 @@ class Hand(object):
|
||||||
self.seating = []
|
self.seating = []
|
||||||
self.players = []
|
self.players = []
|
||||||
self.posted = []
|
self.posted = []
|
||||||
|
self.tourneysPlayersIds = []
|
||||||
|
|
||||||
# Collections indexed by street names
|
# Collections indexed by street names
|
||||||
self.bets = {}
|
self.bets = {}
|
||||||
self.lastBet = {}
|
self.lastBet = {}
|
||||||
|
@ -135,8 +141,6 @@ class Hand(object):
|
||||||
("TABLE NAME", self.tablename),
|
("TABLE NAME", self.tablename),
|
||||||
("HERO", self.hero),
|
("HERO", self.hero),
|
||||||
("MAXSEATS", self.maxseats),
|
("MAXSEATS", self.maxseats),
|
||||||
("TOURNAMENT NO", self.tourNo),
|
|
||||||
("BUYIN", self.buyin),
|
|
||||||
("LEVEL", self.level),
|
("LEVEL", self.level),
|
||||||
("MIXED", self.mixed),
|
("MIXED", self.mixed),
|
||||||
("LASTBET", self.lastBet),
|
("LASTBET", self.lastBet),
|
||||||
|
@ -152,7 +156,20 @@ class Hand(object):
|
||||||
("TOTAL POT", self.totalpot),
|
("TOTAL POT", self.totalpot),
|
||||||
("TOTAL COLLECTED", self.totalcollected),
|
("TOTAL COLLECTED", self.totalcollected),
|
||||||
("RAKE", self.rake),
|
("RAKE", self.rake),
|
||||||
("START TIME", self.starttime),
|
("START TIME", self.startTime),
|
||||||
|
("TOURNAMENT NO", self.tourNo),
|
||||||
|
("TOURNEY ID", self.tourneyId),
|
||||||
|
("TOURNEY TYPE ID", self.tourneyTypeId),
|
||||||
|
("BUYIN", self.buyin),
|
||||||
|
("BUYIN CURRENCY", self.buyinCurrency),
|
||||||
|
("BUYIN CHIPS", self.buyInChips),
|
||||||
|
("FEE", self.fee),
|
||||||
|
("IS REBUY", self.isRebuy),
|
||||||
|
("IS ADDON", self.isAddOn),
|
||||||
|
("IS KO", self.isKO),
|
||||||
|
("IS MATRIX", self.isMatrix),
|
||||||
|
("IS SHOOTOUT", self.isShootout),
|
||||||
|
("TOURNEY COMMENT", self.tourneyComment),
|
||||||
)
|
)
|
||||||
|
|
||||||
structs = ( ("PLAYERS", self.players),
|
structs = ( ("PLAYERS", self.players),
|
||||||
|
@ -167,6 +184,7 @@ class Hand(object):
|
||||||
("BOARD", self.board),
|
("BOARD", self.board),
|
||||||
("DISCARDS", self.discards),
|
("DISCARDS", self.discards),
|
||||||
("HOLECARDS", self.holecards),
|
("HOLECARDS", self.holecards),
|
||||||
|
("TOURNEYS PLAYER IDS", self.tourneysPlayersIds),
|
||||||
)
|
)
|
||||||
str = ''
|
str = ''
|
||||||
for (name, var) in vars:
|
for (name, var) in vars:
|
||||||
|
@ -208,6 +226,15 @@ dealt whether they were seen in a 'dealt to' line
|
||||||
|
|
||||||
#Gametypes
|
#Gametypes
|
||||||
self.dbid_gt = db.getGameTypeId(self.siteId, self.gametype)
|
self.dbid_gt = db.getGameTypeId(self.siteId, self.gametype)
|
||||||
|
|
||||||
|
if self.tourNo!=None:
|
||||||
|
self.tourneyTypeId = db.createOrUpdateTourneyType(self)
|
||||||
|
db.commit()
|
||||||
|
self.tourneyId = db.createOrUpdateTourney(self)
|
||||||
|
db.commit()
|
||||||
|
self.tourneysPlayersIds = db.createOrUpdateTourneysPlayers(self)
|
||||||
|
db.commit()
|
||||||
|
#end def prepInsert
|
||||||
|
|
||||||
def insert(self, db):
|
def insert(self, db):
|
||||||
""" Function to insert Hand into database
|
""" Function to insert Hand into database
|
||||||
|
@ -230,17 +257,15 @@ db: a connected Database object"""
|
||||||
|
|
||||||
self.dbid_hands = db.storeHand(hh)
|
self.dbid_hands = db.storeHand(hh)
|
||||||
db.storeHandsPlayers(self.dbid_hands, self.dbid_pids, self.stats.getHandsPlayers())
|
db.storeHandsPlayers(self.dbid_hands, self.dbid_pids, self.stats.getHandsPlayers())
|
||||||
# HandsActions - all actions for all players for all streets - self.actions
|
# TODO HandsActions - all actions for all players for all streets - self.actions
|
||||||
# HudCache data can be generated from HandsActions (HandsPlayers?)
|
# HudCache data can be generated from HandsActions (HandsPlayers?)
|
||||||
# Tourneys ?
|
|
||||||
# TourneysPlayers
|
|
||||||
else:
|
else:
|
||||||
log.info("Hand.insert(): hid #: %s is a duplicate" % hh['siteHandNo'])
|
log.info("Hand.insert(): hid #: %s is a duplicate" % hh['siteHandNo'])
|
||||||
self.is_duplicate = True # i.e. don't update hudcache
|
self.is_duplicate = True # i.e. don't update hudcache
|
||||||
raise FpdbHandDuplicate(hh['siteHandNo'])
|
raise FpdbHandDuplicate(hh['siteHandNo'])
|
||||||
|
|
||||||
def updateHudCache(self, db):
|
def updateHudCache(self, db):
|
||||||
db.storeHudCache(self.dbid_gt, self.dbid_pids, self.starttime, self.stats.getHandsPlayers())
|
db.storeHudCache(self.dbid_gt, self.dbid_pids, self.startTime, self.stats.getHandsPlayers())
|
||||||
|
|
||||||
def select(self, handId):
|
def select(self, handId):
|
||||||
""" Function to create Hand object from database """
|
""" Function to create Hand object from database """
|
||||||
|
@ -603,10 +628,10 @@ Map the tuple self.gametype onto the pokerstars string describing it
|
||||||
gs = gs + " %s (%s) - " % (self.getGameTypeAsString(), self.getStakesAsString())
|
gs = gs + " %s (%s) - " % (self.getGameTypeAsString(), self.getStakesAsString())
|
||||||
|
|
||||||
try:
|
try:
|
||||||
timestr = datetime.datetime.strftime(self.starttime, '%Y/%m/%d %H:%M:%S ET')
|
timestr = datetime.datetime.strftime(self.startTime, '%Y/%m/%d %H:%M:%S ET')
|
||||||
except TypeError:
|
except TypeError:
|
||||||
print "*** ERROR - HAND: calling writeGameLine with unexpected STARTTIME value, expecting datetime.date object, received:", self.starttime
|
print "*** ERROR - HAND: calling writeGameLine with unexpected STARTTIME value, expecting datetime.date object, received:", self.startTime
|
||||||
print "*** Make sure your HandHistoryConverter is setting hand.starttime properly!"
|
print "*** Make sure your HandHistoryConverter is setting hand.startTime properly!"
|
||||||
print "*** Game String:", gs
|
print "*** Game String:", gs
|
||||||
return gs
|
return gs
|
||||||
else:
|
else:
|
||||||
|
@ -806,7 +831,7 @@ class HoldemOmahaHand(Hand):
|
||||||
T.h1[
|
T.h1[
|
||||||
T.span(class_='site')["%s Game #%s]" % ('PokerStars', self.handid)],
|
T.span(class_='site')["%s Game #%s]" % ('PokerStars', self.handid)],
|
||||||
T.span(class_='type_limit')[ "%s ($%s/$%s)" %(self.getGameTypeAsString(), self.sb, self.bb) ],
|
T.span(class_='type_limit')[ "%s ($%s/$%s)" %(self.getGameTypeAsString(), self.sb, self.bb) ],
|
||||||
T.span(class_='date')[ datetime.datetime.strftime(self.starttime,'%Y/%m/%d - %H:%M:%S ET') ]
|
T.span(class_='date')[ datetime.datetime.strftime(self.startTime,'%Y/%m/%d - %H:%M:%S ET') ]
|
||||||
],
|
],
|
||||||
T.h2[ "Table '%s' %d-max Seat #%s is the button" %(self.tablename,
|
T.h2[ "Table '%s' %d-max Seat #%s is the button" %(self.tablename,
|
||||||
self.maxseats, self.buttonpos)],
|
self.maxseats, self.buttonpos)],
|
||||||
|
@ -1556,7 +1581,7 @@ limit 1""", {'handid':handid})
|
||||||
SELECT
|
SELECT
|
||||||
h.sitehandno as hid,
|
h.sitehandno as hid,
|
||||||
h.tablename as table,
|
h.tablename as table,
|
||||||
h.handstart as starttime
|
h.handstart as startTime
|
||||||
FROM
|
FROM
|
||||||
hands as h
|
hands as h
|
||||||
WHERE h.id = %(handid)s
|
WHERE h.id = %(handid)s
|
||||||
|
@ -1564,7 +1589,7 @@ WHERE h.id = %(handid)s
|
||||||
res = c.fetchone()
|
res = c.fetchone()
|
||||||
h.handid = res[0]
|
h.handid = res[0]
|
||||||
h.tablename = res[1]
|
h.tablename = res[1]
|
||||||
h.starttime = res[2] # automatically a datetime
|
h.startTime = res[2] # automatically a datetime
|
||||||
|
|
||||||
# PlayerStacks
|
# PlayerStacks
|
||||||
c.execute("""
|
c.execute("""
|
||||||
|
|
82
pyfpdb/ImapSummaries.py
Executable file
82
pyfpdb/ImapSummaries.py
Executable file
|
@ -0,0 +1,82 @@
|
||||||
|
#!/usr/bin/python2
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
#Copyright 2008-2010 Steffen Schaumburg
|
||||||
|
#This program is free software: you can redistribute it and/or modify
|
||||||
|
#it under the terms of the GNU Affero General Public License as published by
|
||||||
|
#the Free Software Foundation, version 3 of the License.
|
||||||
|
#
|
||||||
|
#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 Affero General Public License
|
||||||
|
#along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#In the "official" distribution you can find the license in agpl-3.0.txt.
|
||||||
|
|
||||||
|
"""This file is to fetch summaries through IMAP and pass them on to the appropriate parser"""
|
||||||
|
#see http://docs.python.org/library/imaplib.html for the python interface
|
||||||
|
#see http://tools.ietf.org/html/rfc2060#section-6.4.4 for IMAP4 search criteria
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from imaplib import IMAP4_SSL
|
||||||
|
import PokerStarsSummary
|
||||||
|
|
||||||
|
def splitPokerStarsSummaries(emailText):
|
||||||
|
splitSummaries=emailText.split("\nPokerStars Tournament #")[1:]
|
||||||
|
for i in range(len(splitSummaries)):
|
||||||
|
splitSummaries[i]="PokerStars Tournament #"+splitSummaries[i]
|
||||||
|
return splitSummaries
|
||||||
|
#end def emailText
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
#TODO: move all these into the config file. until then usage is: ./ImapSummaries.py YourImapHost YourImapUser YourImapPw
|
||||||
|
configHost=sys.argv[1]
|
||||||
|
configUser=sys.argv[2]
|
||||||
|
configPw=sys.argv[3]
|
||||||
|
#TODO: specify folder, whether to use SSL
|
||||||
|
|
||||||
|
try:
|
||||||
|
server = IMAP4_SSL(configHost) #TODO: optionally non-SSL
|
||||||
|
response = server.login(configUser, configPw) #TODO catch authentication error
|
||||||
|
#print "response to logging in:",response
|
||||||
|
#print "server.list():",server.list() #prints list of folders
|
||||||
|
|
||||||
|
response = server.select("INBOX")
|
||||||
|
#print "response to selecting INBOX:",response
|
||||||
|
if response[0]!="OK":
|
||||||
|
raise error #TODO: show error message
|
||||||
|
|
||||||
|
neededMessages=[]
|
||||||
|
response, searchData = server.search(None, "SUBJECT", "PokerStars Tournament History Request")
|
||||||
|
for messageNumber in searchData[0].split(" "):
|
||||||
|
response, headerData = server.fetch(messageNumber, "(BODY[HEADER.FIELDS (SUBJECT)])")
|
||||||
|
#print "response to fetch subject:",response
|
||||||
|
if response!="OK":
|
||||||
|
raise error #TODO: show error message
|
||||||
|
if headerData[1].find("Subject: PokerStars Tournament History Request - Last x")!=1:
|
||||||
|
neededMessages.append(("PS", messageNumber))
|
||||||
|
|
||||||
|
if (len(neededMessages)==0):
|
||||||
|
raise error #TODO: show error message
|
||||||
|
for messageData in neededMessages:
|
||||||
|
response, bodyData = server.fetch(messageData[1], "(UID BODY[TEXT])")
|
||||||
|
bodyData=bodyData[0][1]
|
||||||
|
if response!="OK":
|
||||||
|
raise error #TODO: show error message
|
||||||
|
if messageData[0]=="PS":
|
||||||
|
summaryTexts=(splitPokerStarsSummaries(bodyData))
|
||||||
|
for summaryText in summaryTexts:
|
||||||
|
result=PokerStarsSummary.PokerStarsSummary(sitename="PokerStars", gametype=None, summaryText=summaryText, builtFrom = "IMAP")
|
||||||
|
#print "result:",result
|
||||||
|
#TODO: count results and output to shell like hand importer does
|
||||||
|
|
||||||
|
print "completed running Imap import, closing server connection"
|
||||||
|
finally:
|
||||||
|
try:
|
||||||
|
server.close()
|
||||||
|
finally:
|
||||||
|
pass
|
||||||
|
server.logout()
|
||||||
|
|
67
pyfpdb/PokerStarsSummary.py
Normal file
67
pyfpdb/PokerStarsSummary.py
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
#!/usr/bin/python2
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
#Copyright 2008-2010 Steffen Schaumburg
|
||||||
|
#This program is free software: you can redistribute it and/or modify
|
||||||
|
#it under the terms of the GNU Affero General Public License as published by
|
||||||
|
#the Free Software Foundation, version 3 of the License.
|
||||||
|
#
|
||||||
|
#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 Affero General Public License
|
||||||
|
#along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#In the "official" distribution you can find the license in agpl-3.0.txt.
|
||||||
|
|
||||||
|
"""pokerstars-specific summary parsing code"""
|
||||||
|
|
||||||
|
from decimal import Decimal
|
||||||
|
|
||||||
|
from PokerStarsToFpdb import PokerStars
|
||||||
|
from TourneySummary import *
|
||||||
|
|
||||||
|
class PokerStarsSummary(TourneySummary):
|
||||||
|
sitename = "PokerStars"
|
||||||
|
siteId = 2
|
||||||
|
#limits = PokerStars.limits
|
||||||
|
#games = PokerStars.games
|
||||||
|
# = PokerStars.
|
||||||
|
|
||||||
|
re_TourNo = re.compile("\#[0-9]+,")
|
||||||
|
re_Entries = re.compile("[0-9]+")
|
||||||
|
re_Prizepool = re.compile("\$[0-9]+\.[0-9]+")
|
||||||
|
re_Player = re.compile("""(?P<RANK>[0-9]+):\s(?P<NAME>.*)\s\(.*\),(\s\$(?P<WINNINGS>[0-9]+\.[0-9]+)\s\()?""")
|
||||||
|
# = re.compile("")
|
||||||
|
|
||||||
|
def parseSummary(self):
|
||||||
|
lines=self.summaryText.splitlines()
|
||||||
|
|
||||||
|
self.tourNo = self.re_TourNo.findall(lines[0])[0][1:-1] #ignore game and limit type as thats not recorded
|
||||||
|
|
||||||
|
#ignore lines[1] as buyin/fee are already recorded by HHC
|
||||||
|
|
||||||
|
self.entries = self.re_Entries.findall(lines[2])[0]
|
||||||
|
|
||||||
|
self.prizepool = self.re_Prizepool.findall(lines[3])[0]
|
||||||
|
self.prizepool = self.prizepool[1:-3]+self.prizepool[-2:]
|
||||||
|
|
||||||
|
#TODO: lines 4 and 5 are dates, read them
|
||||||
|
|
||||||
|
for i in range(6,len(lines)-2): #lines with rank and winnings info
|
||||||
|
if lines[i].find(":")==-1:
|
||||||
|
break
|
||||||
|
result=self.re_Player.search(lines[i])
|
||||||
|
result=result.groupdict()
|
||||||
|
rank=result['RANK']
|
||||||
|
name=result['NAME']
|
||||||
|
winnings=result['WINNINGS']
|
||||||
|
if winnings:
|
||||||
|
winnings=int(100*Decimal(winnings))
|
||||||
|
else:
|
||||||
|
winnings=0
|
||||||
|
|
||||||
|
self.addPlayer(rank, name, winnings, "USD", None, None, None)#TODO: currency, ko/addon/rebuy count -> need examples!
|
||||||
|
#end def parseSummary
|
||||||
|
#end class PokerStarsSummary
|
|
@ -22,6 +22,7 @@
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
from HandHistoryConverter import *
|
from HandHistoryConverter import *
|
||||||
|
from decimal import Decimal
|
||||||
|
|
||||||
# PokerStars HH Format
|
# PokerStars HH Format
|
||||||
|
|
||||||
|
@ -40,6 +41,30 @@ class PokerStars(HandHistoryConverter):
|
||||||
'LEGAL_ISO' : "USD|EUR|GBP|CAD|FPP", # legal ISO currency codes
|
'LEGAL_ISO' : "USD|EUR|GBP|CAD|FPP", # legal ISO currency codes
|
||||||
'LS' : "\$|\xe2\x82\xac|" # legal currency symbols - Euro(cp1252, utf-8)
|
'LS' : "\$|\xe2\x82\xac|" # legal currency symbols - Euro(cp1252, utf-8)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# translations from captured groups to fpdb info strings
|
||||||
|
Lim_Blinds = { '0.04': ('0.01', '0.02'), '0.10': ('0.02', '0.05'), '0.20': ('0.05', '0.10'),
|
||||||
|
'0.40': ('0.10', '0.20'), '0.50': ('0.10', '0.25'), '1.00': ('0.25', '0.50'),
|
||||||
|
'2.00': ('0.50', '1.00'), '2': ('0.50', '1.00'), '4' : ('1.00', '2.00'),
|
||||||
|
'4.00': ('1.00', '2.00'), '6': ('1.00', '3.00'), '6.00': ('1.00', '3.00'),
|
||||||
|
'10.00': ('2.00', '5.00'), '20.00': ('5.00', '10.00'), '30.00': ('10.00', '15.00'),
|
||||||
|
'60.00': ('15.00', '30.00'), '100.00': ('25.00', '50.00'), '200.00': ('50.00', '100.00'),
|
||||||
|
'400.00': ('100.00', '200.00'), '1000.00': ('250.00', '500.00')}
|
||||||
|
|
||||||
|
limits = { 'No Limit':'nl', 'Pot Limit':'pl', 'Limit':'fl', 'LIMIT':'fl' }
|
||||||
|
games = { # base, category
|
||||||
|
"Hold'em" : ('hold','holdem'),
|
||||||
|
'Omaha' : ('hold','omahahi'),
|
||||||
|
'Omaha Hi/Lo' : ('hold','omahahilo'),
|
||||||
|
'Razz' : ('stud','razz'),
|
||||||
|
'RAZZ' : ('stud','razz'),
|
||||||
|
'7 Card Stud' : ('stud','studhi'),
|
||||||
|
'7 Card Stud Hi/Lo' : ('stud','studhilo'),
|
||||||
|
'Badugi' : ('draw','badugi'),
|
||||||
|
'Triple Draw 2-7 Lowball' : ('draw','27_3draw'),
|
||||||
|
'5 Card Draw' : ('draw','fivedraw')
|
||||||
|
}
|
||||||
|
currencies = { u'€':'EUR', '$':'USD', '':'T$' }
|
||||||
|
|
||||||
# Static regexes
|
# Static regexes
|
||||||
re_GameInfo = re.compile(u"""
|
re_GameInfo = re.compile(u"""
|
||||||
|
@ -143,43 +168,20 @@ class PokerStars(HandHistoryConverter):
|
||||||
raise FpdbParseError("Unable to recognise gametype from: '%s'" % tmp)
|
raise FpdbParseError("Unable to recognise gametype from: '%s'" % tmp)
|
||||||
|
|
||||||
mg = m.groupdict()
|
mg = m.groupdict()
|
||||||
# translations from captured groups to fpdb info strings
|
|
||||||
Lim_Blinds = { '0.04': ('0.01', '0.02'), '0.10': ('0.02', '0.05'), '0.20': ('0.05', '0.10'),
|
|
||||||
'0.40': ('0.10', '0.20'), '0.50': ('0.10', '0.25'), '1.00': ('0.25', '0.50'),
|
|
||||||
'2.00': ('0.50', '1.00'), '2': ('0.50', '1.00'), '4' : ('1.00', '2.00'),
|
|
||||||
'4.00': ('1.00', '2.00'), '6': ('1.00', '3.00'), '6.00': ('1.00', '3.00'),
|
|
||||||
'10.00': ('2.00', '5.00'), '20.00': ('5.00', '10.00'), '30.00': ('10.00', '15.00'),
|
|
||||||
'60.00': ('15.00', '30.00'), '100.00': ('25.00', '50.00'), '200.00': ('50.00', '100.00'),
|
|
||||||
'400.00': ('100.00', '200.00'), '1000.00': ('250.00', '500.00')}
|
|
||||||
|
|
||||||
limits = { 'No Limit':'nl', 'Pot Limit':'pl', 'Limit':'fl', 'LIMIT':'fl' }
|
|
||||||
games = { # base, category
|
|
||||||
"Hold'em" : ('hold','holdem'),
|
|
||||||
'Omaha' : ('hold','omahahi'),
|
|
||||||
'Omaha Hi/Lo' : ('hold','omahahilo'),
|
|
||||||
'Razz' : ('stud','razz'),
|
|
||||||
'RAZZ' : ('stud','razz'),
|
|
||||||
'7 Card Stud' : ('stud','studhi'),
|
|
||||||
'7 Card Stud Hi/Lo' : ('stud','studhilo'),
|
|
||||||
'Badugi' : ('draw','badugi'),
|
|
||||||
'Triple Draw 2-7 Lowball' : ('draw','27_3draw'),
|
|
||||||
'5 Card Draw' : ('draw','fivedraw')
|
|
||||||
}
|
|
||||||
currencies = { u'€':'EUR', '$':'USD', '':'T$' }
|
|
||||||
# I don't think this is doing what we think. mg will always have all
|
# I don't think this is doing what we think. mg will always have all
|
||||||
# the expected keys, but the ones that didn't match in the regex will
|
# the expected keys, but the ones that didn't match in the regex will
|
||||||
# have a value of None. It is OK if it throws an exception when it
|
# have a value of None. It is OK if it throws an exception when it
|
||||||
# runs across an unknown game or limit or whatever.
|
# runs across an unknown game or limit or whatever.
|
||||||
if 'LIMIT' in mg:
|
if 'LIMIT' in mg:
|
||||||
info['limitType'] = limits[mg['LIMIT']]
|
info['limitType'] = self.limits[mg['LIMIT']]
|
||||||
if 'GAME' in mg:
|
if 'GAME' in mg:
|
||||||
(info['base'], info['category']) = games[mg['GAME']]
|
(info['base'], info['category']) = self.games[mg['GAME']]
|
||||||
if 'SB' in mg:
|
if 'SB' in mg:
|
||||||
info['sb'] = mg['SB']
|
info['sb'] = mg['SB']
|
||||||
if 'BB' in mg:
|
if 'BB' in mg:
|
||||||
info['bb'] = mg['BB']
|
info['bb'] = mg['BB']
|
||||||
if 'CURRENCY' in mg:
|
if 'CURRENCY' in mg:
|
||||||
info['currency'] = currencies[mg['CURRENCY']]
|
info['currency'] = self.currencies[mg['CURRENCY']]
|
||||||
|
|
||||||
if 'TOURNO' in mg and mg['TOURNO'] is None:
|
if 'TOURNO' in mg and mg['TOURNO'] is None:
|
||||||
info['type'] = 'ring'
|
info['type'] = 'ring'
|
||||||
|
@ -188,8 +190,8 @@ class PokerStars(HandHistoryConverter):
|
||||||
|
|
||||||
if info['limitType'] == 'fl' and info['bb'] is not None and info['type'] == 'ring' and info['base'] != 'stud':
|
if info['limitType'] == 'fl' and info['bb'] is not None and info['type'] == 'ring' and info['base'] != 'stud':
|
||||||
try:
|
try:
|
||||||
info['sb'] = Lim_Blinds[mg['BB']][0]
|
info['sb'] = self.Lim_Blinds[mg['BB']][0]
|
||||||
info['bb'] = Lim_Blinds[mg['BB']][1]
|
info['bb'] = self.Lim_Blinds[mg['BB']][1]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
log.error("determineGameType: Lim_Blinds has no lookup for '%s'" % mg['BB'])
|
log.error("determineGameType: Lim_Blinds has no lookup for '%s'" % mg['BB'])
|
||||||
log.error("determineGameType: Raising FpdbParseError")
|
log.error("determineGameType: Raising FpdbParseError")
|
||||||
|
@ -241,12 +243,22 @@ class PokerStars(HandHistoryConverter):
|
||||||
if key == 'TOURNO':
|
if key == 'TOURNO':
|
||||||
hand.tourNo = info[key]
|
hand.tourNo = info[key]
|
||||||
if key == 'BUYIN':
|
if key == 'BUYIN':
|
||||||
if info[key] == 'Freeroll':
|
if hand.tourNo!=None:
|
||||||
hand.buyin = '$0+$0'
|
if info[key] == 'Freeroll':
|
||||||
else:
|
hand.buyin = 0
|
||||||
#FIXME: The key looks like: '€0.82+€0.18 EUR'
|
hand.fee = 0
|
||||||
# This should be parsed properly and used
|
hand.buyinCurrency = "FREE"
|
||||||
hand.buyin = info[key]
|
else:
|
||||||
|
if info[key].find("$")!=-1:
|
||||||
|
hand.buyinCurrency="USD"
|
||||||
|
elif info[key].find(u"€")!=-1:
|
||||||
|
hand.buyinCurrency="EUR"
|
||||||
|
else:
|
||||||
|
hand.buyinCurrency="NA" #FIXME: handle other currencies, FPP, play money
|
||||||
|
info[key]=info[key][:-4]
|
||||||
|
middle=info[key].find("+")
|
||||||
|
hand.buyin = int(100*Decimal(info[key][1:middle]))
|
||||||
|
hand.fee = int(100*Decimal(info[key][middle+2:]))
|
||||||
if key == 'LEVEL':
|
if key == 'LEVEL':
|
||||||
hand.level = info[key]
|
hand.level = info[key]
|
||||||
|
|
||||||
|
|
279
pyfpdb/SQL.py
279
pyfpdb/SQL.py
|
@ -115,18 +115,18 @@ class Sql:
|
||||||
self.query['createSitesTable'] = """CREATE TABLE Sites (
|
self.query['createSitesTable'] = """CREATE TABLE Sites (
|
||||||
id SMALLINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id),
|
id SMALLINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id),
|
||||||
name varchar(32) NOT NULL,
|
name varchar(32) NOT NULL,
|
||||||
currency char(3) NOT NULL)
|
code char(2) NOT NULL)
|
||||||
ENGINE=INNODB"""
|
ENGINE=INNODB"""
|
||||||
elif db_server == 'postgresql':
|
elif db_server == 'postgresql':
|
||||||
self.query['createSitesTable'] = """CREATE TABLE Sites (
|
self.query['createSitesTable'] = """CREATE TABLE Sites (
|
||||||
id SERIAL, PRIMARY KEY (id),
|
id SERIAL, PRIMARY KEY (id),
|
||||||
name varchar(32),
|
name varchar(32),
|
||||||
currency char(3))"""
|
code char(2))"""
|
||||||
elif db_server == 'sqlite':
|
elif db_server == 'sqlite':
|
||||||
self.query['createSitesTable'] = """CREATE TABLE Sites (
|
self.query['createSitesTable'] = """CREATE TABLE Sites (
|
||||||
id INTEGER PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
currency TEXT NOT NULL)"""
|
code TEXT NOT NULL)"""
|
||||||
|
|
||||||
|
|
||||||
################################
|
################################
|
||||||
|
@ -137,6 +137,7 @@ class Sql:
|
||||||
self.query['createGametypesTable'] = """CREATE TABLE Gametypes (
|
self.query['createGametypesTable'] = """CREATE TABLE Gametypes (
|
||||||
id SMALLINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id),
|
id SMALLINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id),
|
||||||
siteId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (siteId) REFERENCES Sites(id),
|
siteId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (siteId) REFERENCES Sites(id),
|
||||||
|
currency varchar(4) NOT NULL,
|
||||||
type char(4) NOT NULL,
|
type char(4) NOT NULL,
|
||||||
base char(4) NOT NULL,
|
base char(4) NOT NULL,
|
||||||
category varchar(9) NOT NULL,
|
category varchar(9) NOT NULL,
|
||||||
|
@ -151,6 +152,7 @@ class Sql:
|
||||||
self.query['createGametypesTable'] = """CREATE TABLE Gametypes (
|
self.query['createGametypesTable'] = """CREATE TABLE Gametypes (
|
||||||
id SERIAL, PRIMARY KEY (id),
|
id SERIAL, PRIMARY KEY (id),
|
||||||
siteId INTEGER, FOREIGN KEY (siteId) REFERENCES Sites(id),
|
siteId INTEGER, FOREIGN KEY (siteId) REFERENCES Sites(id),
|
||||||
|
currency varchar(4),
|
||||||
type char(4),
|
type char(4),
|
||||||
base char(4),
|
base char(4),
|
||||||
category varchar(9),
|
category varchar(9),
|
||||||
|
@ -164,6 +166,7 @@ class Sql:
|
||||||
self.query['createGametypesTable'] = """CREATE TABLE GameTypes (
|
self.query['createGametypesTable'] = """CREATE TABLE GameTypes (
|
||||||
id INTEGER PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
siteId INTEGER,
|
siteId INTEGER,
|
||||||
|
currency TEXT,
|
||||||
type TEXT,
|
type TEXT,
|
||||||
base TEXT,
|
base TEXT,
|
||||||
category TEXT,
|
category TEXT,
|
||||||
|
@ -254,6 +257,7 @@ class Sql:
|
||||||
importTime DATETIME NOT NULL,
|
importTime DATETIME NOT NULL,
|
||||||
seats TINYINT NOT NULL,
|
seats TINYINT NOT NULL,
|
||||||
maxSeats TINYINT NOT NULL,
|
maxSeats TINYINT NOT NULL,
|
||||||
|
rush BOOLEAN NOT NULL DEFAULT True,
|
||||||
boardcard1 smallint, /* 0=none, 1-13=2-Ah 14-26=2-Ad 27-39=2-Ac 40-52=2-As */
|
boardcard1 smallint, /* 0=none, 1-13=2-Ah 14-26=2-Ad 27-39=2-Ac 40-52=2-As */
|
||||||
boardcard2 smallint,
|
boardcard2 smallint,
|
||||||
boardcard3 smallint,
|
boardcard3 smallint,
|
||||||
|
@ -290,6 +294,7 @@ class Sql:
|
||||||
importTime timestamp without time zone NOT NULL,
|
importTime timestamp without time zone NOT NULL,
|
||||||
seats SMALLINT NOT NULL,
|
seats SMALLINT NOT NULL,
|
||||||
maxSeats SMALLINT NOT NULL,
|
maxSeats SMALLINT NOT NULL,
|
||||||
|
rush BOOLEAN NOT NULL DEFAULT True,
|
||||||
boardcard1 smallint, /* 0=none, 1-13=2-Ah 14-26=2-Ad 27-39=2-Ac 40-52=2-As */
|
boardcard1 smallint, /* 0=none, 1-13=2-Ah 14-26=2-Ad 27-39=2-Ac 40-52=2-As */
|
||||||
boardcard2 smallint,
|
boardcard2 smallint,
|
||||||
boardcard3 smallint,
|
boardcard3 smallint,
|
||||||
|
@ -325,6 +330,7 @@ class Sql:
|
||||||
importTime REAL NOT NULL,
|
importTime REAL NOT NULL,
|
||||||
seats INT NOT NULL,
|
seats INT NOT NULL,
|
||||||
maxSeats INT NOT NULL,
|
maxSeats INT NOT NULL,
|
||||||
|
rush BOOLEAN NOT NULL DEFAULT 1,
|
||||||
boardcard1 INT, /* 0=none, 1-13=2-Ah 14-26=2-Ad 27-39=2-Ac 40-52=2-As */
|
boardcard1 INT, /* 0=none, 1-13=2-Ah 14-26=2-Ad 27-39=2-Ac 40-52=2-As */
|
||||||
boardcard2 INT,
|
boardcard2 INT,
|
||||||
boardcard3 INT,
|
boardcard3 INT,
|
||||||
|
@ -357,50 +363,77 @@ class Sql:
|
||||||
|
|
||||||
if db_server == 'mysql':
|
if db_server == 'mysql':
|
||||||
self.query['createTourneyTypesTable'] = """CREATE TABLE TourneyTypes (
|
self.query['createTourneyTypesTable'] = """CREATE TABLE TourneyTypes (
|
||||||
id SMALLINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id),
|
id SMALLINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id),
|
||||||
siteId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (siteId) REFERENCES Sites(id),
|
siteId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (siteId) REFERENCES Sites(id),
|
||||||
buyin INT NOT NULL,
|
currency varchar(4) NOT NULL,
|
||||||
fee INT NOT NULL,
|
buyIn INT NOT NULL,
|
||||||
maxSeats INT NOT NULL DEFAULT -1,
|
fee INT NOT NULL,
|
||||||
knockout BOOLEAN NOT NULL DEFAULT False,
|
buyInChips INT,
|
||||||
rebuyOrAddon BOOLEAN NOT NULL DEFAULT False,
|
maxSeats INT,
|
||||||
speed varchar(10),
|
rebuy BOOLEAN,
|
||||||
headsUp BOOLEAN NOT NULL DEFAULT False,
|
rebuyCost INT,
|
||||||
shootout BOOLEAN NOT NULL DEFAULT False,
|
rebuyChips INT,
|
||||||
matrix BOOLEAN NOT NULL DEFAULT False,
|
addOn BOOLEAN,
|
||||||
sng BOOLEAN NOT NULL DEFAULT False
|
addOnCost INT,
|
||||||
)
|
addOnChips INT,
|
||||||
|
knockout BOOLEAN,
|
||||||
|
koBounty INT,
|
||||||
|
speed varchar(10),
|
||||||
|
shootout BOOLEAN,
|
||||||
|
matrix BOOLEAN,
|
||||||
|
sng BOOLEAN,
|
||||||
|
satellite BOOLEAN,
|
||||||
|
doubleOrNothing BOOLEAN,
|
||||||
|
guarantee INT)
|
||||||
ENGINE=INNODB"""
|
ENGINE=INNODB"""
|
||||||
elif db_server == 'postgresql':
|
elif db_server == 'postgresql':
|
||||||
self.query['createTourneyTypesTable'] = """CREATE TABLE TourneyTypes (
|
self.query['createTourneyTypesTable'] = """CREATE TABLE TourneyTypes (
|
||||||
id SERIAL, PRIMARY KEY (id),
|
id SERIAL, PRIMARY KEY (id),
|
||||||
siteId INT NOT NULL, FOREIGN KEY (siteId) REFERENCES Sites(id),
|
siteId INT NOT NULL, FOREIGN KEY (siteId) REFERENCES Sites(id),
|
||||||
|
currency varchar(4) NOT NULL,
|
||||||
buyin INT NOT NULL,
|
buyin INT NOT NULL,
|
||||||
fee INT NOT NULL,
|
fee INT NOT NULL,
|
||||||
maxSeats INT NOT NULL DEFAULT -1,
|
buyInChips INT,
|
||||||
knockout BOOLEAN NOT NULL DEFAULT False,
|
maxSeats INT,
|
||||||
rebuyOrAddon BOOLEAN NOT NULL DEFAULT False,
|
rebuy BOOLEAN,
|
||||||
|
rebuyCost INT,
|
||||||
|
rebuyChips INT,
|
||||||
|
addOn BOOLEAN,
|
||||||
|
addOnCost INT,
|
||||||
|
addOnChips INT,
|
||||||
|
knockout BOOLEAN,
|
||||||
|
koBounty INT,
|
||||||
speed varchar(10),
|
speed varchar(10),
|
||||||
headsUp BOOLEAN NOT NULL DEFAULT False,
|
shootout BOOLEAN,
|
||||||
shootout BOOLEAN NOT NULL DEFAULT False,
|
matrix BOOLEAN,
|
||||||
matrix BOOLEAN NOT NULL DEFAULT False,
|
sng BOOLEAN,
|
||||||
sng BOOLEAN NOT NULL DEFAULT False
|
satellite BOOLEAN,
|
||||||
)"""
|
doubleOrNothing BOOLEAN,
|
||||||
|
guarantee INT)"""
|
||||||
elif db_server == 'sqlite':
|
elif db_server == 'sqlite':
|
||||||
self.query['createTourneyTypesTable'] = """CREATE TABLE TourneyTypes (
|
self.query['createTourneyTypesTable'] = """CREATE TABLE TourneyTypes (
|
||||||
id INTEGER PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
siteId INT NOT NULL,
|
siteId INT NOT NULL,
|
||||||
|
currency VARCHAR(4) NOT NULL,
|
||||||
buyin INT NOT NULL,
|
buyin INT NOT NULL,
|
||||||
fee INT NOT NULL,
|
fee INT NOT NULL,
|
||||||
maxSeats INT NOT NULL DEFAULT -1,
|
buyInChips INT,
|
||||||
knockout BOOLEAN NOT NULL DEFAULT 0,
|
maxSeats INT,
|
||||||
rebuyOrAddon BOOLEAN NOT NULL DEFAULT 0,
|
rebuy BOOLEAN,
|
||||||
|
rebuyCost INT,
|
||||||
|
rebuyChips INT,
|
||||||
|
addOn BOOLEAN,
|
||||||
|
addOnCost INT,
|
||||||
|
addOnChips INT,
|
||||||
|
knockout BOOLEAN,
|
||||||
|
koBounty INT,
|
||||||
speed TEXT,
|
speed TEXT,
|
||||||
headsUp BOOLEAN NOT NULL DEFAULT 0,
|
shootout BOOLEAN,
|
||||||
shootout BOOLEAN NOT NULL DEFAULT 0,
|
matrix BOOLEAN,
|
||||||
matrix BOOLEAN NOT NULL DEFAULT 0,
|
sng BOOLEAN,
|
||||||
sng BOOLEAN NOT NULL DEFAULT 0
|
satellite BOOLEAN,
|
||||||
)"""
|
doubleOrNothing BOOLEAN,
|
||||||
|
guarantee INT)"""
|
||||||
|
|
||||||
################################
|
################################
|
||||||
# Create Tourneys
|
# Create Tourneys
|
||||||
|
@ -409,65 +442,47 @@ class Sql:
|
||||||
if db_server == 'mysql':
|
if db_server == 'mysql':
|
||||||
self.query['createTourneysTable'] = """CREATE TABLE Tourneys (
|
self.query['createTourneysTable'] = """CREATE TABLE Tourneys (
|
||||||
id INT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id),
|
id INT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id),
|
||||||
tourneyTypeId SMALLINT UNSIGNED NOT NULL DEFAULT 1, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id),
|
tourneyTypeId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id),
|
||||||
siteTourneyNo BIGINT NOT NULL,
|
siteTourneyNo BIGINT NOT NULL,
|
||||||
entries INT NOT NULL,
|
entries INT,
|
||||||
prizepool INT NOT NULL,
|
prizepool INT,
|
||||||
startTime DATETIME NOT NULL,
|
startTime DATETIME NOT NULL,
|
||||||
endTime DATETIME,
|
endTime DATETIME,
|
||||||
buyinChips INT,
|
|
||||||
tourneyName varchar(40),
|
tourneyName varchar(40),
|
||||||
matrixIdProcessed TINYINT UNSIGNED DEFAULT 0, /* Mask use : 1=Positionnal Winnings|2=Match1|4=Match2|...|pow(2,n)=Matchn */
|
matrixIdProcessed TINYINT UNSIGNED DEFAULT 0, /* Mask use : 1=Positionnal Winnings|2=Match1|4=Match2|...|pow(2,n)=Matchn */
|
||||||
rebuyChips INT DEFAULT 0,
|
totalRebuyCount INT,
|
||||||
addonChips INT DEFAULT 0,
|
totalAddOnCount INT,
|
||||||
rebuyAmount INT DEFAULT 0,
|
|
||||||
addonAmount INT DEFAULT 0,
|
|
||||||
totalRebuys INT DEFAULT 0,
|
|
||||||
totalAddons INT DEFAULT 0,
|
|
||||||
koBounty INT DEFAULT 0,
|
|
||||||
comment TEXT,
|
comment TEXT,
|
||||||
commentTs DATETIME)
|
commentTs DATETIME)
|
||||||
ENGINE=INNODB"""
|
ENGINE=INNODB"""
|
||||||
elif db_server == 'postgresql':
|
elif db_server == 'postgresql':
|
||||||
self.query['createTourneysTable'] = """CREATE TABLE Tourneys (
|
self.query['createTourneysTable'] = """CREATE TABLE Tourneys (
|
||||||
id SERIAL, PRIMARY KEY (id),
|
id SERIAL, PRIMARY KEY (id),
|
||||||
tourneyTypeId INT DEFAULT 1, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id),
|
tourneyTypeId INT, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id),
|
||||||
siteTourneyNo BIGINT,
|
siteTourneyNo BIGINT,
|
||||||
entries INT,
|
entries INT,
|
||||||
prizepool INT,
|
prizepool INT,
|
||||||
startTime timestamp without time zone,
|
startTime timestamp without time zone,
|
||||||
endTime timestamp without time zone,
|
endTime timestamp without time zone,
|
||||||
buyinChips INT,
|
|
||||||
tourneyName varchar(40),
|
tourneyName varchar(40),
|
||||||
matrixIdProcessed SMALLINT DEFAULT 0, /* Mask use : 1=Positionnal Winnings|2=Match1|4=Match2|...|pow(2,n)=Matchn */
|
matrixIdProcessed SMALLINT DEFAULT 0, /* Mask use : 1=Positionnal Winnings|2=Match1|4=Match2|...|pow(2,n)=Matchn */
|
||||||
rebuyChips INT DEFAULT 0,
|
totalRebuyCount INT,
|
||||||
addonChips INT DEFAULT 0,
|
totalAddOnCount INT,
|
||||||
rebuyAmount INT DEFAULT 0,
|
|
||||||
addonAmount INT DEFAULT 0,
|
|
||||||
totalRebuys INT DEFAULT 0,
|
|
||||||
totalAddons INT DEFAULT 0,
|
|
||||||
koBounty INT DEFAULT 0,
|
|
||||||
comment TEXT,
|
comment TEXT,
|
||||||
commentTs timestamp without time zone)"""
|
commentTs timestamp without time zone)"""
|
||||||
elif db_server == 'sqlite':
|
elif db_server == 'sqlite':
|
||||||
self.query['createTourneysTable'] = """CREATE TABLE Tourneys (
|
self.query['createTourneysTable'] = """CREATE TABLE Tourneys (
|
||||||
id INTEGER PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
tourneyTypeId INT DEFAULT 1,
|
tourneyTypeId INT,
|
||||||
siteTourneyNo INT,
|
siteTourneyNo INT,
|
||||||
entries INT,
|
entries INT,
|
||||||
prizepool INT,
|
prizepool INT,
|
||||||
startTime REAL,
|
startTime REAL,
|
||||||
endTime REAL,
|
endTime REAL,
|
||||||
buyinChips INT,
|
|
||||||
tourneyName TEXT,
|
tourneyName TEXT,
|
||||||
matrixIdProcessed INT UNSIGNED DEFAULT 0, /* Mask use : 1=Positionnal Winnings|2=Match1|4=Match2|...|pow(2,n)=Matchn */
|
matrixIdProcessed INT UNSIGNED DEFAULT 0, /* Mask use : 1=Positionnal Winnings|2=Match1|4=Match2|...|pow(2,n)=Matchn */
|
||||||
rebuyChips INT DEFAULT 0,
|
totalRebuyCount INT,
|
||||||
addonChips INT DEFAULT 0,
|
totalAddOnCount INT,
|
||||||
rebuyAmount INT DEFAULT 0,
|
|
||||||
addonAmount INT DEFAULT 0,
|
|
||||||
totalRebuys INT DEFAULT 0,
|
|
||||||
totalAddons INT DEFAULT 0,
|
|
||||||
koBounty INT DEFAULT 0,
|
|
||||||
comment TEXT,
|
comment TEXT,
|
||||||
commentTs REAL)"""
|
commentTs REAL)"""
|
||||||
################################
|
################################
|
||||||
|
@ -482,6 +497,7 @@ class Sql:
|
||||||
startCash INT NOT NULL,
|
startCash INT NOT NULL,
|
||||||
position CHAR(1),
|
position CHAR(1),
|
||||||
seatNo SMALLINT NOT NULL,
|
seatNo SMALLINT NOT NULL,
|
||||||
|
sitout BOOLEAN NOT NULL,
|
||||||
|
|
||||||
card1 smallint NOT NULL, /* 0=none, 1-13=2-Ah 14-26=2-Ad 27-39=2-Ac 40-52=2-As */
|
card1 smallint NOT NULL, /* 0=none, 1-13=2-Ah 14-26=2-Ad 27-39=2-Ac 40-52=2-As */
|
||||||
card2 smallint NOT NULL,
|
card2 smallint NOT NULL,
|
||||||
|
@ -598,6 +614,7 @@ class Sql:
|
||||||
startCash INT NOT NULL,
|
startCash INT NOT NULL,
|
||||||
position CHAR(1),
|
position CHAR(1),
|
||||||
seatNo SMALLINT NOT NULL,
|
seatNo SMALLINT NOT NULL,
|
||||||
|
sitout BOOLEAN NOT NULL,
|
||||||
|
|
||||||
card1 smallint NOT NULL, /* 0=none, 1-13=2-Ah 14-26=2-Ad 27-39=2-Ac 40-52=2-As */
|
card1 smallint NOT NULL, /* 0=none, 1-13=2-Ah 14-26=2-Ad 27-39=2-Ac 40-52=2-As */
|
||||||
card2 smallint NOT NULL,
|
card2 smallint NOT NULL,
|
||||||
|
@ -614,7 +631,7 @@ class Sql:
|
||||||
totalProfit INT,
|
totalProfit INT,
|
||||||
comment text,
|
comment text,
|
||||||
commentTs timestamp without time zone,
|
commentTs timestamp without time zone,
|
||||||
tourneysPlayersId BIGINT,
|
tourneysPlayersId BIGINT, FOREIGN KEY (tourneysPlayersId) REFERENCES TourneysPlayers(id),
|
||||||
tourneyTypeId INT NOT NULL DEFAULT 1, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id),
|
tourneyTypeId INT NOT NULL DEFAULT 1, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id),
|
||||||
|
|
||||||
wonWhenSeenStreet1 FLOAT,
|
wonWhenSeenStreet1 FLOAT,
|
||||||
|
@ -704,9 +721,7 @@ class Sql:
|
||||||
street3Raises SMALLINT,
|
street3Raises SMALLINT,
|
||||||
street4Raises SMALLINT,
|
street4Raises SMALLINT,
|
||||||
|
|
||||||
actionString VARCHAR(15),
|
actionString VARCHAR(15))"""
|
||||||
|
|
||||||
FOREIGN KEY (tourneysPlayersId) REFERENCES TourneysPlayers(id))"""
|
|
||||||
elif db_server == 'sqlite':
|
elif db_server == 'sqlite':
|
||||||
self.query['createHandsPlayersTable'] = """CREATE TABLE HandsPlayers (
|
self.query['createHandsPlayersTable'] = """CREATE TABLE HandsPlayers (
|
||||||
id INTEGER PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
|
@ -715,6 +730,7 @@ class Sql:
|
||||||
startCash INT NOT NULL,
|
startCash INT NOT NULL,
|
||||||
position TEXT,
|
position TEXT,
|
||||||
seatNo INT NOT NULL,
|
seatNo INT NOT NULL,
|
||||||
|
sitout BOOLEAN NOT NULL,
|
||||||
|
|
||||||
card1 INT NOT NULL, /* 0=none, 1-13=2-Ah 14-26=2-Ad 27-39=2-Ac 40-52=2-As */
|
card1 INT NOT NULL, /* 0=none, 1-13=2-Ah 14-26=2-Ad 27-39=2-Ac 40-52=2-As */
|
||||||
card2 INT NOT NULL,
|
card2 INT NOT NULL,
|
||||||
|
@ -820,7 +836,7 @@ class Sql:
|
||||||
street2Raises INT,
|
street2Raises INT,
|
||||||
street3Raises INT,
|
street3Raises INT,
|
||||||
street4Raises INT,
|
street4Raises INT,
|
||||||
actionString REAL)
|
actionString VARCHAR(15))
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
@ -833,12 +849,12 @@ class Sql:
|
||||||
id BIGINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id),
|
id BIGINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id),
|
||||||
tourneyId INT UNSIGNED NOT NULL, FOREIGN KEY (tourneyId) REFERENCES Tourneys(id),
|
tourneyId INT UNSIGNED NOT NULL, FOREIGN KEY (tourneyId) REFERENCES Tourneys(id),
|
||||||
playerId INT UNSIGNED NOT NULL, FOREIGN KEY (playerId) REFERENCES Players(id),
|
playerId INT UNSIGNED NOT NULL, FOREIGN KEY (playerId) REFERENCES Players(id),
|
||||||
payinAmount INT NOT NULL,
|
rank INT,
|
||||||
rank INT NOT NULL,
|
winnings INT,
|
||||||
winnings INT NOT NULL,
|
winningsCurrency VARCHAR(4),
|
||||||
nbRebuys INT DEFAULT 0,
|
rebuyCount INT,
|
||||||
nbAddons INT DEFAULT 0,
|
addOnCount INT,
|
||||||
nbKO INT DEFAULT 0,
|
koCount INT,
|
||||||
comment TEXT,
|
comment TEXT,
|
||||||
commentTs DATETIME)
|
commentTs DATETIME)
|
||||||
ENGINE=INNODB"""
|
ENGINE=INNODB"""
|
||||||
|
@ -847,12 +863,12 @@ class Sql:
|
||||||
id BIGSERIAL, PRIMARY KEY (id),
|
id BIGSERIAL, PRIMARY KEY (id),
|
||||||
tourneyId INT, FOREIGN KEY (tourneyId) REFERENCES Tourneys(id),
|
tourneyId INT, FOREIGN KEY (tourneyId) REFERENCES Tourneys(id),
|
||||||
playerId INT, FOREIGN KEY (playerId) REFERENCES Players(id),
|
playerId INT, FOREIGN KEY (playerId) REFERENCES Players(id),
|
||||||
payinAmount INT,
|
|
||||||
rank INT,
|
rank INT,
|
||||||
winnings INT,
|
winnings INT,
|
||||||
nbRebuys INT DEFAULT 0,
|
winningsCurrency VARCHAR(4),
|
||||||
nbAddons INT DEFAULT 0,
|
rebuyCount INT,
|
||||||
nbKO INT DEFAULT 0,
|
addOnCount INT,
|
||||||
|
koCount INT,
|
||||||
comment TEXT,
|
comment TEXT,
|
||||||
commentTs timestamp without time zone)"""
|
commentTs timestamp without time zone)"""
|
||||||
elif db_server == 'sqlite':
|
elif db_server == 'sqlite':
|
||||||
|
@ -860,12 +876,12 @@ class Sql:
|
||||||
id INT PRIMARY KEY,
|
id INT PRIMARY KEY,
|
||||||
tourneyId INT,
|
tourneyId INT,
|
||||||
playerId INT,
|
playerId INT,
|
||||||
payinAmount INT,
|
|
||||||
rank INT,
|
rank INT,
|
||||||
winnings INT,
|
winnings INT,
|
||||||
nbRebuys INT DEFAULT 0,
|
winningsCurrency VARCHAR(4),
|
||||||
nbAddons INT DEFAULT 0,
|
rebuyCount INT,
|
||||||
nbKO INT DEFAULT 0,
|
addOnCount INT,
|
||||||
|
koCount INT,
|
||||||
comment TEXT,
|
comment TEXT,
|
||||||
commentTs timestamp without time zone,
|
commentTs timestamp without time zone,
|
||||||
FOREIGN KEY (tourneyId) REFERENCES Tourneys(id),
|
FOREIGN KEY (tourneyId) REFERENCES Tourneys(id),
|
||||||
|
@ -1249,14 +1265,14 @@ class Sql:
|
||||||
self.query['addTPlayersIndex'] = """CREATE UNIQUE INDEX tourneyId ON TourneysPlayers (tourneyId, playerId)"""
|
self.query['addTPlayersIndex'] = """CREATE UNIQUE INDEX tourneyId ON TourneysPlayers (tourneyId, playerId)"""
|
||||||
|
|
||||||
if db_server == 'mysql':
|
if db_server == 'mysql':
|
||||||
self.query['addTTypesIndex'] = """ALTER TABLE TourneyTypes ADD UNIQUE INDEX tourneytypes_all(buyin, fee
|
self.query['addTTypesIndex'] = """ALTER TABLE TourneyTypes ADD UNIQUE INDEX tourneytypes_all(siteId, buyin, fee
|
||||||
, maxSeats, knockout, rebuyOrAddon, speed, headsUp, shootout, matrix, sng)"""
|
, maxSeats, knockout, rebuy, addOn, speed, shootout, matrix, sng)"""
|
||||||
elif db_server == 'postgresql':
|
elif db_server == 'postgresql':
|
||||||
self.query['addTTypesIndex'] = """CREATE UNIQUE INDEX tourneyTypes_all ON TourneyTypes (buyin, fee
|
self.query['addTTypesIndex'] = """CREATE UNIQUE INDEX tourneyTypes_all ON TourneyTypes (siteId, buyin, fee
|
||||||
, maxSeats, knockout, rebuyOrAddon, speed, headsUp, shootout, matrix, sng)"""
|
, maxSeats, knockout, rebuy, addOn, speed, shootout, matrix, sng)"""
|
||||||
elif db_server == 'sqlite':
|
elif db_server == 'sqlite':
|
||||||
self.query['addTTypesIndex'] = """CREATE UNIQUE INDEX tourneyTypes_all ON TourneyTypes (buyin, fee
|
self.query['addTTypesIndex'] = """CREATE UNIQUE INDEX tourneyTypes_all ON TourneyTypes (siteId, buyin, fee
|
||||||
, maxSeats, knockout, rebuyOrAddon, speed, headsUp, shootout, matrix, sng)"""
|
, maxSeats, knockout, rebuy, addOn, speed, shootout, matrix, sng)"""
|
||||||
|
|
||||||
self.query['get_last_hand'] = "select max(id) from Hands"
|
self.query['get_last_hand'] = "select max(id) from Hands"
|
||||||
|
|
||||||
|
@ -3560,9 +3576,9 @@ class Sql:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.query['insertGameTypes'] = """INSERT INTO Gametypes
|
self.query['insertGameTypes'] = """INSERT INTO Gametypes
|
||||||
(siteId, type, base, category, limitType
|
(siteId, currency, type, base, category, limitType
|
||||||
,hiLo, smallBlind, bigBlind, smallBet, bigBet)
|
,hiLo, smallBlind, bigBlind, smallBet, bigBet)
|
||||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"""
|
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"""
|
||||||
|
|
||||||
self.query['isAlreadyInDB'] = """SELECT id FROM Hands
|
self.query['isAlreadyInDB'] = """SELECT id FROM Hands
|
||||||
WHERE gametypeId=%s AND siteHandNo=%s
|
WHERE gametypeId=%s AND siteHandNo=%s
|
||||||
|
@ -3573,9 +3589,9 @@ class Sql:
|
||||||
tt.fee,
|
tt.fee,
|
||||||
tt.maxSeats,
|
tt.maxSeats,
|
||||||
tt.knockout,
|
tt.knockout,
|
||||||
tt.rebuyOrAddon,
|
tt.rebuy,
|
||||||
|
tt.addOn,
|
||||||
tt.speed,
|
tt.speed,
|
||||||
tt.headsUp,
|
|
||||||
tt.shootout,
|
tt.shootout,
|
||||||
tt.matrix
|
tt.matrix
|
||||||
FROM TourneyTypes tt
|
FROM TourneyTypes tt
|
||||||
|
@ -3586,51 +3602,34 @@ class Sql:
|
||||||
self.query['getTourneyTypeId'] = """SELECT id
|
self.query['getTourneyTypeId'] = """SELECT id
|
||||||
FROM TourneyTypes
|
FROM TourneyTypes
|
||||||
WHERE siteId=%s
|
WHERE siteId=%s
|
||||||
|
AND currency=%s
|
||||||
AND buyin=%s
|
AND buyin=%s
|
||||||
AND fee=%s
|
AND fee=%s
|
||||||
AND knockout=%s
|
AND knockout=%s
|
||||||
AND rebuyOrAddon=%s
|
AND rebuy=%s
|
||||||
|
AND addOn=%s
|
||||||
AND speed=%s
|
AND speed=%s
|
||||||
AND headsUp=%s
|
|
||||||
AND shootout=%s
|
AND shootout=%s
|
||||||
AND matrix=%s
|
AND matrix=%s
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.query['insertTourneyTypes'] = """INSERT INTO TourneyTypes
|
self.query['insertTourneyType'] = """INSERT INTO TourneyTypes
|
||||||
(siteId, buyin, fee, knockout, rebuyOrAddon
|
(siteId, currency, buyin, fee, buyInChips, knockout, rebuy,
|
||||||
,speed, headsUp, shootout, matrix)
|
addOn ,speed, shootout, matrix)
|
||||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)
|
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.query['getTourney'] = """SELECT t.id,
|
self.query['getTourneyIdByTourneyNo'] = """SELECT t.id
|
||||||
t.tourneyTypeId,
|
FROM Tourneys t
|
||||||
t.entries,
|
INNER JOIN TourneyTypes tt ON (t.tourneyTypeId = tt.id)
|
||||||
t.prizepool,
|
WHERE tt.siteId=%s AND t.siteTourneyNo=%s
|
||||||
t.startTime,
|
|
||||||
t.endTime,
|
|
||||||
t.buyinChips,
|
|
||||||
t.tourneyName,
|
|
||||||
t.matrixIdProcessed,
|
|
||||||
t.rebuyChips,
|
|
||||||
t.addonChips,
|
|
||||||
t.rebuyAmount,
|
|
||||||
t.addonAmount,
|
|
||||||
t.totalRebuys,
|
|
||||||
t.totalAddons,
|
|
||||||
t.koBounty,
|
|
||||||
t.comment
|
|
||||||
FROM Tourneys t
|
|
||||||
INNER JOIN TourneyTypes tt ON (t.tourneyTypeId = tt.id)
|
|
||||||
WHERE t.siteTourneyNo=%s AND tt.siteId=%s
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.query['insertTourney'] = """INSERT INTO Tourneys
|
self.query['insertTourney'] = """INSERT INTO Tourneys
|
||||||
(tourneyTypeId, siteTourneyNo, entries, prizepool,
|
(tourneyTypeId, siteTourneyNo, entries, prizepool,
|
||||||
startTime, endTime, buyinChips, tourneyName, matrixIdProcessed,
|
startTime, endTime, tourneyName, matrixIdProcessed,
|
||||||
rebuyChips, addonChips, rebuyAmount, addonAmount, totalRebuys,
|
totalRebuyCount, totalAddOnCount)
|
||||||
totalAddons, koBounty, comment, commentTs)
|
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
|
||||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s,
|
|
||||||
%s, %s, %s, %s, %s, %s, %s, %s)
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.query['updateTourney'] = """UPDATE Tourneys
|
self.query['updateTourney'] = """UPDATE Tourneys
|
||||||
|
@ -3639,48 +3638,34 @@ class Sql:
|
||||||
prizepool = %s,
|
prizepool = %s,
|
||||||
startTime = %s,
|
startTime = %s,
|
||||||
endTime = %s,
|
endTime = %s,
|
||||||
buyinChips = %s,
|
|
||||||
tourneyName = %s,
|
tourneyName = %s,
|
||||||
matrixIdProcessed = %s,
|
matrixIdProcessed = %s,
|
||||||
rebuyChips = %s,
|
totalRebuyCount = %s,
|
||||||
addonChips = %s,
|
totalAddOnCount = %s,
|
||||||
rebuyAmount = %s,
|
|
||||||
addonAmount = %s,
|
|
||||||
totalRebuys = %s,
|
|
||||||
totalAddons = %s,
|
|
||||||
koBounty = %s,
|
|
||||||
comment = %s,
|
comment = %s,
|
||||||
commentTs = %s
|
commentTs = %s
|
||||||
WHERE id=%s
|
WHERE id=%s
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.query['getTourneysPlayers'] = """SELECT id,
|
self.query['getTourneysPlayersId'] = """SELECT id
|
||||||
payinAmount,
|
|
||||||
rank,
|
|
||||||
winnings,
|
|
||||||
nbRebuys,
|
|
||||||
nbAddons,
|
|
||||||
nbKO,
|
|
||||||
comment,
|
|
||||||
commentTs
|
|
||||||
FROM TourneysPlayers
|
FROM TourneysPlayers
|
||||||
WHERE tourneyId=%s AND playerId+0=%s
|
WHERE tourneyId=%s AND playerId+0=%s
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.query['updateTourneysPlayers'] = """UPDATE TourneysPlayers
|
self.query['updateTourneysPlayers'] = """UPDATE TourneysPlayers
|
||||||
SET payinAmount = %s,
|
SET rank = %s,
|
||||||
rank = %s,
|
|
||||||
winnings = %s,
|
winnings = %s,
|
||||||
nbRebuys = %s,
|
winningsCurrency = %s,
|
||||||
nbAddons = %s,
|
rebuyCount = %s,
|
||||||
nbKO = %s,
|
addOnCount = %s,
|
||||||
|
koCount = %s,
|
||||||
comment = %s,
|
comment = %s,
|
||||||
commentTs = %s
|
commentTs = %s
|
||||||
WHERE id=%s
|
WHERE id=%s
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.query['insertTourneysPlayers'] = """INSERT INTO TourneysPlayers
|
self.query['insertTourneysPlayer'] = """INSERT INTO TourneysPlayers
|
||||||
(tourneyId, playerId, payinAmount, rank, winnings, nbRebuys, nbAddons, nbKO, comment, commentTs)
|
(tourneyId, playerId, rank, winnings, winningsCurrency, rebuyCount, addOnCount, koCount, comment, commentTs)
|
||||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
|
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -3746,6 +3731,7 @@ class Sql:
|
||||||
playerId,
|
playerId,
|
||||||
startCash,
|
startCash,
|
||||||
seatNo,
|
seatNo,
|
||||||
|
sitout,
|
||||||
card1,
|
card1,
|
||||||
card2,
|
card2,
|
||||||
card3,
|
card3,
|
||||||
|
@ -3845,7 +3831,8 @@ class Sql:
|
||||||
%s, %s, %s, %s, %s,
|
%s, %s, %s, %s, %s,
|
||||||
%s, %s, %s, %s, %s,
|
%s, %s, %s, %s, %s,
|
||||||
%s, %s, %s, %s, %s,
|
%s, %s, %s, %s, %s,
|
||||||
%s, %s, %s, %s, %s
|
%s, %s, %s, %s, %s,
|
||||||
|
%s
|
||||||
)"""
|
)"""
|
||||||
|
|
||||||
if db_server == 'mysql':
|
if db_server == 'mysql':
|
||||||
|
|
66
pyfpdb/Summaries.py
Normal file
66
pyfpdb/Summaries.py
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
#!/usr/bin/python2
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
#Copyright 2008-2010 Steffen Schaumburg
|
||||||
|
#This program is free software: you can redistribute it and/or modify
|
||||||
|
#it under the terms of the GNU Affero General Public License as published by
|
||||||
|
#the Free Software Foundation, version 3 of the License.
|
||||||
|
#
|
||||||
|
#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 Affero General Public License
|
||||||
|
#along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#In the "official" distribution you can find the license in agpl-3.0.txt.
|
||||||
|
|
||||||
|
"""This file is to fetch summaries through IMAP and pass them on to the appropriate parser"""
|
||||||
|
#see http://docs.python.org/library/imaplib.html for the python interface
|
||||||
|
#see http://tools.ietf.org/html/rfc2060#section-6.4.4 for IMAP4 search criteria
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from imaplib import IMAP4_SSL
|
||||||
|
from Summaries import Summaries
|
||||||
|
from PokerStarsSummaries import PokerStarsSummaries
|
||||||
|
|
||||||
|
#TODO: move all these into the config file. until then usage is: ./ImapSummaries.py YourImapHost YourImapUser YourImapPw
|
||||||
|
configHost=sys.argv[1]
|
||||||
|
configUser=sys.argv[2]
|
||||||
|
configPw=sys.argv[3]
|
||||||
|
|
||||||
|
server = IMAP4_SSL(configHost) #TODO: optionally non-SSL
|
||||||
|
response = server.login(configUser, configPw) #TODO catch authentication error
|
||||||
|
#print "response to logging in:",response
|
||||||
|
#print "server.list():",server.list() #prints list of folders
|
||||||
|
|
||||||
|
response = server.select("INBOX")
|
||||||
|
#print "response to selecting INBOX:",response
|
||||||
|
if response[0]!="OK":
|
||||||
|
raise error #TODO: show error message
|
||||||
|
|
||||||
|
neededMessages=[]
|
||||||
|
response, searchData = server.search(None, "SUBJECT", "PokerStars Tournament History Request")
|
||||||
|
for messageNumber in searchData[0].split(" "):
|
||||||
|
response, headerData = server.fetch(messageNumber, "(BODY[HEADER.FIELDS (SUBJECT)])")
|
||||||
|
#print "response to fetch subject:",response
|
||||||
|
if response!="OK":
|
||||||
|
raise error #TODO: show error message
|
||||||
|
if headerData[1].find("Subject: PokerStars Tournament History Request - Last x")!=1:
|
||||||
|
neededMessages.append((messageNumber, "PS")
|
||||||
|
|
||||||
|
tourneys=[]
|
||||||
|
if len(neededMessages)==0:
|
||||||
|
raise error #TODO: show error message
|
||||||
|
for messageData in neededMessages:
|
||||||
|
response, bodyData = server.fetch(messageData[0], "(UID BODY[TEXT])")
|
||||||
|
if response!="OK":
|
||||||
|
raise error #TODO: show error message
|
||||||
|
if messageData[0]=="PS":
|
||||||
|
tourneys.append(PokerStarsSummaries.PokerStarsSummaries(bodyData)
|
||||||
|
|
||||||
|
for tourney in tourneys:
|
||||||
|
print "tourney:",tourney
|
||||||
|
|
||||||
|
server.close()
|
||||||
|
server.logout()
|
|
@ -51,7 +51,7 @@ class SummaryParser(htmllib.HTMLParser): # derive new HTML parser
|
||||||
self.nextPool = False
|
self.nextPool = False
|
||||||
self.TourneyPool = None
|
self.TourneyPool = None
|
||||||
self.nextPlayers = False
|
self.nextPlayers = False
|
||||||
self.TourneyPlayers = None
|
self.TourneysPlayers = None
|
||||||
self.nextAllowRebuys = False
|
self.nextAllowRebuys = False
|
||||||
self.TourneyRebuys = None
|
self.TourneyRebuys = None
|
||||||
self.parseResultsA = False
|
self.parseResultsA = False
|
||||||
|
@ -134,7 +134,7 @@ class SummaryParser(htmllib.HTMLParser): # derive new HTML parser
|
||||||
if not self.nextPlayers and x == "Player Count:":
|
if not self.nextPlayers and x == "Player Count:":
|
||||||
self.nextPlayers = True
|
self.nextPlayers = True
|
||||||
elif self.nextPlayers:
|
elif self.nextPlayers:
|
||||||
self.TourneyPlayers = x
|
self.TourneysPlayers = x
|
||||||
self.nextPlayers = False
|
self.nextPlayers = False
|
||||||
|
|
||||||
if not self.nextAllowRebuys and x == "Rebuys possible?:":
|
if not self.nextAllowRebuys and x == "Rebuys possible?:":
|
||||||
|
@ -179,7 +179,7 @@ class EverleafSummary:
|
||||||
print "site=",self.parser.SiteName, "tourneyname=", self.parser.TourneyName, "tourneyid=", self.parser.TourneyId
|
print "site=",self.parser.SiteName, "tourneyname=", self.parser.TourneyName, "tourneyid=", self.parser.TourneyId
|
||||||
print "start time=",self.parser.TourneyStartTime, "end time=",self.parser.TourneyEndTime
|
print "start time=",self.parser.TourneyStartTime, "end time=",self.parser.TourneyEndTime
|
||||||
print "structure=", self.parser.TourneyStructure, "game type=",self.parser.TourneyGameType
|
print "structure=", self.parser.TourneyStructure, "game type=",self.parser.TourneyGameType
|
||||||
print "buy-in=", self.parser.TourneyBuyIn, "rebuys=", self.parser.TourneyRebuys, "total players=", self.parser.TourneyPlayers, "pool=", self.parser.TourneyPool
|
print "buy-in=", self.parser.TourneyBuyIn, "rebuys=", self.parser.TourneyRebuys, "total players=", self.parser.TourneysPlayers, "pool=", self.parser.TourneyPool
|
||||||
print "results=", self.parser.Results
|
print "results=", self.parser.Results
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -87,7 +87,7 @@ class Tournament:
|
||||||
self.buyin = summary.parser.TourneyBuyIn # need to remember to parse the Fee out of this and move it to self.fee
|
self.buyin = summary.parser.TourneyBuyIn # need to remember to parse the Fee out of this and move it to self.fee
|
||||||
self.rebuys = (summary.parser.TourneyRebuys == "yes")
|
self.rebuys = (summary.parser.TourneyRebuys == "yes")
|
||||||
self.prizepool = summary.parser.TourneyPool
|
self.prizepool = summary.parser.TourneyPool
|
||||||
self.numplayers = summary.parser.TourneyPlayers
|
self.numplayers = summary.parser.TourneysPlayers
|
||||||
|
|
||||||
self.openwindow() # let's start by getting any info we need.. meh
|
self.openwindow() # let's start by getting any info we need.. meh
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
#along with this program. If not, see <http://www.gnu.org/licenses/>.
|
#along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#In the "official" distribution you can find the license in agpl-3.0.txt.
|
#In the "official" distribution you can find the license in agpl-3.0.txt.
|
||||||
|
|
||||||
|
"""parses and stores summary sections from e.g. eMail or summary files"""
|
||||||
|
|
||||||
# TODO: check to keep only the needed modules
|
# TODO: check to keep only the needed modules
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
@ -34,7 +36,7 @@ import Card
|
||||||
|
|
||||||
log = logging.getLogger("parser")
|
log = logging.getLogger("parser")
|
||||||
|
|
||||||
class Tourney(object):
|
class TourneySummary(object):
|
||||||
|
|
||||||
################################################################
|
################################################################
|
||||||
# Class Variables
|
# Class Variables
|
||||||
|
@ -49,23 +51,27 @@ class Tourney(object):
|
||||||
self.sitename = sitename
|
self.sitename = sitename
|
||||||
self.siteId = self.SITEIDS[sitename]
|
self.siteId = self.SITEIDS[sitename]
|
||||||
self.gametype = gametype
|
self.gametype = gametype
|
||||||
self.starttime = None
|
|
||||||
self.endtime = None
|
|
||||||
self.summaryText = summaryText
|
self.summaryText = summaryText
|
||||||
self.tourneyName = None
|
self.tourneyName = None
|
||||||
|
self.tourneyTypeId = None
|
||||||
|
self.tourneyId = None
|
||||||
|
self.startTime = None
|
||||||
|
self.endTime = None
|
||||||
self.tourNo = None
|
self.tourNo = None
|
||||||
|
self.currency = None
|
||||||
self.buyin = None
|
self.buyin = None
|
||||||
self.fee = None # the Database code is looking for this one .. ?
|
self.fee = None
|
||||||
self.hero = None
|
self.hero = None
|
||||||
self.maxseats = None
|
self.maxseats = None
|
||||||
self.entries = 0
|
self.entries = 0
|
||||||
self.speed = "Normal"
|
self.speed = "Normal"
|
||||||
self.prizepool = None # Make it a dict in order to deal (eventually later) with non-money winnings : {'MONEY' : amount, 'OTHER' : Value ??}
|
self.prizepool = 0 # Make it a dict in order to deal (eventually later) with non-money winnings : {'MONEY' : amount, 'OTHER' : Value ??}
|
||||||
self.buyInChips = None
|
self.buyInChips = 0
|
||||||
self.mixed = None
|
self.mixed = None
|
||||||
self.isRebuy = False
|
self.isRebuy = False
|
||||||
|
self.isAddOn = False
|
||||||
self.isKO = False
|
self.isKO = False
|
||||||
self.isHU = False
|
|
||||||
self.isMatrix = False
|
self.isMatrix = False
|
||||||
self.isShootout = False
|
self.isShootout = False
|
||||||
self.matrixMatchId = None # For Matrix tourneys : 1-4 => match tables (traditionnal), 0 => Positional winnings info
|
self.matrixMatchId = None # For Matrix tourneys : 1-4 => match tables (traditionnal), 0 => Positional winnings info
|
||||||
|
@ -73,33 +79,44 @@ class Tourney(object):
|
||||||
self.subTourneyFee = None
|
self.subTourneyFee = None
|
||||||
self.rebuyChips = 0
|
self.rebuyChips = 0
|
||||||
self.addOnChips = 0
|
self.addOnChips = 0
|
||||||
self.rebuyAmount = 0
|
self.rebuyCost = 0
|
||||||
self.addOnAmount = 0
|
self.addOnCost = 0
|
||||||
self.totalRebuys = 0
|
self.totalRebuyCount = 0
|
||||||
self.totalAddOns = 0
|
self.totalAddOnCount = 0
|
||||||
self.koBounty = 0
|
self.koBounty = 0
|
||||||
self.tourneyComment = None
|
self.tourneyComment = None
|
||||||
self.players = []
|
self.players = []
|
||||||
|
self.isSng = False
|
||||||
|
self.isSatellite = False
|
||||||
|
self.isDoubleOrNothing = False
|
||||||
|
self.guarantee = 0
|
||||||
|
|
||||||
# Collections indexed by player names
|
# Collections indexed by player names
|
||||||
self.finishPositions = {}
|
self.ranks = {}
|
||||||
self.winnings = {}
|
self.winnings = {}
|
||||||
self.payinAmounts = {}
|
self.winningsCurrency = {}
|
||||||
self.countRebuys = {}
|
self.rebuyCounts = {}
|
||||||
self.countAddOns = {}
|
self.addOnCounts = {}
|
||||||
self.countKO = {}
|
self.koCounts = {}
|
||||||
|
|
||||||
# currency symbol for this summary
|
# currency symbol for this summary
|
||||||
self.sym = None
|
self.sym = None
|
||||||
#self.sym = self.SYMBOL[self.gametype['currency']] # save typing! delete this attr when done
|
#self.sym = self.SYMBOL[self.gametype['currency']] # save typing! delete this attr when done
|
||||||
|
|
||||||
|
if builtFrom=="IMAP":
|
||||||
|
self.parseSummary()
|
||||||
|
#TODO: self.insert()
|
||||||
|
#end def __init__
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
#TODO : Update
|
#TODO : Update
|
||||||
vars = ( ("SITE", self.sitename),
|
vars = ( ("SITE", self.sitename),
|
||||||
("START TIME", self.starttime),
|
("START TIME", self.startTime),
|
||||||
("END TIME", self.endtime),
|
("END TIME", self.endTime),
|
||||||
("TOURNEY NAME", self.tourneyName),
|
("TOURNEY NAME", self.tourneyName),
|
||||||
("TOURNEY NO", self.tourNo),
|
("TOURNEY NO", self.tourNo),
|
||||||
|
("TOURNEY TYPE ID", self.tourneyTypeId),
|
||||||
|
("TOURNEY ID", self.tourneyId),
|
||||||
("BUYIN", self.buyin),
|
("BUYIN", self.buyin),
|
||||||
("FEE", self.fee),
|
("FEE", self.fee),
|
||||||
("HERO", self.hero),
|
("HERO", self.hero),
|
||||||
|
@ -109,9 +126,9 @@ class Tourney(object):
|
||||||
("PRIZE POOL", self.prizepool),
|
("PRIZE POOL", self.prizepool),
|
||||||
("STARTING CHIP COUNT", self.buyInChips),
|
("STARTING CHIP COUNT", self.buyInChips),
|
||||||
("MIXED", self.mixed),
|
("MIXED", self.mixed),
|
||||||
("REBUY ADDON", self.isRebuy),
|
("REBUY", self.isRebuy),
|
||||||
|
("ADDON", self.isAddOn),
|
||||||
("KO", self.isKO),
|
("KO", self.isKO),
|
||||||
("HU", self.isHU),
|
|
||||||
("MATRIX", self.isMatrix),
|
("MATRIX", self.isMatrix),
|
||||||
("SHOOTOUT", self.isShootout),
|
("SHOOTOUT", self.isShootout),
|
||||||
("MATRIX MATCH ID", self.matrixMatchId),
|
("MATRIX MATCH ID", self.matrixMatchId),
|
||||||
|
@ -119,22 +136,25 @@ class Tourney(object):
|
||||||
("SUB TOURNEY FEE", self.subTourneyFee),
|
("SUB TOURNEY FEE", self.subTourneyFee),
|
||||||
("REBUY CHIPS", self.rebuyChips),
|
("REBUY CHIPS", self.rebuyChips),
|
||||||
("ADDON CHIPS", self.addOnChips),
|
("ADDON CHIPS", self.addOnChips),
|
||||||
("REBUY AMOUNT", self.rebuyAmount),
|
("REBUY COST", self.rebuyCost),
|
||||||
("ADDON AMOUNT", self.addOnAmount),
|
("ADDON COST", self.addOnCost),
|
||||||
("TOTAL REBUYS", self.totalRebuys),
|
("TOTAL REBUYS", self.totalRebuyCount),
|
||||||
("TOTAL ADDONS", self.totalAddOns),
|
("TOTAL ADDONS", self.totalAddOnCount),
|
||||||
("KO BOUNTY", self.koBounty),
|
("KO BOUNTY", self.koBounty),
|
||||||
("TOURNEY COMMENT", self.tourneyComment)
|
("TOURNEY COMMENT", self.tourneyComment),
|
||||||
|
("SNG", self.isSng),
|
||||||
|
("SATELLITE", self.isSatellite),
|
||||||
|
("DOUBLE OR NOTHING", self.isDoubleOrNothing),
|
||||||
|
("GUARANTEE", self.guarantee)
|
||||||
)
|
)
|
||||||
|
|
||||||
structs = ( ("GAMETYPE", self.gametype),
|
structs = ( ("GAMETYPE", self.gametype),
|
||||||
("PLAYERS", self.players),
|
("PLAYERS", self.players),
|
||||||
("PAYIN AMOUNTS", self.payinAmounts),
|
("RANKS", self.ranks),
|
||||||
("POSITIONS", self.finishPositions),
|
|
||||||
("WINNINGS", self.winnings),
|
("WINNINGS", self.winnings),
|
||||||
("COUNT REBUYS", self.countRebuys),
|
("COUNT REBUYS", self.rebuyCounts),
|
||||||
("COUNT ADDONS", self.countAddOns),
|
("COUNT ADDONS", self.addOnCounts),
|
||||||
("NB OF KO", self.countKO)
|
("NB OF KO", self.koCounts)
|
||||||
)
|
)
|
||||||
str = ''
|
str = ''
|
||||||
for (name, var) in vars:
|
for (name, var) in vars:
|
||||||
|
@ -143,14 +163,17 @@ class Tourney(object):
|
||||||
for (name, struct) in structs:
|
for (name, struct) in structs:
|
||||||
str = str + "\n%s =\n" % name + pprint.pformat(struct, 4)
|
str = str + "\n%s =\n" % name + pprint.pformat(struct, 4)
|
||||||
return str
|
return str
|
||||||
|
#end def __str__
|
||||||
|
|
||||||
|
def parseSummary(self): abstract
|
||||||
|
"""should fill the class variables with the parsed information"""
|
||||||
|
|
||||||
def getSummaryText(self):
|
def getSummaryText(self):
|
||||||
return self.summaryText
|
return self.summaryText
|
||||||
|
|
||||||
def prepInsert(self, db):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def insert(self, db):
|
def insert(self, db):
|
||||||
|
# Note that this method is not used by the PS tourney storage stuff - this is for summary files only
|
||||||
|
|
||||||
# First : check all needed info is filled in the object, especially for the initial select
|
# First : check all needed info is filled in the object, especially for the initial select
|
||||||
|
|
||||||
# Notes on DB Insert
|
# Notes on DB Insert
|
||||||
|
@ -161,18 +184,18 @@ class Tourney(object):
|
||||||
# Starttime may not match the one in the Summary file : HH = time of the first Hand / could be slighltly different from the one in the summary file
|
# Starttime may not match the one in the Summary file : HH = time of the first Hand / could be slighltly different from the one in the summary file
|
||||||
# Note: If the TourneyNo could be a unique id .... this would really be a relief to deal with matrix matches ==> Ask on the IRC / Ask Fulltilt ??
|
# Note: If the TourneyNo could be a unique id .... this would really be a relief to deal with matrix matches ==> Ask on the IRC / Ask Fulltilt ??
|
||||||
|
|
||||||
dbTourneyTypeId = db.tRecogniseTourneyType(self)
|
dbTourneyTypeId = db.getTourneyTypeId(self)
|
||||||
logging.debug("Tourney Type ID = %d" % dbTourneyTypeId)
|
logging.debug("Tourney Type ID = %d" % dbTourneyTypeId)
|
||||||
dbTourneyId = db.tRecognizeTourney(self, dbTourneyTypeId)
|
dbTourneyId = db.tRecognizeTourney(self, dbTourneyTypeId)
|
||||||
logging.debug("Tourney ID = %d" % dbTourneyId)
|
logging.debug("Tourney ID = %d" % dbTourneyId)
|
||||||
dbTourneysPlayersIds = db.tStoreTourneyPlayers(self, dbTourneyId)
|
dbTourneysPlayersIds = db.tStoreTourneysPlayers(self, dbTourneyId)
|
||||||
logging.debug("TourneysPlayersId = %s" % dbTourneysPlayersIds)
|
logging.debug("TourneysPlayersId = %s" % dbTourneysPlayersIds)
|
||||||
db.tUpdateTourneysHandsPlayers(self, dbTourneysPlayersIds, dbTourneyTypeId)
|
db.tUpdateTourneysHandsPlayers(self, dbTourneysPlayersIds, dbTourneyTypeId)
|
||||||
logging.debug("tUpdateTourneysHandsPlayers done")
|
logging.debug("tUpdateTourneysHandsPlayers done")
|
||||||
logging.debug("Tourney Insert done")
|
logging.debug("Tourney Insert done")
|
||||||
|
|
||||||
# TO DO : Return what has been done (tourney created, updated, nothing)
|
# TO DO : Return what has been done (tourney created, updated, nothing)
|
||||||
# ?? stored = 1 if tourney is fully created / duplicates = 1, if everything was already here and correct / partial=1 if some things were already here (between tourney, tourneyPlayers and handsplayers)
|
# ?? stored = 1 if tourney is fully created / duplicates = 1, if everything was already here and correct / partial=1 if some things were already here (between tourney, tourneysPlayers and handsPlayers)
|
||||||
# if so, prototypes may need changes to know what has been done or make some kind of dict in Tourney object that could be updated during the insert process to store that information
|
# if so, prototypes may need changes to know what has been done or make some kind of dict in Tourney object that could be updated during the insert process to store that information
|
||||||
stored = 0
|
stored = 0
|
||||||
duplicates = 0
|
duplicates = 0
|
||||||
|
@ -181,83 +204,8 @@ class Tourney(object):
|
||||||
ttime = 0
|
ttime = 0
|
||||||
return (stored, duplicates, partial, errors, ttime)
|
return (stored, duplicates, partial, errors, ttime)
|
||||||
|
|
||||||
|
|
||||||
def old_insert_from_Hand(self, db):
|
|
||||||
""" Function to insert Hand into database
|
|
||||||
Should not commit, and do minimal selects. Callers may want to cache commits
|
|
||||||
db: a connected Database object"""
|
|
||||||
# TODO:
|
|
||||||
# Players - base playerid and siteid tuple
|
|
||||||
sqlids = db.getSqlPlayerIDs([p[1] for p in self.players], self.siteId)
|
|
||||||
|
|
||||||
#Gametypes
|
def addPlayer(self, rank, name, winnings, winningsCurrency, rebuyCount, addOnCount, koCount):
|
||||||
gtid = db.getGameTypeId(self.siteId, self.gametype)
|
|
||||||
|
|
||||||
# HudCache data to come from DerivedStats class
|
|
||||||
# HandsActions - all actions for all players for all streets - self.actions
|
|
||||||
# Hands - Summary information of hand indexed by handId - gameinfo
|
|
||||||
#This should be moved to prepInsert
|
|
||||||
hh = {}
|
|
||||||
hh['siteHandNo'] = self.handid
|
|
||||||
hh['handStart'] = self.starttime
|
|
||||||
hh['gameTypeId'] = gtid
|
|
||||||
# seats TINYINT NOT NULL,
|
|
||||||
hh['tableName'] = self.tablename
|
|
||||||
hh['maxSeats'] = self.maxseats
|
|
||||||
hh['seats'] = len(sqlids)
|
|
||||||
# Flop turn and river may all be empty - add (likely) too many elements and trim with range
|
|
||||||
boardcards = self.board['FLOP'] + self.board['TURN'] + self.board['RIVER'] + [u'0x', u'0x', u'0x', u'0x', u'0x']
|
|
||||||
cards = [Card.encodeCard(c) for c in boardcards[0:5]]
|
|
||||||
hh['boardcard1'] = cards[0]
|
|
||||||
hh['boardcard2'] = cards[1]
|
|
||||||
hh['boardcard3'] = cards[2]
|
|
||||||
hh['boardcard4'] = cards[3]
|
|
||||||
hh['boardcard5'] = cards[4]
|
|
||||||
|
|
||||||
# texture smallint,
|
|
||||||
# playersVpi SMALLINT NOT NULL, /* num of players vpi */
|
|
||||||
# Needs to be recorded
|
|
||||||
# playersAtStreet1 SMALLINT NOT NULL, /* num of players seeing flop/street4 */
|
|
||||||
# Needs to be recorded
|
|
||||||
# playersAtStreet2 SMALLINT NOT NULL,
|
|
||||||
# Needs to be recorded
|
|
||||||
# playersAtStreet3 SMALLINT NOT NULL,
|
|
||||||
# Needs to be recorded
|
|
||||||
# playersAtStreet4 SMALLINT NOT NULL,
|
|
||||||
# Needs to be recorded
|
|
||||||
# playersAtShowdown SMALLINT NOT NULL,
|
|
||||||
# Needs to be recorded
|
|
||||||
# street0Raises TINYINT NOT NULL, /* num small bets paid to see flop/street4, including blind */
|
|
||||||
# Needs to be recorded
|
|
||||||
# street1Raises TINYINT NOT NULL, /* num small bets paid to see turn/street5 */
|
|
||||||
# Needs to be recorded
|
|
||||||
# street2Raises TINYINT NOT NULL, /* num big bets paid to see river/street6 */
|
|
||||||
# Needs to be recorded
|
|
||||||
# street3Raises TINYINT NOT NULL, /* num big bets paid to see sd/street7 */
|
|
||||||
# Needs to be recorded
|
|
||||||
# street4Raises TINYINT NOT NULL, /* num big bets paid to see showdown */
|
|
||||||
# Needs to be recorded
|
|
||||||
|
|
||||||
#print "DEBUG: self.getStreetTotals = (%s, %s, %s, %s, %s)" % self.getStreetTotals()
|
|
||||||
#FIXME: Pot size still in decimal, needs to be converted to cents
|
|
||||||
(hh['street1Pot'], hh['street2Pot'], hh['street3Pot'], hh['street4Pot'], hh['showdownPot']) = self.getStreetTotals()
|
|
||||||
|
|
||||||
# comment TEXT,
|
|
||||||
# commentTs DATETIME
|
|
||||||
#print hh
|
|
||||||
handid = db.storeHand(hh)
|
|
||||||
# HandsPlayers - ? ... Do we fix winnings?
|
|
||||||
# Tourneys ?
|
|
||||||
# TourneysPlayers
|
|
||||||
|
|
||||||
pass
|
|
||||||
|
|
||||||
def select(self, tourneyId):
|
|
||||||
""" Function to create Tourney object from database """
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def addPlayer(self, rank, name, winnings, payinAmount, nbRebuys, nbAddons, nbKO):
|
|
||||||
"""\
|
"""\
|
||||||
Adds a player to the tourney, and initialises data structures indexed by player.
|
Adds a player to the tourney, and initialises data structures indexed by player.
|
||||||
rank (int) indicating the finishing rank (can be -1 if unknown)
|
rank (int) indicating the finishing rank (can be -1 if unknown)
|
||||||
|
@ -266,13 +214,16 @@ winnings (decimal) the money the player ended the tourney with (can be 0, or
|
||||||
"""
|
"""
|
||||||
log.debug("addPlayer: rank:%s - name : '%s' - Winnings (%s)" % (rank, name, winnings))
|
log.debug("addPlayer: rank:%s - name : '%s' - Winnings (%s)" % (rank, name, winnings))
|
||||||
self.players.append(name)
|
self.players.append(name)
|
||||||
self.finishPositions.update( { name : Decimal(rank) } )
|
self.ranks.update( { name : Decimal(rank) } )
|
||||||
self.winnings.update( { name : Decimal(winnings) } )
|
self.winnings.update( { name : Decimal(winnings) } )
|
||||||
self.payinAmounts.update( {name : Decimal(payinAmount) } )
|
self.winningsCurrency.update( { name : winningsCurrency } )
|
||||||
self.countRebuys.update( {name: Decimal(nbRebuys) } )
|
if rebuyCount:
|
||||||
self.countAddOns.update( {name: Decimal(nbAddons) } )
|
self.rebuyCounts.update( {name: Decimal(rebuyCount) } )
|
||||||
self.countKO.update( {name : Decimal(nbKO) } )
|
if addOnCount:
|
||||||
|
self.addOnCounts.update( {name: Decimal(addOnCount) } )
|
||||||
|
if koCount:
|
||||||
|
self.koCounts.update( {name : Decimal(koCount) } )
|
||||||
|
#end def addPlayer
|
||||||
|
|
||||||
def incrementPlayerWinnings(self, name, additionnalWinnings):
|
def incrementPlayerWinnings(self, name, additionnalWinnings):
|
||||||
log.debug("incrementPlayerWinnings: name : '%s' - Add Winnings (%s)" % (name, additionnalWinnings))
|
log.debug("incrementPlayerWinnings: name : '%s' - Add Winnings (%s)" % (name, additionnalWinnings))
|
||||||
|
@ -325,7 +276,7 @@ Map the tuple self.gametype onto the pokerstars string describing it
|
||||||
self.writeSummary(sys.stdout)
|
self.writeSummary(sys.stdout)
|
||||||
|
|
||||||
|
|
||||||
def assemble(cnxn, tourneyId):
|
def assemble(cnxn, tourneyId): #TODO: move this method to Hand or Database
|
||||||
# TODO !!
|
# TODO !!
|
||||||
c = cnxn.cursor()
|
c = cnxn.cursor()
|
||||||
|
|
||||||
|
@ -383,7 +334,7 @@ limit 1""", {'handid':handid})
|
||||||
SELECT
|
SELECT
|
||||||
h.sitehandno as hid,
|
h.sitehandno as hid,
|
||||||
h.tablename as table,
|
h.tablename as table,
|
||||||
h.handstart as starttime
|
h.handstart as startTime
|
||||||
FROM
|
FROM
|
||||||
hands as h
|
hands as h
|
||||||
WHERE h.id = %(handid)s
|
WHERE h.id = %(handid)s
|
||||||
|
@ -391,7 +342,7 @@ WHERE h.id = %(handid)s
|
||||||
res = c.fetchone()
|
res = c.fetchone()
|
||||||
h.handid = res[0]
|
h.handid = res[0]
|
||||||
h.tablename = res[1]
|
h.tablename = res[1]
|
||||||
h.starttime = res[2] # automatically a datetime
|
h.startTime = res[2] # automatically a datetime
|
||||||
|
|
||||||
# PlayerStacks
|
# PlayerStacks
|
||||||
c.execute("""
|
c.execute("""
|
|
@ -35,7 +35,10 @@ if os.name == 'nt' and sys.version[0:3] not in ('2.5', '2.6') and '-r' not in sy
|
||||||
os.environ['PATH'] = tmppath
|
os.environ['PATH'] = tmppath
|
||||||
print "Python " + sys.version[0:3] + ' - press return to continue\n'
|
print "Python " + sys.version[0:3] + ' - press return to continue\n'
|
||||||
sys.stdin.readline()
|
sys.stdin.readline()
|
||||||
os.execvpe('pythonw.exe', ('pythonw.exe', 'fpdb.pyw', '-r'), os.environ) # first arg is ignored (name of program being run)
|
if os.name=='nt':
|
||||||
|
os.execvpe('pythonw.exe', ('pythonw.exe', 'fpdb.pyw', '-r'), os.environ) # first arg is ignored (name of program being run)
|
||||||
|
else:
|
||||||
|
os.execvpe('python', ('python', 'fpdb.pyw', '-r'), os.environ) # first arg is ignored (name of program being run)
|
||||||
else:
|
else:
|
||||||
print "\npython 2.5 not found, please install python 2.5 or 2.6 for fpdb\n"
|
print "\npython 2.5 not found, please install python 2.5 or 2.6 for fpdb\n"
|
||||||
raw_input("Press ENTER to continue.")
|
raw_input("Press ENTER to continue.")
|
||||||
|
@ -413,21 +416,24 @@ class fpdb:
|
||||||
# self.release_global_lock()
|
# self.release_global_lock()
|
||||||
# lock_released = True
|
# lock_released = True
|
||||||
self.db.recreate_tables()
|
self.db.recreate_tables()
|
||||||
|
self.release_global_lock()
|
||||||
#else:
|
#else:
|
||||||
# for other dbs use same connection as holds global lock
|
# for other dbs use same connection as holds global lock
|
||||||
# self.fdb_lock.fdb.recreate_tables()
|
# self.fdb_lock.fdb.recreate_tables()
|
||||||
# TODO: figure out why this seems to be necessary
|
# TODO: figure out why this seems to be necessary
|
||||||
dia_restart = gtk.MessageDialog(parent=self.window, flags=0, type=gtk.MESSAGE_WARNING,
|
dia_restart = gtk.MessageDialog(parent=self.window, flags=0, type=gtk.MESSAGE_WARNING,
|
||||||
buttons=(gtk.BUTTONS_OK), message_format="Restart fpdb")
|
buttons=(gtk.BUTTONS_OK), message_format="Restart fpdb")
|
||||||
diastring = "You should now restart fpdb."
|
diastring = "Fpdb now needs to close. Please restart it."
|
||||||
dia_restart.format_secondary_text(diastring)
|
dia_restart.format_secondary_text(diastring)
|
||||||
|
|
||||||
dia_restart.run()
|
dia_restart.run()
|
||||||
dia_restart.destroy()
|
dia_restart.destroy()
|
||||||
|
self.quit(None, None)
|
||||||
elif response == gtk.RESPONSE_NO:
|
elif response == gtk.RESPONSE_NO:
|
||||||
|
self.release_global_lock()
|
||||||
print 'User cancelled recreating tables'
|
print 'User cancelled recreating tables'
|
||||||
#if not lock_released:
|
#if not lock_released:
|
||||||
self.release_global_lock()
|
#end def dia_recreate_tables
|
||||||
|
|
||||||
def dia_recreate_hudcache(self, widget, data=None):
|
def dia_recreate_hudcache(self, widget, data=None):
|
||||||
if self.obtain_global_lock():
|
if self.obtain_global_lock():
|
||||||
|
|
12
setup.py
12
setup.py
|
@ -1,19 +1,11 @@
|
||||||
#!/usr/bin/python2
|
#!/usr/bin/python2
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
#Copyright 2009-2010 Mika Bostrom
|
#Created by Mika Bostrom, released into the public domain as far as legally possible.
|
||||||
#This program is free software: you can redistribute it and/or modify
|
|
||||||
#it under the terms of the GNU Affero General Public License as published by
|
|
||||||
#the Free Software Foundation, version 3 of the License.
|
|
||||||
#
|
#
|
||||||
#This program is distributed in the hope that it will be useful,
|
#This program is distributed in the hope that it will be useful,
|
||||||
#but WITHOUT ANY WARRANTY; without even the implied warranty of
|
#but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
#GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
#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/>.
|
|
||||||
#In the "official" distribution you can find the license in agpl-3.0.txt.
|
|
||||||
|
|
||||||
# Python packaging for fpdb
|
# Python packaging for fpdb
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user