def test_view_entity_inplace_mode( member, resource_a, locale_a, ): """ Inplace mode of get_entites, should return all entities in a single batch. """ TranslatedResourceFactory.create(resource=resource_a, locale=locale_a) ProjectLocaleFactory.create(project=resource_a.project, locale=locale_a) entities = EntityFactory.create_batch(size=3, resource=resource_a) entities_pks = [e.pk for e in entities] response = member.client.post( '/get-entities/', { 'project': resource_a.project.slug, 'locale': locale_a.code, 'paths[]': [resource_a.path], 'inplace_editor': True, # Inplace mode shouldn't respect paging or limiting page 'limit': 1, }, HTTP_X_REQUESTED_WITH='XMLHttpRequest', ) assert response.status_code == 200 assert json.loads(response.content)["has_next"] is False assert ( sorted([e['pk'] for e in json.loads(response.content)['entities']]) == sorted(entities_pks) )
def test_view_translate_not_authed_public_project( client, locale_a, settings_debug, ): """ If the user is not authenticated and we're translating project ID 1, return a 200. """ project = ProjectFactory.create(slug='valid-project') ProjectLocaleFactory.create( project=project, locale=locale_a, ) resource = ResourceFactory.create( project=project, path='foo.lang', total_strings=1, ) TranslatedResourceFactory.create( resource=resource, locale=locale_a, ) response = client.get('/%s/%s/%s/' % (locale_a.code, project.slug, resource.path)) assert response.status_code == 200
def test_view_entity_inplace_mode( member, resource_a, locale_a, ): """ Inplace mode of get_entites, should return all entities in a single batch. """ TranslatedResourceFactory.create(resource=resource_a, locale=locale_a) ProjectLocaleFactory.create(project=resource_a.project, locale=locale_a) entities = EntityFactory.create_batch(size=3, resource=resource_a) entities_pks = [e.pk for e in entities] response = member.client.post( "/get-entities/", { "project": resource_a.project.slug, "locale": locale_a.code, "paths[]": [resource_a.path], "inplace_editor": True, # Inplace mode shouldn't respect paging or limiting page "limit": 1, }, HTTP_X_REQUESTED_WITH="XMLHttpRequest", ) assert response.status_code == 200 assert json.loads(response.content)["has_next"] is False assert sorted([e["pk"] for e in json.loads(response.content)["entities"] ]) == sorted(entities_pks)
def test_view_translate_not_authed_public_project( client, locale_a, settings_debug, ): """ If the user is not authenticated and we're translating project ID 1, return a 200. """ project = ProjectFactory.create(slug='valid-project') ProjectLocaleFactory.create( project=project, locale=locale_a, ) resource = ResourceFactory.create( project=project, path='foo.lang', total_strings=1, ) TranslatedResourceFactory.create( resource=resource, locale=locale_a, ) response = client.get( '/%s/%s/%s/' % (locale_a.code, project.slug, resource.path) ) assert response.status_code == 200
def test_projectlocale_latest_activity_no_latest(project_a, locale_a): """ If the matching ProjectLocale has no latest_translation, return None. """ ProjectLocaleFactory.create(project=project_a, locale=locale_a) assert ProjectLocale.get_latest_activity(project_a, locale_a) is None
def test_view_entity_inplace_mode( member, resource_a, locale_a, ): """ Inplace mode of get_entites, should return all entities in a single batch. """ TranslatedResourceFactory.create(resource=resource_a, locale=locale_a) ProjectLocaleFactory.create(project=resource_a.project, locale=locale_a) entities = EntityFactory.create_batch(size=3, resource=resource_a) entities_pks = [e.pk for e in entities] response = member.client.post( '/get-entities/', { 'project': resource_a.project.slug, 'locale': locale_a.code, 'paths[]': [resource_a.path], 'inplace_editor': True, # Inplace mode shouldn't respect paging or limiting page 'limit': 1, }, HTTP_X_REQUESTED_WITH='XMLHttpRequest', ) assert response.status_code == 200 assert json.loads(response.content)["has_next"] is False assert (sorted([e['pk'] for e in json.loads(response.content)['entities'] ]) == sorted(entities_pks))
def locale_parts(project_b, locale_c, locale_b): ProjectLocaleFactory.create(project=project_b, locale=locale_c) ProjectLocaleFactory.create(project=project_b, locale=locale_b) resourceX = ResourceFactory.create( project=project_b, path="resourceX.po", format="po", ) entityX = EntityFactory.create(resource=resourceX, string="entityX") resourceX.total_strings = 1 resourceX.save() TranslatedResourceFactory.create(locale=locale_c, resource=resourceX) return locale_c, locale_b, entityX
def test_view_entity_exclude_entities( member, resource_a, locale_a, ): """ Excluded entities shouldn't be returned by get_entities. """ TranslatedResource.objects.create(resource=resource_a, locale=locale_a) ProjectLocaleFactory.create(project=resource_a.project, locale=locale_a) entities = EntityFactory.create_batch(size=3, resource=resource_a) excluded_pk = entities[1].pk response = member.client.post( '/get-entities/', { 'project': resource_a.project.slug, 'locale': locale_a.code, 'paths[]': [resource_a.path], 'exclude_entities': [excluded_pk], 'limit': 1, }, HTTP_X_REQUESTED_WITH='XMLHttpRequest', ) assert response.status_code == 200 assert json.loads(response.content)["has_next"] is True assert ( [e['pk'] for e in json.loads(response.content)['entities']] != [excluded_pk] ) exclude_entities = ','.join(map( str, [ entities[2].pk, entities[1].pk, ] )) response = member.client.post( '/get-entities/', { 'project': resource_a.project.slug, 'locale': locale_a.code, 'paths[]': [resource_a.path], 'exclude_entities': exclude_entities, 'limit': 1, }, HTTP_X_REQUESTED_WITH='XMLHttpRequest', ) assert response.status_code == 200 assert json.loads(response.content)["has_next"] is False assert ( [e['pk'] for e in json.loads(response.content)['entities']] == [entities[0].pk] )
def test_repo_url_for_path(project_locale_a, repo_git, locale_b): """ Return the first locale_checkout_path for locales active for the repo's project that matches the given path. """ ProjectLocaleFactory.create( project=repo_git.project, locale=locale_b, ) repo_git.url = 'https://example.com/path/to/{locale_code}/' repo_git.save() assert (repo_git.url_for_path( os.path.join(repo_git.locale_checkout_path(project_locale_a.locale), 'foo/bar.po')) == 'https://example.com/path/to/%s/' % project_locale_a.locale.code)
def translation_dtd_unapproved(): translation = TranslationFactory.create( string='Test Translation', approved=False, entity__key='test', entity__resource__format='dtd', entity__resource__path='test.dtd', ) bulk_run_checks([translation]) ProjectLocaleFactory.create( project=translation.entity.resource.project, locale=translation.locale, ) yield translation
def test_translation_save_latest_update_for_system_project(locale_a, system_project_a): """ When a translation is saved for a system project, update the latest_translation attribute on the project, translatedresource and project_locale objects, but not on the locale object. """ project_locale = ProjectLocaleFactory.create( project=system_project_a, locale=locale_a, ) resource = ResourceFactory.create( project=system_project_a, path="resource.po", format="po", ) tr = TranslatedResourceFactory.create(locale=locale_a, resource=resource) entity = EntityFactory.create(resource=resource, string="Entity X") assert locale_a.latest_translation is None assert system_project_a.latest_translation is None assert tr.latest_translation is None assert project_locale.latest_translation is None translation = TranslationFactory.create( locale=locale_a, entity=entity, date=aware_datetime(1970, 1, 1), ) for i in [locale_a, system_project_a, project_locale, tr]: i.refresh_from_db() assert locale_a.latest_translation is None assert system_project_a.latest_translation == translation assert tr.latest_translation == translation assert project_locale.latest_translation == translation
def test_project_visible_for_users( users_permissions_group, user_a, public_project, private_project ): def get_permissions_group(obj, permissions_group): def _getattr(obj, permissions_group): return getattr(obj, permissions_group) return functools.reduce(_getattr, [obj] + permissions_group.split(".")) projects = Project.objects.visible_for(user_a).filter( pk__in=[public_project.pk, private_project.pk] ) assert list(projects) == [ public_project, ] # Make user_a a project translator private_project_locale = ProjectLocaleFactory.create( project=private_project, locale=LocaleFactory.create() ) get_permissions_group(private_project_locale, users_permissions_group).user_set.add( user_a ) projects = Project.objects.visible_for(user_a).filter( pk__in=[public_project.pk, private_project.pk] ) assert list(projects) == [public_project]
def test_view_entity_exclude_entities( member, resource_a, locale_a, ): """ Excluded entities shouldn't be returned by get_entities. """ TranslatedResource.objects.create(resource=resource_a, locale=locale_a) ProjectLocaleFactory.create(project=resource_a.project, locale=locale_a) entities = EntityFactory.create_batch(size=3, resource=resource_a) excluded_pk = entities[1].pk response = member.client.post( '/get-entities/', { 'project': resource_a.project.slug, 'locale': locale_a.code, 'paths[]': [resource_a.path], 'exclude_entities': [excluded_pk], 'limit': 1, }, HTTP_X_REQUESTED_WITH='XMLHttpRequest', ) assert response.status_code == 200 assert json.loads(response.content)["has_next"] is True assert ([e['pk'] for e in json.loads(response.content)['entities']] != [excluded_pk]) exclude_entities = ','.join(map(str, [ entities[2].pk, entities[1].pk, ])) response = member.client.post( '/get-entities/', { 'project': resource_a.project.slug, 'locale': locale_a.code, 'paths[]': [resource_a.path], 'exclude_entities': exclude_entities, 'limit': 1, }, HTTP_X_REQUESTED_WITH='XMLHttpRequest', ) assert response.status_code == 200 assert json.loads(response.content)["has_next"] is False assert ([e['pk'] for e in json.loads(response.content)['entities'] ] == [entities[0].pk])
def test_repo_pull_multi_locale(project_locale_a, repo_git, locale_b): """ If the repo is multi-locale, pull all of the repos for the active locales. """ locale_a = project_locale_a.locale ProjectLocaleFactory.create( project=repo_git.project, locale=locale_b, ) with patch('pontoon.base.models.update_from_vcs') as m_update_from_vcs: with patch('pontoon.base.models.get_revision') as m_get_revision: repo_git.url = 'https://example.com/{locale_code}/' repo_git.locale_url = ( lambda locale: 'https://example.com/%s' % locale.code ) repo_git.locale_checkout_path = ( lambda locale: '/media/%s' % locale.code ) # Return path as the revision so different locales return # different values. m_get_revision.side_effect = lambda type, path: path assert ( repo_git.pull() == { locale_a.code: '/media/%s' % locale_a.code, locale_b.code: '/media/%s' % locale_b.code, } ) assert ( m_update_from_vcs.call_args_list == [ call( 'git', 'https://example.com/%s' % locale_b.code, '/media/%s' % locale_b.code, '', ), call( 'git', 'https://example.com/%s' % locale_a.code, '/media/%s' % locale_a.code, '', ), ] )
def translation_dtd_unapproved(): translation = TranslationFactory.create( string="Test Translation", active=True, approved=False, entity__key="test", entity__resource__format="dtd", entity__resource__path="test.dtd", ) bulk_run_checks([translation]) ProjectLocaleFactory.create( project=translation.entity.resource.project, locale=translation.locale, ) yield translation
def translation_dtd_invalid_unapproved(): # Provide invalid characters in translation to cause checks to fail translation = TranslationFactory.create( string='!@#$""\'', approved=False, entity__key='test', entity__resource__format='dtd', entity__resource__path='test.dtd', ) bulk_run_checks([translation]) ProjectLocaleFactory.create( project=translation.entity.resource.project, locale=translation.locale, ) yield translation
def test_pretranslate(gt_mock, project_a, locale_a, resource_a, locale_b): project_a.pretranslation_enabled = True project_a.save() resources = [ ResourceFactory(project=project_a, path=x, format="po") for x in ["resource_x.po", "resource_y.po"] ] for i, x in enumerate(["abaa", "abac"]): EntityFactory.create(resource=resources[0], string=x, order=i) for i, x in enumerate(["aaab", "abab"]): EntityFactory.create(resource=resources[1], string=x, order=i) TranslatedResourceFactory.create(resource=resources[0], locale=locale_a) TranslatedResourceFactory.create(resource=resources[0], locale=locale_b) TranslatedResourceFactory.create(resource=resources[1], locale=locale_a) ProjectLocaleFactory.create( project=project_a, locale=locale_a, pretranslation_enabled=True, ) ProjectLocaleFactory.create( project=project_a, locale=locale_b, pretranslation_enabled=True, ) tm_user = User.objects.get(email="*****@*****.**") gt_mock.return_value = [("pretranslation", None, tm_user)] pretranslate(project_a.pk) project_a.refresh_from_db() translations = Translation.objects.filter(user=tm_user) # Total pretranslations = 2(tr_ax) + 2(tr_bx) + 2(tr_ay) assert len(translations) == 6 # pretranslated count == total pretranslations. assert project_a.pretranslated_strings == 6 # latest_translation belongs to pretranslations. assert project_a.latest_translation in translations
def test_view_entity_exclude_entities( member, resource_a, locale_a, ): """ Excluded entities shouldn't be returned by get_entities. """ TranslatedResource.objects.create(resource=resource_a, locale=locale_a) ProjectLocaleFactory.create(project=resource_a.project, locale=locale_a) entities = EntityFactory.create_batch(size=3, resource=resource_a) excluded_pk = entities[1].pk response = member.client.post( "/get-entities/", { "project": resource_a.project.slug, "locale": locale_a.code, "paths[]": [resource_a.path], "exclude_entities": [excluded_pk], "limit": 1, }, HTTP_X_REQUESTED_WITH="XMLHttpRequest", ) assert response.status_code == 200 assert json.loads(response.content)["has_next"] is True assert [e["pk"] for e in json.loads(response.content)["entities"] ] != [excluded_pk] exclude_entities = ",".join(map(str, [entities[2].pk, entities[1].pk])) response = member.client.post( "/get-entities/", { "project": resource_a.project.slug, "locale": locale_a.code, "paths[]": [resource_a.path], "exclude_entities": exclude_entities, "limit": 1, }, HTTP_X_REQUESTED_WITH="XMLHttpRequest", ) assert response.status_code == 200 assert json.loads(response.content)["has_next"] is False assert [e["pk"] for e in json.loads(response.content)["entities"] ] == [entities[0].pk]
def test_repo_url_for_path(project_locale_a, repo_git, locale_b): """ Return the first locale_checkout_path for locales active for the repo's project that matches the given path. """ ProjectLocaleFactory.create( project=repo_git.project, locale=locale_b, ) repo_git.url = 'https://example.com/path/to/{locale_code}/' repo_git.save() assert ( repo_git.url_for_path( os.path.join( repo_git.locale_checkout_path(project_locale_a.locale), 'foo/bar.po' ) ) == 'https://example.com/path/to/%s/' % project_locale_a.locale.code )
def test_project_needs_sync(project_a, project_b, locale_a): """ Project.needs_sync should be True if ChangedEntityLocale objects exist for its entities or if Project has unsynced locales. """ resource = ResourceFactory.create(project=project_a, path="resourceX.po") entity = EntityFactory.create(resource=resource, string="entityX") assert not project_a.needs_sync ChangedEntityLocaleFactory.create(entity=entity, locale=locale_a) assert project_a.needs_sync assert not project_b.needs_sync assert project_b.unsynced_locales == [] del project_b.unsynced_locales ProjectLocaleFactory.create( project=project_b, locale=locale_a, ) assert project_b.needs_sync == [locale_a]
def test_repo_pull_multi_locale(project_locale_a, repo_git, locale_b): """ If the repo is multi-locale, pull all of the repos for the active locales. """ locale_a = project_locale_a.locale ProjectLocaleFactory.create( project=repo_git.project, locale=locale_b, ) with patch("pontoon.sync.vcs.repositories.update_from_vcs" ) as m_update_from_vcs: with patch("pontoon.sync.vcs.repositories.get_revision" ) as m_get_revision: repo_git.url = "https://example.com/{locale_code}/" repo_git.locale_url = lambda locale: "https://example.com/%s" % locale.code repo_git.locale_checkout_path = lambda locale: "/media/%s" % locale.code # Return path as the revision so different locales return # different values. m_get_revision.side_effect = lambda type, path: path assert repo_git.pull() == { locale_a.code: "/media/%s" % locale_a.code, locale_b.code: "/media/%s" % locale_b.code, } assert m_update_from_vcs.call_args_list == [ call( "git", "https://example.com/%s" % locale_b.code, "/media/%s" % locale_b.code, "", ), call( "git", "https://example.com/%s" % locale_a.code, "/media/%s" % locale_a.code, "", ), ]
def test_projectlocale_translators_group(project_a, locale_a, user_a): """ Tests if user has permission to translate project at specific locale after assigment. """ project_locale = ProjectLocaleFactory.create( project=project_a, locale=locale_a, has_custom_translators=True, ) assert user_a.can_translate(locale=locale_a, project=project_a) is False user_a.groups.add(project_locale.translators_group) assert user_a.can_translate(locale=locale_a, project=project_a) is True project_locale.has_custom_translators = False project_locale.save() assert user_a.can_translate(locale=locale_a, project=project_a) is False
def test_translation_save_latest_update(locale_a, project_a): """ When a translation is saved, update the latest_translation attribute on the related project, locale, translatedresource, and project_locale objects. """ project_locale = ProjectLocaleFactory.create( project=project_a, locale=locale_a, ) resource = ResourceFactory.create( project=project_a, path="resource.po", format="po", ) tr = TranslatedResourceFactory.create(locale=locale_a, resource=resource) entity = EntityFactory.create(resource=resource, string="Entity X") assert locale_a.latest_translation is None assert project_a.latest_translation is None assert tr.latest_translation is None assert project_locale.latest_translation is None translation = TranslationFactory.create( locale=locale_a, entity=entity, date=aware_datetime(1970, 1, 1), ) locale_a.refresh_from_db() project_a.refresh_from_db() tr.refresh_from_db() project_locale.refresh_from_db() assert locale_a.latest_translation == translation assert project_a.latest_translation == translation assert tr.latest_translation == translation assert project_locale.latest_translation == translation # Ensure translation is replaced for newer translations newer_translation = TranslationFactory.create( locale=locale_a, entity=entity, date=aware_datetime(1970, 2, 1), ) locale_a.refresh_from_db() project_a.refresh_from_db() tr.refresh_from_db() project_locale.refresh_from_db() assert locale_a.latest_translation == newer_translation assert project_a.latest_translation == newer_translation assert tr.latest_translation == newer_translation assert project_locale.latest_translation == newer_translation # Ensure translation isn't replaced for older translations. TranslationFactory.create( locale=locale_a, entity=entity, date=aware_datetime(1970, 1, 5), ) locale_a.refresh_from_db() project_a.refresh_from_db() tr.refresh_from_db() project_locale.refresh_from_db() assert locale_a.latest_translation == newer_translation assert project_a.latest_translation == newer_translation assert tr.latest_translation == newer_translation assert project_locale.latest_translation == newer_translation # Ensure approved_date is taken into consideration as well. newer_approved_translation = TranslationFactory.create( locale=locale_a, entity=entity, approved_date=aware_datetime(1970, 3, 1), ) locale_a.refresh_from_db() project_a.refresh_from_db() tr.refresh_from_db() project_locale.refresh_from_db() assert locale_a.latest_translation == newer_approved_translation assert project_a.latest_translation == newer_approved_translation assert tr.latest_translation == newer_approved_translation assert project_locale.latest_translation == newer_approved_translation