~launchpad-pqm/launchpad/devel

7675.961.1 by Jeroen Vermeulen
ITranslationPolicy implementation mixin.
1
# Copyright 2010 Canonical Ltd.  This software is licensed under the
2
# GNU Affero General Public License version 3 (see the file LICENSE).
3
4
"""Translation access and sharing policy."""
5
6
__metaclass__ = type
7
__all__ = [
8
    'TranslationPolicyMixin',
9
    ]
10
11
from storm.expr import (
12
    And,
13
    LeftJoin,
14
    )
7675.961.3 by Jeroen Vermeulen
Reformatted imports.
15
from zope.component import getUtility
7675.961.1 by Jeroen Vermeulen
ITranslationPolicy implementation mixin.
16
13130.1.12 by Curtis Hovey
Sorted imports.
17
from canonical.launchpad.interfaces.lpstorm import IStore
13130.1.6 by Curtis Hovey
Move ILaunchpadCelebrity to lp.app.
18
from lp.app.interfaces.launchpad import ILaunchpadCelebrities
7675.961.1 by Jeroen Vermeulen
ITranslationPolicy implementation mixin.
19
from lp.registry.model.person import Person
7675.965.1 by Jeroen Vermeulen
Use ITranslationPolicy for access and sharing models.
20
from lp.translations.enums import TranslationPermission
7675.961.1 by Jeroen Vermeulen
ITranslationPolicy implementation mixin.
21
from lp.translations.interfaces.translationsperson import ITranslationsPerson
22
from lp.translations.model.translationgroup import TranslationGroup
23
from lp.translations.model.translator import Translator
24
25
7675.965.7 by Jeroen Vermeulen
Test fixes.
26
def has_translators(translators_list):
27
    """Did `getTranslators` find any translators?"""
28
    for group, translator, team in translators_list:
29
        if team is not None:
30
            return True
31
    return False
32
33
34
def is_in_one_of_translators(translators_list, person):
35
    """Is `person` a member of one of the entries in `getTranslators`?"""
36
    for group, translator, team in translators_list:
37
        if team is not None and person.inTeam(team):
38
            return True
39
    return False
40
41
7675.961.1 by Jeroen Vermeulen
ITranslationPolicy implementation mixin.
42
class TranslationPolicyMixin:
43
    """Implementation mixin for `ITranslationPolicy`."""
44
45
    def getInheritedTranslationPolicy(self):
46
        """Get any `ITranslationPolicy` objects that this one inherits.
47
48
        To be overridden by the implementing class.  A `Product` may
49
        inherit a policy from a `ProjectGroup` it's in.
50
        """
51
        return None
52
53
    def isTranslationsOwner(self, person):
54
        """Is `person` one of the owners of these translations?
55
56
        To be overridden by the implementing class if it grants special
57
        translation rights to certain people.
58
        """
59
        return False
60
61
    def _hasSpecialTranslationPrivileges(self, person):
62
        """Does this person have special translation editing rights here?"""
63
        celebs = getUtility(ILaunchpadCelebrities)
64
        return (
65
            person.inTeam(celebs.admin) or
66
            person.inTeam(celebs.rosetta_experts) or
67
            self.isTranslationsOwner(person))
68
69
    def _canTranslate(self, person):
70
        """Is `person` in a position to translate?
71
72
        Someone who has declined the translations relicensing agreement
73
        is not.  Someone who hasn't decided on the agreement yet is, but
74
        may be redirected to a form to sign first.
75
        """
76
        translations_person = ITranslationsPerson(person)
77
        agreement = translations_person.translations_relicensing_agreement
78
        return agreement is not False
79
80
    def getTranslationGroups(self):
81
        """See `ITranslationPolicy`."""
82
        inherited = self.getInheritedTranslationPolicy()
83
        if inherited is None:
84
            groups = []
85
        else:
86
            groups = inherited.getTranslationGroups()
87
        my_group = self.translationgroup
88
        if my_group is not None and my_group not in groups:
89
            groups.append(my_group)
90
        return groups
91
92
    def _getTranslator(self, translationgroup, language, store):
93
        """Retrieve one (TranslationGroup, Translator, Person) tuple."""
94
        translator_join = LeftJoin(Translator, And(
95
            Translator.translationgroupID == TranslationGroup.id,
96
            Translator.languageID == language.id))
97
        person_join = LeftJoin(
98
            Person, Person.id == Translator.translatorID)
