def slack(data, account_id): return { 'status': 'failed', 'result': 'This method of slack notification is depreciated.' } db = database.builder('foosbot') account = db.table('accounts').where('id', account_id).first() url = account['slack_url'] if not url: return { 'status': 'failed', 'result': 'Slack not configured for this account' } message = data['message'] data = {'text': message} # url = 'https://hooks.slack.com/services/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' #ping slack response = requests.post(url, json=data) if response.status_code == 200: return {'status': 'success'} else: return {'status': 'failed', 'result': response.content}
def end_match(match_id, winner, loser, streak, points): db = database.builder("foosbot") slack_record = db.table("slack_records").where("match", match_id).first() if not slack_record: print('no slack record for match', match_id) return False slack_connection = db.table('slack_connections').where( 'id', slack_record['slack_connection']).first() if not slack_connection: print('no slack connection for match', match_id, 'connection', slack_record['slack_connection']) return False #In case they remove the connection mid match, don't throw an error. win_message = winner['fname'] + " was Victorious! (+" + str( points) + " points)" if streak > 1: win_message += " - That's " + str(streak) + " in a row!" data = json.loads(slack_record["data"]) data['ts'] = slack_record['timestamp'] data["attachments"] = json.dumps([ { "text": win_message, "color": "good" }, ]) # {"text": "Match Complete!", "color": "good"}, print('updating slack', data) r = Slack.updateMessage(slack_connection, data)
def get_table_leaderboard(data, account_id): db = database.builder('foosbot') users = db.table('users').select( 'id', 'fname', 'lname', 'elo', 'photo').where('account_id', account_id).where_null('deleted_at').order_by( 'elo', 'desc').limit(100).get() data = [] for i, user in enumerate(users): #only show players who have played a game has_games = db.table('matches').where('player1', user['id']).or_where( 'player2', user['id']).exists() if not has_games: continue #add rank user['rank'] = len(data) + 1 user['elo'] = int(round(user['elo'])) if user['elo'] else 0 data.append(user) #Limit 20 results if len(data) >= 10: break #also get matches matches = list(get_match_history(account_id)) return { 'status': 'success', 'leaderboard_data': data, 'match_history': matches }
def ping(self, request): client_data = [] for key in request.META: #We don't need all meta-data, just some more interesting peices that may be useful in the future. if 'HTTP' in key and key in ['HTTP_HOST', 'HTTP_USER_AGENT', 'HTTP_REFERER', 'HTTP_COOKIE']: client_data.append({key: request.META[key]}) # print(client_data) #insert ping row with time, account_id, and ping data. db = database.builder('foosbot') insert_data = {} insert_data['account_id'] = self.account_id insert_data['reader_id'] = request.session['reader_id'] insert_data['ip'] = self.get_client_ip(request) insert_data['created_at'] = str(datetime.now()) insert_data['meta_data'] = str(client_data) db.table('ping').insert(insert_data) # sending the following will force a page reload. needs_reload = db.table('accounts').where('id', self.account_id).where('refresh_reader', 1).exists() if needs_reload: db.table('accounts').where('id', self.account_id).update({'refresh_reader': 0}) return {'status':'success', 'result':'reload'} return {'status':'success'}
def leaderboard(request, account_id): if not request.user.is_authenticated or request.user.account != account_id: raise PermissionDenied db = database.builder('foosbot') account = db.table('accounts').where('id', account_id).first() if not account: return HttpResponseNotFound() #redirect to the token based leaderboard to keep render logic in one place return redirect(leaderboard_token, token=account['token'])
def get_leaderboard(account_id): db = database.builder('foosbot') players = db.table('users').where( 'users.account_id', account_id).where_null('deleted_at').order_by('elo', 'desc').get() # players = db.table('users').left_join('player_stats', 'users.id','=', 'player_stats.player_id')\ # .select('users.id', 'users.fname', 'users.elo', 'player_stats.matches', 'users.photo')\ # .where('users.account_id', account_id).where_null('deleted_at').order_by(db.raw('(matches > 0) desc, elo'), 'desc').get()#).order_by('elo', 'desc').get() return players
def remove(data, account_id, reader_id): db = database.builder('foosbot') #are there any floating matches that need clearing? matches = db.table('matches').where('account_id', account_id).where('reader_id', reader_id).where('status', 'in_progress').get() for match in matches: db.table('matches').where('id', match['id']).update({'status':'failed', 'updated_at': str(datetime.now())}) #also update any slack messages. Slack.clear_match(match)
def post_message(slack_connection, data): db = database.builder('foosbot') data['token'] = slack_connection['token'] data['channel'] = slack_connection['channel_id'] url = "https://slack.com/api/chat.postMessage" r = Slack.call(url, data) return json.loads(r.content)
def remove_slack(request, account_id): if not request.user.is_authenticated or request.user.account != account_id: raise PermissionDenied db = database.builder('foosbot') db.table('accounts').where('id', account_id).update({ 'slack_url': None, 'slack_config_url': None, 'slack_channel': None }) db.table('slack_connections').where('account_id', account_id).delete() return HttpResponse(dumps({'status': 'success'}))
def create_player(player): #We need to specify starting ELO before insertion. db = database.builder('foosbot') #set initial elo # player['elo'] = set_starting_elo(player) player['elo'] = None #strip RFID in case there are spaces player['rfid'] = str(player['rfid']).strip() #save db.table('users').insert(player)
def get_real_elo_change(elo_change, account_id): if elo_change < 5: return [elo_change, elo_change] db = database.builder('foosbot') elo_average = db.table('users').where( 'account_id', account_id).where_null('deleted_at').select( db.raw('avg(elo) as average_elo')).first()['average_elo'] print('elo average', elo_average) if elo_average > 1525: return [elo_change - 1, elo_change + 1] #win less, lose more if elo_average < 1475: return [elo_change + 1, elo_change - 1] #win more, lose less return [elo_change, elo_change]
def get_details(account_id, player_id): db = database.builder('foosbot') player = db.table('users').where('account_id', account_id).where('id', player_id).first() matches = db.table('matches').where( db.query().where('player1', player['id']).or_where('player2', player['id']) )\ .where('status', 'complete')\ .select('player1', 'player2', 'winner', 'points', 'created_at')\ .order_by('created_at', 'desc').get() #add names for displaying PName = PlayerName() longest_streak = 0 streak = 0 won = 0 for match in matches: player2 = match.player1 if match.player1 != player[ 'id'] else match.player2 if match['winner'] == player['id']: match['winner_name'] = player['fname'] match['loser_name'] = PName.getName(player2) won += 1 streak += 1 else: match['winner_name'] = PName.getName(player2) match['loser_name'] = player['fname'] streak = 0 match['points'] = int(match['points']) match['created_at'] = parser.parse(str(match['created_at'])[:11]) match['created_at'] = match['created_at'].strftime("%b %d") if streak > longest_streak: longest_streak = streak data = { 'player': player, 'matches': matches[:25], 'total_played': len(matches), 'total_won': won, 'win_percent': '%.1f%%' % (100 * won / len(matches)), 'longest_streak': longest_streak, 'account_id': account_id } return data
def leaderboard_token(request, token): db = database.builder('foosbot') account = db.table('accounts').where('token', token).first() if not account: return HttpResponseNotFound() from foosbot.modules.leaderboard import get_leaderboard players = get_leaderboard(account['id']) return render(request, 'foosbot/leaderboard.html', context={ 'players': players, 'account_id': account['id'], 'account_name': account['name'] })
def authenticate(self, request, account_id=None, token=None): db = database.builder('foosbot') client = db.table('clients').where('account_id', account_id).where('token', 'token').first() if client: try: user = User.objects.get(pk=account_id) except User.DoesNotExist: # Create a new user. There's no need to set a password # because only the password from settings.py is checked. user = User(pk=account_id, username=str(account_id)) user.is_staff = False user.is_superuser = False user.save() return user
def getName(self, player_id): #have we checked for this id before? if id not in self.players: #nope, so find it from DB db = database.builder('foosbot') player = db.table('users').where('id', player_id).select( 'id', 'fname').first() if not player: return None #cache it for later self.players[player['id']] = player['fname'] return player['fname'] else: #returned the cached name return self.players[player_id]
def match_history(request, account_id): if not request.user.is_authenticated or request.user.account != account_id: raise PermissionDenied db = database.builder('foosbot') account = db.table('accounts').where('id', account_id).first() if not account: return HttpResponseNotFound() #get matches and which ones are editable matches = db.table('matches').where('account_id', account_id).order_by( 'id', 'desc').limit(50).get() return render(request, 'foosbot/match_history.html', context={ 'matches': matches, 'account_id': account['id'], 'account_name': account['name'] })
def start(data, account_id, reader_id): import foosbot.database as database from datetime import datetime, timedelta db = database.builder('foosbot') #New game starting. There should be no in progress games. If there are, set it to failed. in_progress_matches = db.table('matches').where( 'account_id', account_id).where('reader_id', reader_id).where('status', 'in_progress').get() for in_progress_match in in_progress_matches: Slack.clear_match(in_progress_match) db.table('matches').where('account_id', account_id).where( 'status', 'in_progress').where('id', in_progress_match['id']).update({ 'status': 'failed', 'updated_at': str(datetime.now()) }) match = { 'account_id': account_id, 'reader_id': reader_id, 'player1': data['player1'], 'player2': data['player2'], 'status': 'in_progress', 'created_at': str(datetime.now()), } res = db.table('matches').insert_get_id(match) match['id'] = res #return results if res: try: Slack.new_match(match) except Exception as e: print(e) return {'status': 'success'} else: return {'status': 'failed'}
def setup(request, account_id): if not request.user.is_authenticated: return redirect(login) if request.user.account != account_id: raise PermissionDenied db = database.builder('foosbot') account = db.table('accounts').where('id', request.user.account).first() slack_connection = db.table('slack_connections').where( 'account_id', account_id).first() slack_connection = dict(slack_connection) if slack_connection else {} if account: return render(request, 'foosbot/setup.html', context={ 'account_name': account.name, 'account_id': account_id, 'slack_config_url': slack_connection.get('config_url'), 'slack_channel': slack_connection.get('channel') }) else: return HttpResponseNotFound()
def verify_token(request, request_account_id=None): r = request.GET token = r.get('token') db = database.builder('foosbot') #Authentication reader by its token reader = db.table('readers').where('token', token).first() if not reader: return HttpResponse('Reader not configured: ' + str(token)) game = db.table('game_types').where('id', reader['game_type']).first() if not game: game = {'id': 0} account = db.table('accounts').where('id', reader['account']).first() if not account: return HttpResponse('Reader not assigned: ' + str(token)) #Looks good. Authenticate them and redirect to input page. request.session['account_id'] = account['id'] request.session['game_id'] = game['id'] request.session['reader_id'] = reader['id'] request.session.set_expiry(360000000) return redirect(input, account_id=account['id'])
def clear_match(match): db = database.builder('foosbot') #Is there a record to clear? slack_record = db.table('slack_records').where('match', match['id']).first() if not slack_record: return True #Get slack connection info slack_connection = db.table('slack_connections').where( 'id', slack_record['slack_connection']).first() if not slack_connection: return False #format slack data data = json.loads(slack_record["data"]) data['ts'] = slack_record['timestamp'] data["attachments"] = json.dumps([ { "text": "Match Cleared!", "color": "yellow" }, ]) #update r = Slack.updateMessage(slack_connection, data)
def get_match_history(account_id): db = database.builder('foosbot') matches = db.table('matches')\ .join(db.raw('users u'), 'u.id', '=', 'matches.player1')\ .join(db.raw('users u2'), 'u2.id', '=', 'matches.player2')\ .select('matches.player1', 'matches.player2', 'matches.winner','matches.points', 'matches.created_at', db.raw('u.fname as player1_name, u2.fname as player2_name'))\ .where('matches.account_id', account_id).where('matches.status', 'complete').order_by('matches.created_at', 'desc')\ .limit(10).get() for match in matches: match['points'] = f"{float(match['points']):2.0f}" match['created_at'] = parser.parse(str(match['created_at'])[:11]) match['date'] = match['created_at'].strftime("%b %d") match.pop('created_at') if match['player1'] == match['winner']: match['winner_name'] = match['player1_name'] match['loser_name'] = match['player2_name'] else: match['winner_name'] = match['player2_name'] match['loser_name'] = match['player1_name'] return matches
def slack(request): r = request.GET print(r) data = {} data['code'] = r['code'] data['client_id'] = '624952400887.615198951842' data['client_secret'] = 'd91d4794d106de4db1957c2f274346ae' # data['redirect_uri'] = 'https://www.employeearcade.com/slack/' import requests res = requests.get('https://slack.com/api/oauth.access', data) res = res.json() print(res) account_id = request.user.account slack_connection = {} slack_connection['account_id'] = account_id slack_connection['channel'] = res['incoming_webhook']['channel'] slack_connection['channel_id'] = res['incoming_webhook']['channel_id'] slack_connection['url'] = res['incoming_webhook']['url'] slack_connection['config_url'] = res['incoming_webhook'][ 'configuration_url'] slack_connection['token'] = res['access_token'] slack_connection['scope'] = res.get('scope') slack_connection['team_name'] = res.get('team_name') db = database.builder('foosbot') #This is the old way of saving webhook. # db.table('accounts').where('id', account_id).update({'slack_url':slack_url, 'slack_config_url': slack_config_url, 'slack_channel': slack_channel}) #save slack connection db.table('slack_connections').where('account_id', account_id).delete() db.table('slack_connections').insert(slack_connection) #return custom page with link to setup, or redirect to setup return redirect(setup, account_id=int(account_id))
def initialize_elo(player, player2_elo, win=True): db = database.builder('foosbot') players = db.table('users').where( 'account_id', player['account_id']).where_null( 'deleted_at').where_not_null('elo').get() #is this the first player? if not players or len(players) < 2: return 1500 #do some math import statistics elos = [p['elo'] for p in players] std = float(statistics.stdev(elos)) player2_win_prob = float(calculate_win_probability(player2_elo, 1500)) if win: bonus = -0.25 + 0.5 * player2_win_prob else: bonus = -0.75 + 0.5 * player2_win_prob bonus = bonus * std return 1500 + bonus
def rfid(data, account_id): import foosbot.database as database from datetime import datetime, timedelta db = database.builder('foosbot') rfid = data['rfid'] #look up rfid # db.table('users').insert({'username': '******', 'fname':'Proth', 'rfid':2, 'points':1500}) player = db.table('users').where('account_id', account_id).where_null('deleted_at').where('rfid', rfid).first() if not player: return {'status':'not found'} if not player['elo']: player['elo'] = 0 games = db.table('matches').where('created_at', '>', str(datetime.now() - timedelta(days=1))).where( db.query().where('player1', player['id']).or_where('player2', player['id']) ).where('status', 'complete').count() wins = db.table('matches').where('created_at', '>', str(datetime.now() - timedelta(days=1))).where('winner', player['id']).where('status', 'complete').count() #return results return {'status':'success', 'result':{'id':player['id'], 'name':player['fname'], 'games_today': games, 'wins_today': wins, 'points': int(player['elo'])}}
def new_match(match): db = database.builder('foosbot') #first see if they have slack configured. slack_connection = db.table('slack_connections').where( 'account_id', match['account_id']).first() if not slack_connection: return False #get player names player1 = db.table('users').where( 'id', match['player1']).select('fname').first()['fname'] player2 = db.table('users').where( 'id', match['player2']).select('fname').first()['fname'] data = { "text": "*" + player1 + " vs " + player2 + "*", "attachments": json.dumps([{ "text": "Match Started! ", "color": "warning" }]), } r = Slack.post_message(slack_connection, data) if r: record = { 'account_id': slack_connection['account_id'], 'slack_connection': slack_connection['id'], 'match': match['id'] } record['timestamp'] = r['ts'] record['data'] = json.dumps({ 'text': data['text'], 'attachments': data.get('attachments') }) db.table('slack_records').insert(record)
def player(request, account_id): if not request.user.is_authenticated or request.user.account != account_id: raise PermissionDenied db = database.builder('foosbot') #Patch to modify players if request.method == 'PATCH': r = loads(request.body) #Patch means update or insert if r['action'] == 'patch': player = r['player'] player_data = { 'account_id': account_id, 'fname': player['fname'].strip(), 'lname': player['lname'].strip(), 'rfid': player['rfid'], 'photo': player['photo'].strip() } #First make sure this rfid isn't taken. if player['rfid']: player_id = [player.get('id')] taken = db.table('users').where( 'account_id', account_id).where('rfid', player['rfid']).where_not_in( 'id', player_id).exists() if taken: return HttpResponse( dumps({'status': 'rfid taken or invalid'})) #Check if this is an update or new player if player.get('id'): existing = db.table('users').where('account_id', account_id).where( 'id', player['id']).first() db.table('users').where('id', existing['id']).update(player_data) else: #player not in DB. insert it. from foosbot.modules.player import create_player create_player(player_data) #Delete elif r['action'] == 'delete': player = r['player'] db.table('users').where('account_id', account_id).where('id', player['id']).update({ 'deleted_at': datetime.now(), 'rfid': None }) #no action? FAILURE else: return HttpResponse(dumps({'status': 'failed'})) return HttpResponse(dumps({'status': 'success'})) #if it wasn't a patch job, then its a query for player list players = db.table('users').where( 'account_id', request.user.account).where_null('deleted_at').order_by( 'fname', 'asc').get() data = [{ 'id': p.id, 'fname': p.fname, 'lname': p.lname, 'photo': p.photo, 'rfid': p.rfid } for p in players] return HttpResponse(dumps({'status': 'success', 'result': data}))
def end(data, account_id, reader_id): db = database.builder('foosbot') #validate if 'winner' not in data: return {'status': 'no winner given'} winner = data['winner'] loser = data['player1'] if winner != data['player1'] else data['player2'] #load the players winner = db.table('users').where('id', winner).first() loser = db.table('users').where('id', loser).first() #ensure there is a match in progress match = db.table('matches').select('id').where( 'account_id', account_id).where('reader_id', reader_id).where( 'player1', data['player1']).where('player2', data['player2']).where( 'status', 'in_progress').lock_for_update().first() if not match: return {'status': 'no match found'} #find winning player streak streak = 1 games = db.table('matches').where( db.query().where('player1', winner['id']).or_where('player2', winner['id']) ) \ .where('status', 'complete').order_by('created_at', 'desc').get() for game in games: if game['winner'] != winner['id']: break streak += 1 #check if winner is unranked if not winner['elo'] and not loser['elo']: winner['elo'] = 1500 loser['elo'] = 1500 elif not winner['elo']: winner['elo'] = initialize_elo(winner, loser['elo'], True) elif not loser['elo']: loser['elo'] = initialize_elo(loser, winner['elo'], False) #calculate the ELO change elo_change = calculate_elo_change(winner['elo'], loser['elo']) elo_won, elo_lost = get_real_elo_change(elo_change, account_id) # points_won, points_lost = get_points_change(winner, loser, elo_won, elo_lost) #update the match update_data = { 'status': 'complete', 'winner': data['winner'], 'updated_at': str(datetime.now()), 'points': elo_change } db.table('matches').where('id', match['id']).update(update_data) db.table('users').where('id', winner['id']).update({ 'elo': float(winner['elo']) + elo_won }) #'points':winner['points'] + points_won db.table('users').where('id', loser['id']).update({ 'elo': float(loser['elo']) - elo_lost }) #'points':loser['points'] - points_lost #update slack if applicable Slack.end_match(match['id'], winner, loser, streak, int(round(elo_change))) #return results return { 'status': 'success', 'streak': streak, 'points': int(round(elo_change)) }