player.py 6.04 KB
Newer Older
1 2 3 4 5 6 7 8
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
@author: Antoine Lima, Leo Reynaert, Domitille Jehenne
"""

import logging
from enum import Enum
Antoine Lima's avatar
Antoine Lima committed
9
from http import HTTPStatus
Antoine Lima's avatar
Antoine Lima committed
10

11 12 13
from PyQt5.QtCore import Qt, QCoreApplication, QObject, pyqtSlot, QEvent
from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import QDialog, QApplication
Antoine Lima's avatar
Antoine Lima committed
14

15
from Babyfut.babyfut import getMainWin, IMG_PATH
Antoine Lima's avatar
Antoine Lima committed
16
from Babyfut.core.ginger import Ginger
17 18
from Babyfut.core.database import Database, DatabaseError
from Babyfut.ui.consent_dialog_ui import Ui_Dialog as ConsentDialogUI
19 20

class Side(Enum):
21 22 23 24 25 26
	'''
	Values of the enum are used throughout the code for indexing purposes, not to be changed
	'''
	Undef = -1
	Left  = 0
	Right = 1
27

Antoine Lima's avatar
Antoine Lima committed
28 29
	@property
	def opposite(self):
30
		return Side.Right if self==Side.Left else Side.Left
31

Antoine Lima's avatar
Antoine Lima committed
32 33 34 35 36
class ConsentDialog(QDialog):
	def __init__(self, parent):
		QDialog.__init__(self, parent)
		self.ui = ConsentDialogUI()
		self.ui.setupUi(self)
37

Antoine Lima's avatar
Antoine Lima committed
38 39 40 41 42 43 44
		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>
45
			</p>
46

Antoine Lima's avatar
Antoine Lima committed
47 48 49 50 51
			<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>'''))
52

Antoine Lima's avatar
Antoine Lima committed
53 54 55 56 57
	def keyPressEvent(self, e):
		if e.key()==Qt.Key_Return:
			self.accept()
		else:
			self.reject()
58

59
class Player(QObject):
60
	__query_infos = 'SELECT id, login, fname, lname FROM Players WHERE rfid==?'
Antoine Lima's avatar
Antoine Lima committed
61 62 63 64
	__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_victories = 'SELECT COUNT(*) AS victories FROM Players INNER JOIN Teams ON (Players.id==Teams.player1 OR Players.id==Teams.player2) INNER JOIN  Matchs ON (Teams.id==Matchs.winningTeam) WHERE Players.id==?'

	_placeholder_pic_path = ':ui/img/placeholder_head.jpg'
65

66 67
	def __init__(self, id, rfid, login, fname, lname, stats=None):
		QObject.__init__(self)
68
		self.id = id
69
		self.rfid = rfid
70
		self.login = login
71 72
		self.fname = fname
		self.lname = lname
73 74 75 76

		self.pic_path = Player._placeholder_pic_path
		if self.login:
			self.pic_path = Player._utcPictureURL.format(self.login)
Antoine Lima's avatar
Antoine Lima committed
77 78 79 80 81

		if stats==None:
			self.stats = { 'time_played': 0, 'goals_scored': 0, 'games_played': 0, 'victories': 0 }
		else:
			self.stats = stats
82

83
	@staticmethod
Antoine Lima's avatar
Antoine Lima committed
84
	def fromRFID(rfid):
Antoine Lima's avatar
Antoine Lima committed
85 86
		if Database.instance().rfid_exists(rfid):
			player = Player._loadFromDB(rfid)
Antoine Lima's avatar
Antoine Lima committed
87 88 89 90 91
		else:
			### Retrieve player from API
			# Ask for consent
			consentDialog = ConsentDialog(getMainWin())
			consentDialog.exec()
92

Antoine Lima's avatar
Antoine Lima committed
93
			if consentDialog.result()==QDialog.Accepted:
Antoine Lima's avatar
Antoine Lima committed
94
				player = Player._loadFromAPI(rfid)
Antoine Lima's avatar
Antoine Lima committed
95
			else:
96
				logging.info('Consent refused when retrieving a player, returning Guest')
Antoine Lima's avatar
Antoine Lima committed
97 98 99
				player = PlayerGuest

		return player
100 101

	def displayImg(self, container_widget):
Antoine Lima's avatar
Antoine Lima committed
102 103 104 105 106
	@staticmethod
	def _loadFromDB(rfid):
		db = Database.instance()
		try:
			# Retrieve generic informations
107
			id, login, fname, lname = db.select_one(Player.__query_infos, rfid)
Antoine Lima's avatar
Antoine Lima committed
108 109 110 111 112 113 114 115 116 117

			# Retrieve stats
			stats = {}
			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)

			for key, val in stats.items():
				if val==None:
					stats[key] = 0

118
			return Player(id, rfid, login, fname, lname, stats)
Antoine Lima's avatar
Antoine Lima committed
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134

		except DatabaseError as e:
			logging.warn('DB Error: {}'.format(e))
			return PlayerGuest

	@staticmethod
	def _loadFromAPI(rfid):
		'''
		Retrieves a player's informations from the Ginger API
		'''
		response = Ginger.call('badge/{}'.format(rfid))
		if isinstance(response, HTTPStatus):
			logging.debug('Request to Ginger failed ({}): returning Guest'.format(response.value))
			return PlayerGuest
		else:
			infos = json.loads(response)
135
			Database.instance().insert_player(infos['rfid'], infos['login'], infos['nom'], infos['prenom'])
Antoine Lima's avatar
Antoine Lima committed
136 137 138

		return Player._loadFromDB(rfid)

139 140 141 142
		self.pic_container = container_widget

		if self.pic_path.startswith('http'):
			# Download from the internet
143 144 145
			self.pic_container.setStyleSheet('border-image: url({});'.format(Player._placeholder_pic_path))
			Downloader.instance().request(self.pic_path, os.path.join(IMG_PATH, '{}.jpg'.format(self.id)))
			Downloader.instance().finished.connect(self._downloader_callback)
146 147
		else:
			# Already downloaded and stored locally
148 149 150 151 152 153 154 155 156
			self.pic_container.setStyleSheet('border-image: url({});'.format(self.pic_path))
			self._forceWidgetUpdate()
			QApplication.processEvents()

	@pyqtSlot(str)
	def _downloader_callback(self, path):
		self.pic_path = path
		Downloader.instance().finished.disconnect(self._downloader_callback)
		self.displayImg(self.pic_container)
157

Antoine Lima's avatar
Antoine Lima committed
158
	def forgetPicture(self):
Antoine Lima's avatar
Antoine Lima committed
159
		self.pic_path = Player._placeholder_pic_path
160
		self.login = None
Antoine Lima's avatar
Antoine Lima committed
161 162
		Database.instance().delete_playerpic(self.id)

Antoine Lima's avatar
Antoine Lima committed
163
	def make_private(self):
Antoine Lima's avatar
Antoine Lima committed
164 165 166
		self.private = True
		Database.instance().make_player_private(self.id)

167 168
	@property
	def name(self):
169
		return '{} {}'.format(self.fname, self.lname.upper())
170

171
	@property
Antoine Lima's avatar
Antoine Lima committed
172
	def stats_property(self):
173 174 175 176 177
		'''
		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
		'''
Antoine Lima's avatar
Antoine Lima committed
178 179 180 181 182 183
		class Stat:
			def __init__(self, stats):
				self.victories = stats['victories']
				self.time_played = stats['time_played']
				self.goals_scored = stats['goals_scored']
				self.games_played = stats['games_played']
184

Antoine Lima's avatar
Antoine Lima committed
185
		return Stat(self.stats)
186

187
	@staticmethod
Antoine Lima's avatar
Antoine Lima committed
188
	def allStoredPlayers():
189
		return [Player.fromRFID(rfid) for rfid, in Database.instance().select_all_rfid()]
190

191
PlayerGuest = Player.fromRFID(-1)
192
PlayerEmpty = Player(-1, -42, '', '', Player._placeholder_pic_path, {'time_played':'', 'goals_scored':'', 'games_played':'', 'victories': ''})