def person_is_translator(self): """Is this person active in translations?""" if self.context.is_team: return False person = ITranslationsPerson(self.context) history = person.getTranslationHistory(self.history_horizon).any() return history is not None
def user_is_new_translator(self): """Is this user someone who has done no translation work yet?""" user = getUtility(ILaunchBag).user if user is not None: translationsperson = ITranslationsPerson(user) if not translationsperson.hasTranslated(): return True return False
def test_skips_translation_relicensing_agreements(self): person = self.factory.makePerson() translations_person = ITranslationsPerson(person) translations_person.translations_relicensing_agreement = True person_id = person.id account_id = person.account.id script = self.makeScript([six.ensure_str(person.name)]) with dbuser('launchpad'): self.runScript(script) self.assertRemoved(account_id, person_id) self.assertTrue(translations_person.translations_relicensing_agreement)
def _review_targets(self): """Query and aggregate the top targets for review. :return: a list of translation targets. Multiple `POFile`s may be aggregated together into a single target. """ person = ITranslationsPerson(self.context) pofiles = person.getReviewableTranslationFiles( no_older_than=self.history_horizon) return ReviewLinksAggregator().aggregate(pofiles)
def test_canTranslate(self): # A user who has declined the licensing agreement can't # translate. Someone who has agreed, or not made a decision # yet, can. user = self.factory.makePerson() translations_user = ITranslationsPerson(user) self.assertTrue(self.policy._canTranslate(user)) translations_user.translations_relicensing_agreement = True self.assertTrue(self.policy._canTranslate(user)) translations_user.translations_relicensing_agreement = False self.assertFalse(self.policy._canTranslate(user))
def _getTargetsForTranslation(self, max_fetch=None): """Get translation targets for this person to translate. Results are ordered from most to fewest untranslated messages. """ person = ITranslationsPerson(self.context) urgent_first = (max_fetch >= 0) pofiles = person.getTranslatableFiles( no_older_than=self.history_horizon, urgent_first=urgent_first) if max_fetch is not None: pofiles = pofiles[:abs(max_fetch)] return TranslateLinksAggregator().aggregate(pofiles)
def initialize(self): self.pofile = self.context translations_person = ITranslationsPerson(self.user, None) if (self.user is not None and translations_person.translations_relicensing_agreement is None): url = str(self.request.URL).decode('US-ASCII', 'replace') if self.request.get('QUERY_STRING', None): url = url + '?' + self.request['QUERY_STRING'] return self.request.response.redirect( canonical_url(self.user, view_name='+licensing', rootsite='translations') + '?' + urllib.urlencode({'back_to': url})) # The handling of errors is slightly tricky here. Because this # form displays multiple POMsgSetViews, we need to track the # various errors individually. This dictionary is keyed on # POTMsgSet; it's a slightly unusual key value but it will be # useful for doing display of only widgets with errors when we # do that. self.errors = {} self.translationmessage_views = [] # The batchnav's start should change when the user mutates a # filtered views of messages. self.start_offset = 0 self._initializeShowOption() super(POFileTranslateView, self).initialize()
def latest_activity(self): """Single latest translation activity by this person.""" translations_person = ITranslationsPerson(self.context) latest = list(translations_person.translation_history[:1]) if len(latest) == 0: return None else: return ActivityDescriptor(self.context, latest[0])
def access_level_description(self): """Must not be called when there's no translation group.""" if self.user is None: return ("You are not logged in. Please log in to work " "on translations.") translations_person = ITranslationsPerson(self.user) translations_contact_link = None if self.translation_team: translations_contact_link = PersonFormatterAPI( self.translation_team.translator).link(None) elif self.translation_group: translations_contact_link = PersonFormatterAPI( self.translation_group.owner).link(None) else: assert self.translation_group is not None, ( "Must not be called when there's no translation group.") if not translations_person.translations_relicensing_agreement: translation_license_url = PersonFormatterAPI( self.user).url( view_name='+licensing', rootsite='translations') return ("To make translations in Launchpad you need to " "agree with the " "<a href='%s'>Translations licensing</a>.") % ( translation_license_url) if len(self.pofiles) > 0: sample_pofile = self.pofiles[0] if sample_pofile.canEditTranslations(self.user): return "You can add and review translations." if sample_pofile.canAddSuggestions(self.user): return ("Your suggestions will be held for review by " "%s. If you need help, or your translations are " "not being reviewed, please get in touch with " "%s.") % ( translations_contact_link, translations_contact_link) permission = sample_pofile.translationpermission if permission == TranslationPermission.CLOSED: return ("These templates can be translated only by " "their managers.") if self.translation_team is None: return ("Since there is nobody to manage translation " "approvals into this language, you cannot add " "new suggestions. If you are interested in making " "translations, please contact %s.") % ( translations_contact_link) raise AssertionError( "BUG! Couldn't identify the user's access level for these " "translations.")
def test_checkSubmitConditions_rejects_license_decliners(self): # Users who have declined the relicensing agreement can't post # translations. decliner = self.factory.makePerson() ITranslationsPerson(decliner).translations_relicensing_agreement = ( False) with person_logged_in(decliner): view = self._makeView() self.assertRaises(UnexpectedFormData, view._checkSubmitConditions)
def _canTranslate(self, person): """Is `person` in a position to translate? Someone who has declined the translations relicensing agreement is not. Someone who hasn't decided on the agreement yet is, but may be redirected to a form to sign first. """ translations_person = ITranslationsPerson(person) agreement = translations_person.translations_relicensing_agreement return agreement is not False
def __call__(self, context): """See `IContextSourceBinder`.""" user = getUtility(ILaunchBag).user if user is not None and user.languages: translations_user = ITranslationsPerson(user) terms = [ SimpleTerm(language, language.code, language.displayname) for language in translations_user.translatable_languages] if terms: return SimpleVocabulary(terms) return getVocabularyRegistry().get(None, "TranslatableLanguage")
def translation_teams(self): translation_teams = [] for translation_team in self.context.translation_teams: # translation_team would be either a person or a team. translation_teams.append({ 'expert': translation_team, 'groups': ITranslationsPerson(translation_team).translation_groups, }) return translation_teams
def batchnav(self): """Iterate over person's translation_history.""" translations_person = ITranslationsPerson(self.context) batchnav = BatchNavigator(translations_person.translation_history, self.request) pofiletranslatorset = getUtility(IPOFileTranslatorSet) batch = batchnav.currentBatch() self._pofiletranslator_cache = ( pofiletranslatorset.prefetchPOFileTranslatorRelations(batch)) return batchnav
def initial_values(self): """Set the default value for the relicensing radio buttons.""" translations_person = ITranslationsPerson(self.context) # If the person has previously made a choice, we default to that. # Otherwise, we default to BSD, because that's what we'd prefer. if translations_person.translations_relicensing_agreement == False: default = TranslationRelicensingAgreementOptions.REMOVE else: default = TranslationRelicensingAgreementOptions.BSD return { "allow_relicensing": default, "back_to": self.request.get('back_to'), }
def submit_action(self, action, data): """Store person's decision about translations relicensing. The user's decision is stored through `ITranslationsPerson.translations_relicensing_agreement` which is backed by the TranslationRelicensingAgreement table. """ translations_person = ITranslationsPerson(self.context) allow_relicensing = data['allow_relicensing'] if allow_relicensing == TranslationRelicensingAgreementOptions.BSD: translations_person.translations_relicensing_agreement = True self.request.response.addInfoNotification( _("Thank you for BSD-licensing your translations.")) elif (allow_relicensing == TranslationRelicensingAgreementOptions.REMOVE): translations_person.translations_relicensing_agreement = False self.request.response.addInfoNotification( _("We respect your choice. " "Thanks for trying out Launchpad Translations.")) else: raise AssertionError("Unknown allow_relicensing value: %r" % allow_relicensing) self.next_url = self.getSafeRedirectURL(data['back_to'])
def submit_action(self, action, data): """Store person's decision about translations relicensing. The user's decision is stored through `ITranslationsPerson.translations_relicensing_agreement` which is backed by the TranslationRelicensingAgreement table. """ translations_person = ITranslationsPerson(self.context) allow_relicensing = data['allow_relicensing'] if allow_relicensing == TranslationRelicensingAgreementOptions.BSD: translations_person.translations_relicensing_agreement = True self.request.response.addInfoNotification(_( "Thank you for BSD-licensing your translations.")) elif (allow_relicensing == TranslationRelicensingAgreementOptions.REMOVE): translations_person.translations_relicensing_agreement = False self.request.response.addInfoNotification(_( "We respect your choice. " "Thanks for trying out Launchpad Translations.")) else: raise AssertionError( "Unknown allow_relicensing value: %r" % allow_relicensing) self.next_url = self.getSafeRedirectURL(data['back_to'])
def test_query_count(self): person = self.factory.makePerson() login_person(person) ITranslationsPerson(person).translations_relicensing_agreement = True product = self.factory.makeProduct(owner=person) product.translationpermission = TranslationPermission.OPEN pofile = self.factory.makePOFile( potemplate=self.factory.makePOTemplate( productseries=product.series[0])) pofile.potemplate.productseries.product potmsgsets = [ self.factory.makePOTMsgSet(pofile.potemplate) for i in range(10)] # Preload a few transaction-crossing caches that would give # extra queries to the first request. getUtility(ILaunchBag).time_zone getUtility(ILaunchpadCelebrities).ubuntu person.inTeam(getUtility(ILaunchpadCelebrities).admin) person.inTeam(getUtility(ILaunchpadCelebrities).rosetta_experts) def create_suggestions(): for potmsgset in potmsgsets: pot = self.factory.makePOTemplate() self.factory.makeCurrentTranslationMessage( potmsgset=self.factory.makePOTMsgSet( singular=potmsgset.msgid_singular.msgid, potemplate=pot), language=pofile.language, translations=[self.factory.getUniqueUnicode()]) # A suggestion only shows up if it's actually in a # POFile. self.factory.makePOFile( potemplate=pot, language=pofile.language) self.factory.makeSuggestion( pofile=pofile, potmsgset=potmsgset) # Ensure that these are valid suggestions. templateset = getUtility(IPOTemplateSet) templateset.wipeSuggestivePOTemplatesCache() templateset.populateSuggestivePOTemplatesCache() nb_objects = 2 recorder1, recorder2 = record_two_runs( lambda: create_initialized_view( pofile, '+translate', principal=person)(), create_suggestions, nb_objects) self.assertThat(recorder2, HasQueryCount.byEquality(recorder1))
def recent_activity(self): """Recent translation activity by this person. If the translation activity is associated with a project, we ensure that the project is active. """ all_entries = ITranslationsPerson(self.context).translation_history def is_active(entry): potemplate = entry.pofile.potemplate if potemplate is None: return True product = potemplate.product product_is_active = (product is None or (product.active and product.translations_usage == ServiceUsage.LAUNCHPAD)) return product_is_active active_entries = (entry for entry in all_entries if is_active(entry)) return [ ActivityDescriptor(self.context, entry) for entry in islice(active_entries, 10) ]
def person_is_reviewer(person): """Is `person` a translations reviewer?""" groups = ITranslationsPerson(person).translation_groups return groups.any() is not None
def test_hasTranslated(self): person = self.factory.makePerson() translationsperson = ITranslationsPerson(person) self.assertFalse(translationsperson.hasTranslated()) self.factory.makeSuggestion(translator=person) self.assertTrue(translationsperson.hasTranslated())
def translators(self): """Return translators a person is a member of.""" translations_person = ITranslationsPerson(self.context) return list(translations_person.translators)
def test_baseline(self): person = ITranslationsPerson(self.factory.makePerson()) self.assertTrue(verifyObject(ITranslationsPerson, person))
def _getReviewables(self, *args, **kwargs): """Shorthand for `self.person.getReviewableTranslationFiles`.""" person = ITranslationsPerson(self.person) return list(person.getReviewableTranslationFiles(*args, **kwargs))
def _getReviewables(self, *args, **kwargs): """Shorthand for `self.person.getReviewableTranslationFiles`.""" person = ITranslationsPerson(self.person) return list(person.getReviewableTranslationFiles( *args, **kwargs))