def test_add_task_invalidates_video_cache(self): team_video = TeamVideoFactory() with assert_invalidates_model_cache(team_video.video): task = Task(team=team_video.team, team_video=team_video, language='en', type=Task.TYPE_IDS['Translate']) task.save(update_team_video_index=False)
def _create_necessary_tasks(version, team_video, workflow, committer, complete): """Create any necessary tasks for the newly added version. By the time we call this function we know that: * There are no existing open tasks for this version/language. * The committer cannot bypass moderation. So we may (or may not) need to create a task for this version/language. """ from teams.models import Task if complete: # If the subtitles are complete, then the new task will be either # a review or approve, depending on the team. if workflow.review_allowed: task_type = Task.TYPE_IDS['Review'] elif workflow.approve_allowed: task_type = Task.TYPE_IDS['Approve'] else: # Note that we may not have selected either of these, if the team # does not require review or approval. That's okay, we're done in # that case. return else: # Otherwise the new task will be a subtitle or translate, depending # on the type of subs. # TODO: More advanced logic here? if version.subtitle_language.is_primary_audio_language(): task_type = Task.TYPE_IDS['Subtitle'] else: task_type = Task.TYPE_IDS['Translate'] # We now know the type of task we need to create, so go ahead and make it. task = Task(team=team_video.team, team_video=team_video, language=version.language_code, type=task_type, new_subtitle_version=version) # Assign it to the correct user. if task.get_type_display() in ('Subtitle', 'Translate'): # If it's a subtitle/translate task, then someone just added # some incomplete subtitles. We'll assign it to them by # default. task.assignee = committer else: # Otherwise it's a review/approve task, so we'll see if anyone # has reviewed or approved this before. If so, assign it back # to them. Otherwise just leave it unassigned. task.assignee = task._find_previous_assignee(task.get_type_display()) task.save()
def _create_review_or_approve_task(self, subtitle_version): team_video = subtitle_version.video.get_team_video() lang = subtitle_version.subtitle_language.language_code workflow = Workflow.get_for_team_video(team_video) if workflow.review_allowed: type = Task.TYPE_IDS['Review'] can_do = partial(can_review, allow_own=True) elif workflow.approve_allowed: type = Task.TYPE_IDS['Approve'] can_do = can_approve else: return None # TODO: Dedupe this and Task._find_previous_assignee # Find the assignee. # # For now, we'll assign the review/approval task to whomever did # it last time (if it was indeed done), but only if they're # still eligible to perform it now. last_task = team_video.task_set.complete().filter( language=lang, type=type).order_by('-completed')[:1] assignee = None if last_task: candidate = last_task[0].assignee if candidate and can_do(team_video, candidate, lang): assignee = candidate task = Task(team=team_video.team, team_video=team_video, assignee=assignee, language=lang, type=type) task.set_expiration() task.new_subtitle_version = subtitle_version if task.get_type_display() in ['Review', 'Approve']: task.new_review_base_version = subtitle_version task.save()
def _moderate_incomplete_version(self, subtitle_version, user): """ Verifies if it's possible to create a transcribe/translate task (if there's no other transcribe/translate task) and tries to assign to user. Also, if the video belongs to a team, change its status. """ team_video = subtitle_version.video.get_team_video() if not team_video: return language = subtitle_version.language.language # if there's any incomplete task, we can't create yet another. transcribe_task = team_video.task_set.incomplete().filter( language=language) if transcribe_task.exists(): return subtitle_version.moderation_status = WAITING_MODERATION subtitle_version.save() if subtitle_version.is_dependent(): task_type = Task.TYPE_IDS['Translate'] can_do = can_create_and_edit_translations else: task_type = Task.TYPE_IDS['Subtitle'] can_do = can_create_and_edit_subtitles task = Task(team=team_video.team, team_video=team_video, language=language, type=task_type) if can_do(user, team_video): task.assignee = user task.save()
def test_translation_tasks_not_blocked(self): # test that translation tasks are not blocked if the admin unpublishes # the version # make a translation task task = Task(team=self.team, team_video=self.team_video, assignee=self.user, type=Task.TYPE_IDS['Translate'], language='ru') task.save() # complete the translation task to create an approval task lang = self.make_dependent_language('ru', self.versions[-1]) task.new_subtitle_version = lang.get_tip() approve_task = task.complete() # complete the parent subtitles language, so that that's not an issue # for is_blocked(). self.language.subtitles_complete = True self.language.save() # unpublish the last version and check that that doesn't block the # approval task self.versions[-1].visibility_override = 'private' self.versions[-1].save() self.assertEquals(approve_task.is_blocked(), False)
def test_can_create_task_subtitle(self): team, user, outsider = self.team, self.user, self.outsider # When no subtitles exist yet, it depends on the team's task creation # policy. self.assertTrue(can_create_task_subtitle(self.nonproject_video)) # Any team member. team.task_assign_policy = Team.TASK_ASSIGN_IDS['Any team member'] team.save() for r in [ROLE_CONTRIBUTOR, ROLE_MANAGER, ROLE_ADMIN, ROLE_OWNER]: with self.role(r): self.assertTrue( can_create_task_subtitle(self.nonproject_video, user)) self.assertFalse( can_create_task_subtitle(self.nonproject_video, outsider)) # Manager+ team.task_assign_policy = Team.TASK_ASSIGN_IDS['Managers and admins'] team.save() for r in [ROLE_MANAGER, ROLE_ADMIN, ROLE_OWNER]: with self.role(r): self.assertTrue( can_create_task_subtitle(self.nonproject_video, user)) for r in [ROLE_CONTRIBUTOR]: with self.role(r): self.assertFalse( can_create_task_subtitle(self.nonproject_video, user)) for r in [ROLE_MANAGER, ROLE_ADMIN]: with self.role(r, self.test_project): self.assertFalse( can_create_task_subtitle(self.nonproject_video, user)) self.assertFalse( can_create_task_subtitle(self.nonproject_video, outsider)) # Admin+ team.task_assign_policy = Team.TASK_ASSIGN_IDS['Admins only'] team.save() for r in [ROLE_ADMIN, ROLE_OWNER]: with self.role(r): self.assertTrue( can_create_task_subtitle(self.nonproject_video, user)) for r in [ROLE_CONTRIBUTOR, ROLE_MANAGER]: with self.role(r): self.assertFalse( can_create_task_subtitle(self.nonproject_video, user)) for r in [ROLE_ADMIN]: with self.role(r, self.test_project): self.assertFalse( can_create_task_subtitle(self.nonproject_video, user)) self.assertFalse( can_create_task_subtitle(self.nonproject_video, outsider)) # Once a subtitle task exists, no one can create another. team.task_assign_policy = Team.TASK_ASSIGN_IDS['Any team member'] team.save() t = Task(type=Task.TYPE_IDS['Subtitle'], team=team, team_video=self.nonproject_video) t.save() for r in [ROLE_CONTRIBUTOR, ROLE_MANAGER, ROLE_ADMIN, ROLE_OWNER]: with self.role(r): self.assertFalse( can_create_task_subtitle(self.nonproject_video, user)) # Even if it's completed. t.completed = datetime.datetime.now() t.save() for r in [ROLE_CONTRIBUTOR, ROLE_MANAGER, ROLE_ADMIN, ROLE_OWNER]: with self.role(r): self.assertFalse( can_create_task_subtitle(self.nonproject_video, user)) # Unless it's deleted, of course. t.deleted = True t.save() for r in [ROLE_CONTRIBUTOR, ROLE_MANAGER, ROLE_ADMIN, ROLE_OWNER]: with self.role(r): self.assertTrue( can_create_task_subtitle(self.nonproject_video, user)) # Once subtitles exist, no one can create a new task. helpers._add_language_via_pipeline(self.nonproject_video.video, 'en') self.assertFalse(can_create_task_subtitle(self.nonproject_video)) for r in [ROLE_CONTRIBUTOR, ROLE_MANAGER, ROLE_ADMIN, ROLE_OWNER]: with self.role(r): self.assertFalse( can_create_task_subtitle(self.nonproject_video, user)) self.assertFalse( can_create_task_subtitle(self.nonproject_video, outsider))
def test_moderated_notifies_only_when_published(self): """ Set up a public team, add new video and new version. Notification should be sent. Setup a team with moderated videos """ from teams.moderation_const import WAITING_MODERATION, APPROVED def video_with_two_followers(): v, c = Video.get_or_create_for_url( "http://blip.tv/file/get/Miropcf-AboutUniversalSubtitles847.ogv" ) f1 = User.objects.all()[0] f2 = User.objects.all()[1] f1.notify_by_email = f2.notify_by_email = True f1.save() f2.save() v.followers.add(f1, f2) return v def new_version(v): language, created = SubtitleLanguage.objects.get_or_create( video=v, language='en', is_original=True) prev = language.version(public_only=False) version_no = 0 if prev: version_no = prev.version_no + 1 sv = SubtitleVersion(language=language, user=User.objects.all()[2], version_no=version_no, datetime_started=datetime.now()) sv.save() s = Subtitle(version=sv, subtitle_text=str(version_no + random.random()), subtitle_order=1, subtitle_id=str(version_no), start_time=random.random()) s.save() return sv v = video_with_two_followers() mail.outbox = [] from videos.tasks import video_changed_tasks v = video_with_two_followers() sv = new_version(v) video_changed_tasks(v.pk, sv.pk) # notifications are only sent on the second version of a video # as optimization sv = new_version(v) video_changed_tasks(v.pk, sv.pk) # video is public , followers should be notified self.assertEquals(len(mail.outbox), 2) mail.outbox = [] # add to a moderated video team = Team.objects.create(slug='my-team', name='myteam', workflow_enabled=True) workflow = Workflow(team=team, review_allowed=20, approve_allowed=20) workflow.save() tv = TeamVideo(team=team, video=v, added_by=User.objects.all()[2]) tv.save() sv = new_version(v) # with the widget, this would set up correctly sv.moderation_status = WAITING_MODERATION sv.save() video_changed_tasks(v.pk, sv.pk) sv = SubtitleVersion.objects.get(pk=sv.pk) self.assertFalse(sv.is_public) # approve video t = Task(type=40, approved=20, team_video=tv, team=team, language='en', subtitle_version=sv) t.save() t.complete() video_changed_tasks(v.pk, sv.pk) self.assertEqual(len(mail.outbox), 2)
def save_subtitles(self, parser, video=None, language=None, update_video=True, is_complete=True): video = video or self.cleaned_data['video'] if not video.has_original_language(): self._save_original_language(video, self.cleaned_data['video_language']) if language: self._sl_created = False language = language else: language, self._sl_created = self._find_appropriate_language( video, self.cleaned_data['language']) language = save_subtitle(video, language, parser, self.user, update_video) # If there are any outstanding tasks for this language, associate the # new version with them. team_video = video.get_team_video() if team_video: new_version = language.latest_version(public_only=False) # TODO: Refactor all of this out into some kind of generic "add subtitles" pipeline. # Determine if we need to moderate these subtitles and create a # review/approve task for them. workflow = team_video.get_workflow() # user can bypass moderation if: # 1) he is a moderator and # 2) it's a post-publish edit # 3) subtitle is complete can_bypass_moderation = (is_complete and not self._sl_created and can_publish_edits_immediately( team_video, self.user, language.language)) if can_bypass_moderation: new_version.moderate = APPROVED elif workflow.review_allowed or workflow.approve_allowed: new_version.moderation_status = WAITING_MODERATION else: new_version.moderation_status = UNMODERATED new_version.save() outstanding_tasks = team_video.task_set.incomplete().filter( language__in=[language.language, '']) if outstanding_tasks.exists(): if new_version.moderation_status != WAITING_MODERATION: outstanding_tasks.update(subtitle_version=new_version, language=language.language) elif not can_bypass_moderation: # we just need to create review/approve/subtitle if the language # is a new one or, if it's a post-publish edit, if the user can't # approve subtitles by himself. task_type = None if new_version.is_synced() and is_complete: if workflow.review_allowed: task_type = Task.TYPE_IDS['Review'] elif workflow.approve_allowed: task_type = Task.TYPE_IDS['Approve'] else: task_type = Task.TYPE_IDS['Subtitle'] if task_type: task = Task(team=team_video.team, team_video=team_video, language=language.language, type=task_type, subtitle_version=new_version) if not self._sl_created: task.assignee = task._find_previous_assignee( Task.TYPE_NAMES[task_type]) else: if task_type == Task.TYPE_IDS['Subtitle']: task.assignee = self.user task.save() return language