Commit a3989a83 authored by Antoine Lima's avatar Antoine Lima
Browse files

Player deletetion from leaderboards

parent 94caf50c
...@@ -11,6 +11,7 @@ pyuic5 --import-from=ui ui/authleague.ui -o ui/authleague_ui.py ...@@ -11,6 +11,7 @@ pyuic5 --import-from=ui ui/authleague.ui -o ui/authleague_ui.py
pyuic5 --import-from=ui ui/leaderboard.ui -o ui/leaderboard_ui.py pyuic5 --import-from=ui ui/leaderboard.ui -o ui/leaderboard_ui.py
# Custom widgets # Custom widgets
pyuic5 --import-from=ui ui/playerlist.ui -o ui/playerlist_ui.py pyuic5 --import-from=ui ui/playerlist.ui -o ui/playerlist_ui.py
pyuic5 --import-from=ui ui/delete_dialog.ui -o ui/delete_dialog_ui.py
pyrcc5 -root /ui ui/assets.qrc -o ui/assets_rc.py pyrcc5 -root /ui ui/assets.qrc -o ui/assets_rc.py
...@@ -9,6 +9,8 @@ Created on Wed Apr 18 18:34:40 2018 ...@@ -9,6 +9,8 @@ Created on Wed Apr 18 18:34:40 2018
import logging import logging
import sqlite3 import sqlite3
from settings import Settings
class DatabaseError(Exception): class DatabaseError(Exception):
pass pass
...@@ -50,15 +52,23 @@ class Database(): ...@@ -50,15 +52,23 @@ class Database():
if len(players)<2: if len(players)<2:
players.append(None) players.append(None)
logging.debug('DB Inserting {} to table Teams'.format((goals, players[0], players[1],)))
self._cursor.execute('INSERT INTO Teams (nGoals, player1, player2) VALUES (?, ?, ?)', (goals, players[0], players[1],)) self._cursor.execute('INSERT INTO Teams (nGoals, player1, player2) VALUES (?, ?, ?)', (goals, players[0], players[1],))
self._connection.commit() self._connection.commit()
return self._cursor.execute('SELECT seq FROM sqlite_sequence WHERE name="Teams"').fetchone()[0] return self._cursor.execute('SELECT seq FROM sqlite_sequence WHERE name="Teams"').fetchone()[0]
def insert_match(self, start_time, duration, team1, team2): def insert_match(self, start_time, duration, team1, team2):
logging.debug('DB Inserting {} to table Matchs'.format((start_time, duration, team1, team2,)))
self._cursor.execute('INSERT INTO Matchs (timestamp, duration, winningTeam, losingTeam) VALUES (?, ?, ?, ?)', (start_time, duration, team1, team2,)) self._cursor.execute('INSERT INTO Matchs (timestamp, duration, winningTeam, losingTeam) VALUES (?, ?, ?, ?)', (start_time, duration, team1, team2,))
self._connection.commit() self._connection.commit()
def select_all_rfid(self, debug=False):
if Settings['app.mode']=='prod':
return self._cursor.execute('SELECT rfid FROM Players WHERE rfid>0').fetchall()
else:
return self._cursor.execute('SELECT rfid FROM Players WHERE rfid<-1').fetchall()
def delete_player(self, playerID):
self._cursor.execute('DELETE FROM Players WHERE id==?', (playerID,))
self._connection.commit()
def close(self): def close(self):
self._connection.close() self._connection.close()
...@@ -21,8 +21,6 @@ from PyQt5.QtCore import QTime, Qt ...@@ -21,8 +21,6 @@ from PyQt5.QtCore import QTime, Qt
from ui.main_ui import Ui_MainWindow from ui.main_ui import Ui_MainWindow
from modules import * from modules import *
from player import Side from player import Side
from input import GPIOThread
from database import Database
class MainWin(QtWidgets.QMainWindow): class MainWin(QtWidgets.QMainWindow):
def __init__(self, parent=None): def __init__(self, parent=None):
...@@ -98,6 +96,8 @@ class MainWin(QtWidgets.QMainWindow): ...@@ -98,6 +96,8 @@ class MainWin(QtWidgets.QMainWindow):
if __name__=='__main__': if __name__=='__main__':
from settings import Settings from settings import Settings
from input import GPIOThread
from database import Database
from replay import Replay as ReplayThread from replay import Replay as ReplayThread
try: try:
......
...@@ -12,8 +12,6 @@ from PyQt5 import QtWidgets ...@@ -12,8 +12,6 @@ from PyQt5 import QtWidgets
from PyQt5.QtCore import QTime, QTimer, Qt from PyQt5.QtCore import QTime, QTimer, Qt
from PyQt5.QtWidgets import QTableWidgetItem, QComboBox, QApplication from PyQt5.QtWidgets import QTableWidgetItem, QComboBox, QApplication
from modules import *
class Module(QtWidgets.QWidget): class Module(QtWidgets.QWidget):
def __init__(self, parent, widget): def __init__(self, parent, widget):
# UI Setup # UI Setup
......
...@@ -9,18 +9,21 @@ Created on Wed Apr 18 18:34:40 2018 ...@@ -9,18 +9,21 @@ Created on Wed Apr 18 18:34:40 2018
import logging import logging
from operator import attrgetter from operator import attrgetter
from PyQt5 import QtWidgets from PyQt5.QtWidgets import QWidget, QDialog, QListWidgetItem
from PyQt5.QtCore import QTime, Qt, QSize, QItemSelectionModel from PyQt5.QtCore import QTime, Qt, QSize, QItemSelectionModel
from module import Module
import modules import modules
from player import PlayerGuest, Player from module import Module
from ui.leaderboard_ui import Ui_Form as LeaderboardWidget from player import Player, Side
from ui.playerlist_ui import Ui_Form as PlayerListWidget from database import Database
from ui.leaderboard_ui import Ui_Form as LeaderboardWidget
from ui.playerlist_ui import Ui_Form as PlayerListWidget
from ui.delete_dialog_ui import Ui_Dialog as PlayerDeleteDialog
class LeaderboardItemWidget(QtWidgets.QWidget): class LeaderboardItemWidget(QWidget):
def __init__(self, parent, player): def __init__(self, parent, player):
QtWidgets.QWidget.__init__(self, parent) QWidget.__init__(self, parent)
self.ui = PlayerListWidget() self.ui = PlayerListWidget()
self.ui.setupUi(self) self.ui.setupUi(self)
...@@ -35,6 +38,23 @@ class LeaderboardItemWidget(QtWidgets.QWidget): ...@@ -35,6 +38,23 @@ class LeaderboardItemWidget(QtWidgets.QWidget):
self.ui.pushButton.clicked.connect(lambda: logging.debug('clicked')) self.ui.pushButton.clicked.connect(lambda: logging.debug('clicked'))
class DeleteDialog(QDialog):
def __init__(self, parent, player):
print('DeleteDialog {}'.format(player.name))
QDialog.__init__(self, parent)
self.ui = PlayerDeleteDialog()
self.ui.setupUi(self)
self.player = player
self.ui.lblTitle.setText(self.ui.lblTitle.text().format(player.name))
def check(self, rfid):
return rfid == -self.player.id
# Debug
def keyPressEvent(self, e):
if e.key() == Qt.Key_Return:
self.parent().send(modules.LeaderboardModule, rfid=self.player.rfid, source=Side.Right)
class LeaderboardModule(Module): class LeaderboardModule(Module):
def __init__(self, parent): def __init__(self, parent):
super().__init__(parent, LeaderboardWidget()) super().__init__(parent, LeaderboardWidget())
...@@ -51,6 +71,7 @@ class LeaderboardModule(Module): ...@@ -51,6 +71,7 @@ class LeaderboardModule(Module):
self.sortMethodAttr = ['lname', 'stats_property.victories', 'stats_property.goals_scored', 'stats_property.games_played', 'stats_property.time_played'] self.sortMethodAttr = ['lname', 'stats_property.victories', 'stats_property.goals_scored', 'stats_property.games_played', 'stats_property.time_played']
self.sortMethodRB[self.selectedSort].setChecked(True) self.sortMethodRB[self.selectedSort].setChecked(True)
self.deleteDialog = None
def load(self): def load(self):
logging.debug('Loading LeaderboardModule') logging.debug('Loading LeaderboardModule')
...@@ -63,6 +84,18 @@ class LeaderboardModule(Module): ...@@ -63,6 +84,18 @@ class LeaderboardModule(Module):
def other(self, **kwargs): def other(self, **kwargs):
logging.debug('Other LeaderboardModule') logging.debug('Other LeaderboardModule')
for key, val in kwargs.items():
if key=='rfid' and self.deleteDialog and self.deleteDialog.check(val):
Database.instance().delete_player(self.deleteDialog.player.id)
# Reset the dialog and the player list
self.deleteDialog.close()
del self.deleteDialog
self.deleteDialog = None
self.players = []
self.ui.listWidget.clear()
self.loadList()
def changeSort(self, rbSort): def changeSort(self, rbSort):
self.selectedSort = self.sortMethodRB.index(rbSort) self.selectedSort = self.sortMethodRB.index(rbSort)
...@@ -72,12 +105,12 @@ class LeaderboardModule(Module): ...@@ -72,12 +105,12 @@ class LeaderboardModule(Module):
if self.players: if self.players:
self.ui.listWidget.clear() self.ui.listWidget.clear()
else: else:
self.players = [Player.fromRFID(id) for id in range(-2 , -7, -1)] self.players = Player.allPlayers()
self.players.sort(key=attrgetter(self.sortMethodAttr[self.selectedSort]), reverse=True) self.players.sort(key=attrgetter(self.sortMethodAttr[self.selectedSort]), reverse=True)
for player in self.players: for player in self.players:
item = QtWidgets.QListWidgetItem() item = QListWidgetItem()
playerWidget = LeaderboardItemWidget(self.ui.listWidget, player) playerWidget = LeaderboardItemWidget(self.ui.listWidget, player)
item.setSizeHint(playerWidget.size()) item.setSizeHint(playerWidget.size())
self.ui.listWidget.addItem(item) self.ui.listWidget.addItem(item)
...@@ -107,6 +140,10 @@ class LeaderboardModule(Module): ...@@ -107,6 +140,10 @@ class LeaderboardModule(Module):
elif e.key() == Qt.Key_Right: elif e.key() == Qt.Key_Right:
newSort = curSort+1 if curSort!=len(self.sortMethodRB)-1 else 0 newSort = curSort+1 if curSort!=len(self.sortMethodRB)-1 else 0
self.sortMethodRB[newSort].animateClick() self.sortMethodRB[newSort].animateClick()
elif e.key() == Qt.Key_Delete:
self.deleteDialog = DeleteDialog(self, self.players[curRow])
self.deleteDialog.open()
def handleExit(self): def handleExit(self):
self.switchModule(modules.MenuModule) self.switchModule(modules.MenuModule)
...@@ -10,7 +10,6 @@ import logging ...@@ -10,7 +10,6 @@ import logging
import sqlite3 import sqlite3
from enum import Enum from enum import Enum
from database import Database, DatabaseError
class Side(Enum): class Side(Enum):
''' '''
...@@ -24,6 +23,8 @@ class Side(Enum): ...@@ -24,6 +23,8 @@ class Side(Enum):
def opposite(self): def opposite(self):
return Side.Right if self==Side.Left else Side.Left return Side.Right if self==Side.Left else Side.Left
from database import Database, DatabaseError
class Player(): class Player():
__query_infos = 'SELECT id, fname, lname, pic FROM Players WHERE rfid==?' __query_infos = 'SELECT id, fname, lname, pic FROM Players WHERE rfid==?'
__query_time_goals_games = 'SELECT SUM(Matchs.duration) AS timePlayed, SUM(Teams.nGoals) AS goalsScored, COUNT(*) AS gamesPlayed FROM Teams INNER JOIN Matchs ON (Teams.id==Matchs.winningTeam OR Teams.id==Matchs.losingTeam) WHERE (Teams.player1==? OR player2==?)' __query_time_goals_games = 'SELECT SUM(Matchs.duration) AS timePlayed, SUM(Teams.nGoals) AS goalsScored, COUNT(*) AS gamesPlayed FROM Teams INNER JOIN Matchs ON (Teams.id==Matchs.winningTeam OR Teams.id==Matchs.losingTeam) WHERE (Teams.player1==? OR player2==?)'
...@@ -31,8 +32,9 @@ class Player(): ...@@ -31,8 +32,9 @@ class Player():
_placeholder_pic_path = ':ui/img/placeholder_head.jpg' _placeholder_pic_path = ':ui/img/placeholder_head.jpg'
def __init__(self, id, fname, lname, pic_path, stats): def __init__(self, id, rfid, fname, lname, pic_path, stats):
self.id = id self.id = id
self.rfid = rfid
self.fname = fname self.fname = fname
self.lname = lname self.lname = lname
self.pic_path = pic_path if pic_path else Player._placeholder_pic_path # Default pic if None self.pic_path = pic_path if pic_path else Player._placeholder_pic_path # Default pic if None
...@@ -51,7 +53,11 @@ class Player(): ...@@ -51,7 +53,11 @@ class Player():
stats['time_played'], stats['goals_scored'], stats['games_played'] = db.select_one(Player.__query_time_goals_games, id, id) stats['time_played'], stats['goals_scored'], stats['games_played'] = db.select_one(Player.__query_time_goals_games, id, id)
stats['victories'], = db.select_one(Player.__query_victories, id) stats['victories'], = db.select_one(Player.__query_victories, id)
return Player(id, fname, lname, pic, stats) for key, val in stats.items():
if val==None:
stats[key] = 0
return Player(id, rfid, fname, lname, pic, stats)
except DatabaseError as e: except DatabaseError as e:
logging.warn('DB Error: {}'.format(e)) logging.warn('DB Error: {}'.format(e))
...@@ -71,6 +77,11 @@ class Player(): ...@@ -71,6 +77,11 @@ class Player():
@property @property
def stats_property(self): def stats_property(self):
'''
Compatibility property allowing to access stats as a object member and not dict
ex: player.stats['victories'] can be accessed with player.stats_property.victories'
This is mostly used for sorting players in leaderboard.py
'''
class Stat: class Stat:
def __init__(self, stats): def __init__(self, stats):
self.victories = stats['victories'] self.victories = stats['victories']
...@@ -79,6 +90,10 @@ class Player(): ...@@ -79,6 +90,10 @@ class Player():
self.games_played = stats['games_played'] self.games_played = stats['games_played']
return Stat(self.stats) return Stat(self.stats)
@staticmethod
def allPlayers():
return [Player.fromRFID(rfid) for rfid, in Database.instance().select_all_rfid()]
PlayerGuest = Player.fromRFID(-1) PlayerGuest = Player.fromRFID(-1)
PlayerEmpty = Player(-1, '', '', Player._placeholder_pic_path, {'time_played':'', 'goals_scored':'', 'games_played':'', 'victories': ''}) PlayerEmpty = Player(-1, -42, '', '', Player._placeholder_pic_path, {'time_played':'', 'goals_scored':'', 'games_played':'', 'victories': ''})
...@@ -7,7 +7,6 @@ Created on Wed Apr 18 18:34:40 2018 ...@@ -7,7 +7,6 @@ Created on Wed Apr 18 18:34:40 2018
""" """
import json import json
import main
class MyEncoder(json.JSONEncoder): class MyEncoder(json.JSONEncoder):
def default(self, obj): def default(self, obj):
...@@ -120,4 +119,5 @@ class SettingsHolder(object): ...@@ -120,4 +119,5 @@ class SettingsHolder(object):
self.settingsPath = settingsPath self.settingsPath = settingsPath
import main
Settings = SettingsHolder(main.MainWin.getContent('settings.json')) Settings = SettingsHolder(main.MainWin.getContent('settings.json'))
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Dialog</class>
<widget class="QDialog" name="Dialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>720</width>
<height>405</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="lblTitle">
<property name="font">
<font>
<pointsize>25</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Deleting {}'s profile</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="lblMsg">
<property name="font">
<font>
<pointsize>20</pointsize>
</font>
</property>
<property name="text">
<string>Pass your badge to validate this...</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
...@@ -299,7 +299,7 @@ QRadioButton::indicator { ...@@ -299,7 +299,7 @@ QRadioButton::indicator {
<bool>true</bool> <bool>true</bool>
</property> </property>
<property name="title"> <property name="title">
<string>Number of players per side</string> <string>League - Number of players per side</string>
</property> </property>
<property name="alignment"> <property name="alignment">
<set>Qt::AlignCenter</set> <set>Qt::AlignCenter</set>
......
...@@ -68,7 +68,7 @@ ...@@ -68,7 +68,7 @@
<item> <item>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<item> <item>
<widget class="QLabel" name="lblFName"> <widget class="QLabel" name="lblLName">
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>200</width> <width>200</width>
...@@ -94,7 +94,7 @@ ...@@ -94,7 +94,7 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QLabel" name="lblLName"> <widget class="QLabel" name="lblFName">
<property name="maximumSize"> <property name="maximumSize">
<size> <size>
<width>200</width> <width>200</width>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment