def make_approve_task(team_video, language_code, user): """Move a video through the tasks process to the approve stage, then return that task. assumptions: - there are no Tasks or SubtitleVersions for this video+language - approve is enabled for the team """ team = team_video.team assert team.get_workflow().approve_allowed != 0 task = Task(team=team, team_video=team_video, assignee=None, language=language_code, type=Task.TYPE_IDS['Translate']) task.save() v = pipeline.add_subtitles(team_video.video, language_code, None, complete=False, visibility='private') task.assignee = user task.new_subtitle_version = v task = task.complete() if task.type == Task.TYPE_IDS['Review']: task.assignee = user task.approved = Task.APPROVED_IDS['Approved'] return task.complete() else: # approve task return task
def test_delete_tasks(self): # Add a review task for the last SubtitleVersion Task(team=self.team, team_video=self.team_video, assignee=None, language=self.language.language_code, type=Task.TYPE_IDS['Review'], new_subtitle_version=self.versions[-1]).save() # add a completed review task for the one before that Task(team=self.team, team_video=self.team_video, assignee=None, language=self.language.language_code, type=Task.TYPE_IDS['Review'], approved=Task.APPROVED_IDS['Approved'], new_subtitle_version=self.versions[-1]).save() # add a task for another video, but with the same language other_team_video = test_factories.create_team_video( self.team, self.user) Task(team=self.team, team_video=other_team_video, assignee=None, language=self.language.language_code, type=Task.TYPE_IDS['Translate']).save() self.check_task_count(3) # deleting the language should delete both tasks for this video, but # not the task for the other video. self.language.nuke_language() self.check_task_count(1)
def test_sent_back(self): self.setup_team() # go through the subtitle task phase task = Task(team=self.team, team_video=self.team_video, language='en', type=Task.TYPE_IDS['Subtitle'], assignee=self.user) lang = self.add_completed_subtitles('en', [ (0, 1000, "Hello, ", { 'new_paragraph': True }), (1500, 2500, "World"), ], visibility='private') task.new_subtitle_version = lang.get_tip(public=False) review_task = task.complete() # have the video get sent back in the review phase self.assertEquals(review_task.type, Task.TYPE_IDS['Review']) review_task.assignee = self.user review_task.approved = Task.APPROVED_IDS['Rejected'] new_subtitle_task = review_task.complete() # now in the approval phase self.assertEquals(new_subtitle_task.type, Task.TYPE_IDS['Subtitle']) self.assertEquals( views.LanguageList(self.video).items, [ ('English', 'needs-review', ['original', 'needs editing' ], lang.get_absolute_url()), ])
def test_delete_translation_tasks(self): # We should delete translation tasks if there are no more languages # with public versions available. However, we should not delete # in-progress translation tasks, or review/approve tasks. Those can # continue alright with the forked language. # make a translation task Task(team=self.team, team_video=self.team_video, assignee=None, language='de', type=Task.TYPE_IDS['Translate']).save() # make an in-progress translation task v = pipeline.add_subtitles(self.video, 'ja', None, complete=False, visibility='private') Task(team=self.team, team_video=self.team_video, language='ja', type=Task.TYPE_IDS['Translate'], assignee=self.user, new_subtitle_version=v).save() # make review/approve tasks test_factories.make_review_task(self.team_video, 'es', self.user) test_factories.make_approve_task(self.team_video, 'sv', self.user) # check initial task counts translate_qs = Task.objects.incomplete_translate().filter( language='de') in_progress_qs = Task.objects.incomplete_translate().filter( language='ja') review_qs = Task.objects.incomplete_review().filter(language='es') approve_qs = Task.objects.incomplete_approve().filter(language='sv') self.assertEquals(translate_qs.count(), 1) self.assertEquals(in_progress_qs.count(), 1) self.assertEquals(review_qs.count(), 1) self.assertEquals(approve_qs.count(), 1) # make a second language. If we delete that language, we should still # keep translation tasks. other_lang_version = pipeline.add_subtitles(self.video, 'fr', None) other_lang_version.subtitle_language.nuke_language() self.assertEquals(translate_qs.count(), 1) self.assertEquals(in_progress_qs.count(), 1) self.assertEquals(review_qs.count(), 1) self.assertEquals(approve_qs.count(), 1) # but when we delete our original language, then there's no source # languages, so we should delete the translation task, but keep # in-progress translation tasks, as well as review tasks self.language.nuke_language() self.assertEquals(translate_qs.count(), 0) self.assertEquals(in_progress_qs.count(), 1) self.assertEquals(review_qs.count(), 1) self.assertEquals(approve_qs.count(), 1)
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 apps.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 make_review_task(team_video, language_code, user): """Move a video through the tasks process to the review stage, then return that task. assumptions: - there are no Tasks or SubtitleVersions for this video+language - review is enabled for the team """ team = team_video.team task = Task(team=team, team_video=team_video, assignee=None, language=language_code, type=Task.TYPE_IDS['Translate']) task.save() v = pipeline.add_subtitles(team_video.video, language_code, None, complete=False, visibility='private') task.assignee = user task.new_subtitle_version = v return task.complete()
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): # TODO: should this use the new visibility settings instead of the old # moderation stuff? """ 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 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): subs = [(0, 1000, 'Hello', {}), (2000, 5000, 'world.', {})] add_subtitles(v, 'en', subs, author=self.author, committer=self.author) subs = [(0, 1000, 'Hello', {}), (3000, 5000, 'world.', {})] return add_subtitles(v, 'en', subs, author=self.author, committer=self.author) 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 = sub_models.SubtitleVersion.objects.get(pk=sv.pk) self.assertFalse(sv.is_public()) # no emails should be sent before the video is approved self.assertEqual(len(mail.outbox), 0) # approve video t = Task(type=40, approved=20, team_video=tv, team=team, language='en', new_subtitle_version=sv, assignee=self.author) t.save() t.complete() self.assertTrue(sv.is_public()) video_changed_tasks(v.pk, sv.pk) # Once the video is approved, we should send out the # team-task-approved-published.html email and the # email_notification_non_editors.html to the author self.assertEqual(len(mail.outbox), 2)