~launchpad-pqm/launchpad/devel

11626.3.7 by Curtis Hovey
Fixed copyright dates.
1
# Copyright 2009-2010 Canonical Ltd.  This software is licensed under the
8687.15.18 by Karl Fogel
Add the copyright header block to files under lib/canonical/.
2
# GNU Affero General Public License version 3 (see the file LICENSE).
4673.6.1 by Jeroen Vermeulen
Provide download of all translations for a productseries.
3
4
"""View class for requesting translation exports."""
5
6
__metaclass__ = type
7
__all__ = ['BaseExportView']
8
4767.9.26 by Carlos Perello Marin
Applied review comments
9
10315.2.1 by Jeroen Vermeulen
Show export queue status on export request pages.
10
from datetime import timedelta
11
4673.6.1 by Jeroen Vermeulen
Provide download of all translations for a productseries.
12
from zope.component import getUtility
13
14600.1.12 by Curtis Hovey
Move i18n to lp.
14
from lp import _
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
15
from canonical.launchpad.webapp import (
16
    canonical_url,
17
    LaunchpadView,
18
    )
11626.3.2 by Curtis Hovey
Move tales gto lp.app.
19
from lp.app.browser.tales import DurationFormatterAPI
11382.6.34 by Gavin Panella
Reformat imports in all files touched so far.
20
from lp.services.propertycache import cachedproperty
11882.1.1 by Jeroen Vermeulen
Independence for IHasTranslationTemplates\!
21
from lp.translations.interfaces.hastranslationtemplates import (
22
    IHasTranslationTemplates,
23
    )
14550.1.1 by Steve Kowalik
Run format-imports over lib/lp and lib/canonical/launchpad
24
from lp.translations.interfaces.poexportrequest import IPOExportRequestSet
8751.1.1 by Danilo Šegan
Store migration changes so far.
25
from lp.translations.interfaces.translationexporter import (
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
26
    ITranslationExporter,
27
    )
8751.1.1 by Danilo Šegan
Store migration changes so far.
28
from lp.translations.interfaces.translationfileformat import (
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
29
    TranslationFileFormat,
30
    )
4673.6.1 by Jeroen Vermeulen
Provide download of all translations for a productseries.
31
32
33
class BaseExportView(LaunchpadView):
34
    """Base class for PO export views."""
35
4767.9.26 by Carlos Perello Marin
Applied review comments
36
    @cachedproperty
37
    def uses_translations(self):
8778.3.1 by Jeroen Vermeulen
Ported from old branch, with lots of changes.
38
        return self.context.has_current_translation_templates
4767.9.26 by Carlos Perello Marin
Applied review comments
39
10315.2.1 by Jeroen Vermeulen
Show export queue status on export request pages.
40
    @property
41
    def export_queue_status(self):
42
        """Summary of queue status."""
43
        queue_size = self.request_set.entry_count
44
        estimated_backlog = self.request_set.estimateBacklog()
45
46
        size_text = self.describeQueueSize(queue_size)
47
        backlog_text = self.describeBacklog(estimated_backlog)
48
49
        return " ".join((size_text, backlog_text))
50
51
    def describeQueueSize(self, queue_size):
52
        """Return string describing the given queue size."""
53
        if queue_size == 0:
54
            return "The export queue is currently empty."
55
        elif queue_size == 1:
56
            return "There is 1 file request on the export queue."
57
        else:
58
            return (
59
                "There are %d file requests on the export queue."
60
                % queue_size)
61
62
    def describeBacklog(self, estimated_backlog):
63
        """Return string describing the current export backlog."""
10315.2.8 by Jeroen Vermeulen
Review chang.
64
        threshold = timedelta(minutes=10)
65
        if estimated_backlog is None or estimated_backlog < threshold:
10315.2.1 by Jeroen Vermeulen
Show export queue status on export request pages.
66
            return ""
67
68
        formatter = DurationFormatterAPI(estimated_backlog)
69
        time_string = formatter.approximateduration()
70
        return "The backlog is approximately %s." % time_string
71
4673.6.6 by Jeroen Vermeulen
Changes based on ongoing review.
72
    def getDefaultFormat(self):
8777.5.3 by Danilo Šegan
Some cleanups in BaseExport view.
73
        """Overridable: return default file format to use for the export."""
8777.5.1 by Danilo Šegan
Move shared methods into BaseExportView.
74
        if not IHasTranslationTemplates.providedBy(self.context):
75
            raise NotImplementedError(
76
                'Subclass not implementing `IHasTranslationsTemplates` '
77
                'interface.  Either override getDefaultFormat implementation '
78
                'or implement `IHasTranslationsTemplates`.')
79
80
        templates = self.context.getCurrentTranslationTemplates()
81
        if not bool(templates.any()):
82
            return None
12622.6.27 by Henning Eggers
Reintroduced shortlist.
83
        formats = self.context.getTranslationTemplateFormats()
8777.5.1 by Danilo Šegan
Move shared methods into BaseExportView.
84
        format = formats[0]
85
        if len(formats) > 1:
86
            self.request.response.addInfoNotification(
87
                "This package has templates with different native "
88
                "file formats.  If you proceed, all translations will be "
89
                "exported in the single format you specify.")
90
        return format
4673.6.6 by Jeroen Vermeulen
Changes based on ongoing review.
91
92
    def processForm(self):
