mirror of
https://github.com/zoffline/zwift-offline.git
synced 2026-08-03 01:15:46 -07:00
Merge pull request #23 from Argon2000/master
Use db session instead of engine
This commit is contained in:
@@ -33,10 +33,12 @@
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
<script>
|
||||
var elements = document.getElementsByClassName('text-shadow');
|
||||
for(var i = 0; i < elements.length; i++) {
|
||||
var el = elements[i];
|
||||
el.setAttribute('data-innertext', el.textContent);
|
||||
if(document.getElementsByClassName) {
|
||||
var elements = document.getElementsByClassName('text-shadow');
|
||||
for(var i = 0; i < elements.length; i++) {
|
||||
var el = elements[i];
|
||||
el.setAttribute('data-innertext', el.textContent);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
{% block scripts %}{% endblock %}
|
||||
|
||||
@@ -20,7 +20,17 @@
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12 top-buffer">
|
||||
<input type="submit" value="Login" class="btn btn-sm btn-light">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="rememberlogin" name="rememberlogin">
|
||||
<label class="form-check-label text-shadow" for="rememberlogin">
|
||||
Remember login
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12 top-buffer">
|
||||
<input type="submit" value="Login" class="btn btn-sm btn-light" onclick="rememberLogin()">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@@ -38,3 +48,29 @@
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block scripts %}
|
||||
<script>
|
||||
var checkbox = document.getElementById('rememberlogin');
|
||||
var username = document.getElementById('username');
|
||||
var password = document.getElementById('password');
|
||||
function rememberLogin() {
|
||||
if(checkbox.checked && username.value !== '' && password.value !== '') {
|
||||
localStorage.setItem('username', username.value);
|
||||
localStorage.setItem('password', password.value);
|
||||
}
|
||||
else if(!checkbox.checked) {
|
||||
localStorage.removeItem('username')
|
||||
localStorage.removeItem('password');
|
||||
}
|
||||
}
|
||||
|
||||
var usernameVal = localStorage.getItem('username');
|
||||
var passwordVal = localStorage.getItem('password');
|
||||
if(usernameVal !== undefined && usernameVal !== null && usernameVal !== '' &&
|
||||
passwordVal !== undefined && passwordVal !== null && passwordVal !== '') {
|
||||
checkbox.checked = true;
|
||||
username.value = usernameVal;
|
||||
password.value = passwordVal;
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
+57
-59
@@ -463,7 +463,8 @@ def insert_protobuf_into_db(table_name, msg):
|
||||
columns = ', '.join(list(msg_dict.keys()))
|
||||
placeholders = ':'+', :'.join(list(msg_dict.keys()))
|
||||
query = 'INSERT INTO %s (%s) VALUES (%s)' % (table_name, columns, placeholders)
|
||||
db.engine.execute(query, msg_dict)
|
||||
db.session.execute(query, msg_dict)
|
||||
db.session.commit()
|
||||
|
||||
|
||||
# XXX: can't be used to 'nullify' a column value
|
||||
@@ -480,7 +481,8 @@ def update_protobuf_in_db(table_name, msg, id):
|
||||
placeholders = ':'+', :'.join(list(msg_dict.keys()))
|
||||
setters = ', '.join('{}=:{}'.format(key, key) for key in msg_dict)
|
||||
query = 'UPDATE %s SET %s WHERE id=%s' % (table_name, setters, id)
|
||||
db.engine.execute(query, msg_dict)
|
||||
db.session.execute(query, msg_dict)
|
||||
db.session.commit()
|
||||
|
||||
|
||||
def row_to_protobuf(row, msg, exclude_fields=[]):
|
||||
@@ -503,7 +505,7 @@ def get_id(table_name):
|
||||
# I think activity id is actually only uint32. On the off chance it's
|
||||
# int32, stick with 31 bits.
|
||||
ident = int(random.getrandbits(31))
|
||||
row = db.engine.execute("SELECT id FROM %s WHERE id = %s" % (table_name, ident)).first()
|
||||
row = db.session.execute(sqlalchemy.text("SELECT id FROM %s WHERE id = %s" % (table_name, ident))).first()
|
||||
if not row:
|
||||
break
|
||||
return ident
|
||||
@@ -647,9 +649,10 @@ def api_profiles_me():
|
||||
# However, without it, anyone "upgrading" to multiplayer mode will lose their existing data.
|
||||
# TODO: need a warning in README that switching to multiplayer mode and back to single player will lose your existing data.
|
||||
if profile.id != profile_id:
|
||||
db.engine.execute('UPDATE activity SET player_id = ? WHERE player_id = ?', (str(profile_id), str(profile.id)))
|
||||
db.engine.execute('UPDATE goal SET player_id = ? WHERE player_id = ?', (str(profile_id), str(profile.id)))
|
||||
db.engine.execute('UPDATE segment_result SET player_id = ? WHERE player_id = ?', (str(profile_id), str(profile.id)))
|
||||
db.session.execute(sqlalchemy.text('UPDATE activity SET player_id = %s WHERE player_id = %s' % (profile_id, profile.id)))
|
||||
db.session.execute(sqlalchemy.text('UPDATE goal SET player_id = %s WHERE player_id = %s' % (profile_id, profile.id)))
|
||||
db.session.execute(sqlalchemy.text('UPDATE segment_result SET player_id = %s WHERE player_id = %s' % (profile_id, profile.id)))
|
||||
db.session.commit()
|
||||
profile.id = profile_id
|
||||
elif current_user.player_id != profile.id:
|
||||
# Update AnonUser's player_id to match
|
||||
@@ -700,19 +703,19 @@ def api_profiles_activities(player_id):
|
||||
# request.method == 'GET'
|
||||
activities = activity_pb2.Activities()
|
||||
# Select every column except 'fit' - despite being a blob python 3 treats it like a utf-8 string and tries to decode it
|
||||
rows = db.engine.execute("SELECT id, player_id, f3, name, f5, f6, start_date, end_date, distance, avg_heart_rate, max_heart_rate, avg_watts, max_watts, avg_cadence, max_cadence, avg_speed, max_speed, calories, total_elevation, strava_upload_id, strava_activity_id, f23, fit_filename, f29, date FROM activity WHERE player_id = ?", (str(player_id),))
|
||||
rows = db.session.execute(sqlalchemy.text("SELECT id, player_id, f3, name, f5, f6, start_date, end_date, distance, avg_heart_rate, max_heart_rate, avg_watts, max_watts, avg_cadence, max_cadence, avg_speed, max_speed, calories, total_elevation, strava_upload_id, strava_activity_id, f23, fit_filename, f29, date FROM activity WHERE player_id = %s" % str(player_id)))
|
||||
should_remove = list()
|
||||
for row in rows:
|
||||
activity = activities.activities.add()
|
||||
row_to_protobuf(row, activity, exclude_fields=['fit'])
|
||||
a = activity
|
||||
#If all values for saved activity is 0, remove it from DB and results
|
||||
#if (a.avg_cadence == 0 and a.avg_heart_rate == 0 and a.avg_speed == 0 and
|
||||
#a.avg_watts == 0 and a.calories == 0 and a.distance == 0 and a.max_cadence == 0 and
|
||||
#a.max_heart_rate == 0 and a.max_speed == 0 and a.max_watts == 0):
|
||||
if a.distance == 0:
|
||||
db.engine.execute("DELETE FROM activity WHERE id = %s" % a.id)
|
||||
activities.activities.remove(a)
|
||||
|
||||
#Remove activities with less than 100m distance
|
||||
if a.distance < 100:
|
||||
should_remove.append(a)
|
||||
for a in should_remove:
|
||||
db.session.execute(sqlalchemy.text("DELETE FROM activity WHERE id = %s" % a.id))
|
||||
db.session.commit()
|
||||
activities.activities.remove(a)
|
||||
return activities.SerializeToString(), 200
|
||||
|
||||
|
||||
@@ -909,13 +912,14 @@ def fill_in_goal_progress(goal, player_id):
|
||||
first_dt, last_dt = get_week_range(now)
|
||||
else: # monthly
|
||||
first_dt, last_dt = get_month_range(now)
|
||||
|
||||
common_sql = ("""FROM activity
|
||||
WHERE player_id = %s
|
||||
AND strftime('%s', start_date) >= strftime('%s', '%s')
|
||||
AND strftime('%s', start_date) <= strftime('%s', '%s')""" %
|
||||
(player_id, '%s', '%s', first_dt, '%s', '%s', last_dt))
|
||||
if goal.type == 0: # distance
|
||||
distance = db.engine.execute("""SELECT SUM(distance) FROM activity
|
||||
WHERE player_id = ?
|
||||
AND strftime('%s', start_date) >= strftime('%s', ?)
|
||||
AND strftime('%s', start_date) <= strftime('%s', ?)
|
||||
AND end_date IS NOT NULL""",
|
||||
(str(player_id), first_dt, last_dt)).first()[0]
|
||||
distance = db.session.execute(sqlalchemy.text('SELECT SUM(distance) %s' % common_sql)).first()[0]
|
||||
if distance:
|
||||
goal.actual_distance = distance
|
||||
goal.actual_duration = distance
|
||||
@@ -924,13 +928,7 @@ def fill_in_goal_progress(goal, player_id):
|
||||
goal.actual_duration = 0.0
|
||||
|
||||
else: # duration
|
||||
duration = db.engine.execute("""SELECT SUM(julianday(end_date) - julianday(start_date))
|
||||
FROM activity
|
||||
WHERE player_id = ?
|
||||
AND strftime('%s', start_date) >= strftime('%s', ?)
|
||||
AND strftime('%s', start_date) <= strftime('%s', ?)
|
||||
AND end_date IS NOT NULL""",
|
||||
(str(player_id), first_dt, last_dt)).first()[0]
|
||||
duration = db.session.execute(sqlalchemy.text('SELECT SUM(julianday(end_date) - julianday(start_date)) %s' % common_sql)).first()[0]
|
||||
if duration:
|
||||
goal.actual_duration = duration*1440 # convert from days to minutes
|
||||
goal.actual_distance = duration*1440
|
||||
@@ -968,16 +966,19 @@ def api_profiles_goals(player_id):
|
||||
|
||||
# request.method == 'GET'
|
||||
goals = goal_pb2.Goals()
|
||||
rows = db.engine.execute("SELECT * FROM goal WHERE player_id = ?", (str(player_id),))
|
||||
rows = db.session.execute(sqlalchemy.text("SELECT * FROM goal WHERE player_id = %s" % player_id))
|
||||
need_update = list()
|
||||
for row in rows:
|
||||
goal = goals.goals.add()
|
||||
row_to_protobuf(row, goal)
|
||||
end_dt = datetime.datetime.fromtimestamp(goal.period_end_date / 1000)
|
||||
now = get_utc_date_time()
|
||||
if end_dt < now:
|
||||
set_goal_end_date(goal, now)
|
||||
update_protobuf_in_db('goal', goal, goal.id)
|
||||
need_update.append(goal)
|
||||
fill_in_goal_progress(goal, player_id)
|
||||
for goal in need_update:
|
||||
set_goal_end_date(goal, now)
|
||||
update_protobuf_in_db('goal', goal, goal.id)
|
||||
|
||||
return goals.SerializeToString(), 200
|
||||
|
||||
@@ -989,7 +990,8 @@ def api_profiles_goals_id(player_id, goal_id):
|
||||
if player_id != current_user.player_id:
|
||||
return '', 401
|
||||
goal_id = int(goal_id) & 0xffffffffffffffff
|
||||
db.engine.execute("DELETE FROM goal WHERE id = ?", (str(goal_id),))
|
||||
db.session.execute(sqlalchemy.text("DELETE FROM goal WHERE id = %s" % goal_id))
|
||||
db.session.commit()
|
||||
return '', 200
|
||||
|
||||
|
||||
@@ -1204,30 +1206,25 @@ def relay_periodic_info():
|
||||
|
||||
|
||||
def add_segment_results(segment_id, player_id, only_best, from_date, to_date, results):
|
||||
where_stmt = "WHERE segment_id = ?"
|
||||
where_args = [str(segment_id)]
|
||||
where_stmt = ("WHERE segment_id = %s" % segment_id)
|
||||
rows = None
|
||||
if player_id:
|
||||
where_stmt += " AND player_id = ?"
|
||||
where_args.append(player_id)
|
||||
where_stmt += (" AND player_id = %s" % player_id)
|
||||
if from_date:
|
||||
where_stmt += " AND strftime('%s', finish_time_str) > strftime('%s', ?)"
|
||||
where_args.append(from_date)
|
||||
where_stmt += (" AND strftime('%s', finish_time_str) > strftime('%s', '%s')" % ('%s', '%s', from_date))
|
||||
if to_date:
|
||||
where_stmt += " AND strftime('%s', finish_time_str) < strftime('%s', ?)"
|
||||
where_args.append(to_date)
|
||||
where_stmt += (" AND strftime('%s', finish_time_str) < strftime('%s', '%s')" % ('%s', '%s', to_date))
|
||||
if only_best:
|
||||
where_stmt += " AND world_time > ?"
|
||||
#Only include results from max 1 hour ago
|
||||
where_args.append(world_time()-(60*60*1000))
|
||||
rows = db.engine.execute("""SELECT s1.* FROM segment_result s1
|
||||
where_stmt += (" AND world_time > '%s'" % (world_time()-(60*60*1000)))
|
||||
rows = db.session.execute(sqlalchemy.text("""SELECT s1.* FROM segment_result s1
|
||||
JOIN (SELECT s.player_id, MIN(Cast(s.elapsed_ms AS INTEGER)) AS min_time
|
||||
FROM segment_result s %s GROUP BY s.player_id) s2 ON s2.player_id = s1.player_id AND s2.min_time = CAST(s1.elapsed_ms AS INTEGER)
|
||||
GROUP BY s1.player_id, s1.elapsed_ms
|
||||
ORDER BY CAST(s1.elapsed_ms AS INTEGER)
|
||||
LIMIT 1000""" % where_stmt, where_args)
|
||||
LIMIT 1000""" % where_stmt))
|
||||
else:
|
||||
rows = db.engine.execute("SELECT * FROM segment_result %s" % where_stmt, where_args)
|
||||
rows = db.session.execute(sqlalchemy.text("SELECT * FROM segment_result %s" % where_stmt))
|
||||
for row in rows:
|
||||
result = results.segment_results.add()
|
||||
row_to_protobuf(row, result, ['f3', 'f4', 'segment_id', 'event_subgroup_id', 'finish_time_str', 'f14', 'f17', 'f18'])
|
||||
@@ -1294,9 +1291,7 @@ def relay_worlds_leave(world_id):
|
||||
|
||||
@app.teardown_request
|
||||
def teardown_request(exception):
|
||||
db.close_all_sessions()
|
||||
db.session.close()
|
||||
db.engine.dispose()
|
||||
if exception != None:
|
||||
print('Exception: %s' % exception)
|
||||
|
||||
@@ -1307,14 +1302,16 @@ def init_database():
|
||||
with open(DATABASE_INIT_SQL, 'r') as f:
|
||||
sql_statements = f.read().split('\n\n')
|
||||
for sql_statement in sql_statements:
|
||||
db.engine.execute(sql_statement)
|
||||
db.engine.execute('INSERT INTO version VALUES (?)', (DATABASE_CUR_VER,))
|
||||
db.session.execute(sql_statement)
|
||||
db.session.commit()
|
||||
db.session.execute('INSERT INTO version VALUES (:ver)', {'ver': DATABASE_CUR_VER})
|
||||
db.session.commit()
|
||||
return
|
||||
# Migrate database if necessary
|
||||
if not os.access(DATABASE_PATH, os.W_OK):
|
||||
logging.error("zwift-offline.db is not writable. Unable to upgrade database!")
|
||||
return
|
||||
version = db.engine.execute('SELECT version FROM version').first()[0]
|
||||
version = db.session.execute('SELECT version FROM version').first()[0]
|
||||
if version == DATABASE_CUR_VER:
|
||||
return
|
||||
# Database needs to be upgraded, try to back it up first
|
||||
@@ -1329,17 +1326,19 @@ def init_database():
|
||||
if version < 1:
|
||||
# Adjust old world_time values in segment results to new rough estimate of Zwift's
|
||||
logging.info("Upgrading zwift-offline.db to version 2")
|
||||
db.engine.execute('UPDATE segment_result SET world_time = world_time-1414016075000')
|
||||
db.engine.execute('UPDATE version SET version = 2')
|
||||
db.session.execute('UPDATE segment_result SET world_time = world_time-1414016075000')
|
||||
db.session.execute('UPDATE version SET version = 2')
|
||||
db.session.commit()
|
||||
|
||||
if version == 1:
|
||||
logging.info("Upgrading zwift-offline.db to version 2")
|
||||
db.engine.execute('UPDATE segment_result SET world_time = cast(world_time/64.4131403573055-1414016075 as int)*1000')
|
||||
db.engine.execute('UPDATE version SET version = 2')
|
||||
db.session.execute('UPDATE segment_result SET world_time = cast(world_time/64.4131403573055-1414016075 as int)*1000')
|
||||
db.session.execute('UPDATE version SET version = 2')
|
||||
db.session.commit()
|
||||
|
||||
|
||||
def check_columns():
|
||||
rows = db.engine.execute(sqlalchemy.text("PRAGMA table_info(user)"))
|
||||
rows = db.session.execute(sqlalchemy.text("PRAGMA table_info(user)"))
|
||||
should_have_columns = User.metadata.tables['user'].columns
|
||||
current_columns = list()
|
||||
for row in rows:
|
||||
@@ -1356,7 +1355,8 @@ def check_columns():
|
||||
defaulttext = ""
|
||||
else:
|
||||
defaulttext = " DEFAULT %s" % column.default.arg
|
||||
db.engine.execute(sqlalchemy.text("ALTER TABLE user ADD %s %s %s%s;" % (column.name, str(column.type), nulltext, defaulttext)))
|
||||
db.session.execute(sqlalchemy.text("ALTER TABLE user ADD %s %s %s%s;" % (column.name, str(column.type), nulltext, defaulttext)))
|
||||
db.session.commit()
|
||||
|
||||
|
||||
def send_server_back_online_message():
|
||||
@@ -1368,8 +1368,8 @@ def send_server_back_online_message():
|
||||
def before_first_request():
|
||||
init_database()
|
||||
db.create_all(app=app)
|
||||
db.session.commit()
|
||||
check_columns()
|
||||
db.session.close()
|
||||
send_message_thread = threading.Thread(target=send_server_back_online_message)
|
||||
send_message_thread.start()
|
||||
|
||||
@@ -1512,8 +1512,6 @@ def run_standalone(passed_online, passed_global_pace_partners, passed_global_bot
|
||||
if not MULTIPLAYER:
|
||||
login_manager.anonymous_user = AnonUser
|
||||
login_manager.init_app(app)
|
||||
db.close_all_sessions()
|
||||
db.engine.dispose()
|
||||
|
||||
@login_manager.user_loader
|
||||
def load_user(uid):
|
||||
|
||||
Reference in New Issue
Block a user