Compare commits
3 Commits
d46281fda7
...
7a02bbb262
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a02bbb262 | ||
|
|
dd9f08aa5e | ||
|
|
49de6b1f35 |
@@ -1,12 +1,10 @@
|
||||
from typing import Any, cast
|
||||
|
||||
from PySide6.QtCore import (
|
||||
QByteArray,
|
||||
QDate,
|
||||
QModelIndex,
|
||||
QPersistentModelIndex,
|
||||
QPoint,
|
||||
QSettings,
|
||||
Qt,
|
||||
Signal,
|
||||
Slot,
|
||||
@@ -15,19 +13,25 @@ from PySide6.QtGui import (
|
||||
QCloseEvent,
|
||||
QColor,
|
||||
)
|
||||
from PySide6.QtSql import QSqlTableModel
|
||||
from PySide6.QtSql import QSqlQuery, QSqlTableModel
|
||||
from PySide6.QtWidgets import (
|
||||
QAbstractItemView,
|
||||
QHBoxLayout,
|
||||
QHeaderView,
|
||||
QLabel,
|
||||
QMainWindow,
|
||||
QProgressBar,
|
||||
QPushButton,
|
||||
QSizePolicy,
|
||||
QStyledItemDelegate,
|
||||
QStyleOptionViewItem,
|
||||
QWidget,
|
||||
)
|
||||
|
||||
from docketModel import docketModel
|
||||
from lib.utils import QStyleOptionViewItemInit, readGeometry, writeGeometry
|
||||
from lib.utils import QStyleOptionViewItemInit, query_error, readGeometry, writeGeometry
|
||||
from ui.MainWindow import Ui_MainWindow
|
||||
from workers import updateThread
|
||||
from workers import loadCases, updateThread
|
||||
|
||||
|
||||
class dateDelegate(QStyledItemDelegate):
|
||||
@@ -115,6 +119,7 @@ class casesModel(QSqlTableModel):
|
||||
|
||||
class MainWindow(QMainWindow, Ui_MainWindow):
|
||||
show_entries = Signal(int)
|
||||
update_status = Signal()
|
||||
|
||||
loadThread = None
|
||||
|
||||
@@ -169,12 +174,77 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
||||
self.docketView.horizontalHeader().setSectionResizeMode(
|
||||
1, QHeaderView.ResizeMode.Stretch
|
||||
)
|
||||
|
||||
widget = QWidget()
|
||||
layout = QHBoxLayout(widget)
|
||||
self.status = QLabel("Status")
|
||||
layout.addWidget(self.status)
|
||||
layout.addStretch()
|
||||
self.progress = QProgressBar()
|
||||
self.progress.setRange(0,100)
|
||||
self.progress.setValue(0)
|
||||
self.progress.setMinimumWidth(150)
|
||||
self.progress.setMaximumWidth(150)
|
||||
self.progress.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Preferred)
|
||||
layout.addWidget(self.progress)
|
||||
self.loadButton = QPushButton()
|
||||
self.loadButton.setObjectName("loadButton")
|
||||
self.loadButton.setText("Load Cases")
|
||||
layout.addWidget(self.loadButton)
|
||||
self.statusbar.addWidget(widget,10)
|
||||
|
||||
self.loadButton.clicked.connect(self.loadCases)
|
||||
self.update_status.connect(self.statusBarUpdate)
|
||||
self.update_status.emit()
|
||||
return
|
||||
|
||||
def closeEvent(self, event: QCloseEvent) -> None:
|
||||
writeGeometry(self)
|
||||
super().closeEvent(event)
|
||||
return
|
||||
|
||||
@Slot()
|
||||
def loadCases(self) -> None:
|
||||
if self.loadThread is None:
|
||||
self.loadThread = loadCases()
|
||||
self.loadThread.caseLoaded.connect(self.progress.setValue)
|
||||
self.loadThread.finished.connect(self.loadCasesDone)
|
||||
self.loadButton.setEnabled(False)
|
||||
self.loadThread.start()
|
||||
return
|
||||
@Slot()
|
||||
def loadCasesDone(self) -> None:
|
||||
self.loadButton.setEnabled(True)
|
||||
self.update_status.emit()
|
||||
return
|
||||
|
||||
@Slot()
|
||||
def statusBarUpdate(self) -> None:
|
||||
if self.loadThread is None:
|
||||
year = ''
|
||||
max = 'unknown'
|
||||
else:
|
||||
year = self.loadThread.year
|
||||
max = self.loadThread.number
|
||||
query = QSqlQuery()
|
||||
query.prepare("SELECT COUNT(*) AS number_active FROM cases WHERE active=1")
|
||||
if not query.exec():
|
||||
query_error(query)
|
||||
if query.next():
|
||||
active = query.value('number_active')
|
||||
query.prepare("select SUBSTRING(docket_id,1,2) AS year, "
|
||||
"SUBSTRING(docket_id,3,1) AS type, "
|
||||
"MAX(CAST(SUBSTRING(docket_id,4) AS INTEGER)) AS number "
|
||||
"FROM cases "
|
||||
"GROUP BY year, type "
|
||||
"ORDER BY type, year, number"
|
||||
"LIMIT 2")
|
||||
#if not query.exec():
|
||||
# query_error(query)
|
||||
msg=f"Oldest: {year}, Active: {active}, Max. Case: {max}"
|
||||
self.status.setText(msg)
|
||||
return
|
||||
|
||||
@Slot(QModelIndex) # type: ignore
|
||||
def rowClicked(self, index: QModelIndex) -> None:
|
||||
if not index.isValid():
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
from datetime import date
|
||||
|
||||
from PySide6.QtCore import QSettings
|
||||
from pony.orm import ( # type: ignore[import-untyped]
|
||||
Database,
|
||||
LongStr,
|
||||
@@ -10,9 +9,11 @@ from pony.orm import ( # type: ignore[import-untyped]
|
||||
Set,
|
||||
set_sql_debug,
|
||||
)
|
||||
from PySide6.QtCore import QSettings
|
||||
|
||||
db = Database()
|
||||
|
||||
|
||||
class Cases(db.Entity): # type: ignore[name-defined]
|
||||
case_id = PrimaryKey(int, auto=True)
|
||||
docket_id = Required(str)
|
||||
@@ -32,32 +33,29 @@ class Entries(db.Entity): # type: ignore[name-defined]
|
||||
text = Required(LongStr)
|
||||
documents = Set("Documents")
|
||||
|
||||
|
||||
class Documents(db.Entity): # type: ignore[name-defined]
|
||||
document_id = PrimaryKey(int, auto=True)
|
||||
entry_id = Required(Entries)
|
||||
name = Required(str)
|
||||
url = Required(LongStr)
|
||||
|
||||
|
||||
class History(db.Entity): # type: ignore[name-defined]
|
||||
history_id = PrimaryKey(int, auto=True)
|
||||
year = Required(str, max_len=3)
|
||||
edocket = Required(bool)
|
||||
number = Required(int)
|
||||
|
||||
|
||||
def updateDatabase(settings: QSettings) -> None:
|
||||
set_sql_debug(True)
|
||||
engine = settings.value('engine')
|
||||
if engine not in ['QMYSQL', 'MARIADB']:
|
||||
engine = settings.value("engine")
|
||||
if engine not in ["QMYSQL", "MARIADB"]:
|
||||
raise Exception(f"Unknown database engine: {engine}")
|
||||
db.bind(
|
||||
provider="mysql",
|
||||
user=settings.value('user'),
|
||||
host=settings.value('hostname'),
|
||||
database=settings.value('databasename'),
|
||||
password=settings.value('password'),
|
||||
user=settings.value("user"),
|
||||
host=settings.value("hostname"),
|
||||
database=settings.value("databasename"),
|
||||
password=settings.value("password"),
|
||||
)
|
||||
db.generate_mapping(create_tables=True)
|
||||
db.disconnect()
|
||||
|
||||
20
lib/utils.py
20
lib/utils.py
@@ -1,6 +1,11 @@
|
||||
from typing import NoReturn, cast
|
||||
from typing import NoReturn
|
||||
|
||||
from PySide6.QtCore import QByteArray, QCoreApplication, QObject, QRect, QSettings, Signal
|
||||
from PySide6.QtCore import (
|
||||
QByteArray,
|
||||
QCoreApplication,
|
||||
QRect,
|
||||
QSettings,
|
||||
)
|
||||
from PySide6.QtGui import QColor, QFont
|
||||
from PySide6.QtSql import QSqlQuery
|
||||
from PySide6.QtWidgets import QStyleOptionViewItem, QWidget
|
||||
@@ -29,23 +34,26 @@ class QStyleOptionViewItemInit(QStyleOptionViewItem):
|
||||
font: QFont
|
||||
text: str
|
||||
|
||||
def openSettings(group:str|None = None) -> QSettings:
|
||||
|
||||
def openSettings(group: str | None = None) -> QSettings:
|
||||
settings = QSettings("Troglodite Services", "SCOTUS Watch")
|
||||
if group is not None:
|
||||
settings.beginGroup(group)
|
||||
return settings
|
||||
|
||||
def readGeometry(widget:QWidget) -> None:
|
||||
|
||||
def readGeometry(widget: QWidget) -> None:
|
||||
settings = openSettings(widget.objectName())
|
||||
geometry = settings.value('geometry', QByteArray())
|
||||
geometry = settings.value("geometry", QByteArray())
|
||||
assert isinstance(geometry, QByteArray)
|
||||
if not geometry.isEmpty():
|
||||
widget.restoreGeometry(geometry)
|
||||
settings.endGroup()
|
||||
return
|
||||
|
||||
|
||||
def writeGeometry(widget: QWidget) -> None:
|
||||
settings = openSettings(widget.objectName())
|
||||
settings.setValue('geometry', widget.saveGeometry())
|
||||
settings.setValue("geometry", widget.saveGeometry())
|
||||
settings.endGroup()
|
||||
return
|
||||
|
||||
@@ -83,7 +83,7 @@ class PDFViewer(QDialog, Ui_pdfViewer):
|
||||
def __init__(self, parent: QWidget | None) -> None:
|
||||
super(PDFViewer, self).__init__(parent)
|
||||
self.setupUi(self)
|
||||
self.setObjectName('PDFViewer')
|
||||
self.setObjectName("PDFViewer")
|
||||
readGeometry(self)
|
||||
print(self.objectName())
|
||||
self.zoomSelector = ZoomSelector(self)
|
||||
|
||||
@@ -25,20 +25,20 @@ from MainWindow import MainWindow
|
||||
def main() -> int:
|
||||
#
|
||||
app = QApplication(sys.argv)
|
||||
settings = openSettings('database')
|
||||
settings = openSettings("database")
|
||||
file = QFile(settings.fileName())
|
||||
if not file.exists():
|
||||
result = setupDialog().exec()
|
||||
if result == QDialog.DialogCode.Rejected:
|
||||
print(f"We require database credentials")
|
||||
return(2)
|
||||
return 2
|
||||
updateDatabase(settings)
|
||||
db = QSqlDatabase.addDatabase("QMYSQL")
|
||||
db.setHostName(settings.value("hostname"))
|
||||
portStr = cast(str, settings.value('port', '3306'))
|
||||
portStr = cast(str, settings.value("port", "3306"))
|
||||
db.setPort(int(portStr))
|
||||
db.setDatabaseName(settings.value("databasename","scotus")) # type: ignore
|
||||
db.setUserName(settings.value("user","scotus")) # type: ignore
|
||||
db.setDatabaseName(settings.value("databasename", "scotus")) # type: ignore
|
||||
db.setUserName(settings.value("user", "scotus")) # type: ignore
|
||||
db.setPassword(settings.value("password"))
|
||||
settings.endGroup()
|
||||
db.open()
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
from PySide6.QtCore import Slot, Qt
|
||||
from PySide6.QtCore import Qt, Slot
|
||||
from PySide6.QtGui import QPalette
|
||||
from PySide6.QtWidgets import QDialog, QStatusBar, QVBoxLayout, QWidget
|
||||
|
||||
from lib.utils import openSettings
|
||||
from ui.dbSetup import Ui_setupDialog
|
||||
|
||||
class setupDialog(QDialog,Ui_setupDialog):
|
||||
def __init__(self, parent: QWidget | None = None):
|
||||
super(setupDialog,self).__init__(parent)
|
||||
|
||||
class setupDialog(QDialog, Ui_setupDialog):
|
||||
def __init__(self, parent: QWidget | None = None) -> None:
|
||||
super(setupDialog, self).__init__(parent)
|
||||
self.setupUi(self)
|
||||
self.sqliteEdit.setEnabled(False)
|
||||
|
||||
layout = self.layout()
|
||||
assert isinstance(layout, QVBoxLayout)
|
||||
self.statusBar = QStatusBar(self)
|
||||
self.statusBar.setObjectName('statusBar')
|
||||
self.statusBar.setObjectName("statusBar")
|
||||
where = layout.indexOf(self.buttonBox)
|
||||
layout.insertWidget(where, self.statusBar)
|
||||
self.pwEdit.editingFinished.connect(self.pwDone)
|
||||
@@ -22,7 +23,7 @@ class setupDialog(QDialog,Ui_setupDialog):
|
||||
return
|
||||
|
||||
@Slot()
|
||||
def pwDone(self):
|
||||
def pwDone(self) -> None:
|
||||
pw = self.pwEdit.text()
|
||||
confirm = self.pwConfirmEdit.text()
|
||||
|
||||
@@ -37,29 +38,29 @@ class setupDialog(QDialog,Ui_setupDialog):
|
||||
self.pwGood = True
|
||||
return
|
||||
|
||||
@Slot(int) # type: ignore
|
||||
def done(self, r:int) -> None:
|
||||
@Slot(int) # type: ignore
|
||||
def done(self, r: int) -> None:
|
||||
if r == QDialog.DialogCode.Rejected:
|
||||
super(setupDialog,self).done(r)
|
||||
super(setupDialog, self).done(r)
|
||||
return
|
||||
self.pwDone()
|
||||
if not self.pwGood:
|
||||
return
|
||||
super(setupDialog,self).done(r)
|
||||
super(setupDialog, self).done(r)
|
||||
return
|
||||
|
||||
@Slot()
|
||||
def accept(self) -> None:
|
||||
settings=openSettings('database')
|
||||
settings.setValue('hostname', self.hostEdit.text())
|
||||
settings.setValue('databasename', self.dbEdit.text())
|
||||
settings.setValue('user',self.userEdit.text())
|
||||
settings.setValue('password', self.pwEdit.text())
|
||||
settings.setValue('port', self.portEdit.text())
|
||||
settings = openSettings("database")
|
||||
settings.setValue("hostname", self.hostEdit.text())
|
||||
settings.setValue("databasename", self.dbEdit.text())
|
||||
settings.setValue("user", self.userEdit.text())
|
||||
settings.setValue("password", self.pwEdit.text())
|
||||
settings.setValue("port", self.portEdit.text())
|
||||
if self.comboBox.currentIndex() == 0:
|
||||
settings.setValue('engine', 'QMYSQL')
|
||||
settings.setValue("engine", "QMYSQL")
|
||||
elif self.comboBox.currentIndex() == 1:
|
||||
settings.setValue('engine', 'QSQLITE')
|
||||
settings.setValue("engine", "QSQLITE")
|
||||
# Other types: QDB2, QIBASE, QOCI, QODBC, QPSQL, QMIMER
|
||||
else:
|
||||
print("Bad Database Type")
|
||||
|
||||
68
workers.py
68
workers.py
@@ -4,7 +4,7 @@ import re
|
||||
import dateparser
|
||||
import requests
|
||||
from bs4 import BeautifulSoup, Tag
|
||||
from PySide6.QtCore import QDateTime, QThread
|
||||
from PySide6.QtCore import QDateTime, QThread, Signal
|
||||
from PySide6.QtSql import QSqlDatabase, QSqlQuery
|
||||
|
||||
from lib.utils import query_error
|
||||
@@ -223,9 +223,17 @@ def update_db(case_id: str, db: QSqlDatabase) -> int:
|
||||
#
|
||||
# If there is a linked case, we need to get the ID for that case.
|
||||
if linked is not None:
|
||||
#
|
||||
# If this case is on the Emergency Docket and it is linked to
|
||||
# a case on the regular docket, then this case is no longer active
|
||||
#
|
||||
deactivate = False
|
||||
|
||||
linked = linked.replace("Linked with ", "")
|
||||
for did in linked.split(","):
|
||||
did = did.strip()
|
||||
if re.match(r"\d+-\d+$", did):
|
||||
deactivate = True
|
||||
query.prepare("SELECT * FROM cases WHERE docket_id = :did")
|
||||
query.bindValue(":did", linked)
|
||||
if not query.exec():
|
||||
@@ -255,6 +263,14 @@ def update_db(case_id: str, db: QSqlDatabase) -> int:
|
||||
query.bindValue(":rhs", linked_id)
|
||||
if not query.exec():
|
||||
query_error(query)
|
||||
if re.match(r"\d+-\d+$", docket_id):
|
||||
deactivate = False
|
||||
if deactivate:
|
||||
query.prepare("UPDATE cases SET active=0 WHERE case_id = :cid")
|
||||
query.bindValue(":cid", case_id)
|
||||
if not query.exec():
|
||||
query_error(query)
|
||||
|
||||
#
|
||||
# XXX - Process lower courts
|
||||
#
|
||||
@@ -295,15 +311,19 @@ class updateThread(QThread):
|
||||
|
||||
|
||||
class loadCases(QThread):
|
||||
caseLoaded = Signal(int)
|
||||
year = QDateTime.currentDateTime().toString("yy")
|
||||
number = 0
|
||||
|
||||
def run(self) -> None:
|
||||
db = QSqlDatabase.cloneDatabase("qt_sql_default_connection", "load")
|
||||
if not db.open():
|
||||
raise Exception("db.open()")
|
||||
year = QDateTime.currentDateTime().toString("yy")
|
||||
|
||||
query = QSqlQuery(db)
|
||||
query.prepare("SELECT * FROM history WHERE year = :year")
|
||||
print(f"year = {year}")
|
||||
query.bindValue(":year", year)
|
||||
print(f"year = {self.year}")
|
||||
query.bindValue(":year", self.year)
|
||||
if not query.exec():
|
||||
query_error(query)
|
||||
|
||||
@@ -312,48 +332,49 @@ class loadCases(QThread):
|
||||
"INSERT INTO history (year, edocket, number) "
|
||||
"VALUES (:year, 0, 1)"
|
||||
)
|
||||
query.bindValue(":year", year)
|
||||
query.bindValue(":year", self.year)
|
||||
if not query.exec():
|
||||
query_error(query)
|
||||
edocket = 0
|
||||
number = 1
|
||||
self.number = 1
|
||||
history_id = query.lastInsertId()
|
||||
else:
|
||||
history_id = query.value("history_id")
|
||||
edocket = query.value("edocket")
|
||||
number = query.value("number")
|
||||
self.number = query.value("number")
|
||||
count = 0
|
||||
|
||||
while year > "00" and count < 100:
|
||||
while self.year > "00" and count < 100:
|
||||
self.caseLoaded.emit(count)
|
||||
query.prepare("SELECT * FROM cases WHERE docket_id = :did")
|
||||
if edocket == 1:
|
||||
docket_id = f"{year}A{number}"
|
||||
docket_id = f"{self.year}A{self.number}"
|
||||
else:
|
||||
docket_id = f"{year}-{number}"
|
||||
docket_id = f"{self.year}-{self.number}"
|
||||
query.bindValue(":did", docket_id)
|
||||
if not query.exec():
|
||||
query_error(query)
|
||||
if query.next():
|
||||
if query.value("active") == 0:
|
||||
print("Already exists and is inactive")
|
||||
number += 1
|
||||
self.number += 1
|
||||
continue
|
||||
result = update_db(docket_id, db)
|
||||
print(f"result: {result}")
|
||||
if result < 0:
|
||||
year = f"{int(year) - 1:02d}"
|
||||
if number > 1:
|
||||
self.year = f"{int(self.year) - 1:02d}"
|
||||
if self.number > 1:
|
||||
query.prepare(
|
||||
"UPDATE history set number = :number WHERE history_id=:hid"
|
||||
)
|
||||
query.bindValue(":number", number - 1)
|
||||
query.bindValue(":number", self.number - 1)
|
||||
query.bindValue(":hid", history_id)
|
||||
if not query.exec():
|
||||
query_error(query)
|
||||
|
||||
query.prepare("SELECT * FROM history WHERE year = :year")
|
||||
print(f"year = {year}")
|
||||
query.bindValue(":year", year)
|
||||
print(f"year = {self.year}")
|
||||
query.bindValue(":year", self.year)
|
||||
if not query.exec():
|
||||
query_error(query)
|
||||
|
||||
@@ -362,29 +383,30 @@ class loadCases(QThread):
|
||||
"INSERT INTO history (year, edocket, number) "
|
||||
"VALUES (:year, 0, 1)"
|
||||
)
|
||||
query.bindValue(":year", year)
|
||||
query.bindValue(":year", self.year)
|
||||
if not query.exec():
|
||||
query_error(query)
|
||||
edocket = 0
|
||||
number = 1
|
||||
self.number = 1
|
||||
history_id = query.lastInsertId()
|
||||
else:
|
||||
history_id = query.value("history_id")
|
||||
edocket = query.value("edocket")
|
||||
number = query.value("number")
|
||||
self.number = query.value("number")
|
||||
continue
|
||||
|
||||
number += 1
|
||||
self.number += 1
|
||||
count += 1
|
||||
if number > 1:
|
||||
if self.number > 1:
|
||||
query.prepare(
|
||||
"UPDATE history SET number= :number WHERE year = :year"
|
||||
)
|
||||
query.bindValue(":number", number)
|
||||
query.bindValue(":year", year)
|
||||
query.bindValue(":number", self.number)
|
||||
query.bindValue(":year", self.year)
|
||||
if not query.exec():
|
||||
query_error(query)
|
||||
db.close()
|
||||
del db
|
||||
QSqlDatabase.removeDatabase("load")
|
||||
self.caseLoaded.emit(0)
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user