Merge lp:~adeuring/launchpad/bug-39674-change-remaining-lfa-http_url into lp:launchpad/db-devel

Proposed by Abel Deuring
Status: Merged
Merged at revision: 9619
Proposed branch: lp:~adeuring/launchpad/bug-39674-change-remaining-lfa-http_url
Merge into: lp:launchpad/db-devel
Diff against target: 514 lines (+105/-48)
17 files modified
lib/canonical/launchpad/browser/librarian.py (+4/-2)
lib/canonical/launchpad/webapp/launchbag.py (+1/-1)
lib/canonical/librarian/client.py (+1/-0)
lib/lp/bugs/adapters/bugchange.py (+13/-4)
lib/lp/bugs/browser/bug.py (+8/-1)
lib/lp/bugs/browser/bugattachment.py (+4/-2)
lib/lp/bugs/browser/bugtarget.py (+5/-0)
lib/lp/bugs/doc/bug-change.txt (+6/-4)
lib/lp/bugs/doc/bug-export.txt (+1/-1)
lib/lp/bugs/doc/bugnotification-email.txt (+10/-20)
lib/lp/bugs/model/bugattachment.py (+5/-0)
lib/lp/bugs/scripts/bugexport.py (+3/-1)
lib/lp/bugs/stories/bugattachments/xx-attachments-to-bug-report.txt (+5/-1)
lib/lp/bugs/stories/bugattachments/xx-delete-bug-attachment.txt (+3/-1)
lib/lp/bugs/stories/bugs/xx-bug-text-pages.txt (+24/-5)
lib/lp/bugs/templates/bugtarget-patches.pt (+2/-2)
lib/lp/bugs/tests/test_bugchanges.py (+10/-3)
To merge this branch: bzr merge lp:~adeuring/launchpad/bug-39674-change-remaining-lfa-http_url
Reviewer Review Type Date Requested Status
Deryck Hodge (community) code Approve
Review via email: mp+31754@code.launchpad.net

Description of the change

This branch changes the URLs of LFAs of bug attachments shown in
some web pages and notification emails from LFA.http_url to
ProxiedLibraryFileAlias.http_url and fixes some related issues.

lib/canonical/launchpad/browser/librarian.py:

The URLs created by ProxiedLibraryFileAlias.http_url were not properly
escaped; non-ASCII-characters in file names caused exceptions, for example
in lib/lp/bugs/stories/bugs/xx-bug-text-pages.txt

I copied the pattern to generate URLs from LFA.http_url resp.
FileDownloadClient.getURLForAlias().

lib/canonical/launchpad/webapp/launchbag.py:

Some tests failed because canonical_url(bug_attachment) wants to access
launchbag.bugtask, but this property is not defined for a freshly created
launchbag.

lib/canonical/librarian/client.py:

The function quote() is now also used in ProxiedLibraryFileAlias.http_url,
so it should appear in __all__.

lib/lp/bugs/adapters/bugchange.py:

The data generated by class BugAttachmentChange when an attachment
is created or deleted now contains URLs from ProxiedLFAs.

lib/lp/bugs/browser/bug.py:

class BugView has a new method proxiedUrlForLibraryFile(). This method
is called from at least one page template. (Sorry, can't remember
which template is it -- this branch contains too many small changes...)

BugTextView.attachment_text() uses proxied LFA URLs.

lib/lp/bugs/browser/bugattachment.py:

BugAttachmentEditView.delete_action shows proxied LFA URLs in a notification.

lib/lp/bugs/browser/bugtarget.py:

A new helper method to get proxied LFA URLs in class BugsPatchesView,
similar to that ini class BugView.

lib/lp/bugs/model/bugattachment.py:

When notifications about a new bug attachment are created,
canonical_url(new_attachment) is called; this function needs the
bug attachment ID, and this ID is not available if the DB record
is not yet created. Hence the Store.of(attachment).flush() call.

The remaining changes are in tests which are affected by the changed
URLs. The test lib/lp/bugs/stories/bugs/xx-bug-text-pages.txt
now looks quite ugly in line 197ff: The download URLs now start with
regular bug URLs, i.e., we can access the LFAs via

http://bugs.launchpad.dev/bugs/1/+attachment/1/+files/file_a.txt

as well as

http://bugs.launchpad.dev/firefox/+bug/1/+attachment/1/+files/file_a.txt

Which URL is created, depends on the existence of a bugtask in LaunchBag.

This is a bit silly for the file content, but I simply did not have enough
time to fix it, and I'd like to really make bug attachments private
for private bugs in the next release...

tests: many. All those which I touched...

To post a comment you must log in.
Revision history for this message
Deryck Hodge (deryck) wrote :

The changes generally look good, Abel. Thanks for all the work you've been doing to get this ready!

I have two minor requests:

1) If there are bugs for these related issues that are fixed, can you link the branch to them so they get marked fixed when this lands?

2) Can you add a comment in code explaining why the flush is required?

Consider this r=me with these minor changes.

Cheers,
deryck

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/canonical/launchpad/browser/librarian.py'
--- lib/canonical/launchpad/browser/librarian.py 2010-08-03 13:37:55 +0000
+++ lib/canonical/launchpad/browser/librarian.py 2010-08-04 15:48:48 +0000
@@ -1,4 +1,4 @@
1# Copyright 2009 Canonical Ltd. This software is licensed under the1# Copyright 2010 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4"""Browser file for LibraryFileAlias."""4"""Browser file for LibraryFileAlias."""
@@ -32,6 +32,7 @@
32 IWebBrowserOriginatingRequest)32 IWebBrowserOriginatingRequest)
33from canonical.launchpad.webapp.url import urlappend33from canonical.launchpad.webapp.url import urlappend
34from canonical.lazr.utils import get_current_browser_request34from canonical.lazr.utils import get_current_browser_request
35from canonical.librarian.client import quote
35from canonical.librarian.interfaces import LibrarianServerError36from canonical.librarian.interfaces import LibrarianServerError
36from canonical.librarian.utils import filechunks, guess_librarian_encoding37from canonical.librarian.utils import filechunks, guess_librarian_encoding
3738
@@ -220,5 +221,6 @@
220221
221 parent_url = canonical_url(self.parent, request=request)222 parent_url = canonical_url(self.parent, request=request)
222 traversal_url = urlappend(parent_url, '+files')223 traversal_url = urlappend(parent_url, '+files')
223 url = urlappend(traversal_url, self.context.filename)224 url = urlappend(
225 traversal_url, quote(self.context.filename.encode('utf-8')))
224 return url226 return url
225227
=== modified file 'lib/canonical/launchpad/webapp/launchbag.py'
--- lib/canonical/launchpad/webapp/launchbag.py 2010-07-30 00:06:00 +0000
+++ lib/canonical/launchpad/webapp/launchbag.py 2010-08-04 15:48:48 +0000
@@ -136,7 +136,7 @@
136136
137 @property137 @property
138 def bugtask(self):138 def bugtask(self):
139 return self._store.bugtask139 return getattr(self._store, "bugtask", None)
140140
141 @property141 @property
142 def time_zone(self):142 def time_zone(self):
143143
=== modified file 'lib/canonical/librarian/client.py'
--- lib/canonical/librarian/client.py 2010-03-25 20:03:55 +0000
+++ lib/canonical/librarian/client.py 2010-08-04 15:48:48 +0000
@@ -8,6 +8,7 @@
8 'FileUploadClient',8 'FileUploadClient',
9 'LibrarianClient',9 'LibrarianClient',
10 'RestrictedLibrarianClient',10 'RestrictedLibrarianClient',
11 'quote',
11 ]12 ]
1213
1314
1415
=== modified file 'lib/lp/bugs/adapters/bugchange.py'
--- lib/lp/bugs/adapters/bugchange.py 2010-06-09 16:24:23 +0000
+++ lib/lp/bugs/adapters/bugchange.py 2010-08-04 15:48:48 +0000
@@ -38,6 +38,7 @@
38from lp.bugs.interfaces.bugchange import IBugChange38from lp.bugs.interfaces.bugchange import IBugChange
39from lp.bugs.interfaces.bugtask import IBugTask39from lp.bugs.interfaces.bugtask import IBugTask
40from lp.registry.interfaces.product import IProduct40from lp.registry.interfaces.product import IProduct
41from canonical.launchpad.browser.librarian import ProxiedLibraryFileAlias
41from canonical.launchpad.webapp.publisher import canonical_url42from canonical.launchpad.webapp.publisher import canonical_url
4243
4344
@@ -527,6 +528,12 @@
527 return {'text': "\n".join(messages)}528 return {'text': "\n".join(messages)}
528529
529530
531def download_url_of_bugattachment(attachment):
532 """Return the URL of the ProxiedLibraryFileAlias for the attachment."""
533 return ProxiedLibraryFileAlias(
534 attachment.libraryfile, attachment).http_url
535
536
530class BugAttachmentChange(AttributeChange):537class BugAttachmentChange(AttributeChange):
531 """Used to represent a change to an `IBug`'s attachments."""538 """Used to represent a change to an `IBug`'s attachments."""
532539
@@ -535,12 +542,14 @@
535 what_changed = "attachment added"542 what_changed = "attachment added"
536 old_value = None543 old_value = None
537 new_value = "%s %s" % (544 new_value = "%s %s" % (
538 self.new_value.title, self.new_value.libraryfile.http_url)545 self.new_value.title,
546 download_url_of_bugattachment(self.new_value))
539 else:547 else:
540 what_changed = "attachment removed"548 what_changed = "attachment removed"
541 attachment = self.new_value549 attachment = self.new_value
542 old_value = "%s %s" % (550 old_value = "%s %s" % (
543 self.old_value.title, self.old_value.libraryfile.http_url)551 self.old_value.title,
552 download_url_of_bugattachment(self.old_value))
544 new_value = None553 new_value = None
545554
546 return {555 return {
@@ -557,7 +566,7 @@
557 attachment_str = 'Attachment'566 attachment_str = 'Attachment'
558 message = '** %s added: "%s"\n %s' % (567 message = '** %s added: "%s"\n %s' % (
559 attachment_str, self.new_value.title,568 attachment_str, self.new_value.title,
560 self.new_value.libraryfile.http_url)569 download_url_of_bugattachment(self.new_value))
561 else:570 else:
562 if self.old_value.is_patch:571 if self.old_value.is_patch:
563 attachment_str = 'Patch'572 attachment_str = 'Patch'
@@ -565,7 +574,7 @@
565 attachment_str = 'Attachment'574 attachment_str = 'Attachment'
566 message = '** %s removed: "%s"\n %s' % (575 message = '** %s removed: "%s"\n %s' % (
567 attachment_str, self.old_value.title,576 attachment_str, self.old_value.title,
568 self.old_value.libraryfile.http_url)577 download_url_of_bugattachment(self.old_value))
569578
570 return {'text': message}579 return {'text': message}
571580
572581
=== modified file 'lib/lp/bugs/browser/bug.py'
--- lib/lp/bugs/browser/bug.py 2010-08-03 08:49:19 +0000
+++ lib/lp/bugs/browser/bug.py 2010-08-04 15:48:48 +0000
@@ -557,6 +557,11 @@
557557
558 return dupes558 return dupes
559559
560 def proxiedUrlForLibraryFile(self, attachment):
561 """Return the proxied download URL for a Librarian file."""
562 return ProxiedLibraryFileAlias(
563 attachment.libraryfile, attachment).http_url
564
560565
561class BugWithoutContextView:566class BugWithoutContextView:
562 """View that redirects to the new bug page.567 """View that redirects to the new bug page.
@@ -870,7 +875,9 @@
870 """Return a text representation of a bug attachment."""875 """Return a text representation of a bug attachment."""
871 mime_type = normalize_mime_type.sub(876 mime_type = normalize_mime_type.sub(
872 ' ', attachment.libraryfile.mimetype)877 ' ', attachment.libraryfile.mimetype)
873 return "%s %s" % (attachment.libraryfile.http_url, mime_type)878 download_url = ProxiedLibraryFileAlias(
879 attachment.libraryfile, attachment).http_url
880 return "%s %s" % (download_url, mime_type)
874881
875 def comment_text(self):882 def comment_text(self):
876 """Return a text representation of bug comments."""883 """Return a text representation of bug comments."""
877884
=== modified file 'lib/lp/bugs/browser/bugattachment.py'
--- lib/lp/bugs/browser/bugattachment.py 2010-08-03 13:37:55 +0000
+++ lib/lp/bugs/browser/bugattachment.py 2010-08-04 15:48:48 +0000
@@ -20,7 +20,7 @@
20from zope.contenttype import guess_content_type20from zope.contenttype import guess_content_type
2121
22from canonical.launchpad.browser.librarian import (22from canonical.launchpad.browser.librarian import (
23 FileNavigationMixin, StreamOrRedirectLibraryFileAliasView)23 FileNavigationMixin, ProxiedLibraryFileAlias, StreamOrRedirectLibraryFileAliasView)
24from canonical.launchpad.webapp import (24from canonical.launchpad.webapp import (
25 canonical_url, custom_widget, GetitemNavigation, Navigation)25 canonical_url, custom_widget, GetitemNavigation, Navigation)
26from canonical.launchpad.interfaces.librarian import ILibraryFileAliasSet26from canonical.launchpad.interfaces.librarian import ILibraryFileAliasSet
@@ -156,9 +156,11 @@
156156
157 @action('Delete Attachment', name='delete')157 @action('Delete Attachment', name='delete')
158 def delete_action(self, action, data):158 def delete_action(self, action, data):
159 libraryfile_url = ProxiedLibraryFileAlias(
160 self.context.libraryfile, self.context).http_url
159 self.request.response.addInfoNotification(structured(161 self.request.response.addInfoNotification(structured(
160 'Attachment "<a href="%(url)s">%(name)s</a>" has been deleted.',162 'Attachment "<a href="%(url)s">%(name)s</a>" has been deleted.',
161 url=self.context.libraryfile.http_url, name=self.context.title))163 url=libraryfile_url, name=self.context.title))
162 self.context.removeFromBug(user=self.user)164 self.context.removeFromBug(user=self.user)
163165
164 def updateContentType(self, new_content_type):166 def updateContentType(self, new_content_type):
165167
=== modified file 'lib/lp/bugs/browser/bugtarget.py'
--- lib/lp/bugs/browser/bugtarget.py 2010-08-02 02:13:52 +0000
+++ lib/lp/bugs/browser/bugtarget.py 2010-08-04 15:48:48 +0000
@@ -57,6 +57,7 @@
57from canonical.launchpad import _57from canonical.launchpad import _
58from canonical.launchpad.browser.feeds import (58from canonical.launchpad.browser.feeds import (
59 BugFeedLink, BugTargetLatestBugsFeedLink, FeedsMixin)59 BugFeedLink, BugTargetLatestBugsFeedLink, FeedsMixin)
60from canonical.launchpad.browser.librarian import ProxiedLibraryFileAlias
60from lp.bugs.interfaces.bugsupervisor import IHasBugSupervisor61from lp.bugs.interfaces.bugsupervisor import IHasBugSupervisor
61from lp.bugs.interfaces.bugtarget import (62from lp.bugs.interfaces.bugtarget import (
62 IBugTarget, IOfficialBugTagTargetPublic, IOfficialBugTagTargetRestricted)63 IBugTarget, IOfficialBugTagTargetPublic, IOfficialBugTagTargetRestricted)
@@ -1469,3 +1470,7 @@
1469 """Return a timedelta object for the age of a patch attachment."""1470 """Return a timedelta object for the age of a patch attachment."""
1470 now = datetime.now(timezone('UTC'))1471 now = datetime.now(timezone('UTC'))
1471 return now - patch.message.datecreated1472 return now - patch.message.datecreated
1473
1474 def proxiedUrlForLibraryFile(self, patch):
1475 """Return the proxied download URL for a Librarian file."""
1476 return ProxiedLibraryFileAlias(patch.libraryfile, patch).http_url
14721477
=== modified file 'lib/lp/bugs/doc/bug-change.txt'
--- lib/lp/bugs/doc/bug-change.txt 2010-06-16 08:27:19 +0000
+++ lib/lp/bugs/doc/bug-change.txt 2010-08-04 15:48:48 +0000
@@ -479,13 +479,14 @@
479 ... old_value=None, new_value=attachment)479 ... old_value=None, new_value=attachment)
480480
481 >>> print pretty(attachment_change.getBugActivity())481 >>> print pretty(attachment_change.getBugActivity())
482 {'newvalue': u'sample-attachment http://...',482 {'newvalue':
483 u'sample-attachment http://bugs.launchpad.dev/bugs/...+files/...',
483 'oldvalue': None,484 'oldvalue': None,
484 'whatchanged': 'attachment added'}485 'whatchanged': 'attachment added'}
485486
486 >>> print attachment_change.getBugNotification()['text']487 >>> print attachment_change.getBugNotification()['text']
487 ** Attachment added: "sample-attachment"488 ** Attachment added: "sample-attachment"
488 http...489 http://bugs.launchpad.dev/bugs/.../+attachment/1/+files/...
489490
490Or remove one.491Or remove one.
491492
@@ -496,12 +497,13 @@
496497
497 >>> print pretty(attachment_change.getBugActivity())498 >>> print pretty(attachment_change.getBugActivity())
498 {'newvalue': None,499 {'newvalue': None,
499 'oldvalue': u'sample-attachment http://...',500 'oldvalue':
501 u'sample-attachment http://bugs.launchpad.dev/bugs/...+files/...',
500 'whatchanged': 'attachment removed'}502 'whatchanged': 'attachment removed'}
501503
502 >>> print attachment_change.getBugNotification()['text']504 >>> print attachment_change.getBugNotification()['text']
503 ** Attachment removed: "sample-attachment"505 ** Attachment removed: "sample-attachment"
504 http...506 http://bugs.launchpad.dev/bugs/.../+attachment/1/+files/...
505507
506508
507== BugTaskAttributeChange ==509== BugTaskAttributeChange ==
508510
=== modified file 'lib/lp/bugs/doc/bug-export.txt'
--- lib/lp/bugs/doc/bug-export.txt 2009-09-04 10:43:39 +0000
+++ lib/lp/bugs/doc/bug-export.txt 2010-08-04 15:48:48 +0000
@@ -141,7 +141,7 @@
141 <sender name="name12">Sample Person</sender>141 <sender name="name12">Sample Person</sender>
142 <date>...</date>142 <date>...</date>
143 <text>Added attachment</text>143 <text>Added attachment</text>
144 <attachment href="http://localhost:58000/.../hello.txt">144 <attachment href="http://bugs.launchpad.dev/bugs/1/.../+files/hello.txt">
145 <type>UNSPECIFIED</type>145 <type>UNSPECIFIED</type>
146 <filename>hello.txt</filename>146 <filename>hello.txt</filename>
147 <title>"Hello World" attachment</title>147 <title>"Hello World" attachment</title>
148148
=== modified file 'lib/lp/bugs/doc/bugnotification-email.txt'
--- lib/lp/bugs/doc/bugnotification-email.txt 2010-07-28 22:33:59 +0000
+++ lib/lp/bugs/doc/bugnotification-email.txt 2010-08-04 15:48:48 +0000
@@ -343,18 +343,9 @@
343343
344Adding an attachment will generate a notification that looks as follows:344Adding an attachment will generate a notification that looks as follows:
345345
346 >>> class MockLibraryFile:346 >>> attachment = factory.makeBugAttachment(
347 ... def __init__(self, url):347 ... description="A screenshot of the problem",
348 ... self.http_url = url348 ... filename='screenshot.png')
349 >>> class MockAttachment:
350 ... def __init__(self, title, libraryfile, is_patch=False):
351 ... self.title = title
352 ... self.libraryfile = libraryfile
353 ... self.is_patch = is_patch
354 >>> attachment = MockAttachment(
355 ... title="A screenshot of the problem",
356 ... libraryfile=MockLibraryFile('http://foo.com/screenshot.png'))
357
358 >>> bug_delta = BugDelta(349 >>> bug_delta = BugDelta(
359 ... bug=edited_bug,350 ... bug=edited_bug,
360 ... bugurl="http://www.example.com/bugs/2",351 ... bugurl="http://www.example.com/bugs/2",
@@ -365,7 +356,7 @@
365 ... print notification['text'] #doctest: -NORMALIZE_WHITESPACE356 ... print notification['text'] #doctest: -NORMALIZE_WHITESPACE
366 ... print "-----------------------------"357 ... print "-----------------------------"
367 ** Attachment added: "A screenshot of the problem"358 ** Attachment added: "A screenshot of the problem"
368 http://foo.com/screenshot.png359 http://bugs.launchpad.dev/bugs/.../+attachment/1/+files/screenshot.png
369 -----------------------------360 -----------------------------
370361
371Removing an attachment generates a notification, too.362Removing an attachment generates a notification, too.
@@ -380,16 +371,15 @@
380 ... print notification['text'] #doctest: -NORMALIZE_WHITESPACE371 ... print notification['text'] #doctest: -NORMALIZE_WHITESPACE
381 ... print "-----------------------------"372 ... print "-----------------------------"
382 ** Attachment removed: "A screenshot of the problem"373 ** Attachment removed: "A screenshot of the problem"
383 http://foo.com/screenshot.png374 http://bugs.launchpad.dev/bugs/.../+attachment/1/+files/screenshot.png
384 -----------------------------375 -----------------------------
385376
386Adding an attachment and marking it as a patch generates a different377Adding an attachment and marking it as a patch generates a different
387notification.378notification.
388379
389 >>> attachment = MockAttachment(380 >>> attachment = factory.makeBugAttachment(
390 ... title="A new icon for the application",381 ... description="A new icon for the application",
391 ... libraryfile=MockLibraryFile('http://foo.com/new-icon.png'),382 ... filename='new-icon.png', is_patch=True)
392 ... is_patch=True)
393 >>> bug_delta = BugDelta(383 >>> bug_delta = BugDelta(
394 ... bug=edited_bug,384 ... bug=edited_bug,
395 ... bugurl="http://www.example.com/bugs/2",385 ... bugurl="http://www.example.com/bugs/2",
@@ -400,7 +390,7 @@
400 ... print notification['text'] #doctest: -NORMALIZE_WHITESPACE390 ... print notification['text'] #doctest: -NORMALIZE_WHITESPACE
401 ... print "-----------------------------"391 ... print "-----------------------------"
402 ** Patch added: "A new icon for the application"392 ** Patch added: "A new icon for the application"
403 http://foo.com/new-icon.png393 http://bugs.launchpad.dev/bugs/.../+attachment/2/+files/new-icon.png
404 -----------------------------394 -----------------------------
405395
406Removing a patch also generates a different notification.396Removing a patch also generates a different notification.
@@ -415,7 +405,7 @@
415 ... print notification['text'] #doctest: -NORMALIZE_WHITESPACE405 ... print notification['text'] #doctest: -NORMALIZE_WHITESPACE
416 ... print "-----------------------------"406 ... print "-----------------------------"
417 ** Patch removed: "A new icon for the application"407 ** Patch removed: "A new icon for the application"
418 http://foo.com/new-icon.png408 http://bugs.launchpad.dev/bugs/.../+attachment/2/+files/new-icon.png
419 -----------------------------409 -----------------------------
420410
421411
422412
=== modified file 'lib/lp/bugs/model/bugattachment.py'
--- lib/lp/bugs/model/bugattachment.py 2010-08-03 08:49:19 +0000
+++ lib/lp/bugs/model/bugattachment.py 2010-08-04 15:48:48 +0000
@@ -12,6 +12,7 @@
12from lazr.lifecycle.event import ObjectCreatedEvent, ObjectDeletedEvent12from lazr.lifecycle.event import ObjectCreatedEvent, ObjectDeletedEvent
1313
14from sqlobject import ForeignKey, StringCol, SQLObjectNotFound14from sqlobject import ForeignKey, StringCol, SQLObjectNotFound
15from storm.store import Store
1516
16from canonical.database.enumcol import EnumCol17from canonical.database.enumcol import EnumCol
17from canonical.database.sqlbase import SQLBase18from canonical.database.sqlbase import SQLBase
@@ -92,6 +93,10 @@
92 attachment = BugAttachment(93 attachment = BugAttachment(
93 bug=bug, libraryfile=filealias, type=attach_type, title=title,94 bug=bug, libraryfile=filealias, type=attach_type, title=title,
94 message=message)95 message=message)
96 # canonial_url(attachment) (called by notification subscribers
97 # to generate the download URL of the attachments) blows up if
98 # attachment.id is not (yet) set.
99 Store.of(attachment).flush()
95 if send_notifications:100 if send_notifications:
96 notify(ObjectCreatedEvent(attachment, user=message.owner))101 notify(ObjectCreatedEvent(attachment, user=message.owner))
97 return attachment102 return attachment
98103
=== modified file 'lib/lp/bugs/scripts/bugexport.py'
--- lib/lp/bugs/scripts/bugexport.py 2009-09-04 10:43:39 +0000
+++ lib/lp/bugs/scripts/bugexport.py 2010-08-04 15:48:48 +0000
@@ -15,6 +15,7 @@
1515
16from zope.component import getUtility16from zope.component import getUtility
17from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities17from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities
18from canonical.launchpad.browser.librarian import ProxiedLibraryFileAlias
18from lp.bugs.interfaces.bugtask import BugTaskSearchParams, IBugTaskSet19from lp.bugs.interfaces.bugtask import BugTaskSearchParams, IBugTaskSet
19from lp.bugs.browser.bugtask import get_comments_for_bugtask20from lp.bugs.browser.bugtask import get_comments_for_bugtask
2021
@@ -80,7 +81,8 @@
80 for attachment in comment.bugattachments:81 for attachment in comment.bugattachments:
81 attachment_node = ET.SubElement(82 attachment_node = ET.SubElement(
82 comment_node, 'attachment',83 comment_node, 'attachment',
83 href=attachment.libraryfile.http_url)84 href=ProxiedLibraryFileAlias(
85 attachment.libraryfile, attachment).http_url)
84 attachment_node.text = attachment_node.tail = '\n'86 attachment_node.text = attachment_node.tail = '\n'
85 addnode(attachment_node, 'type', attachment.type.name)87 addnode(attachment_node, 'type', attachment.type.name)
86 addnode(attachment_node, 'filename',88 addnode(attachment_node, 'filename',
8789
=== modified file 'lib/lp/bugs/stories/bugattachments/xx-attachments-to-bug-report.txt'
--- lib/lp/bugs/stories/bugattachments/xx-attachments-to-bug-report.txt 2010-07-29 11:20:47 +0000
+++ lib/lp/bugs/stories/bugattachments/xx-attachments-to-bug-report.txt 2010-08-04 15:48:48 +0000
@@ -23,8 +23,11 @@
23 >>> from zope.component import getUtility23 >>> from zope.component import getUtility
24 >>> from canonical.launchpad.ftests import login, logout, syncUpdate24 >>> from canonical.launchpad.ftests import login, logout, syncUpdate
25 >>> from canonical.launchpad.interfaces import IBugSet25 >>> from canonical.launchpad.interfaces import IBugSet
26 >>> from canonical.launchpad.webapp.interfaces import ILaunchBag
26 >>> login("test@canonical.com")27 >>> login("test@canonical.com")
27 >>> bug_11 = getUtility(IBugSet).get(11)28 >>> bug_11 = getUtility(IBugSet).get(11)
29 >>> launchbag = getUtility(ILaunchBag)
30 >>> launchbag.clear()
28 >>> attachment = bug_11.addAttachment(31 >>> attachment = bug_11.addAttachment(
29 ... owner=None, data=StringIO.StringIO('whatever'),32 ... owner=None, data=StringIO.StringIO('whatever'),
30 ... comment=bug_11.initial_message, filename='test.txt',33 ... comment=bug_11.initial_message, filename='test.txt',
@@ -55,6 +58,7 @@
55== Patch attachments are shown before non-patch attachments ==58== Patch attachments are shown before non-patch attachments ==
5659
57 >>> login("test@canonical.com")60 >>> login("test@canonical.com")
61 >>> launchbag.clear()
58 >>> patch_attachment = bug_11.addAttachment(62 >>> patch_attachment = bug_11.addAttachment(
59 ... owner=None, data=StringIO.StringIO('patchy patch patch'),63 ... owner=None, data=StringIO.StringIO('patchy patch patch'),
60 ... comment=bug_11.initial_message, filename='patch.txt',64 ... comment=bug_11.initial_message, filename='patch.txt',
6165
=== modified file 'lib/lp/bugs/stories/bugattachments/xx-delete-bug-attachment.txt'
--- lib/lp/bugs/stories/bugattachments/xx-delete-bug-attachment.txt 2010-07-29 11:20:47 +0000
+++ lib/lp/bugs/stories/bugattachments/xx-delete-bug-attachment.txt 2010-08-04 15:48:48 +0000
@@ -51,7 +51,9 @@
51 'http://.../+bug/2'51 'http://.../+bug/2'
52 >>> for message in find_tags_by_class(user_browser.contents, 'message'):52 >>> for message in find_tags_by_class(user_browser.contents, 'message'):
53 ... print message.renderContents()53 ... print message.renderContents()
54 Attachment "<a href="...">Great deal</a>" has been deleted.54 Attachment
55 "<a href="http://bugs.launchpad.dev/...+files/foo.txt">Great deal</a>"
56 has been deleted.
5557
56 >>> print find_portlet(user_browser.contents, 'Bug attachments')58 >>> print find_portlet(user_browser.contents, 'Bug attachments')
57 None59 None
5860
=== modified file 'lib/lp/bugs/stories/bugs/xx-bug-text-pages.txt'
--- lib/lp/bugs/stories/bugs/xx-bug-text-pages.txt 2010-06-25 13:34:37 +0000
+++ lib/lp/bugs/stories/bugs/xx-bug-text-pages.txt 2010-08-04 15:48:48 +0000
@@ -70,8 +70,9 @@
70 duplicate-of: 70 duplicate-of:
71 duplicates: 71 duplicates:
72 attachments:72 attachments:
73 http://.../file_a.txt text/html73 http://bugs.launchpad.dev/.../+files/file_a.txt text/html
74 http://.../file%20with%20space.txt text/plain; name="file with space.txt"74 http://bugs.launchpad.dev/.../+files/file%20with%20space.txt
75 text/plain; name="file with space.txt"
75 patches:76 patches:
76 http://.../bug-patch.diff text/plain77 http://.../bug-patch.diff text/plain
77 tags: 78 tags:
@@ -149,7 +150,7 @@
149 >>> attachments_text = text_bug[text_bug.find('attachments:'):]150 >>> attachments_text = text_bug[text_bug.find('attachments:'):]
150 >>> attachment_2 = attachments_text.split('\n')[2]151 >>> attachment_2 = attachments_text.split('\n')[2]
151 >>> attachment_2152 >>> attachment_2
152 ' http://localhost:58000/.../file%20with%20space.txt text/plain;153 ' http://bugs.launchpad.dev/.../file%20with%20space.txt text/plain;
153 name="file with space.txt"'154 name="file with space.txt"'
154155
155156
@@ -196,11 +197,29 @@
196 >>> separator_bug = separator_regex.findall(text_bug)[0]197 >>> separator_bug = separator_regex.findall(text_bug)[0]
197 >>> separator_bug_task = separator_regex.findall(text_bug_task)[0]198 >>> separator_bug_task = separator_regex.findall(text_bug_task)[0]
198199
199Now we can show that the individual sections are identical for each report:200Now we can show that the individual sections are identical for each report.
201The only differences are the download URLs of bug attachments:
200202
201 >>> text_bug.split(separator_bug) == text_bug_task.split(separator_bug_task)203 >>> text_bug_chunks = text_bug.split(separator_bug)
204 >>> text_bug_task_chunks = text_bug_task.split(separator_bug_task)
205 >>> len(text_bug_chunks) == len(text_bug_task_chunks)
202 True206 True
203207
208 >>> for chunk_no in range(len(text_bug_task_chunks)):
209 ... if text_bug_task_chunks[chunk_no] != text_bug_chunks[chunk_no]:
210 ... bug_task_lines = text_bug_task_chunks[chunk_no].split('\n')
211 ... bug_lines = text_bug_chunks[chunk_no].split('\n')
212 ... assert(len(bug_task_lines) == len(bug_lines))
213 ... for line_no in range(len(bug_task_lines)):
214 ... if bug_lines[line_no] != bug_task_lines[line_no]:
215 ... print bug_lines[line_no]
216 ... print bug_task_lines[line_no]
217 http://bugs.launchpad.dev/bugs/1/+attachment/1/+files/file_a.txt text/html
218 http://bugs.launchpad.dev/firefox/+bug/.../+files/file_a.txt text/html
219 http://bugs.launchpad.dev/bugs/1/.../+files/file%20with%20space.txt...
220 http://bugs.launchpad.dev/firefox/+bug/.../+files/file%20with%20space.txt...
221 http://bugs.launchpad.dev/bugs/1/.../+files/bug-patch.diff text/plain
222 http://bugs.launchpad.dev/firefox/+bug/.../+files/bug-patch.diff text/plain
204223
205== Duplicate Bugs ==224== Duplicate Bugs ==
206225
207226
=== modified file 'lib/lp/bugs/templates/bugtarget-patches.pt'
--- lib/lp/bugs/templates/bugtarget-patches.pt 2010-02-24 06:17:33 +0000
+++ lib/lp/bugs/templates/bugtarget-patches.pt 2010-08-04 15:48:48 +0000
@@ -74,7 +74,7 @@
74 tal:define="patch patch_task/bug/latest_patch;74 tal:define="patch patch_task/bug/latest_patch;
75 age python:view.patchAge(patch)"75 age python:view.patchAge(patch)"
76 tal:attributes="id string:patch-cell-${repeat/patch_task/index}">76 tal:attributes="id string:patch-cell-${repeat/patch_task/index}">
77 <a tal:attributes="href patch/libraryfile/http_url"77 <a tal:attributes="href python:view.proxiedUrlForLibraryFile(patch)"
78 tal:content="age/fmt:approximateduration/use-digits"></a>78 tal:content="age/fmt:approximateduration/use-digits"></a>
79 <div class="popupTitle"79 <div class="popupTitle"
80 tal:attributes="id string:patch-popup-${repeat/patch_task/index};">80 tal:attributes="id string:patch-popup-${repeat/patch_task/index};">
@@ -82,7 +82,7 @@
82 <strong>From:</strong>82 <strong>From:</strong>
83 <a tal:replace="structure submitter/fmt:link"></a><br/>83 <a tal:replace="structure submitter/fmt:link"></a><br/>
84 <strong>Link:</strong>84 <strong>Link:</strong>
85 <a tal:attributes="href patch/libraryfile/http_url"85 <a tal:attributes="href python:view.proxiedUrlForLibraryFile(patch)"
86 tal:content="patch/libraryfile/filename"></a></p>86 tal:content="patch/libraryfile/filename"></a></p>
87 <p tal:content="string:${patch/title}"></p>87 <p tal:content="string:${patch/title}"></p>
88 </div>88 </div>
8989
=== modified file 'lib/lp/bugs/tests/test_bugchanges.py'
--- lib/lp/bugs/tests/test_bugchanges.py 2010-07-22 12:17:41 +0000
+++ lib/lp/bugs/tests/test_bugchanges.py 2010-08-04 15:48:48 +0000
@@ -12,6 +12,7 @@
12from lazr.lifecycle.event import ObjectCreatedEvent, ObjectModifiedEvent12from lazr.lifecycle.event import ObjectCreatedEvent, ObjectModifiedEvent
13from lazr.lifecycle.snapshot import Snapshot13from lazr.lifecycle.snapshot import Snapshot
1414
15from canonical.launchpad.browser.librarian import ProxiedLibraryFileAlias
15from canonical.launchpad.database import BugNotification16from canonical.launchpad.database import BugNotification
16from canonical.launchpad.ftests import login17from canonical.launchpad.ftests import login
17from lp.bugs.interfaces.bug import IBug18from lp.bugs.interfaces.bug import IBug
@@ -686,13 +687,17 @@
686 'whatchanged': 'attachment added',687 'whatchanged': 'attachment added',
687 'oldvalue': None,688 'oldvalue': None,
688 'newvalue': '%s %s' % (689 'newvalue': '%s %s' % (
689 attachment.title, attachment.libraryfile.http_url),690 attachment.title,
691 ProxiedLibraryFileAlias(
692 attachment.libraryfile, attachment).http_url),
690 }693 }
691694
692 attachment_added_notification = {695 attachment_added_notification = {
693 'person': self.user,696 'person': self.user,
694 'text': '** Attachment added: "%s"\n %s' % (697 'text': '** Attachment added: "%s"\n %s' % (
695 attachment.title, attachment.libraryfile.http_url),698 attachment.title,
699 ProxiedLibraryFileAlias(
700 attachment.libraryfile, attachment).http_url),
696 }701 }
697702
698 self.assertRecordedChange(703 self.assertRecordedChange(
@@ -705,7 +710,9 @@
705 attachment = self.factory.makeBugAttachment(710 attachment = self.factory.makeBugAttachment(
706 bug=self.bug, owner=self.user)711 bug=self.bug, owner=self.user)
707 self.saveOldChanges()712 self.saveOldChanges()
708 download_url = attachment.libraryfile.http_url713 download_url = ProxiedLibraryFileAlias(
714 attachment.libraryfile, attachment).http_url
715
709 attachment.removeFromBug(user=self.user)716 attachment.removeFromBug(user=self.user)
710717
711 attachment_removed_activity = {718 attachment_removed_activity = {

Subscribers

People subscribed via source and target branches

to status/vote changes: