~launchpad-pqm/launchpad/devel

14349.1.4 by Gavin Panella
Update copyright.
1
# Copyright 2009-2011 Canonical Ltd.  This software is licensed under the
8687.15.17 by Karl Fogel
Add the copyright header block to the rest of the files under lib/lp/.
2
# GNU Affero General Public License version 3 (see the file LICENSE).
3
5608.11.5 by Aaron Bentley
Make comment pages reachable
4
__metaclass__ = type
5
5608.11.12 by Aaron Bentley
Get reply-to URL working
6
__all__ = [
6334.6.36 by Aaron Bentley
Rename code review messages to code review comments
7
    'CodeReviewCommentAddView',
6602.1.1 by Tim Penhey
Some touchy feely changes to code review page.!
8
    'CodeReviewCommentContextMenu',
6998.1.1 by Tim Penhey
Update the primary contexts for branch merge proposals, branch subscriptions, code review comments, and bug branch links.
9
    'CodeReviewCommentPrimaryContext',
6334.6.36 by Aaron Bentley
Rename code review messages to code review comments
10
    'CodeReviewCommentSummary',
6602.1.2 by Tim Penhey
Javascript expansion of comments in main view.
11
    'CodeReviewCommentView',
8971.8.1 by Tim Penhey
Make the +reply and +comment views use the service/comment rendering.
12
    'CodeReviewDisplayComment',
5608.11.12 by Aaron Bentley
Get reply-to URL working
13
    ]
5608.11.11 by Aaron Bentley
Commit work-in-progress
14
8971.8.1 by Tim Penhey
Make the +reply and +comment views use the service/comment rendering.
15
from lazr.delegates import delegates
8559.4.2 by Aaron Bentley
Enable voting from comment fields.
16
from lazr.restful.interface import copy_field
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
17
from zope.app.form.browser import (
18
    DropdownWidget,
19
    TextAreaWidget,
20
    )
21
from zope.interface import (
22
    implements,
23
    Interface,
24
    )
25
from zope.schema import Text
6602.1.1 by Tim Penhey
Some touchy feely changes to code review page.!
26
14600.1.12 by Curtis Hovey
Move i18n to lp.
27
from lp import _
11929.9.1 by Tim Penhey
Move launchpadform into lp.app.browser.
28
from lp.app.browser.launchpadform import (
29
    action,
30
    custom_widget,
31
    LaunchpadFormView,
32
    )
8971.8.1 by Tim Penhey
Make the +reply and +comment views use the service/comment rendering.
33
from lp.code.interfaces.codereviewcomment import ICodeReviewComment
34
from lp.code.interfaces.codereviewvote import ICodeReviewVoteReference
35
from lp.services.comments.interfaces.conversation import IComment
14612.2.1 by William Grant
format-imports on lib/. So many imports.
36
from lp.services.config import config
14578.2.1 by William Grant
Move librarian stuff from canonical.launchpad to lp.services.librarian. canonical.librarian remains untouched.
37
from lp.services.librarian.interfaces import ILibraryFileAlias
14349.1.2 by Gavin Panella
Use get_property_cache() in places where it is now required.
38
from lp.services.propertycache import (
39
    cachedproperty,
40
    get_property_cache,
41
    )
14612.2.1 by William Grant
format-imports on lib/. So many imports.
42
from lp.services.webapp import (
43
    canonical_url,
44
    ContextMenu,
45
    LaunchpadView,
46
    Link,
47
    )
48
from lp.services.webapp.interfaces import IPrimaryContext
6998.1.1 by Tim Penhey
Update the primary contexts for branch merge proposals, branch subscriptions, code review comments, and bug branch links.
49
50
7675.831.1 by Michael Nelson
Fixed failing code tests that were rendering the default comment template.
51
class ICodeReviewDisplayComment(IComment, ICodeReviewComment):
52
    """Marker interface for displaying code review comments."""
53
54
8971.8.1 by Tim Penhey
Make the +reply and +comment views use the service/comment rendering.
55
class CodeReviewDisplayComment:
8971.8.2 by Tim Penhey
Make the code review comment +index use the service/comment rendering.
56
    """A code review comment or activity or both.
57
58
    The CodeReviewComment itself does not implement the IComment interface as
59
    this is purely a display interface, and doesn't make sense to have display
60
    only code in the model itself.
61
    """
8971.8.1 by Tim Penhey
Make the +reply and +comment views use the service/comment rendering.
62
7675.831.1 by Michael Nelson
Fixed failing code tests that were rendering the default comment template.
63
    implements(ICodeReviewDisplayComment)
8971.8.1 by Tim Penhey
Make the +reply and +comment views use the service/comment rendering.
64
65
    delegates(ICodeReviewComment, 'comment')
66
10272.1.2 by Aaron Bentley
Distinguish betwen comments on this proposal and superseded ones.
67
    def __init__(self, comment, from_superseded=False):
8971.8.1 by Tim Penhey
Make the +reply and +comment views use the service/comment rendering.
68
        self.comment = comment
14349.1.2 by Gavin Panella
Use get_property_cache() in places where it is now required.
69
        get_property_cache(self).has_body = bool(self.comment.message_body)
10272.1.4 by Aaron Bentley
Updates from review.
70
        self.has_footer = self.comment.vote is not None
8971.8.2 by Tim Penhey
Make the code review comment +index use the service/comment rendering.
71
        # The date attribute is used to sort the comments in the conversation.
8971.8.1 by Tim Penhey
Make the +reply and +comment views use the service/comment rendering.
72
        self.date = self.comment.message.datecreated
10272.1.2 by Aaron Bentley
Distinguish betwen comments on this proposal and superseded ones.
73
        self.from_superseded = from_superseded
8971.8.1 by Tim Penhey
Make the +reply and +comment views use the service/comment rendering.
74
10272.1.3 by Aaron Bentley
Properly style superseded, move text to footer.
75
    @property
10272.1.6 by Aaron Bentley
Updates from review.
76
    def extra_css_class(self):
10272.1.3 by Aaron Bentley
Properly style superseded, move text to footer.
77
        if self.from_superseded:
10272.1.6 by Aaron Bentley
Updates from review.
78
            return 'from-superseded'
10272.1.4 by Aaron Bentley
Updates from review.
79
        else:
80
            return ''
10272.1.3 by Aaron Bentley
Properly style superseded, move text to footer.
81
7675.820.23 by Michael Nelson
Updated code to provide IComment attributes on the display comment rather than the view.
82
    @cachedproperty
83
    def comment_author(self):
84
        """The author of the comment."""
85
        return self.comment.message.owner
86
87
    @cachedproperty
88
    def has_body(self):
89
        """Is there body text?"""
90
        return bool(self.body_text)
91
92
    @cachedproperty
93
    def body_text(self):
94
        """Get the body text for the message."""
95
        return self.comment.message_body
96
97
    @cachedproperty
98
    def comment_date(self):
99
        """The date of the comment."""
100
        return self.comment.message.datecreated
101
7675.820.24 by Michael Nelson
Tested interface for Code's display comment model.
102
    @cachedproperty
103
    def all_attachments(self):
104
        return self.comment.getAttachments()
105
106
    @cachedproperty
107
    def display_attachments(self):
108
        # Attachments to show.
109
        return [DiffAttachment(alias) for alias in self.all_attachments[0]]
110
111
    @cachedproperty
112
    def other_attachments(self):
113
        # Attachments to not show.
114
        return self.all_attachments[1]
115
8971.8.1 by Tim Penhey
Make the +reply and +comment views use the service/comment rendering.
116
6998.1.1 by Tim Penhey
Update the primary contexts for branch merge proposals, branch subscriptions, code review comments, and bug branch links.
117
class CodeReviewCommentPrimaryContext:
118
    """The primary context is the comment is that of the source branch."""
119
120
    implements(IPrimaryContext)
121
122
    def __init__(self, comment):
123
        self.context = IPrimaryContext(
124
            comment.branch_merge_proposal).context
6602.1.1 by Tim Penhey
Some touchy feely changes to code review page.!
125
126
127
class CodeReviewCommentContextMenu(ContextMenu):
128
    """Context menu for branches."""
129
130
    usedfor = ICodeReviewComment
131
    links = ['reply']
132
133
    def reply(self):
7055.6.17 by Tim Penhey
Fixed resubmit and link visibility.
134
        enabled = self.context.branch_merge_proposal.isMergable()
135
        return Link('+reply', 'Reply', icon='add', enabled=enabled)
5608.11.12 by Aaron Bentley
Get reply-to URL working
136
137
9795.3.1 by Tim Penhey
Add a DiffAttachment that knows how to decode itself.
138
class DiffAttachment:
139
    """An attachment that we are going to display."""
140
141
    implements(ILibraryFileAlias)
142
143
    delegates(ILibraryFileAlias, 'alias')
144
145
    def __init__(self, alias):
146
        self.alias = alias
147
148
    @cachedproperty
149
    def text(self):
150
        """Read the text out of the librarin."""
151
        self.alias.open()
152
        try:
153
            return self.alias.read(config.diff.max_read_size)
154
        finally:
155
            self.alias.close()
156
157
    @cachedproperty
158
    def diff_text(self):
159
        """Get the text and attempt to decode it."""
160
        try:
161
            diff = self.text.decode('utf-8')
162
        except UnicodeDecodeError:
163
            diff = self.text.decode('windows-1252', 'replace')
164
        # Strip off the trailing carriage returns.
165
        return diff.rstrip('\n')
166
167
6602.1.2 by Tim Penhey
Javascript expansion of comments in main view.
168
class CodeReviewCommentView(LaunchpadView):
169
    """Standard view of a CodeReviewComment"""
170
9209.1.6 by Tim Penhey
Move codereviewcomment-index to 3.0.
171
    page_title = "Code review comment"
172
8971.8.2 by Tim Penhey
Make the code review comment +index use the service/comment rendering.
173
    @cachedproperty
174
    def comment(self):
175
        """The decorated code review comment."""
176
        return CodeReviewDisplayComment(self.context)
8624.1.3 by Tim Penhey
Working but needs clean up.
177
14412.3.10 by mbp at canonical
Add meta description on code review comment page
178
    @property
179
    def page_description(self):
180
        return self.context.message_body
181
6602.1.2 by Tim Penhey
Javascript expansion of comments in main view.
182
    # Should the comment be shown in full?
183
    full_comment = True
184
    # Show comment expanders?
185
    show_expanders = False
186
7407.1.2 by Tim Penhey
Add attachment code.
187
188
class CodeReviewCommentSummary(CodeReviewCommentView):
6602.1.2 by Tim Penhey
Javascript expansion of comments in main view.
189
    """Summary view of a CodeReviewComment"""
5608.11.47 by Aaron Bentley
Change threaded view on BranchMergeProposal to a summarized form
190
6602.1.1 by Tim Penhey
Some touchy feely changes to code review page.!
191
    # How many lines do we show in the main view?
6602.1.2 by Tim Penhey
Javascript expansion of comments in main view.
192
    SHORT_MESSAGE_LENGTH = 3
193
194
    # Show comment expanders?
195
    show_expanders = True
196
197
    # Should the comment be shown in full?
198
    @property
199
    def full_comment(self):
200
        """Show the full comment if it is short."""
201
        return not self.is_long_message
6602.1.1 by Tim Penhey
Some touchy feely changes to code review page.!
202
203
    @cachedproperty
204
    def _comment_lines(self):
205
        return self.context.message.text_contents.splitlines()
206
207
    @property
208
    def is_long_message(self):
209
        return len(self._comment_lines) > self.SHORT_MESSAGE_LENGTH
210
211
    @property
212
    def message_summary(self):
7055.8.7 by Tim Penhey
Updates following review.
213
        """Return an elided message with the first X lines of the comment."""
7055.6.9 by Tim Penhey
Change the look of the code review comments.
214
        short_message = (
215
            '\n'.join(self._comment_lines[:self.SHORT_MESSAGE_LENGTH]))
216
        short_message += "..."
217
        return short_message
5608.11.12 by Aaron Bentley
Get reply-to URL working
218
219
6334.6.36 by Aaron Bentley
Rename code review messages to code review comments
220
class IEditCodeReviewComment(Interface):
221
    """Interface for use as a schema for CodeReviewComment forms."""
5608.11.26 by Aaron Bentley
Add page and link for creating CodeReviewMessage
222
8559.4.2 by Aaron Bentley
Enable voting from comment fields.
223
    vote = copy_field(ICodeReviewComment['vote'], required=False)
224
9656.1.4 by Nathan Handler
Wrap lines to resolve some make lint warnings
225
    review_type = copy_field(
226
        ICodeReviewVoteReference['review_type'],
9656.1.5 by Nathan Handler
Resolve one last make lint warning due to a line being too long
227
        description=u'Lowercase keywords describing the type of review you '
228
                     'are performing.')
8559.4.2 by Aaron Bentley
Enable voting from comment fields.
229
230
    comment = Text(title=_('Comment'), required=False)
5608.11.63 by Aaron Bentley
Shove support for vote_tag from the DB through to the templates
231
5608.11.23 by Aaron Bentley
Initial support for replying to comments
232
6334.6.36 by Aaron Bentley
Rename code review messages to code review comments
233
class CodeReviewCommentAddView(LaunchpadFormView):
234
    """View for adding a CodeReviewComment."""
5608.11.20 by Aaron Bentley
Break reply handling again
235
8559.4.17 by Aaron Bentley
Force no-value display name to -Select-.
236
    class MyDropWidget(DropdownWidget):
237
        "Override the default no-value display name to -Select-."
9935.2.5 by Tim Penhey
tweaks
238
        _messageNoValue = 'Comment only'
8559.4.17 by Aaron Bentley
Force no-value display name to -Select-.
239
6334.6.36 by Aaron Bentley
Rename code review messages to code review comments
240
    schema = IEditCodeReviewComment
5608.11.20 by Aaron Bentley
Break reply handling again
241
7316.6.1 by Paul Hummer
Fixed the font width issues in code reviews
242
    custom_widget('comment', TextAreaWidget, cssClass='codereviewcomment')
8559.4.17 by Aaron Bentley
Force no-value display name to -Select-.
243
    custom_widget('vote', MyDropWidget)
244
9209.1.7 by Tim Penhey
Code review reply view and template to 3.0.
245
    page_title = 'Reply to code review comment'
7316.6.1 by Paul Hummer
Fixed the font width issues in code reviews
246
5608.11.26 by Aaron Bentley
Add page and link for creating CodeReviewMessage
247
    @property
7573.2.7 by Paul Hummer
Added the ability to quote comments
248
    def initial_values(self):
7573.2.11 by Paul Hummer
Responded to Michael's review
249
        """The initial values are used to populate the form fields.
250
8037.2.1 by Brad Crittenden
fixed annoying typos
251
        In this case, the default value of the comment should be the
7573.2.11 by Paul Hummer
Responded to Michael's review
252
        quoted comment being replied to.
253
        """
8040.1.1 by Tim Penhey
Fix the quoting of messages.
254
        if self.is_reply:
9742.8.1 by Aaron Bentley
Paste quoted text when reply is clicked.
255
            comment = self.reply_to.as_quoted_email
7573.2.7 by Paul Hummer
Added the ability to quote comments
256
        else:
257
            comment = ''
258
        return {'comment': comment}
259
260
    @property
5608.11.26 by Aaron Bentley
Add page and link for creating CodeReviewMessage
261
    def is_reply(self):
6334.6.36 by Aaron Bentley
Rename code review messages to code review comments
262
        """True if this comment is a reply to another comment, else False."""
263
        return ICodeReviewComment.providedBy(self.context)
5608.11.26 by Aaron Bentley
Add page and link for creating CodeReviewMessage
264
5608.11.27 by Aaron Bentley
Get new comments working
265
    @property
266
    def branch_merge_proposal(self):
5608.15.7 by Aaron Bentley
Cleanups
267
        """The BranchMergeProposal being commented on."""
5608.11.27 by Aaron Bentley
Get new comments working
268
        if self.is_reply:
269
            return self.context.branch_merge_proposal
270
        else:
271
            return self.context
272
8971.8.1 by Tim Penhey
Make the +reply and +comment views use the service/comment rendering.
273
    @cachedproperty
5608.11.27 by Aaron Bentley
Get new comments working
274
    def reply_to(self):
6334.6.36 by Aaron Bentley
Rename code review messages to code review comments
275
        """The comment being replied to, or None."""
5608.11.27 by Aaron Bentley
Get new comments working
276
        if self.is_reply:
8971.8.1 by Tim Penhey
Make the +reply and +comment views use the service/comment rendering.
277
            return CodeReviewDisplayComment(self.context)
5608.11.27 by Aaron Bentley
Get new comments working
278
        else:
279
            return None
280
7055.6.11 by Tim Penhey
Lots of changes to do with the request reviewer, voting and comment pages.
281
    @action('Save Comment', name='add')
5608.11.20 by Aaron Bentley
Break reply handling again
282
    def add_action(self, action, data):
283
        """Create the comment..."""
9935.2.1 by Tim Penhey
Change the look of the review form
284
        vote = data.get('vote')
285
        review_type = data.get('review_type')
11929.9.1 by Tim Penhey
Move launchpadform into lp.app.browser.
286
        self.branch_merge_proposal.createComment(
7055.6.11 by Tim Penhey
Lots of changes to do with the request reviewer, voting and comment pages.
287
            self.user, subject=None, content=data['comment'],
9935.2.1 by Tim Penhey
Change the look of the review form
288
            parent=self.reply_to, vote=vote, review_type=review_type)
5608.11.59 by Aaron Bentley
Apply many review comments
289
290
    @property
6602.1.4 by Tim Penhey
Fix the pagetests.
291
    def next_url(self):
292
        """Always take the user back to the merge proposal itself."""
293
        return canonical_url(self.branch_merge_proposal)
294
295
    cancel_url = next_url