| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234 |
- from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QDir, QDirIterator, QObject, QVariant
- from PyQt5.QtSql import QSqlDatabase, QSqlQuery, QSqlTableModel, QSqlField, QSqlRecord
- import hashlib
- import os
- from RBK.Model.DataType import DataType
- from RBK.Model.Field import Field
- from RBK.Model.Functions import runQuery, createModel, isError
- import RBK.Model.Functions as Func
- class Database(QObject):
- errored = pyqtSignal(str)
- relayAddField = pyqtSignal(str, str)
- relayRemoveField = pyqtSignal(str, str)
- relayAddDataType = pyqtSignal(str)
- relayRemoveDataType = pyqtSignal(str)
- def __init__(self):
- super().__init__()
- # Create a db w/ a list of the Games, versions and available Core Rulebooks
- self.models = {}
- self.db = QSqlDatabase().addDatabase('QSQLITE', 'db')
- self.dbcore = QSqlDatabase().addDatabase('QSQLITE', 'dbcore')
- self.rulebooks = QSqlDatabase().addDatabase('QSQLITE', 'rulebooks')
- self.rulebooks.setDatabaseName(':memory:')
- self.rulebooks.open()
- runQuery(self.rulebooks, "CREATE TABLE Rulebooks(GameName TEXT NOT NULL, GameVersion REAL NOT NULL, RulebookName TEXT PRIMARY KEY NOT NULL, Hash TEXT NOT NULL, Core TEXT NOT NULL, CoreRulebook TEXT, CoreRulebookHash TEXT)")
- runQuery(self.rulebooks, "CREATE TABLE ChangeLog(Table TEXT NOT NULL, Field TEXT NOT NULL, OldValue TEXT NOT NULL, NewValue TEXT NOT NULL)")
- iter = QDirIterator('Rulebooks/', ['*.rbk'], QDir.NoFilter, QDirIterator.Subdirectories)
- while(iter.hasNext()):
- rbk = iter.next()
- self.db.setDatabaseName(rbk)
- if not self.db.open():
- errored.emit('Error: Cannot open database: {0}'.format(self.db.lastError().text()))
- else:
- hasher = hashlib.sha256()
- with open(rbk, 'rb') as dbfile:
- buffer = dbfile.read()
- hasher.update(buffer)
- hash = hasher.hexdigest()
- print('{0}\t{1}'.format(rbk, hash))
- dbfile.close()
- rbkquery = runQuery(self.db, 'SELECT * FROM Rulebook LIMIT 1')
- rbkinfo = rbkquery.getValue()[0]
- result = runQuery(self.rulebooks, ('INSERT INTO Rulebooks VALUES ("{0}", "{1}", "{2}", "{3}", "{4}", "{5}", "{6}")'.format(rbkinfo.value('GameName'), rbkinfo.value('GameVersion'), rbkinfo.value('RulebookName'), hash, rbkinfo.value('Core'), rbkinfo.value('CoreRulebook'), rbkinfo.value('CoreRulebookHash'))))
- self.db.close()
- self.models['rulebooks'] = QSqlTableModel(None, self.rulebooks)
- self.models['rulebooks'].setTable('Rulebooks')
- self.models['rulebooks'].select()
- def newRulebook(self, game, version, rbk, core, corerbk, corehash):
- # Create directory structures if they don't already exist
- if not os.path.exists('Rulebooks/{0}'.format(game)):
- os.makedirs('Rulebooks/{0}'.format(game))
- os.makedirs('Rulebooks/{0}/{1}'.format(game, version))
- elif not os.path.exists('Rulebooks/{0}/{1}'.format(game, version)):
- os.makedirs('Rulebooks/{0}/{1}'.format(game, version))
- filename = 'Rulebooks/{0}/{1}/{2}.rbk'.format(game, version, rbk)
- self.db.setDatabaseName(filename)
- if not self.db.open():
- errored.emit('Error: Cannot open database: {0}'.format(self.lastError().text()))
- return False
- self.dataTypeModel = DataType(self)
- self.relayAddDataType.connect(self.dataTypeModel.addDataType)
- self.relayRemoveDataType.connect(self.dataTypeModel.removeDataType)
- self.fieldModel = Field(self)
- self.relayAddField.connect(self.fieldModel.addField)
- self.relayRemoveField.connect(self.fieldModel.removeField)
- runQuery(self.db, "CREATE TABLE Rulebook(GameName TEXT NOT NULL, GameVersion TEXT NOT NULL, RulebookName TEXT PRIMARY KEY NOT NULL, Core TEXT NOT NULL, CoreRulebook TEXT, CoreRulebookHash TEXT)")
- result = runQuery(self.db, 'INSERT INTO Rulebook (GameName, GameVersion, RulebookName, Core, CoreRulebook, CoreRulebookHash) VALUES ("{0}", "{1}", "{2}", "{3}", "{4}", "{5}")'.format(game, version, rbk, core, corerbk, corehash))
- if core=='True':
- self.addDataType('DataTypes')
- self.addDataType('Actions')
- self.addDataType('Currencies')
- self.addDataType('Character')
- for table in self.db.tables():
- createModel(self, table)
- if core=='False':
- coreFilename = 'Rulebooks/{0}/{1}/{2}.rbk'.format(game, version, corerbk)
- self.openCoreRulebook(coreFilename)
- return True
- def openRulebook(self, filename):
- self.db.setDatabaseName(filename)
- if not self.db.open():
- self.errored.emit('Error: Cannot open database: {0}'.format(self.db.lastError().text()))
- return False
- for table in self.db.tables():
- createModel(self, table)
- if not self.isCore(self.db):
- result = runQuery(self.db, 'SELECT GameName, GameVersion, CoreRulebook FROM Rulebook LIMIT 1')
- if not isError(result):
- rbk = result.getValue()[0]
- game = rbk.value('GameName')
- version = rbk.value('GameVersion')
- corerbk = rbk.value('CoreRulebook')
- coreFilename = 'Rulebooks/{0}/{1}/{2}.rbk'.format(game, version, corerbk)
- self.openCoreRulebook(coreFilename)
- else:
- message = result.getValue()
- self.errored.emit(message)
- return False
- self.dataTypeModel = DataType(self)
- self.relayAddDataType.connect(self.dataTypeModel.addDataType)
- self.relayRemoveDataType.connect(self.dataTypeModel.removeDataType)
- self.dataTypeModel.errored.connect(self.errorReceived)
- self.fieldModel = Field(self)
- self.relayAddField.connect(self.fieldModel.addField)
- self.relayRemoveField.connect(self.fieldModel.removeField)
- self.fieldModel.errored.connect(self.errorReceived)
- return True
- def openCoreRulebook(self, filename):
- self.dbcore.setDatabaseName(filename)
- if not self.dbcore.open():
- self.errored.emit('Error: Cannot open core database: {0}'.format(self.dbcore.lastError().text()))
- return False
- createModel(self, 'DataTypes')
- dtr = runQuery(self.dbcore, 'SELECT * FROM DataTypes')
- if not isError(dtr):
- datatypes = dtr.getValue()
- for dt in datatypes:
- s = 'Struct ' + dt.value(0)
- createModel(self, s)
- self.addDataType(dt.value(0))
- for r in range(self.models[s].rowCount()):
- f = self.models[s].record(r).value(0)
- if not ((f=='Name' or f=='Rulebook PDF Destination' or f=='Character Sheet Field')):
- self.addField(dt.value(0), f)
- return True
- else:
- return False
- def closeRulebook(self):
- self.db.close()
- # store a copy of the rulebooks model, clear the models, and restore the rulebook model
- rbk = self.models['rulebooks']
- self.models.clear()
- self.models['rulebooks'] = rbk
- def getModels(db):
- return db.models
- def isCore(self, db):
- return Func.isCore(db)
- #return RBK.Model.Functions.isCore(db)
- @pyqtSlot(str, str)
- def addField(self, datatype, newfield):
- self.relayAddField.emit(datatype, newfield)
- @pyqtSlot(str, str)
- def removeField(self, datatype, fieldrow):
- self.relayRemoveField.emit(datatype, fieldrow)
- @pyqtSlot(str)
- def addDataType(self, text):
- self.relayAddDataType.emit(text)
- @pyqtSlot(str)
- def removeDataType(self, dt):
- self.relayRemoveDataType.emit(dt)
- @pyqtSlot(str)
- def errorReceived(self, message):
- self.errored.emit(message)
- def getGameList(self):
- gameList = []
- gameList.append('New Game...')
- gamesresult = runQuery(self.rulebooks, 'SELECT DISTINCT GameName From Rulebooks ORDER BY GameName ASC')
- if not isError(gamesresult):
- games = gamesresult.getValue()
- print('# Games: {0}'.format(str(len(games))))
- for game in games:
- print(game.value(0))
- gameList.append(game.value(0))
- print(gameList)
- return gameList
- def getVersionList(self, gamename):
- versionList = []
- versionList.append('New Version...')
- versionsresult = runQuery(self.rulebooks, 'SELECT DISTINCT GameVersion FROM Rulebooks WHERE GameName = "{0}" ORDER BY GameVersion DESC'.format(gamename))
- if not isError(versionsresult):
- versions = versionsresult.getValue()
- for version in versions:
- versionList.append(str(version.value(0)))
- return versionList
- def getCoreRulebooksList(self, gamename, version):
- coreBookList = []
- if not ((gamename=='New Game...') or (version=='New Version...')):
- coreBookResults = runQuery(self.rulebooks, 'SELECT DISTINCT RulebookName FROM Rulebooks WHERE GameName = "{0}" AND GameVersion = "{1}" And Core = "True" ORDER BY RulebookName ASC'.format(gamename, version))
- if not isError(coreBookResults):
- corebooks = coreBookResults.getValue()
- for corebook in corebooks:
- coreBookList.append(str(corebook.value(0)))
- return coreBookList
- def getCoreRulebookHash(self, gamename, version, coreRulebook):
- corehash = None
- hashresult = runQuery(self.rulebooks, 'SELECT CoreRulebookHash FROM Rulebooks WHERE GameName = "{0}" AND GameVersion = "{1}" And RulebookName = "{2}"'.format(gamename, version, coreRulebook))
- print(hashresult.getValue())
- if not isError(hashresult):
- #corehash = hashresult.getValue()[0].value('CoreRulebookHash')
- print(corehash)
- return corehash
|