def _rollback_to(video, language_code, version_number, rollback_author): sl = SubtitleLanguage.objects.get(video=video, language_code=language_code) current = sl.get_tip(full=True) target = sl.subtitleversion_set.full().get(version_number=version_number) # The new version is mostly a copy of the target. data = { 'video': target.video, 'language_code': target.language_code, 'subtitles': target.get_subtitles(), 'title': target.title, 'description': target.description, 'visibility_override': None, 'committer': None, 'created': None, 'action': None, 'note': target.note, 'metadata': target.get_metadata(), 'origin': ORIGIN_ROLLBACK, } # If any version in the history is public, then rollbacks should also result # in public versions. existing_versions = target.sibling_set.extant() data['visibility'] = ('public' if any(v.is_public() for v in existing_versions) else 'private') # The author of the rollback is distinct from the target's author. data['author'] = rollback_author # The new version is always simply a child of the current tip. data['parents'] = None # Finally, rollback versions have a special attribute to track them. data['rollback_of_version_number'] = version_number version = _add_subtitles(**data) # Rolling back to a version with a different number of subtitles needs to # fork the dependent translations. For now. Once the new UI is in place # this horrible "forking" crap is going away entirely. if current.subtitle_count != target.subtitle_count: _fork_dependents(version.subtitle_language) from teams.signals import api_subtitles_edited api_subtitles_edited.send(version) return version
def save_finished(self, request, user, session, subtitles, new_title=None, completed=None, forked=False, new_description=None, task_id=None, task_notes=None, task_approved=None, task_type=None, save_for_later=None): # TODO: lock all this in a transaction please! language = session.language new_version = self._get_new_version_for_save(subtitles, language, session, user, forked, new_title, new_description, save_for_later) language.release_writelock() self._update_language_attributes_for_save(language, completed) if new_version: video_changed_tasks.delay(language.video.id, new_version.id) api_subtitles_edited.send(new_version) else: video_changed_tasks.delay(language.video.id) api_video_edited.send(language.video) is_complete = language.is_complete or language.calculate_percent_done( ) == 100 user_message = self._get_user_message_for_save(user, language, is_complete) error = self._save_tasks_for_save(request, save_for_later, language, new_version, is_complete, task_id, task_type, task_notes, task_approved) if error: return error return {'response': 'ok', 'user_message': user_message}
def add_subtitles(video, language_code, subtitles, title=None, description=None, author=None, visibility=None, visibility_override=None, parents=None, committer=None, complete=None, created=None, note=None, origin=None, metadata=None, action=None, duration=None): """Add subtitles in the language to the video. It all starts here. This function is your main entry point to the subtitle pipeline. It runs in a transaction, so while it may fail the DB should be left in a consistent state. If you already have a transaction running you can use unsafe_add_subtitles to avoid dealing with nested transactions. You need to check writelocking yourself. For now. This may change in the future. Subtitles can be given as a SubtitleSet, or a list of (from_ms, to_ms, content) tuples, or a string containing a hunk of DXFP XML. Title and description should be strings, or can be omitted to set them to ''. If you want them to be set to the same thing as the previous version you need to pass it yourself. Author can be given as a CustomUser object. If omitted the author will be marked as anonymous. Visibility and visibility_override can be given as the strings 'public' or 'private', or omitted to use the defaults ('public' and '' respectively). Parents can be given as an iterable of parent identifiers. These can be SubtitleVersion objects, or integers representing primary keys of SubtitleVersions, or tuples of (language_code, version_number). Note that the previous version of the language (if any) will always be marked as a parent. Committer can be given as a CustomUser object. This should be the user actually performing the action of adding the subtitles. Permissions and such will be checked as if this user is adding them. If omitted, the permission checks will be skipped, as if a "superuser" were adding the subtitles. Complete is a deprecated param that is needed for the API. It alters how we handle the subtitles_complete attribute on the language. New code should use action instead. action can be given as an action string. If given, we will perform that action using the saved version. Created should be a datetime that will set the "created" date for the resulting version. If not given it will default to today. """ # complete and action do similar things. In _add_subtitles _add_subtitles # we only want to deal with action, not complete. this action = _calc_action_for_add_subtitles(video, language_code, author, complete, action) if action: visibility = action.subtitle_visibility with transaction.atomic(): subtitle_language = _get_language(video, language_code) subtitle_language.freeze() version = _add_subtitles(video, subtitle_language, subtitles, title, duration, description, author, visibility, visibility_override, parents, None, committer, created, note, origin, metadata, action) video.cache.invalidate() api_subtitles_edited.send(version) if action: action.perform(author, video, version.subtitle_language, version) subtitle_language.thaw() return version