diff --git a/cutter/cutter/main.py b/cutter/cutter/main.py index 65dd889..6fee313 100644 --- a/cutter/cutter/main.py +++ b/cutter/cutter/main.py @@ -86,6 +86,10 @@ class CandidateGone(Exception): """Exception indicating a job candidate is no longer available""" +class JobCancelled(Exception): + """Exception indicating a job was cancelled by an operator after we had claimed it.""" + + class Cutter(object): NO_CANDIDATES_RETRY_INTERVAL = 1 ERROR_RETRY_INTERVAL = 5 @@ -125,7 +129,10 @@ class Cutter(object): self.claim_job(job) except CandidateGone: continue - self.cut_job(job) + try: + self.cut_job(job) + except JobCancelled: + self.logger.info("Job was cancelled while we were cutting it: {}".format(format_job(job))) def refresh_conn(self): """After errors, we reconnect in case the error was connection-related.""" @@ -332,6 +339,10 @@ class Cutter(object): )) result = query(self.conn, built_query, id=job.id, name=self.name, **kwargs) if result.rowcount != 1: + # If we hadn't yet set finalizing, then this means an operator cancelled the job + # while we were cutting it. This isn't a problem. + if not finalize_begun: + raise JobCancelled() raise JobConsistencyError("No job with id {} and uploader {} when setting: {}".format( job.id, self.name, ", ".join("{} = {!r}".format(k, v) for k, v in kwargs.items()) )) @@ -372,7 +383,7 @@ class Cutter(object): tags=self.tags + [job.category, job.sheet_name], data=upload_wrapper(), ) - except (JobConsistencyError, UploadError): + except (JobConsistencyError, JobCancelled, UploadError): raise # this ensures these aren't not caught in the except Exception block except Exception as ex: self.refresh_conn() diff --git a/thrimshim/thrimshim/main.py b/thrimshim/thrimshim/main.py index 41d5b2f..9eb188a 100644 --- a/thrimshim/thrimshim/main.py +++ b/thrimshim/thrimshim/main.py @@ -300,15 +300,24 @@ def manual_link(ident, editor=None): @request_stats @authenticate def reset_row(ident, editor=None): - """Clear state and video_link columns and reset state to 'UNEDITED'.""" + """Clear state and video_link columns and reset state to 'UNEDITED'. + If force is 'true', it will do so regardless of current state. + Otherwise, it will only do so if we know no video has been uploaded + (state is UNEDITED, EDITED or CLAIMED) + """ + force = (flask.request.args.get('force', '').lower() == "true") conn = app.db_manager.get_conn() - results = database.query(conn, """ + query = """ UPDATE events SET state='UNEDITED', error = NULL, video_id = NULL, video_link = NULL, uploader = NULL, editor = NULL, edit_time = NULL, upload_time = NULL - WHERE id = %s""", ident) + WHERE id = %s{} + """.format( + "" if force else " AND state IN ('UNEDITED', 'EDITED', 'CLAIMED')", + ) + results = database.query(conn, query, ident) if results.rowcount != 1: - return 'Row id = {} not found'.format(ident), 404 + return 'Row id = {} not found or not in cancellable state'.format(ident), 404 logging.info("Row {} reset to 'UNEDITED'".format(ident)) return ''