thrimshim changes for modified

would be ideal to check all args to see if any don't match (and refuse to modify in that case)
but eh too much work to properly normalise.
pull/295/head
Mike Lang 3 years ago committed by Mike Lang
parent c4a1d72240
commit f06be1f391

@ -163,3 +163,4 @@ columns | type | role
`editor` | `TEXT` | state | Email address of the last editor; corresponds to an entry in the `editors` table. Only set when state is not `UNEDITED`. `editor` | `TEXT` | state | Email address of the last editor; corresponds to an entry in the `editors` table. Only set when state is not `UNEDITED`.
`edit_time` | `TIMESTAMP` | state | Time of the last edit. Only set when state is not `UNEDITED`. `edit_time` | `TIMESTAMP` | state | Time of the last edit. Only set when state is not `UNEDITED`.
`upload_time` | `TIMESTAMP` | state | Time when video state is set to `DONE`. Only set when state is `DONE`. `upload_time` | `TIMESTAMP` | state | Time when video state is set to `DONE`. Only set when state is `DONE`.
`last_modified` | `TIMESTAMP` | state | Time when video state was last set to `MODIFIED`, or NULL if it has never been. Only used for diagnostics.

@ -3,8 +3,6 @@ from functools import wraps
import json import json
import logging import logging
import re import re
import signal
import sys
import argh import argh
import flask import flask
@ -213,6 +211,12 @@ def update_row(ident, editor=None):
'sheet_name', 'event_start', 'event_end', 'sheet_name', 'event_start', 'event_end',
'category', 'description', 'notes', 'tags', 'category', 'description', 'notes', 'tags',
] ]
# These columns may be modified when a video is in state 'DONE',
# and are a subset of edit_columns.
modifiable_columns = [
'video_title', 'video_description', 'video_tags',
]
assert set(modifiable_columns) - set(edit_columns) == set()
# 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)
@ -274,7 +278,10 @@ def update_row(ident, editor=None):
return 'Row {} not found'.format(ident), 404 return 'Row {} not found'.format(ident), 404
assert old_row['id'] == ident assert old_row['id'] == ident
if old_row['state'] not in ['UNEDITED', 'EDITED', 'CLAIMED']: if new_row['state'] == 'MODIFIED':
if old_row['state'] not in ['DONE', 'MODIFIED']:
return 'Video is in state {} and cannot be modified'.format(old_row['state']), 403
elif old_row['state'] not in ['UNEDITED', 'EDITED', 'CLAIMED']:
return 'Video already published', 403 return 'Video already published', 403
# check whether row has been changed in the sheet since editing has begun # check whether row has been changed in the sheet since editing has begun
@ -293,39 +300,60 @@ def update_row(ident, editor=None):
if changes and not override_changes: if changes and not override_changes:
return 'Sheet columns have changed since editing has begun. Please review changes\n' + changes, 409 return 'Sheet columns have changed since editing has begun. Please review changes\n' + changes, 409
# handle state columns if new_row['state'] == 'MODIFIED':
if new_row['state'] == 'EDITED': # Modifying published rows is more limited, we ignore all other fields.
missing = [] for column in set(modifiable_columns) & set(non_null_columns):
for column in non_null_columns:
if new_row[column] is None: if new_row[column] is None:
missing.append(column) missing.append(column)
if missing: if missing:
return 'Fields {} must be non-null for video to be cut'.format(', '.join(missing)), 400 return 'Fields {} must be non-null for modified video'.format(', '.join(missing)), 400
if len(new_row.get('video_title', '')) <= len(app.title_header): build_query = sql.SQL("""
return 'Video title must not be blank', 400 UPDATE events
if len(new_row.get('video_description', '')) <= len(app.description_footer): SET last_modified = NOW(), error = NULL, state = 'MODIFIED', {}
return 'Video description must not be blank. If you have nothing else to say, just repeat the title.', 400 WHERE id = %(id)s AND state IN ('DONE', 'MODIFIED')
elif new_row['state'] != 'UNEDITED': """).format(sql.SQL(", ").join(
return 'Invalid state {}'.format(new_row['state']), 400 sql.SQL("{} = {}").format(
new_row['uploader'] = None sql.Identifier(column), database.get_column_placeholder(column),
new_row['error'] = None ) for column in modifiable_columns
new_row['editor'] = editor ))
new_row['edit_time'] = datetime.datetime.utcnow() result = database.query(conn, build_query, id=ident, **new_row)
if result.rowcount != 1:
# actually update database return 'Video changed state while we were updating - maybe it was reset?', 403
build_query = sql.SQL("""
UPDATE events else:
SET {} # handle state columns
WHERE id = %(id)s if new_row['state'] == 'EDITED':
AND state IN ('UNEDITED', 'EDITED', 'CLAIMED')""" missing = []
for column in non_null_columns:
if new_row[column] is None:
missing.append(column)
if missing:
return 'Fields {} must be non-null for video to be cut'.format(', '.join(missing)), 400
if len(new_row.get('video_title', '')) <= len(app.title_header):
return 'Video title must not be blank', 400
if len(new_row.get('video_description', '')) <= len(app.description_footer):
return 'Video description must not be blank. If you have nothing else to say, just repeat the title.', 400
elif new_row['state'] != 'UNEDITED':
return 'Invalid state {}'.format(new_row['state']), 400
new_row['uploader'] = None
new_row['error'] = None
new_row['editor'] = editor
new_row['edit_time'] = datetime.datetime.utcnow()
# actually update database
build_query = sql.SQL("""
UPDATE events
SET {}
WHERE id = %(id)s
AND state IN ('UNEDITED', 'EDITED', 'CLAIMED')"""
).format(sql.SQL(", ").join( ).format(sql.SQL(", ").join(
sql.SQL("{} = {}").format( sql.SQL("{} = {}").format(
sql.Identifier(column), database.get_column_placeholder(column), sql.Identifier(column), database.get_column_placeholder(column),
) for column in new_row.keys() if column not in sheet_columns ) for column in new_row.keys() if column not in sheet_columns
)) ))
result = database.query(conn, build_query, id=ident, **new_row) result = database.query(conn, build_query, id=ident, **new_row)
if result.rowcount != 1: if result.rowcount != 1:
return 'Video likely already published', 403 return 'Video likely already published', 403
logging.info('Row {} updated to state {}'.format(ident, new_row['state'])) logging.info('Row {} updated to state {}'.format(ident, new_row['state']))
return '' return ''
@ -386,7 +414,8 @@ def reset_row(ident, editor=None):
query = """ query = """
UPDATE events UPDATE events
SET state='UNEDITED', error = NULL, video_id = NULL, video_link = NULL, SET state='UNEDITED', error = NULL, video_id = NULL, video_link = NULL,
uploader = NULL, editor = NULL, edit_time = NULL, upload_time = NULL uploader = NULL, editor = NULL, edit_time = NULL, upload_time = NULL,
last_modified = NULL
WHERE id = %s {} WHERE id = %s {}
""".format( """.format(
"" if force else "AND state IN ('UNEDITED', 'EDITED', 'CLAIMED')", "" if force else "AND state IN ('UNEDITED', 'EDITED', 'CLAIMED')",

Loading…
Cancel
Save