8777.5.3 by Danilo Šegan
Some cleanups in BaseExport view.
93
        """Return templates and translations requested to be exported.
4673.6.6 by Jeroen Vermeulen
Changes based on ongoing review.
94
8777.5.3 by Danilo Šegan
Some cleanups in BaseExport view.
95
        Overridable in a child class.  Must do one of:
4673.6.6 by Jeroen Vermeulen
Changes based on ongoing review.
96
        a. Add an error notification to the page and return `None`
8777.5.6 by Danilo Šegan
Apply review Brad's comments.
97
        b. Return a tuple of two iterables or None, of requested templates
8816.1.2 by Danilo Šegan
Apply noodles' review comments.
98
           and of requested pofiles IDs.
4673.6.6 by Jeroen Vermeulen
Changes based on ongoing review.
99
        c. Redirect and return `None`.
100
        """
8777.5.3 by Danilo Šegan
Some cleanups in BaseExport view.
101
        if not IHasTranslationTemplates.providedBy(self.context):
102
            raise NotImplementedError(
103
                'Subclass not implementing `IHasTranslationsTemplates` '
104
                'interface.  Either override getDefaultFormat implementation '
105
                'or implement `IHasTranslationsTemplates`.')
106
8816.1.2 by Danilo Šegan
Apply noodles' review comments.
107
        translation_templates_ids = (
8816.1.1 by Danilo Šegan
Return a ResultSet over IDs instead of over full objects in BaseExportView.processForm.
108
            self.context.getCurrentTranslationTemplates(just_ids=True))
8816.1.2 by Danilo Šegan
Apply noodles' review comments.
109
        pofiles_ids = self.context.getCurrentTranslationFiles(just_ids=True)
110
        if not bool(pofiles_ids.any()):
111
            pofiles_ids = None
112
        return (translation_templates_ids, pofiles_ids)
4673.6.6 by Jeroen Vermeulen
Changes based on ongoing review.
113
7675.1015.19 by Henning Eggers
Fixed the bug.
114
    def getExportFormat(self):
115
        """Optional overridable: The requested export format."""
116
        return self.request.form.get("format")
7667.11.2 by Henning Eggers
PO export form completed.
117
4673.6.1 by Jeroen Vermeulen
Provide download of all translations for a productseries.
118
    def initialize(self):
119
        self.request_set = getUtility(IPOExportRequestSet)
4940.1.8 by Jeroen Vermeulen
Must initialize default_format even for POSTs.
120
121
        # Ask our derived class to figure out the default file format for this
122
        # export.  We do that here because the method may issue warnings,
123
        # which must be attached to our response early on.
124
        self.default_format = self.getDefaultFormat()
125
4673.6.6 by Jeroen Vermeulen
Changes based on ongoing review.
126
        if self.request.method != "POST":
127
            return
128
129
        bad_format_message = _("Please select a valid format for download.")
7675.1015.19 by Henning Eggers
Fixed the bug.
130
        format_name = self.getExportFormat()
4673.6.6 by Jeroen Vermeulen
Changes based on ongoing review.
131
        if format_name is None:
132
            self.request.response.addErrorNotification(bad_format_message)
133
            return
134
        try:
135
            format = TranslationFileFormat.items[format_name]
136
        except KeyError:
137
            self.request.response.addErrorNotification(bad_format_message)
138
            return
139
140
        requested_files = self.processForm()
141
        if requested_files is None:
142
            return
143
144
        templates, pofiles = requested_files
145
        if not templates and not pofiles:
146
            self.request.response.addErrorNotification(
147
                "Please select at least one translation or template.")
148
        else:
4940.1.9 by Jeroen Vermeulen
Cosmetic.
149
            self.request_set.addRequest(self.user, templates, pofiles, format)
4673.6.6 by Jeroen Vermeulen
Changes based on ongoing review.
150
            self.nextURL()
4673.6.1 by Jeroen Vermeulen
Provide download of all translations for a productseries.
151
152
    def nextURL(self):
153
        self.request.response.addInfoNotification(_(
154
            "Your request has been received. Expect to receive an email "
155
            "shortly."))
11388.1.11 by Tim Penhey
Yet more explicit translations references.
156
        self.request.response.redirect(
157
            canonical_url(self.context, rootsite='translations'))
4673.6.1 by Jeroen Vermeulen
Provide download of all translations for a productseries.
158
159
    def formats(self):
160
        """Return a list of formats available for translation exports."""
161
162
        class BrowserFormat:
11626.3.10 by Curtis Hovey
Hush lints epic complaints about the changes files.
163
4673.6.1 by Jeroen Vermeulen
Provide download of all translations for a productseries.
164
            def __init__(self, title, value, is_default=False):
165
                self.title = title
166
                self.value = value
167
                self.is_default = is_default
168
4769.2.17 by Danilo Šegan
Final review comments from Brad, Tom, Bjorn.
169
        translation_exporter = getUtility(ITranslationExporter)
170
        exporters = translation_exporter.getExportersForSupportedFileFormat(
4940.1.7 by Jeroen Vermeulen
Show warning if source package has translation templates in multiple formats.
171
            self.default_format)
4769.2.8 by Danilo Šegan
Fix supported formats.
172
        for exporter in exporters:
173
            format = exporter.format
4940.1.7 by Jeroen Vermeulen
Show warning if source package has translation templates in multiple formats.
174
            if format == self.default_format:
4769.2.11 by Danilo Šegan
Implemented review comments from Tom Berger.
175
                is_default = True
176
            else:
177
                is_default = False
4673.6.1 by Jeroen Vermeulen
Provide download of all translations for a productseries.
178
            yield BrowserFormat(format.title, format.name, is_default)