thrimshim: misc cleanup

pull/224/head
Mike Lang 3 years ago committed by Mike Lang
parent 9fad66c6be
commit d42d850153

@ -47,7 +47,6 @@ def cors(app):
return handle return handle
def authenticate(f): def authenticate(f):
"""Authenticate a token against the database. """Authenticate a token against the database.
@ -82,15 +81,16 @@ def authenticate(f):
return f(*args, editor=email, **kwargs) return f(*args, editor=email, **kwargs)
return auth_wrapper return auth_wrapper
@app.route('/thrimshim/auth-test', methods=['POST']) @app.route('/thrimshim/auth-test', methods=['POST'])
@request_stats @request_stats
@authenticate @authenticate
def test(editor=None): def test(editor=None):
return json.dumps(editor) return json.dumps(editor)
# To make nginx proxying simpler, we want to allow /metrics/* to work # To make nginx proxying simpler, we want to allow /metrics/* to work
@app.route('/metrics/<trailing>') @app.route('/metrics/<trailing>')
@request_stats @request_stats
@ -98,12 +98,14 @@ def metrics_with_trailing(trailing):
"""Expose Prometheus metrics.""" """Expose Prometheus metrics."""
return prometheus_client.generate_latest() return prometheus_client.generate_latest()
@app.route('/metrics') @app.route('/metrics')
@request_stats @request_stats
def metrics(): def metrics():
"""Expose Prometheus metrics.""" """Expose Prometheus metrics."""
return prometheus_client.generate_latest() return prometheus_client.generate_latest()
@app.route('/thrimshim') @app.route('/thrimshim')
@request_stats @request_stats
def get_all_rows(): def get_all_rows():
@ -112,7 +114,8 @@ def get_all_rows():
results = database.query(conn, """ results = database.query(conn, """
SELECT * SELECT *
FROM events FROM events
ORDER BY event_start""") ORDER BY event_start
""")
rows = [] rows = []
for row in results: for row in results:
row = row._asdict() row = row._asdict()
@ -149,7 +152,8 @@ def get_row(ident):
results = database.query(conn, """ results = database.query(conn, """
SELECT * SELECT *
FROM events FROM events
WHERE id = %s""", ident) WHERE id = %s
""", ident)
row = results.fetchone() row = results.fetchone()
if row is None: if row is None:
return 'Row id = {} not found'.format(ident), 404 return 'Row id = {} not found'.format(ident), 404
@ -187,30 +191,33 @@ def get_row(ident):
logging.info('Row {} fetched'.format(ident)) logging.info('Row {} fetched'.format(ident))
return json.dumps(response) return json.dumps(response)
@app.route('/thrimshim/<uuid:ident>', methods=['POST']) @app.route('/thrimshim/<uuid:ident>', methods=['POST'])
@request_stats @request_stats
@authenticate @authenticate
def update_row(ident, editor=None): def update_row(ident, editor=None):
"""Updates row of database with id = ident with the edit columns in new_row."""
new_row = flask.request.json new_row = flask.request.json
override_changes = new_row.get('override_changes', False) override_changes = new_row.get('override_changes', False)
"""Updates row of database with id = ident with the edit columns in
new_row."""
state_columns = ['state', 'uploader', 'error', 'video_link'] state_columns = ['state', 'uploader', 'error', 'video_link']
#these have to be set before a video can be set as 'EDITED' # These have to be set before a video can be set as 'EDITED'
non_null_columns = ['upload_location', 'video_start', 'video_end', non_null_columns = [
'video_channel', 'video_quality', 'video_title', 'video_description', 'video_tags'] 'upload_location', 'video_start', 'video_end',
'video_channel', 'video_quality', 'video_title',
'video_description', 'video_tags',
]
edit_columns = non_null_columns + ['allow_holes', 'uploader_whitelist'] edit_columns = non_null_columns + ['allow_holes', 'uploader_whitelist']
sheet_columns = [ sheet_columns = [
'sheet_name', 'event_start', 'event_end', 'category', 'description', 'notes', 'tags' 'sheet_name', 'event_start', 'event_end',
'category', 'description', 'notes', 'tags',
] ]
#check vital edit columns are in new_row # Check vital edit columns are in new_row
wanted = set(non_null_columns + ['state'] + sheet_columns) wanted = set(non_null_columns + ['state'] + sheet_columns)
missing = wanted - set(new_row) missing = wanted - set(new_row)
if missing: if missing:
return 'Fields missing in JSON: {}'.format(', '.join(missing)), 400 return 'Fields missing in JSON: {}'.format(', '.join(missing)), 400
#get rid of irrelevant columns # Get rid of irrelevant columns
extras = set(new_row) - set(edit_columns + state_columns + sheet_columns) extras = set(new_row) - set(edit_columns + state_columns + sheet_columns)
for extra in extras: for extra in extras:
del new_row[extra] del new_row[extra]
@ -221,15 +228,15 @@ def update_row(ident, editor=None):
if 'video_description' in new_row: if 'video_description' in new_row:
new_row['video_description'] += app.description_footer new_row['video_description'] += app.description_footer
#validate title length # Validate title length
if len(new_row['video_title']) > MAX_TITLE_LENGTH: if len(new_row['video_title']) > MAX_TITLE_LENGTH:
return 'Title must be {} characters or less, including prefix'.format(MAX_TITLE_LENGTH), 400 return 'Title must be {} characters or less, including prefix'.format(MAX_TITLE_LENGTH), 400
#validate start time is less than end time # Validate start time is less than end time
if new_row['video_start'] > new_row['video_end']: if new_row['video_start'] > new_row['video_end']:
return 'Video Start must be less than Video End.', 400 return 'Video Start must be less than Video End.', 400
conn = app.db_manager.get_conn() conn = app.db_manager.get_conn()
#check a row with id = ident is in the database # Check a row with id = ident is in the database
built_query = sql.SQL(""" built_query = sql.SQL("""
SELECT id, state, {} SELECT id, state, {}
FROM events FROM events
@ -299,6 +306,7 @@ def update_row(ident, editor=None):
logging.info('Row {} updated to state {}'.format(ident, new_row['state'])) logging.info('Row {} updated to state {}'.format(ident, new_row['state']))
return '' return ''
@app.route('/thrimshim/manual-link/<uuid:ident>', methods=['POST']) @app.route('/thrimshim/manual-link/<uuid:ident>', methods=['POST'])
@request_stats @request_stats
@authenticate @authenticate
@ -308,7 +316,6 @@ def manual_link(ident, editor=None):
link = flask.request.json['link'] link = flask.request.json['link']
upload_location = flask.request.json.get('upload_location', 'manual') upload_location = flask.request.json.get('upload_location', 'manual')
if upload_location == 'youtube-manual': if upload_location == 'youtube-manual':
YOUTUBE_URL_RE = r'^https?://(?:youtu\.be/|youtube.com/watch\?v=)([a-zA-Z0-9_-]{11})$' YOUTUBE_URL_RE = r'^https?://(?:youtu\.be/|youtube.com/watch\?v=)([a-zA-Z0-9_-]{11})$'
match = re.match(YOUTUBE_URL_RE, link) match = re.match(YOUTUBE_URL_RE, link)
@ -370,16 +377,17 @@ def reset_row(ident, editor=None):
@argh.arg('--host', help='Address or socket server will listen to. Default is 0.0.0.0 (everything on the local machine).') @argh.arg('--host', help='Address or socket server will listen to. Default is 0.0.0.0 (everything on the local machine).')
@argh.arg('--port', help='Port server will listen on. Default is 8004.') @argh.arg('--port', help='Port server will listen on. Default is 8004.')
@argh.arg('connection-string', help='Postgres connection string, which is either a space-separated list of key=value pairs, or a URI like: postgresql://USER:PASSWORD@HOST/DBNAME?KEY=VALUE') @argh.arg('connection-string', help='Postgres connection string, which is either a space-separated list of key=value pairs, or a URI like: postgresql://USER:PASSWORD@HOST/DBNAME?KEY=VALUE')
@argh.arg('default-channel', help='The default channel this instance will serve events for') @argh.arg('default-channel', help='The default video_channel sent to the editor and assumed if not given on write')
@argh.arg('bustime-start', help='The start time in UTC for the event, for UTC-Bustime conversion') @argh.arg('bustime-start', help='The start time in UTC for the event, for UTC-Bustime conversion')
@argh.arg('--backdoor-port', help='Port for gevent.backdoor access. By default disabled.') @argh.arg('--backdoor-port', help='Port for gevent.backdoor access. By default disabled.')
@argh.arg('--no-authentication', help='Do not authenticate') @argh.arg('--no-authentication', help='Bypass authentication (act as though all calls are authenticated)')
@argh.arg('--title-header', help='A header to prefix all titles with, seperated from the submitted title by " - "') @argh.arg('--title-header', help='A header to prefix all titles with, seperated from the submitted title by " - "')
@argh.arg('--description-footer', help='A footer to suffix all descriptions with, seperated from the submitted description by a blank line.') @argh.arg('--description-footer', help='A footer to suffix all descriptions with, seperated from the submitted description by a blank line.')
@argh.arg('--upload-locations', help='A comma-seperated list of valid upload locations, to pass to thrimbletrimmer. The first is the default. Note this is NOT validated on write.') @argh.arg('--upload-locations', help='A comma-seperated list of valid upload locations, to pass to thrimbletrimmer. The first is the default. Note this is NOT validated on write.')
def main(connection_string, default_channel, bustime_start, host='0.0.0.0', port=8004, backdoor_port=0, def main(
no_authentication=False, title_header=None, description_footer=None, upload_locations=''): connection_string, default_channel, bustime_start, host='0.0.0.0', port=8004, backdoor_port=0,
"""Thrimshim service.""" no_authentication=False, title_header=None, description_footer=None, upload_locations='',
):
server = WSGIServer((host, port), cors(app)) server = WSGIServer((host, port), cors(app))
app.no_authentication = no_authentication app.no_authentication = no_authentication

Loading…
Cancel
Save