99
100
        source = store.using(TranslationGroup, translator_join, person_join)
101
        return source.find(
102
            (TranslationGroup, Translator, Person),
103
            TranslationGroup.id == translationgroup.id).one()
104
105
    def getTranslators(self, language, store=None):
106
        """See `ITranslationPolicy`."""
107
        if store is None:
108
            store = IStore(TranslationGroup)
109
        return [
110
            self._getTranslator(group, language, store)
111
            for group in self.getTranslationGroups()]
112
113
    def getEffectiveTranslationPermission(self):
114
        """See `ITranslationPolicy`."""
115
        inherited = self.getInheritedTranslationPolicy()
116
        if inherited is None:
117
            return self.translationpermission
118
        else:
119
            return max([
120
                self.translationpermission,
121
                inherited.getEffectiveTranslationPermission()])
7675.965.1 by Jeroen Vermeulen
Use ITranslationPolicy for access and sharing models.
122
123
    def invitesTranslationEdits(self, person, language):
124
        """See `ITranslationPolicy`."""
125
        if person is None:
126
            return False
127
7675.965.5 by Jeroen Vermeulen
Test fixes.
128
        model = self.getEffectiveTranslationPermission()
7675.965.1 by Jeroen Vermeulen
Use ITranslationPolicy for access and sharing models.
129
        if model == TranslationPermission.OPEN:
130
            # Open permissions invite all contributions.
131
            return True
132
7675.965.4 by Jeroen Vermeulen
Testing fixes.
133
        translators = self.getTranslators(language)
7675.965.1 by Jeroen Vermeulen
Use ITranslationPolicy for access and sharing models.
134
        if model == TranslationPermission.STRUCTURED:
135
            # Structured permissions act like Open if no translators
136
            # have been assigned for the language.
7675.965.7 by Jeroen Vermeulen
Test fixes.
137
            if not has_translators(translators):
7675.965.1 by Jeroen Vermeulen
Use ITranslationPolicy for access and sharing models.
138
                return True
139
140
        # Translation-team members are always invited to edit.
7675.965.7 by Jeroen Vermeulen
Test fixes.
141
        return is_in_one_of_translators(translators, person)
7675.965.1 by Jeroen Vermeulen
Use ITranslationPolicy for access and sharing models.
142
143
    def invitesTranslationSuggestions(self, person, language):
144
        """See `ITranslationPolicy`."""
145
        if person is None:
146
            return False
147
7675.965.5 by Jeroen Vermeulen
Test fixes.
148
        model = self.getEffectiveTranslationPermission()
7675.965.1 by Jeroen Vermeulen
Use ITranslationPolicy for access and sharing models.
149
150
        # These models always invite suggestions from anyone.
151
        welcoming_models = [
152
            TranslationPermission.OPEN,
153
            TranslationPermission.STRUCTURED,
154
            ]
155
        if model in welcoming_models:
156
            return True
157
7675.965.4 by Jeroen Vermeulen
Testing fixes.
158
        translators = self.getTranslators(language)
7675.965.1 by Jeroen Vermeulen
Use ITranslationPolicy for access and sharing models.
159
        if model == TranslationPermission.RESTRICTED:
7675.965.7 by Jeroen Vermeulen
Test fixes.
160
            if has_translators(translators):
7675.965.1 by Jeroen Vermeulen
Use ITranslationPolicy for access and sharing models.
161
                # Restricted invites any user's suggestions as long as
162
                # there is a translation team to handle them.
163
                return True
164
165
        # Translation-team members are always invited to suggest.
7675.965.7 by Jeroen Vermeulen
Test fixes.
166
        return is_in_one_of_translators(translators, person)
7675.965.1 by Jeroen Vermeulen
Use ITranslationPolicy for access and sharing models.
167
168
    def allowsTranslationEdits(self, person, language):
169
        """See `ITranslationPolicy`."""
170
        if person is None:
171
            return False
172
        if self._hasSpecialTranslationPrivileges(person):
173
            return True
174
        return (
175
            self._canTranslate(person) and
176
            self.invitesTranslationEdits(person, language))
177
178
    def allowsTranslationSuggestions(self, person, language):
179
        """See `ITranslationPolicy`."""
180
        if person is None:
181
            return False
182
        if self._hasSpecialTranslationPrivileges(person):
183
            return True
184
        return (
185
            self._canTranslate(person) and
186
            self.invitesTranslationSuggestions(person, language))