Last active
May 22, 2019 12:04
-
-
Save alexpogue/ce29856bb4d5eb285747addb5f10e967 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from facebook import get_user_from_cookie, GraphAPI | |
from flask import Flask, g, render_template, session, request, redirect, url_for, abort | |
from flask_sqlalchemy import SQLAlchemy | |
from sqlalchemy.sql import func | |
import datetime | |
import dateutil.parser | |
import calendar | |
from enum import Enum | |
import json | |
app = Flask(__name__) | |
app.config.from_pyfile('../config.py') | |
db = SQLAlchemy(app) | |
db.init_app(app) | |
from .models import User, Bet, BetEvent, Moderation, WagerEncoder | |
#db.drop_all() | |
db.create_all() | |
# Facebook app details | |
FB_APP_ID = app.config["FB_APP_ID"] | |
FB_APP_NAME = app.config["FB_APP_NAME"] | |
FB_APP_SECRET = app.config["FB_APP_SECRET"] | |
@app.route('/') | |
def index(): | |
# If a user was set in the get_current_user function before the request, | |
# the user is logged in. | |
if g.user: | |
num_events = 5 | |
user = User.query.get(g.user['id']) | |
return render_template('index.html', app_id=FB_APP_ID, | |
app_name=FB_APP_NAME, user=user, bet_events=__get_bet_events(num_events), get_betevent_state=get_betevent_state, BetEventState=BetEventState, assignPoints=assignPoints()) | |
# Otherwise, a user is not logged in. | |
return render_template('login.html', app_id=FB_APP_ID, name=FB_APP_NAME) | |
@app.route('/logout') | |
def logout(): | |
"""Log out the user from the application. | |
Log out the user from the application by removing them from the | |
session. Note: this does not log the user out of Facebook - this is done | |
by the JavaScript SDK. | |
""" | |
session.pop('user', None) | |
return redirect(url_for('index')) | |
@app.route('/bet') | |
def bet_page(): | |
if g.user: | |
user = User.query.get(g.user['id']) | |
return render_template('betting-page.html', app_id=FB_APP_ID, name=FB_APP_NAME, user=user, bet_events=__get_bet_events(), BetEventState=BetEventState, get_betevent_state=get_betevent_state,assignPoints=assignPoints()) | |
return redirect(url_for('index')) | |
@app.route('/moderate') | |
def moderate_page(): | |
if g.user: | |
user = User.query.get(g.user['id']) | |
return render_template('moderating-page.html', app_id=FB_APP_ID, name=FB_APP_NAME, user=user, bet_events=__get_bet_events(), BetEventState=BetEventState, get_betevent_state=get_betevent_state,assignPoints=assignPoints()) | |
return redirect(url_for('index')) | |
@app.route('/flag') | |
def flag_page(): | |
if g.user: | |
user = User.query.get(g.user['id']) | |
return render_template('flagging-page.html', app_id=FB_APP_ID, name=FB_APP_NAME, user=user, bet_events=__get_bet_events(), BetEventState=BetEventState, get_betevent_state=get_betevent_state,assignPoints=assignPoints()) | |
return redirect(url_for('index')) | |
def __get_bet_events(limit=None): | |
return BetEvent.query.order_by(BetEvent.view_count.desc()).limit(limit).all() | |
def get_bet_events(): | |
return BetEvent.query.filter_by(hasBeenDistributed=0, status="closed").all() | |
@app.route('/new-bet-event') | |
def bet_event_page(): | |
return render_template('new-bet-event.html') | |
def __get_user(user_id): | |
return User.query.get(user_id) | |
@app.route('/api/user/<user_id>') | |
def get_user(user_id): | |
user = __get_user(user_id) | |
# TODO: get rid of this - we seem to need it to have 'betevents' be included in json output - without it, throws error | |
print("user = {}".format(user)) | |
if not user: | |
return "", 404 | |
else: | |
return json.dumps(user, cls=WagerEncoder) | |
class BetEventState(Enum): | |
not_yet_created= 1 | |
betting = 2 | |
moderating = 3 | |
flagging = 4 | |
closed = 5 | |
def get_betevent_state(betevent): | |
now = datetime.datetime.utcnow() | |
return get_betevent_state_time(betevent, now) | |
def get_betevent_state_time(betevent, now): | |
#moderating_hours = 2 | |
moderating_minutes = 15 | |
#flagging_minutes = 15 | |
flagging_minutes = 1 | |
#moderation_end_time = betevent.end_time + datetime.timedelta(hours=moderating_hours) | |
moderation_end_time = betevent.end_time + datetime.timedelta(minutes=moderating_minutes) | |
flagging_end_time = moderation_end_time + datetime.timedelta(minutes=flagging_minutes) | |
if now < betevent.created: | |
return BetEventState.not_yet_created | |
elif now < betevent.end_time: | |
betevent.status = "betting" | |
db.session.commit() | |
return BetEventState.betting | |
elif now < moderation_end_time: | |
betevent.status = "moderating" | |
db.session.commit() | |
return BetEventState.moderating | |
elif now < flagging_end_time: | |
betevent.status = "flagging" | |
db.session.commit() | |
return BetEventState.flagging | |
else: | |
betevent.status = "closed" | |
db.session.commit() | |
return BetEventState.closed | |
@app.route('/api/moderate', methods=['PUT']) | |
def moderate(): | |
if request.is_json: | |
print("detected request is json") | |
data = request.get_json() | |
betevent_id=data['betevent'] | |
option = data['option'] | |
betevent = BetEvent.query.filter(BetEvent.id == betevent_id).first() | |
if get_betevent_state(betevent) != BetEventState.moderating: | |
abort(400, {'data': 'Can\'t moderate a BetEvent that\'s not in moderating state'}) | |
user = User.query.get(g.user['id']) | |
#user = User.query.get(1) # for testing for iOS before we get facebook login | |
if betevent is None: | |
abort(400, {'data': 'Could not find BetEvent with id {}'.format(betevent_id)}) | |
# Look up existing moderation to update if it's there | |
moderation = Moderation.query.filter_by(users_id=user.id, betevents_id=betevent_id).first() | |
print("moderation = {}".format(moderation)) | |
if moderation is None: | |
moderation = Moderation(users_id=user.id, option=option) | |
moderation.betevent = betevent | |
user.moderations.append(moderation) | |
db.session.add(user) | |
db.session.commit() | |
return json.dumps({'data': 'stored'}) | |
else: | |
moderation = Moderation.query.filter_by(users_id=user.id, betevents_id=betevent_id).first() | |
moderation.option = option | |
db.session.commit() | |
return json.dumps({'data': 'updated'}) | |
@app.route('/api/bet', methods=['GET', 'PUT']) | |
def place_bet(): | |
if request.method == 'PUT': | |
print(request.data) | |
if request.is_json: | |
print("detected request is json") | |
data = request.get_json() | |
betevent_id=data['betevent'] | |
amount = data['amount'] | |
option = data['option'] | |
else: | |
print("detected request not json - treating as form") | |
betevent_id=request.form['betevent'] | |
amount = request.form['amount'] | |
option = request.form['option'] | |
betevent = BetEvent.query.filter(BetEvent.id == betevent_id).first() | |
if get_betevent_state(betevent) != BetEventState.betting: | |
abort(400, {'message': 'Can\'t bet on BetEvent that\'s not in betting state'}) | |
if betevent is None: | |
abort(404) | |
user = User.query.get(g.user['id']) | |
# user = User.query.get(1) # for testing for iOS before we get facebook login | |
#The case where the user doesn't have enough points | |
#If they don't have enough points we need to send them a message through Ajax that tells them they can't bet that many points. | |
bet = Bet.query.filter_by(users_id=user.id, betevents_id=betevent_id).first() | |
if bet is None: | |
if user.points < int(amount): | |
errorMessage = "Insufficient points" | |
return json.dumps({'data':errorMessage}) | |
else: | |
if(user.points + bet.amount < int(amount)): | |
errorMessage = "Insufficient points" | |
return json.dumps({'data':errorMessage}) | |
#The case where the user has enough points | |
#If they have enough points we want to subtract the amount from their total points in the database | |
if int(amount) <= 0: | |
errorMessage = "Yo bro, you can't bet nothing" | |
return json.dumps({'data':errorMessage}) | |
# Look up existing bet to update if it's there | |
bet = Bet.query.filter_by(users_id=user.id, betevents_id=betevent_id).first() | |
if bet is None: | |
bet = Bet(users_id=user.id, amount=amount, option=option) | |
bet.betevent = betevent | |
user.points -= int(amount) | |
betevent.totalAmount += int(amount) | |
user.betevents.append(bet) | |
db.session.add(user) | |
db.session.commit() | |
return json.dumps({'data': ''}) | |
else: | |
bet = Bet.query.filter_by(users_id=user.id, betevents_id=betevent_id).first() | |
#Get the old amount | |
oldAmount = bet.amount | |
#Update the new amount | |
bet.amount = amount | |
#Add the old amount back to the user's points in the database | |
user.points += oldAmount | |
betevent.totalAmount -=oldAmount | |
#subtract out the new amount | |
user.points -= int(amount) | |
betevent.totalAmount += int(amount) | |
#save changes | |
bet.option = option | |
db.session.commit() | |
return json.dumps({'data': ''}) | |
elif request.method == 'GET': | |
bets = Bet.query.all() | |
return json.dumps({'results': bets}, cls=WagerEncoder) | |
@app.route('/api/betevent', methods=['GET', 'POST']) | |
def bet_events(): | |
if request.method == 'POST': | |
if request.is_json: | |
print("detected request is json") | |
data = request.get_json() | |
name=data['name'] | |
description=data['description'] | |
end_datetime_str = data['beteventend'] | |
else: | |
print("detected request not json - treating as form") | |
name = request.form.getlist('beteventname')[0] | |
description = request.form.getlist('beteventdescription')[0] | |
end_datetime_str = request.form.getlist('beteventend')[0] | |
#print("datebeforeparsing= {}".format(end_datetime_str)) | |
end_datetime = dateutil.parser.parse(end_datetime_str) | |
#print("date = {}".format(end_datetime.isoformat())) | |
event = BetEvent(name=name, description=description, end_time=end_datetime) | |
app.logger.info(event.id) | |
db.session.add(event) | |
db.session.commit() | |
app.logger.info(event.id) | |
return redirect(url_for('bet_event_view', bet_event_id=event.id)) | |
elif request.method == 'GET': | |
bet_events = __get_bet_events() | |
for event in bet_events: | |
# TODO: get rid of this - we seem to need it to have 'betters' be included in json output - without it, throws error | |
print("bet_event = {}".format(event)) | |
return json.dumps({'results': bet_events}, cls=WagerEncoder) | |
def __get_bet_event(bet_event_id): | |
return BetEvent.query.get(bet_event_id) | |
def __update_bet_event(bet_event_id, updates): | |
db.session.query(BetEvent).filter_by(id=bet_event_id).update(updates) | |
@app.route('/api/betevent/<bet_event_id>', methods=['GET', 'PUT']) | |
def bet_event(bet_event_id): | |
if request.method == 'GET': | |
bet_event = __get_bet_event(bet_event_id) | |
# TODO: get rid of this - we seem to need it to have 'betters' be included in json output - without it, throws error | |
print("bet_event = {}".format(bet_event)) | |
if not bet_event: | |
return "", 404 | |
else: | |
return json.dumps(bet_event, cls=WagerEncoder) | |
elif request.method == 'PUT': | |
if request.is_json: | |
print("detected request is json") | |
data = request.get_json() | |
state_str = data['state'] | |
if state_str is not None: | |
state_enum = BetEventState[state_str] | |
if state_enum is None: | |
print("Error: couldn't find enum called {}".format(state_str)) | |
return "", 500 | |
event = __get_bet_event(bet_event_id) | |
if event is None: | |
return "", 404 | |
__update_bet_event(bet_event_id, updates={"state": state_enum}) | |
db.session.commit() | |
return "success", 200 | |
else: | |
print("Error: expected json input to /api/betevent/<bet_event_id>") | |
def datetime_to_utc(dt): | |
return calendar.timegm(dt.utctimetuple()) | |
# get a single bet event | |
@app.route('/betevent/<bet_event_id>') | |
def bet_event_view(bet_event_id): | |
bet_event = __get_bet_event(bet_event_id) | |
if not bet_event: | |
return "", 404 | |
else: | |
user = User.query.get(g.user['id']) | |
bet_event.view_count = bet_event.view_count + 1 | |
db.session.commit() | |
return render_template('bet-event-view.html', bet_event=bet_event, user=user, BetEventState=BetEventState, betevent_state=get_betevent_state(bet_event), assignPoints=assignPoints()) | |
def assignPoints(): | |
#First we have to get a list of the bet events | |
betEvents = get_bet_events() | |
#if len(betEvents) == 0: | |
# print("No bet events to show!") | |
#while betEvents is not empty | |
while len(betEvents) != 0: | |
#pop the first bet event | |
event = betEvents.pop(0) | |
#extract the bet_event_id, the list of betters, the total amount on the bet event, and the list of moderators | |
betEventId = event.id | |
betters = event.betters | |
totalAmount = event.totalAmount | |
moderators = event.moderators | |
print() | |
print() | |
print("The bet id is: " + str(betEventId)) | |
print("The list of betters are: " + str(betters)) | |
print("The total amount of the event is: " + str(totalAmount)) | |
print("The list of moderators are: " + str(moderators)) | |
#Completed: determine the option by checking through the list of moderators and seeing what the popular option was (could do ratio, ect) | |
#We need to make moderate work first before doing the step above | |
#TODO: Add points to people's acounts for moderating a winning event. | |
winningOption = 0 | |
zeroCount = 0 | |
oneCount = 0 | |
if len(moderators) != 0: | |
for mod in moderators: | |
if mod.option == 0: | |
zeroCount+=1 | |
else: | |
oneCount+=1 | |
print("The number of moderators that chose option 0 are: " + str(zeroCount)) | |
print("The number of moderators that chose option 1 are: " + str(oneCount)) | |
if zeroCount > oneCount: | |
payModerators(moderators,0) | |
winningOption = 0 | |
elif zeroCount < oneCount: | |
payModerators(moderators,1) | |
winningOption = 1 | |
else: | |
#Right now, we will just set the winning option to 0 when they're equal. I will try and figure out what to do with this later. | |
winningOption = 0 | |
winningAmount = 0 | |
print("The winning option is: " + str(winningOption)) | |
#*BETS | |
for better in betters: | |
if(better.option == winningOption): | |
betterId = better.users_id | |
winningAmount+= better.amount | |
print("The better id's are: " + str(betterId)) | |
print("The winning amount is: " + str(winningAmount)) | |
for better in betters: | |
if(better.option == winningOption): | |
betterId = better.users_id | |
payOut = (better.amount / winningAmount) * totalAmount | |
print("The payout for: " + str(better.better.name + " is: " + str(payOut))) | |
user = User.query.get(betterId) | |
user.points += payOut | |
event.hasBeenDistributed = 1 | |
db.session.commit() | |
print() | |
print() | |
#for each better, extract the amount and calculate how much of the winnings for that event they get, and add it to their User table | |
#Move on to the next event. | |
#Distribute points, and shift the bit from 0 to 1 | |
return u'success' | |
def payModerators(moderators, option): | |
for moderator in moderators: | |
modUserId = moderator.users_id | |
if moderator.option == option: | |
user = User.query.get(modUserId) | |
user.points +=10 | |
db.session.commit() | |
@app.before_request | |
def get_current_user(): | |
"""Set g.user to the currently logged in user. | |
Called before each request, get_current_user sets the global g.user | |
variable to the currently logged in user. A currently logged in user is | |
determined by seeing if it exists in Flask's session dictionary. | |
If it is the first time the user is logging into this application it will | |
create the user and insert it into the database. If the user is not logged | |
in, None will be set to g.user. | |
""" | |
# Set the user in the session dictionary as a global g.user and bail out | |
# of this function early. | |
if session.get('user'): | |
g.user = session.get('user') | |
return | |
# Attempt to get the short term access token for the current user. | |
result = get_user_from_cookie(cookies=request.cookies, app_id=FB_APP_ID, | |
app_secret=FB_APP_SECRET) | |
# If there is no result, we assume the user is not logged in. | |
if result: | |
# Check to see if this user is already in our database. | |
user = User.query.filter(User.fb_id == result['uid']).first() | |
if not user: | |
# Not an existing user so get info | |
graph = GraphAPI(result['access_token']) | |
profile = graph.get_object('me') | |
if 'link' not in profile: | |
profile['link'] = "" | |
# Create the user and insert it into the database | |
user = User(fb_id=str(profile['id']), name=profile['name'], | |
profile_url=profile['link'], | |
access_token=result['access_token']) | |
db.session.add(user) | |
elif user.access_token != result['access_token']: | |
# If an existing user, update the access token | |
user.access_token = result['access_token'] | |
# Commit changes to the database | |
db.session.commit() | |
# Add the user to the current session | |
session['user'] = dict(id=user.id, name=user.name, profile_url=user.profile_url, | |
fb_id=user.fb_id, points=user.points,access_token=user.access_token) | |
# set the user as a global g.user | |
g.user = session.get('user', None) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment