Commit fd0e6b96 authored by Antoine Lima's avatar Antoine Lima

Consent module and dialogs

parent bcea9eda
......@@ -12,11 +12,21 @@ import logging
from os.path import dirname, abspath, join
from PyQt5 import QtWidgets, QtCore
from PyQt5.QtWidgets import QMainWindow, QApplication
def getContent(path):
contentFolder = join(dirname(dirname(abspath(__file__))), 'content')
return join(contentFolder, path)
def getMainWin():
from ui.mainwin import MainWin
# Global function to find the (open) QMainWindow in application
for widget in QApplication.instance().topLevelWidgets():
if isinstance(widget, QMainWindow):
return widget
return None
if __name__=='__main__':
from ui.mainwin import MainWin
from modules import GameModule
......
......@@ -17,10 +17,12 @@ case "$1" in
pyuic5 --import-from=ui ui/authquick.ui -o ui/authquick_ui.py
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/privacy.ui -o ui/privacy_ui.py
echo " Custom Widgets"
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
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
pyuic5 --import-from=ui ui/consent_dialog.ui -o ui/consent_dialog_ui.py
echo " Resources"
pyrcc5 -root /ui ui/assets.qrc -o ui/assets_rc.py
......
......@@ -5,3 +5,4 @@ from modules.endgame import EndGameModule
from modules.menu import MenuModule
from modules.options import OptionsModule
from modules.leaderboard import LeaderboardModule
from modules.privacy import PrivacyModule
......@@ -6,6 +6,8 @@
import logging
from PyQt5.QtCore import QCoreApplication
from PyQt5.QtWidgets import QAbstractItemView
from modules.auth import AuthModuleBase
from ui.authleague_ui import Ui_Form as AuthLeagueWidget
......@@ -37,7 +39,7 @@ class AuthLeagueModule(AuthModuleBase):
self.players = {Side.Left: l, Side.Right: l}
def addPlayer(self, side, player):
_translate = QtCore.QCoreApplication.translate
_translate = QCoreApplication.translate
# Add the player if not already in the list
if all([p.id!=player.id for p in self.players[side]]):
......
......@@ -5,6 +5,7 @@
"""
import logging
from enum import Enum
from operator import attrgetter
from PyQt5.QtWidgets import QWidget, QDialog, QListWidgetItem
......@@ -37,6 +38,11 @@ class LeaderboardItemWidget(QWidget):
self.ui.pushButton.clicked.connect(lambda: logging.debug('clicked'))
class DeleteDialog(QDialog):
class Actions(Enum):
DeleteAll = 0
DeletePicture = 1
HideAccount = 2
def __init__(self, parent, player):
QDialog.__init__(self, parent)
self.ui = PlayerDeleteDialog()
......@@ -47,11 +53,25 @@ class DeleteDialog(QDialog):
def check(self, rfid):
return rfid == -self.player.id
# Debug
def action(self):
dict_actions = {
self.ui.rbDeleteAll: DeleteDialog.Actions.DeleteAll,
self.ui.rbDeletePicture: DeleteDialog.Actions.DeletePicture,
self.ui.rbHideAccount: DeleteDialog.Actions.HideAccount
}
for key, val in dict_actions.items():
if key.isChecked():
return val
return None
def keyPressEvent(self, e):
if e.key() == Qt.Key_Return:
# Debug
self.parent().send(modules.LeaderboardModule, rfid=self.player.rfid, source=Side.Right)
elif e.key() == Qt.Key_Escape:
self.reject()
class LeaderboardModule(Module):
def __init__(self, parent):
super().__init__(parent, LeaderboardWidget())
......@@ -84,7 +104,16 @@ class LeaderboardModule(Module):
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)
# Do something corresponding to the selected action
action = self.deleteDialog.action()
if action==DeleteDialog.Actions.DeleteAll:
Database.instance().delete_player(self.deleteDialog.player.id)
elif action==DeleteDialog.Actions.DeletePicture:
logging.error('Unimplemented action: delete picture')
elif action==DeleteDialog.Actions.HideAccount:
logging.error('Unimplemented action: Hide account')
else:
logging.error('Unknown action {}'.format(action))
# Reset the dialog and the player list
self.deleteDialog.close()
......@@ -102,7 +131,7 @@ class LeaderboardModule(Module):
if self.players:
self.ui.listWidget.clear()
else:
self.players = Player.allPlayers()
self.players = Player.allStoredPlayers()
self.players.sort(key=attrgetter(self.sortMethodAttr[self.selectedSort]), reverse=(self.sortMethodAttr[self.selectedSort]!='lname'))
......
......@@ -24,6 +24,7 @@ class MenuModule(Module):
self.ui.btnStartLeague.clicked.connect(lambda: self.switchModule(modules.AuthLeagueModule))
self.ui.btnLeaderboard.clicked.connect(lambda: self.switchModule(modules.LeaderboardModule))
self.ui.btnOptions.clicked.connect (lambda: self.switchModule(modules.OptionsModule))
self.ui.btnPrivacy.clicked.connect (lambda: self.switchModule(modules.PrivacyModule))
def load(self):
logging.debug('Loading MenuModule')
......
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
@author: Antoine Lima, Leo Reynaert, Domitille Jehenne
"""
import logging
from PyQt5.QtCore import Qt, QCoreApplication
from module import Module
import modules
from ui.privacy_ui import Ui_Form as PrivacyWidget
class PrivacyModule(Module):
def __init__(self, parent):
super().__init__(parent, PrivacyWidget())
self.ui.txtPrivacy.setHtml(QCoreApplication.translate('consent', '''<p>
This software uses personnal information in accordance to GDPR, such as:
<ul>
<li>Your Name and Surname</li>
<li>Your Picture (if public)</li>
<li>...</li>
</ul>
</p>
<p>
That way players can keep track of their score and compare it with others.
<br/>
yada yada
</p>'''))
def load(self):
logging.debug('Loading PrivacyModule')
def unload(self):
logging.debug('Unloading PrivacyModule')
def other(self, **kwargs):
logging.debug('Other PrivacyModule')
def keyPressEvent(self, e):
if e.key() == Qt.Key_Escape:
self.handleBack()
super().keyPressEvent(e)
def handleBack(self):
self.switchModule(modules.MenuModule)
......@@ -7,8 +7,13 @@ Created on Wed Apr 18 18:34:40 2018
"""
import logging
from enum import Enum
from database import Database, DatabaseError
from PyQt5.QtCore import Qt, QCoreApplication
from PyQt5.QtWidgets import QDialog
from ui.consent_dialog_ui import Ui_Dialog as ConsentDialogUI
class Side(Enum):
'''
......@@ -22,8 +27,33 @@ class Side(Enum):
def opposite(self):
return Side.Right if self==Side.Left else Side.Left
from database import Database, DatabaseError
class ConsentDialog(QDialog):
def __init__(self, parent):
QDialog.__init__(self, parent)
self.ui = ConsentDialogUI()
self.ui.setupUi(self)
self.ui.txtConsent.setHtml(QCoreApplication.translate('consent', '''<p>
You are about to connect yourself for the first time. We will need to access:
<ul>
<li>Your Name and Surname</li>
<li>Your Picture (if public)</li>
<li>...</li>
</ul>
</p>
<p>
It is possible to play withtout connecting yourslef, but this will allow you to keep track of your score and to provide a better experience for you and the ones you play with!
<br/><br/>
Do you agree with this?
</p>'''))
def keyPressEvent(self, e):
if e.key()==Qt.Key_Return:
self.accept()
else:
self.reject()
class Player():
__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==?)'
......@@ -31,6 +61,8 @@ class Player():
_placeholder_pic_path = ':ui/img/placeholder_head.jpg'
_first_time = True # Debug
def __init__(self, id, rfid, fname, lname, pic_path, stats):
self.id = id
self.rfid = rfid
......@@ -47,6 +79,16 @@ class Player():
# Retrieve generic informations
id, fname, lname, pic = db.select_one(Player.__query_infos, rfid)
# Ask for consent
if rfid==-2 and Player._first_time:
import babyfut
consentDialog = ConsentDialog(babyfut.getMainWin())
consentDialog.exec()
if not consentDialog.result()==QDialog.Accepted:
Player._first_time = False
return PlayerGuest
# Retrieve stats
stats = {}
stats['time_played'], stats['goals_scored'], stats['games_played'] = db.select_one(Player.__query_time_goals_games, id, id)
......@@ -91,7 +133,7 @@ class Player():
return Stat(self.stats)
@staticmethod
def allPlayers():
def allStoredPlayers():
return [Player.fromRFID(rfid) for rfid, in Database.instance().select_all_rfid()]
PlayerGuest = Player.fromRFID(-1)
......
......@@ -3,25 +3,55 @@
<context>
<name>Dialog</name>
<message>
<location filename="../ui/delete_dialog_ui.py" line="47"/>
<location filename="../ui/delete_dialog_ui.py" line="70"/>
<source>Dialog</source>
<translation>Supression</translation>
</message>
<message>
<location filename="../ui/delete_dialog_ui.py" line="48"/>
<source>Deleting {}&apos;s profile</source>
<translation>Supression du profil de {}</translation>
<translation type="obsolete">Supression du profil de {}</translation>
</message>
<message>
<location filename="../ui/delete_dialog_ui.py" line="49"/>
<source>Pass your badge to validate this...</source>
<translation>Passez votre badge pour valider la supression...</translation>
<translation type="obsolete">Passez votre badge pour valider la supression...</translation>
</message>
<message>
<location filename="../ui/consent_dialog_ui.py" line="39"/>
<source>Consent Approval Needed</source>
<translation>Validation de Consentement</translation>
</message>
<message>
<location filename="../ui/delete_dialog_ui.py" line="71"/>
<source>Changing {}&apos;s profile</source>
<translation>Modification du profile de {}</translation>
</message>
<message>
<location filename="../ui/delete_dialog_ui.py" line="72"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;center&quot;&gt;Select an option&lt;br/&gt;then validate by passing your badge on the table&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;center&quot;&gt;Choisissez une option&lt;br/&gt;et validez en passant votre carte sur la table&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../ui/delete_dialog_ui.py" line="73"/>
<source>Delete all records</source>
<translation>Supprimer toutes les données</translation>
</message>
<message>
<location filename="../ui/delete_dialog_ui.py" line="74"/>
<source>Remove the Picture</source>
<translation>Suprrimer la photo</translation>
</message>
<message>
<location filename="../ui/delete_dialog_ui.py" line="75"/>
<source>Make the accout private</source>
<translation>Rendre privé</translation>
</message>
</context>
<context>
<name>Form</name>
<message>
<location filename="../ui/playerlist_ui.py" line="94"/>
<location filename="../ui/privacy_ui.py" line="52"/>
<source>Form</source>
<translation>Form</translation>
</message>
......@@ -81,7 +111,7 @@
<translation>0</translation>
</message>
<message>
<location filename="../ui/menu_ui.py" line="122"/>
<location filename="../ui/menu_ui.py" line="137"/>
<source>Leaderboard</source>
<translation>Classements</translation>
</message>
......@@ -116,17 +146,17 @@
<translation>Sauter à</translation>
</message>
<message>
<location filename="../ui/menu_ui.py" line="119"/>
<location filename="../ui/menu_ui.py" line="134"/>
<source>Babyf&apos; UT</source>
<translation>Babyf&apos;UT</translation>
</message>
<message>
<location filename="../ui/menu_ui.py" line="120"/>
<location filename="../ui/menu_ui.py" line="135"/>
<source>Start Quick Game</source>
<translation>Partie Rapide</translation>
</message>
<message>
<location filename="../ui/menu_ui.py" line="121"/>
<location filename="../ui/menu_ui.py" line="136"/>
<source>Start League Mode</source>
<translation>Championnat</translation>
</message>
......@@ -210,6 +240,11 @@
<source>#### Minutes Played</source>
<translation>#### Minutes Jouées</translation>
</message>
<message>
<location filename="../ui/privacy_ui.py" line="53"/>
<source>Privacy</source>
<translation>Vie Privée</translation>
</message>
<message encoding="UTF-8">
<location filename="../ui/options_ui.py" line="229"/>
<source>Français</source>
......@@ -239,4 +274,43 @@
<translation>Babyf&apos;UT</translation>
</message>
</context>
<context>
<name>consent</name>
<message>
<location filename="../player.py" line="36"/>
<source>&lt;p&gt;
<byte value="x9"/><byte value="x9"/><byte value="x9"/>You are about to connect yourself for the first time. We will need to access:
<byte value="x9"/><byte value="x9"/><byte value="x9"/>&lt;ul&gt;
<byte value="x9"/><byte value="x9"/><byte value="x9"/><byte value="x9"/>&lt;li&gt;Your Name and Surname&lt;/li&gt;
<byte value="x9"/><byte value="x9"/><byte value="x9"/><byte value="x9"/>&lt;li&gt;Your Picture (if public)&lt;/li&gt;
<byte value="x9"/><byte value="x9"/><byte value="x9"/><byte value="x9"/>&lt;li&gt;...&lt;/li&gt;
<byte value="x9"/><byte value="x9"/><byte value="x9"/>&lt;/ul&gt;
<byte value="x9"/><byte value="x9"/><byte value="x9"/>&lt;/p&gt;
<byte value="x9"/><byte value="x9"/><byte value="x9"/>&lt;p&gt;
<byte value="x9"/><byte value="x9"/><byte value="x9"/>It is possible to play withtout connecting yourslef, but this will allow you to keep track of your score and to provide a better experience for you and the ones you play with!
<byte value="x9"/><byte value="x9"/><byte value="x9"/>&lt;br/&gt;&lt;br/&gt;
<byte value="x9"/><byte value="x9"/><byte value="x9"/>Do you agree with this?
<byte value="x9"/><byte value="x9"/><byte value="x9"/>&lt;/p&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../modules/privacy.py" line="18"/>
<source>&lt;p&gt;
<byte value="x9"/><byte value="x9"/>This software uses personnal information in accordance to GDPR, such as:
<byte value="x9"/><byte value="x9"/>&lt;ul&gt;
<byte value="x9"/><byte value="x9"/><byte value="x9"/>&lt;li&gt;Your Name and Surname&lt;/li&gt;
<byte value="x9"/><byte value="x9"/><byte value="x9"/>&lt;li&gt;Your Picture (if public)&lt;/li&gt;
<byte value="x9"/><byte value="x9"/><byte value="x9"/>&lt;li&gt;...&lt;/li&gt;
<byte value="x9"/><byte value="x9"/>&lt;/ul&gt;
<byte value="x9"/><byte value="x9"/>&lt;/p&gt;
<byte value="x9"/><byte value="x9"/>&lt;p&gt;
<byte value="x9"/><byte value="x9"/>That way players can keep track of their score and compare it with others.
<byte value="x9"/><byte value="x9"/>&lt;br/&gt;
<byte value="x9"/><byte value="x9"/>yada yada
<byte value="x9"/><byte value="x9"/>&lt;/p&gt;</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>
<?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>
<widget class="QLabel" name="lblTitle">
<property name="font">
<font>
<pointsize>22</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Consent Approval Needed</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="sizeType">
<enum>QSizePolicy::Preferred</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QTextEdit" name="txtConsent">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
......@@ -6,27 +6,17 @@
<rect>
<x>0</x>
<y>0</y>
<width>720</width>
<height>405</height>
<width>800</width>
<height>433</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(52, 53, 77)</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">
......@@ -37,7 +27,7 @@
</font>
</property>
<property name="text">
<string>Deleting {}'s profile</string>
<string>Changing {}'s profile</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
......@@ -45,14 +35,17 @@
</widget>
</item>
<item>
<spacer name="verticalSpacer_3">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Preferred</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
<height>20</height>
</size>
</property>
</spacer>
......@@ -65,7 +58,7 @@
</font>
</property>
<property name="text">
<string>Pass your badge to validate this...</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;center&quot;&gt;Select an option&lt;br/&gt;then validate by passing your badge on the table&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
......@@ -85,6 +78,49 @@
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QRadioButton" name="rbDeleteAll">
<property name="font">
<font>
<pointsize>16</pointsize>
</font>
</property>
<property name="text">
<string>Delete all records</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="rbDeletePicture">
<property name="font">
<font>
<pointsize>16</pointsize>
</font>
</property>
<property name="text">
<string>Remove the Picture</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="rbHideAccount">
<property name="font">
<font>
<pointsize>16</pointsize>
</font>
</property>
<property name="text">
<string>Make the accout private</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_4">
<property name="orientation">
......@@ -100,6 +136,11 @@
</item>
</layout>
</widget>
<tabstops>
<tabstop>rbDeleteAll</tabstop>
<tabstop>rbDeletePicture</tabstop>
<tabstop>rbHideAccount</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>
......@@ -34,7 +34,8 @@ class MainWin(QtWidgets.QMainWindow):
modules.GameModule(self),
modules.EndGameModule(self),
modules.LeaderboardModule(self),
modules.OptionsModule(self)
modules.OptionsModule(self),
modules.PrivacyModule(self)
]
for mod in self.modules:
......@@ -79,4 +80,4 @@ class MainWin(QtWidgets.QMainWindow):
QApplication.setOverrideCursor(Qt.BlankCursor);
else:
self.showNormal()
QApplication.setOverrideCursor(Qt.ArrowCursor);
\ No newline at end of file
QApplication.setOverrideCursor(Qt.ArrowCursor);
......@@ -294,6 +294,49 @@
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="btnPrivacy">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Privacy</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
......
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Form</class>
<widget class="QWidget" name="Form">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1280</width>
<height>720</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<property name="styleSheet">
<string notr="true">QRadioButton {
border: 2px solid rgb(74, 74, 107);
border-radius: 10px;
border-color: rgb(74, 74, 107);
}
QRadioButton::checked {
background-color: rgba(44, 44, 63, 240);
}
QRadioButton::indicator {
background-color: transparent;
border: 0px solid transparent;
}</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>15</number>
</property>
<property name="topMargin">
<number>15</number>
</property>
<property name="rightMargin">
<number>15</number>
</property>
<property name="bottomMargin">
<number>9</number>
</property>
<item>
<widget class="QLabel" name="label">