Merge lp:~bac/launchpad/lp3-announcements into lp:launchpad

Proposed by Brad Crittenden
Status: Merged
Approved by: Curtis Hovey
Approved revision: no longer in the source branch.
Merged at revision: not available
Proposed branch: lp:~bac/launchpad/lp3-announcements
Merge into: lp:launchpad
Diff against target: None lines
To merge this branch: bzr merge lp:~bac/launchpad/lp3-announcements
Reviewer Review Type Date Requested Status
Paul Hummer (community) ui Approve
Curtis Hovey (community) code Approve
Canonical Launchpad Engineering Pending
Review via email: mp+10275@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Brad Crittenden (bac) wrote :
Download full text (4.3 KiB)

= Summary =

Update the <project>/+announcements page for 3.0 goodness, which is bug 414836.

Also solves:

Bug #175936: Announcements action (edit, publish & delete) links too close
 Remedy: links removed

Bug #253920: Project +announcements page should have a "Make announcement" link on it
 Remedy: add link in portlet

Bug #297518: "Created" doesn't make sense for announcements
 Remedy: reworded to 'written by'

== Proposed fix ==

Redesign the page to make individual announcements stand-out more. Removed editing
links which were problematic.

== Pre-implementation notes ==

Lots of helpful discussions with Curtis.

== Implementation details ==

As above.

== Tests ==

bin/test --vvm lp.registry -t announcement

== Demo and Q/A ==

Go to the following and ensure all looks right:
https://launchpad.dev/mozilla/+announcements
https://launchpad.dev/firefox/+announcements
https://launchpad.dev/kubuntu/+announcements

= Launchpad lint =

Checking for conflicts. and issues in doctests and templates.
Running jslint, xmllint, pyflakes, and pylint.
Using normal rules.

Linting changed files:
  lib/lp/registry/browser/configure.zcml
  lib/lp/registry/templates/hasannouncements-index.pt
  lib/lp/registry/stories/announcements/xx-announcements.txt
  lib/lp/registry/browser/announcement.py
  lib/lp/registry/templates/announcement-edit.pt
  lib/canonical/launchpad/icing/style-3-0.css
  lib/lp/registry/templates/announcement-listing-detailed.pt

== XmlLint notices ==

lib/lp/registry/templates/announcement-listing-detailed.pt
    1: namespace error : Namespace prefix tal for attributes on div is not defined
    <div class="portlet" tal:attributes="id string:${context/id}">
    ^
    3: namespace error : Namespace prefix tal for attributes on a is not defined
    <a tal:attributes="href string:${context/fmt:url}">
    ^
    5: namespace error : Namespace prefix tal for condition on date is not defined
    <tal:date tal:condition="context/date_announced">
    ^
    5: namespace error : Namespace prefix tal on date is not defined
    <tal:date tal:condition="context/date_announced">
    ^
    6: namespace error : Namespace prefix tal for replace on span is not defined
    <span tal:replace="context/date_announced/fmt:date"/>:
    ^
    8: namespace error : Namespace prefix tal on title is not defined
    <tal:title content="context/title">News item title</tal:title>
    ^
    14: namespace error : Namespace prefix tal on pillar is not defined
    <tal:pillar replace="structure context/target/fmt:link" />
    ^
    16: namespace error : Namespace prefix tal on registrant is not defined
    <tal:registrant replace="structure context/registrant/fmt:link" />.
    ^
    20: namespace error : Namespace prefix tal for replace on summary is not defined
    tal:replace="structure context/summary/fmt:text-to-html" />
    ^
    20: namespace error : Namespace prefix tal on summary is not defined
    tal:replace="structure context/summary/fmt:text-to-html" />
    ^
    22: namespace error : Namespace prefix tal on future is not defined
    <tal:future condition="context/future">
    ^
    24: namespace error : Namespace prefix tal for condition on strong is not define...

Read more...

Revision history for this message
Curtis Hovey (sinzui) wrote :
Download full text (10.7 KiB)

Hi Brad.

This is very nice. I think we should tweak the layout a bit before
landing this. I explain XMLLint's spazzing below.

> === modified file 'lib/canonical/launchpad/icing/style-3-0.css'
> --- lib/canonical/launchpad/icing/style-3-0.css 2009-08-17 11:22:39 +0000
> +++ lib/canonical/launchpad/icing/style-3-0.css 2009-08-17 20:36:01 +0000
...

> @@ -581,6 +581,10 @@
> border-top: 1px solid #d0d0d0;
> border-bottom: 1px solid #d0d0d0;
> }
> +.announcement .registered {
> + font-size: 95%;

This is not a support font-size you must use one of the percentages
from the table to guarantee that they display the same on all platforms.

    font-size: 93%;

is official.

> + margin-top: -2px

Missing semi-colon.

+ }

...

> === modified file 'lib/lp/registry/browser/announcement.py'
> --- lib/lp/registry/browser/announcement.py 2009-08-11 04:00:47 +0000
> +++ lib/lp/registry/browser/announcement.py 2009-08-17 20:36:01 +0000

...

> @@ -70,6 +69,12 @@
> text = 'Delete announcement'
> return Link('+delete', text, icon='trash-icon')
>
> + @enabled_with_permission('launchpad.Edit')
> + def announce(self):
> + text = 'Make announcement'
> + summary = 'Publish an item of news for this project'
> + return Link('+announce', text, summary, icon='add')

We use publish to describe the act of making public, not creating.

...

> @@ -100,6 +105,19 @@
> self.context = context
>
>
> +class IAnnouncementCreateMenu(Interface):
> + """A marker interface for creation announcement navigation menu."""
> +
> +
> +class AnnouncementCreateNavigationMenu(NavigationMenu, AnnouncementMenuMixin):
> + """A sub-menu for different aspects of modifying an announcement."""
> +
> + usedfor = IAnnouncementCreateMenu
> + facet = 'overview'
> + title = 'Create announcement'
> + links = ('announce', )xmlns:tal="http://xml.zope.org/namespaces/tal"

Menus assume that links are a mutable list. This works, but may lead to
cryptic errors if someone extends the menu,

...

> === modified file 'lib/lp/registry/stories/announcements/xx-announcements.txt'
> --- lib/lp/registry/stories/announcements/xx-announcements.txt 2009-08-13 18:10:15 +0000
> +++ lib/lp/registry/stories/announcements/xx-announcements.txt 2009-08-17 20:36:01 +0000

...

> @@ -418,47 +419,16 @@
> Editing announcements
> ---------------------
...

> -If you have the necessary privileges you will see links to edit the
> -announcements.
> +To edit an announcement you must go to the individual announcement
> +page and then follow the proper links.

Me? I am not doing anything. I think No Privileges Person is doing this.

> >>> priv_browser.open('http://launchpad.dev/tomcat/+announcements')
> - >>> listed_announcements = find_tag_by_id(
> - ... priv_browser.contents, 'announcements')
> - >>> edit_links = listed_announcements.fetch('a', text=edit_link_text)
> - >>> len(edit_links)
> - 2
> -
> -Following a link takes you to a form where you can change the headline,
> -summary and URL of the announcement:
> -
> - >>> 'Modified headline' not in announcements(priv_browser.contents)
> - True
> - ...

review: Needs Fixing (code)
Revision history for this message
Brad Crittenden (bac) wrote :
Download full text (12.7 KiB)

Thanks for the review Curtis.

On Aug 18, 2009, at 11:37 , Curtis Hovey wrote:

> Review: Needs Fixing code
> Hi Brad.
>
> This is very nice. I think we should tweak the layout a bit before
> landing this. I explain XMLLint's spazzing below.

Great.

>
>> === modified file 'lib/canonical/launchpad/icing/style-3-0.css'
>> --- lib/canonical/launchpad/icing/style-3-0.css 2009-08-17 11:22:39
>> +0000
>> +++ lib/canonical/launchpad/icing/style-3-0.css 2009-08-17 20:36:01
>> +0000
> ...
>
>> @@ -581,6 +581,10 @@
>> border-top: 1px solid #d0d0d0;
>> border-bottom: 1px solid #d0d0d0;
>> }
>> +.announcement .registered {
>> + font-size: 95%;
>
> This is not a support font-size you must use one of the percentages
> from the table to guarantee that they display the same on all
> platforms.
>
> font-size: 93%;
>
> is official.

Didn't see that comment in the CSS. Thanks for catching it.

>
>> + margin-top: -2px
>
> Missing semi-colon.
>

Duh.

> + }
>
> ...
>
>> === modified file 'lib/lp/registry/browser/announcement.py'
>> --- lib/lp/registry/browser/announcement.py 2009-08-11 04:00:47 +0000
>> +++ lib/lp/registry/browser/announcement.py 2009-08-17 20:36:01 +0000
>
> ...
>
>> @@ -70,6 +69,12 @@
>> text = 'Delete announcement'
>> return Link('+delete', text, icon='trash-icon')
>>
>> + @enabled_with_permission('launchpad.Edit')
>> + def announce(self):
>> + text = 'Make announcement'
>> + summary = 'Publish an item of news for this project'
>> + return Link('+announce', text, summary, icon='add')
>
> We use publish to describe the act of making public, not creating.

'Create an item...'

>
> ...
>
>> @@ -100,6 +105,19 @@
>> self.context = context
>>
>>
>> +class IAnnouncementCreateMenu(Interface):
>> + """A marker interface for creation announcement navigation
>> menu."""
>> +
>> +
>> +class AnnouncementCreateNavigationMenu(NavigationMenu,
>> AnnouncementMenuMixin):
>> + """A sub-menu for different aspects of modifying an
>> announcement."""
>> +
>> + usedfor = IAnnouncementCreateMenu
>> + facet = 'overview'
>> + title = 'Create announcement'
>> + links = ('announce', )xmlns:tal="http://xml.zope.org/namespaces/tal
>> "
>
> Menus assume that links are a mutable list. This works, but may lead
> to
> cryptic errors if someone extends the menu,

Really? From webapp/menu.py:

         assert isinstance(self.links, (tuple, list)), (
             "self.links must be a tuple or list.")

Just grepping through registry/browser/*.py I see a few other examples
of links being tuples. I've changed this one and the others in this
module.

>
> ...
>
>> === modified file 'lib/lp/registry/stories/announcements/xx-
>> announcements.txt'
>> --- lib/lp/registry/stories/announcements/xx-announcements.txt
>> 2009-08-13 18:10:15 +0000
>> +++ lib/lp/registry/stories/announcements/xx-announcements.txt
>> 2009-08-17 20:36:01 +0000
>
> ...
>
>> @@ -418,47 +419,16 @@
>> Editing announcements
>> ---------------------
> ...
>
>> -If you have the necessary privileges you will see links to edit the
>> -announcements.
>> +To edit an announcement you must go to the i...

Revision history for this message
Brad Crittenden (bac) wrote :
Download full text (15.6 KiB)

=== modified file 'lib/canonical/launchpad/icing/style-3-0.css'
--- lib/canonical/launchpad/icing/style-3-0.css 2009-08-17 20:36:01 +0000
+++ lib/canonical/launchpad/icing/style-3-0.css 2009-08-18 15:40:42 +0000
@@ -582,8 +582,8 @@
     border-bottom: 1px solid #d0d0d0;
     }
 .announcement .registered {
- font-size: 95%;
- margin-top: -2px
+ font-size: 93%;
+ margin-top: -2px;
     }

 /* From nice_pre in tales.py */

=== modified file 'lib/lp/registry/browser/announcement.py'
--- lib/lp/registry/browser/announcement.py 2009-08-17 20:36:01 +0000
+++ lib/lp/registry/browser/announcement.py 2009-08-19 00:45:18 +0000
@@ -72,14 +72,14 @@
     @enabled_with_permission('launchpad.Edit')
     def announce(self):
         text = 'Make announcement'
- summary = 'Publish an item of news for this project'
+ summary = 'Create an item of news for this project'
         return Link('+announce', text, summary, icon='add')

 class AnnouncementContextMenu(ContextMenu, AnnouncementMenuMixin):
     """The menu for working with an Announcement."""
     usedfor = IAnnouncement
- links = ('edit', 'retarget', 'publish', 'retract', 'delete')
+ links = ['edit', 'retarget', 'publish', 'retract', 'delete']

 class IAnnouncementEditMenu(Interface):
@@ -92,7 +92,7 @@
     usedfor = IAnnouncementEditMenu
     facet = 'overview'
     title = 'Change announcement'
- links = ('edit', 'retarget', 'publish', 'retract', 'delete')
+ links = ['edit', 'retarget', 'publish', 'retract', 'delete']

     def __init__(self, context):
         super(AnnouncementEditNavigationMenu, self).__init__(context)
@@ -115,7 +115,7 @@
     usedfor = IAnnouncementCreateMenu
     facet = 'overview'
     title = 'Create announcement'
- links = ('announce', )
+ links = ['announce']

 class AnnouncementFormMixin:

=== modified file 'lib/lp/registry/stories/announcements/xx-announcements.txt'
--- lib/lp/registry/stories/announcements/xx-announcements.txt 2009-08-17 20:36:01 +0000
+++ lib/lp/registry/stories/announcements/xx-announcements.txt 2009-08-19 01:15:01 +0000
@@ -75,6 +75,8 @@

     >>> print priv_browser.url
     http://launchpad.dev/apache
+ >>> print priv_browser.title
+ Apache in Launchpad

 We'll repeat the process for Tomcat, an IProduct that is part of the
 Apache project, but this time we won't specify a URL, and we will
@@ -107,8 +109,8 @@
     ... name='field.publication_date.announcement_date').value = (
     ... '2007-11-24 09:00:00')
     >>> priv_browser.getControl('Make announcement').click()
- >>> print priv_browser.url
- http://launchpad.dev/tomcat
+ >>> print priv_browser.title
+ Tomcat in Launchpad

 And check out the results:

@@ -138,8 +140,8 @@
     >>> priv_browser.getControl('Summary').value = (
     ... 'Derby announcement summary')
     >>> priv_browser.getControl('Make announcement').click()
- >>> print priv_browser.url
- http://launchpad.dev/derby
+ >>> print priv_browser.title
+ Derby - Java Database in Launchpad
     >>> 'Derby announcement' in latest_news(priv_browser.contents)
     True

@@ -158,8 +160,8 @@
     ... name='field.publication_date.announce...

Revision history for this message
Curtis Hovey (sinzui) wrote :

Hi Brad.

This looks good. I have a few remarks. Since we are adding the index
page to this I am marking this

   review needs_fixing

On Wed, 2009-08-19 at 00:45 +0000, Brad Crittenden wrote:
> Thanks for the review Curtis.
...
> class AnnouncementCreateNavigationMenu(NavigationMenu,
> >> AnnouncementMenuMixin):
> >> + """A sub-menu for different aspects of modifying an
> >> announcement."""
> >> +
> >> + usedfor = IAnnouncementCreateMenu
> >> + facet = 'overview'
> >> + title = 'Create announcement'
> >> + links = ('announce', )xmlns:tal="http://xml.zope.org/namespaces/tal
> >> "
> >
> > Menus assume that links are a mutable list. This works, but may lead
> > to
> > cryptic errors if someone extends the menu,
>
> Really? From webapp/menu.py:
>
> assert isinstance(self.links, (tuple, list)), (
> "self.links must be a tuple or list.")
>
> Just grepping through registry/browser/*.py I see a few other examples
> of links being tuples. I've changed this one and the others in this
> module.

Ah! Thank you for showing me this. I am now understand the problem was
not the use if a tuple, but that the engineer assumed the menu he was
extending was a mutable list. You can use a list or a tuple as you want.

...

> > + <a tal:condition="context/url"
> > + tal:attributes="href context/url">
> > + <img src="/@@/link" alt="Link" /> Read more</a>
> >
> > This does not look right. We use sprites. The icon used is for
> > offsite links
> > which these announcements are not. Maybe we need an new sprite for
> > announcement. I think we should report a bug and assign it to Martin.
>
> It is an off-site link. There is no sprite for an off-site link.
> Should we go that route or just leave this as is?

Yes, there is a sprite. The external links on the project page use it.
'external-link' which is the globe the link us showing now.

...
...

> class AnnouncementContextMenu(ContextMenu, AnnouncementMenuMixin):
> """The menu for working with an Announcement."""
> usedfor = IAnnouncement
> - links = ('edit', 'retarget', 'publish', 'retract', 'delete')
> + links = ['edit', 'retarget', 'publish', 'retract', 'delete']

I think we can delete this class. I do not think it will be used since
we have converted all the pages that use this with the index page

...

> === modified file 'lib/lp/registry/templates/hasannouncements-index.pt'
> --- lib/lp/registry/templates/hasannouncements-index.pt 2009-08-17 20:36:01 +0000
> +++ lib/lp/registry/templates/hasannouncements-index.pt 2009-08-19 00:43:48 +0000
> @@ -17,6 +17,7 @@
> <h1>News and announcements</h1>
> </tal:heading>
> <div metal:fill-slot="main">
> + <br />

This looks wrong. <br> are not meant to create blank lines. They so not
belong between block elements because block elements define margins and
padding.

I think you want the op content, or all the content wrapped in a
<div class="top-portlet"> which sets margins and padding.

--

__C U R T I S C. H O V E Y_______
Guilty of stealing everything I am.

review: Needs Fixing
Revision history for this message
Brad Crittenden (bac) wrote :

On Aug 19, 2009, at 16:30 , Curtis Hovey wrote:

> Review: Needs Fixing
> Hi Brad.
>
> This looks good. I have a few remarks. Since we are adding the index
> page to this I am marking this
>
> review needs_fixing

Sure, that work is included in the diff I've got now.

>
> On Wed, 2009-08-19 at 00:45 +0000, Brad Crittenden wrote:
>
>>> + <a tal:condition="context/url"
>>> + tal:attributes="href context/url">
>>> + <img src="/@@/link" alt="Link" /> Read more</a>
>>>
>>> This does not look right. We use sprites. The icon used is for
>>> offsite links
>>> which these announcements are not. Maybe we need an new sprite for
>>> announcement. I think we should report a bug and assign it to
>>> Martin.
>>
>> It is an off-site link. There is no sprite for an off-site link.
>> Should we go that route or just leave this as is?
>
> Yes, there is a sprite. The external links on the project page use it.
> 'external-link' which is the globe the link us showing now.

Thanks for the pointer. I see it uses 'no-follow' too, which I
definitely should have here.

>
> ...
> ...
>
>> class AnnouncementContextMenu(ContextMenu, AnnouncementMenuMixin):
>> """The menu for working with an Announcement."""
>> usedfor = IAnnouncement
>> - links = ('edit', 'retarget', 'publish', 'retract', 'delete')
>> + links = ['edit', 'retarget', 'publish', 'retract', 'delete']
>
> I think we can delete this class. I do not think it will be used since
> we have converted all the pages that use this with the index page

Good call

>
> ...
>
>> === modified file 'lib/lp/registry/templates/hasannouncements-
>> index.pt'
>> --- lib/lp/registry/templates/hasannouncements-index.pt 2009-08-17
>> 20:36:01 +0000
>> +++ lib/lp/registry/templates/hasannouncements-index.pt 2009-08-19
>> 00:43:48 +0000
>> @@ -17,6 +17,7 @@
>> <h1>News and announcements</h1>
>> </tal:heading>
>> <div metal:fill-slot="main">
>> + <br />
>
> This looks wrong. <br> are not meant to create blank lines. They so
> not
> belong between block elements because block elements define margins
> and
> padding.
>
> I think you want the op content, or all the content wrapped in a
> <div class="top-portlet"> which sets margins and padding.

I inserted <div class="top-portlet" style="margin-top: 0.5em;"> which
seems to give a reasonable amount of spacing.

In the update I've also updated announcement-index.pt and made a fix
where the index page for a distribution was getting messed up due to
changes to HasAnnouncementsView (it is marked with an XXX that needs
to be removed when the update to distribution happens).

Revision history for this message
Brad Crittenden (bac) wrote :
Revision history for this message
Brad Crittenden (bac) wrote :

> The diff is at:
>
> http://pastebin.ubuntu.com/256050/

Wrong diff. The real one is at: http://pastebin.ubuntu.com/256052/

Revision history for this message
Curtis Hovey (sinzui) wrote :

Thanks for the fixes and leaving me a XXX to complete my part of task. This is good to land.

review: Approve (code)
Revision history for this message
Brad Crittenden (bac) wrote :

There were additional test problems caused by the fact the distribution page has not been updated. The fixes here are temporary as the tests will be reworked in that effort, especially the distribution navigation tests.

Diff: http://pastebin.ubuntu.com/256282/

Revision history for this message
Brad Crittenden (bac) wrote :

Screenshots for UI review may be found at: https://devpad.canonical.com/~bac/announcements/

Revision history for this message
Paul Hummer (rockstar) wrote :

So, you noticed that the bylines are styled wrong. If the problem is invasive, please file a bug a fix it soon. If it's not, please fix before landing. Otherwise, this looks really good.

review: Approve (ui)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/canonical/launchpad/icing/style-3-0.css'
--- lib/canonical/launchpad/icing/style-3-0.css 2009-08-17 11:22:39 +0000
+++ lib/canonical/launchpad/icing/style-3-0.css 2009-08-17 20:36:01 +0000
@@ -292,11 +292,11 @@
292 font-size: 116%;292 font-size: 116%;
293 }293 }
294ol {294ol {
295 margin-left: 1.8em;295 margin-left: 1.8em;
296 }296 }
297ol li {297ol li {
298 list-style: decimal outside;298 list-style: decimal outside;
299 }299 }
300li {300li {
301 padding-bottom: .3em;301 padding-bottom: .3em;
302 }302 }
@@ -581,6 +581,10 @@
581 border-top: 1px solid #d0d0d0;581 border-top: 1px solid #d0d0d0;
582 border-bottom: 1px solid #d0d0d0;582 border-bottom: 1px solid #d0d0d0;
583 }583 }
584.announcement .registered {
585 font-size: 95%;
586 margin-top: -2px
587 }
584588
585/* From nice_pre in tales.py */589/* From nice_pre in tales.py */
586pre.wrap {590pre.wrap {
@@ -589,4 +593,3 @@
589 white-space: pre-wrap;593 white-space: pre-wrap;
590 word-wrap: break-word;594 word-wrap: break-word;
591}595}
592
593596
=== modified file 'lib/lp/registry/browser/announcement.py'
--- lib/lp/registry/browser/announcement.py 2009-08-11 04:00:47 +0000
+++ lib/lp/registry/browser/announcement.py 2009-08-17 20:36:01 +0000
@@ -21,7 +21,6 @@
21from zope.schema import Choice, TextLine21from zope.schema import Choice, TextLine
2222
23from canonical.cachedproperty import cachedproperty23from canonical.cachedproperty import cachedproperty
24from canonical.config import config
2524
26from lp.registry.interfaces.announcement import IAnnouncement25from lp.registry.interfaces.announcement import IAnnouncement
2726
@@ -70,6 +69,12 @@
70 text = 'Delete announcement'69 text = 'Delete announcement'
71 return Link('+delete', text, icon='trash-icon')70 return Link('+delete', text, icon='trash-icon')
7271
72 @enabled_with_permission('launchpad.Edit')
73 def announce(self):
74 text = 'Make announcement'
75 summary = 'Publish an item of news for this project'
76 return Link('+announce', text, summary, icon='add')
77
7378
74class AnnouncementContextMenu(ContextMenu, AnnouncementMenuMixin):79class AnnouncementContextMenu(ContextMenu, AnnouncementMenuMixin):
75 """The menu for working with an Announcement."""80 """The menu for working with an Announcement."""
@@ -100,6 +105,19 @@
100 self.context = context105 self.context = context
101106
102107
108class IAnnouncementCreateMenu(Interface):
109 """A marker interface for creation announcement navigation menu."""
110
111
112class AnnouncementCreateNavigationMenu(NavigationMenu, AnnouncementMenuMixin):
113 """A sub-menu for different aspects of modifying an announcement."""
114
115 usedfor = IAnnouncementCreateMenu
116 facet = 'overview'
117 title = 'Create announcement'
118 links = ('announce', )
119
120
103class AnnouncementFormMixin:121class AnnouncementFormMixin:
104 """A mixin to provide the common form features."""122 """A mixin to provide the common form features."""
105123
@@ -268,6 +286,9 @@
268286
269class HasAnnouncementsView(LaunchpadView, FeedsMixin):287class HasAnnouncementsView(LaunchpadView, FeedsMixin):
270 """A view class for pillars which have announcements."""288 """A view class for pillars which have announcements."""
289 implements(IAnnouncementCreateMenu)
290
291 batch_size = 5
271292
272 @cachedproperty293 @cachedproperty
273 def feed_url(self):294 def feed_url(self):
@@ -299,7 +320,7 @@
299 def announcement_nav(self):320 def announcement_nav(self):
300 return BatchNavigator(321 return BatchNavigator(
301 self.announcements, self.request,322 self.announcements, self.request,
302 size=config.launchpad.default_batch_size)323 size=self.batch_size)
303324
304325
305class AnnouncementSetView(HasAnnouncementsView):326class AnnouncementSetView(HasAnnouncementsView):
306327
=== modified file 'lib/lp/registry/browser/configure.zcml'
--- lib/lp/registry/browser/configure.zcml 2009-08-16 21:14:53 +0000
+++ lib/lp/registry/browser/configure.zcml 2009-08-17 20:36:01 +0000
@@ -774,6 +774,7 @@
774 module="lp.registry.browser.announcement"774 module="lp.registry.browser.announcement"
775 classes="775 classes="
776 AnnouncementContextMenu776 AnnouncementContextMenu
777 AnnouncementCreateNavigationMenu
777 AnnouncementEditNavigationMenu"/>778 AnnouncementEditNavigationMenu"/>
778 <facet779 <facet
779 facet="overview">780 facet="overview">
780781
=== modified file 'lib/lp/registry/stories/announcements/xx-announcements.txt'
--- lib/lp/registry/stories/announcements/xx-announcements.txt 2009-08-13 18:10:15 +0000
+++ lib/lp/registry/stories/announcements/xx-announcements.txt 2009-08-17 20:36:01 +0000
@@ -205,7 +205,7 @@
205anon_browser.205anon_browser.
206206
207 >>> priv_browser.open('http://launchpad.dev/kubuntu/+announcements')207 >>> priv_browser.open('http://launchpad.dev/kubuntu/+announcements')
208 >>> priv_browser.getLink('Permalink').click()208 >>> priv_browser.getLink('Kubuntu announcement headline').click()
209 >>> link_url = priv_browser.url209 >>> link_url = priv_browser.url
210 >>> anon_browser.open(link_url)210 >>> anon_browser.open(link_url)
211 Traceback (most recent call last):211 Traceback (most recent call last):
@@ -216,7 +216,7 @@
216published:216published:
217217
218 >>> anon_browser.open('http://launchpad.dev/apache/+announcements')218 >>> anon_browser.open('http://launchpad.dev/apache/+announcements')
219 >>> anon_browser.getLink('Permalink').click()219 >>> anon_browser.getLink('Derby announcement headline').click()
220 >>> print anon_browser.title220 >>> print anon_browser.title
221 Derby announcement221 Derby announcement
222222
@@ -317,7 +317,8 @@
317317
318We can publish this announcement immediately.318We can publish this announcement immediately.
319319
320 >>> priv_browser.getLink('Publish now').click()320 >>> priv_browser.getLink('Kubuntu announcement headline').click()
321 >>> priv_browser.getLink('Publish announcement').click()
321 >>> priv_browser.url322 >>> priv_browser.url
322 'http://launchpad.dev/kubuntu/+announceme.../+publish'323 'http://launchpad.dev/kubuntu/+announceme.../+publish'
323 >>> radio = priv_browser.getControl(name="field.publication_date.action")324 >>> radio = priv_browser.getControl(name="field.publication_date.action")
@@ -418,47 +419,16 @@
418Editing announcements419Editing announcements
419---------------------420---------------------
420421
421The page to edit that announcement is linked from the announcement422To edit an announcement you must go to the individual announcement
422listing. If you are anonymous or don't have the right privileges then423page and then follow the proper links.
423you cannot see any edit links:
424
425 >>> anon_browser.open('http://launchpad.dev/tomcat/+announcements')
426 >>> listed_announcements = find_tag_by_id(
427 ... anon_browser.contents, 'announcements')
428 >>> edit_link_text = 'Edit this announcement.'
429 >>> edit_links = listed_announcements.fetch('a', text=edit_link_text)
430 >>> len(edit_links)
431 0
432
433 >>> nopriv_browser.open('http://launchpad.dev/tomcat/+announcements')
434 >>> listed_announcements = find_tag_by_id(
435 ... nopriv_browser.contents, 'announcements')
436 >>> edit_links = listed_announcements.fetch('a', text=edit_link_text)
437 >>> len(edit_links)
438 0
439
440If you have the necessary privileges you will see links to edit the
441announcements.
442424
443 >>> priv_browser.open('http://launchpad.dev/tomcat/+announcements')425 >>> priv_browser.open('http://launchpad.dev/tomcat/+announcements')
444 >>> listed_announcements = find_tag_by_id(
445 ... priv_browser.contents, 'announcements')
446 >>> edit_links = listed_announcements.fetch('a', text=edit_link_text)
447 >>> len(edit_links)
448 2
449
450Following a link takes you to a form where you can change the headline,
451summary and URL of the announcement:
452
453 >>> 'Modified headline' not in announcements(priv_browser.contents)
454 True
455 >>> 'Modified summary' not in announcements(priv_browser.contents)
456 True
457 >>> print priv_browser.getLink('Read more').url426 >>> print priv_browser.getLink('Read more').url
458 http://apache.org/announcement/rocking/427 http://apache.org/announcement/rocking/
459 >>> priv_browser.getLink(edit_link_text).click()428 >>> priv_browser.getLink('Apache announcement headline').click()
429 >>> priv_browser.getLink('Modify announcement').click()
460 >>> print priv_browser.url430 >>> print priv_browser.url
461 http://launchpad.dev/apache/+announcement/...431 http://launchpad.dev/apache/+announcement/.../+edit
462 >>> headline = priv_browser.getControl('Headline')432 >>> headline = priv_browser.getControl('Headline')
463 >>> print headline.value433 >>> print headline.value
464 Apache announcement headline434 Apache announcement headline
@@ -494,7 +464,9 @@
494 True464 True
495 >>> 'Retracted' in announcements(priv_browser.contents)465 >>> 'Retracted' in announcements(priv_browser.contents)
496 False466 False
497 >>> priv_browser.getLink('Retract').click()467 >>> priv_browser.getLink('Kubuntu announcement headline').click()
468 >>> priv_browser.getLink('Delete announcement').click()
469 >>> priv_browser.getLink('retracting the announcement').click()
498 >>> priv_browser.url470 >>> priv_browser.url
499 'http://launchpad.dev/kubuntu/+announcement/.../+retract'471 'http://launchpad.dev/kubuntu/+announcement/.../+retract'
500472
@@ -525,7 +497,8 @@
525497
526Once something has been retracted, it can be published again.498Once something has been retracted, it can be published again.
527499
528 >>> priv_browser.getLink('Publish now').click()500 >>> priv_browser.getLink('Kubuntu announcement headline').click()
501 >>> priv_browser.getLink('Publish announcement').click()
529 >>> priv_browser.url502 >>> priv_browser.url
530 'http://launchpad.dev/kubuntu/+announceme.../+publish'503 'http://launchpad.dev/kubuntu/+announceme.../+publish'
531 >>> radio = priv_browser.getControl(name="field.publication_date.action")504 >>> radio = priv_browser.getControl(name="field.publication_date.action")
@@ -553,7 +526,7 @@
553it.526it.
554527
555 >>> priv_browser.open('http://launchpad.dev/kubuntu/+announcements')528 >>> priv_browser.open('http://launchpad.dev/kubuntu/+announcements')
556 >>> priv_browser.getLink(edit_link_text).click()529 >>> priv_browser.getLink('Kubuntu announcement headline').click()
557 >>> priv_browser.getLink('Move announcement').click()530 >>> priv_browser.getLink('Move announcement').click()
558 >>> print priv_browser.url531 >>> print priv_browser.url
559 http://launchpad.dev/kubuntu/+announcement/.../+retarget532 http://launchpad.dev/kubuntu/+announcement/.../+retarget
@@ -570,7 +543,7 @@
570 >>> kamion_browser = \543 >>> kamion_browser = \
571 ... setupBrowser(auth="Basic colin.watson@ubuntulinux.com:test")544 ... setupBrowser(auth="Basic colin.watson@ubuntulinux.com:test")
572 >>> kamion_browser.open('http://launchpad.dev/guadalinex/+announcements')545 >>> kamion_browser.open('http://launchpad.dev/guadalinex/+announcements')
573 >>> kamion_browser.getLink(edit_link_text).click()546 >>> kamion_browser.getLink('Kubuntu announcement headline').click()
574 >>> kamion_browser.getLink('Move announcement').click()547 >>> kamion_browser.getLink('Move announcement').click()
575 >>> print kamion_browser.url548 >>> print kamion_browser.url
576 http://launchpad.dev/guadalinex/+announcement/.../+retarget549 http://launchpad.dev/guadalinex/+announcement/.../+retarget
@@ -641,8 +614,9 @@
641 >>> priv_browser.open('http://launchpad.dev/guadalinex/+announcements')614 >>> priv_browser.open('http://launchpad.dev/guadalinex/+announcements')
642 >>> 'Kubuntu announcement headline' in announcements(priv_browser.contents)615 >>> 'Kubuntu announcement headline' in announcements(priv_browser.contents)
643 True616 True
644617 >>> priv_browser.getLink('Kubuntu announcement headline').click()
645 >>> priv_browser.getLink('Retract').click()618 >>> priv_browser.getLink('Delete announcement').click()
619 >>> priv_browser.getLink('retracting the announcement').click()
646 >>> priv_browser.url620 >>> priv_browser.url
647 'http://launchpad.dev/guadalinex/+announcement/.../+retract'621 'http://launchpad.dev/guadalinex/+announcement/.../+retract'
648 >>> priv_browser.getControl('Retract').click()622 >>> priv_browser.getControl('Retract').click()
@@ -734,7 +708,8 @@
734 >>> kamion_browser.open('http://launchpad.dev/guadalinex/+announcements')708 >>> kamion_browser.open('http://launchpad.dev/guadalinex/+announcements')
735 >>> no_announcements(kamion_browser.contents)709 >>> no_announcements(kamion_browser.contents)
736 False710 False
737 >>> kamion_browser.getLink('Permanently delete').click()711 >>> kamion_browser.getLink('Kubuntu announcement headline').click()
712 >>> kamion_browser.getLink('Delete announcement').click()
738 >>> print kamion_browser.url713 >>> print kamion_browser.url
739 http://launchpad.dev/guadalinex/+announcement/.../+delete714 http://launchpad.dev/guadalinex/+announcement/.../+delete
740 >>> kamion_browser.getControl('Delete').click()715 >>> kamion_browser.getControl('Delete').click()
741716
=== modified file 'lib/lp/registry/templates/announcement-edit.pt'
--- lib/lp/registry/templates/announcement-edit.pt 2009-08-01 02:04:55 +0000
+++ lib/lp/registry/templates/announcement-edit.pt 2009-08-17 20:36:01 +0000
@@ -5,10 +5,6 @@
5 xmlns:i18n="http://xml.zope.org/namespaces/i18n"5 xmlns:i18n="http://xml.zope.org/namespaces/i18n"
6 metal:use-macro="view/macro:page/main_only"6 metal:use-macro="view/macro:page/main_only"
7 i18n:domain="launchpad">7 i18n:domain="launchpad">
8 <metal:block fill-slot="head_epilogue">
9 <metal:yui-dependencies
10 use-macro="context/@@launchpad_widget_macros/yui2calendar-dependencies" />
11 </metal:block>
12 <body>8 <body>
13 <div metal:fill-slot="main">9 <div metal:fill-slot="main">
14 <div class="top-portlet">10 <div class="top-portlet">
1511
=== modified file 'lib/lp/registry/templates/announcement-listing-detailed.pt'
--- lib/lp/registry/templates/announcement-listing-detailed.pt 2009-07-17 17:59:07 +0000
+++ lib/lp/registry/templates/announcement-listing-detailed.pt 2009-08-17 20:36:01 +0000
@@ -1,59 +1,47 @@
1<h2>1<div class="portlet" tal:attributes="id string:${context/id}">
2 <tal:date tal:condition="context/date_announced">2 <div class="announcement">
3 <span tal:replace="context/date_announced/fmt:date">3 <a tal:attributes="href string:${context/fmt:url}">
4 22 Oct 20084 <h2>
5 </span>:5 <tal:date tal:condition="context/date_announced">
6 </tal:date>6 <span tal:replace="context/date_announced/fmt:date"/>:
7 <tal:title content="context/title">News item title</tal:title>7 </tal:date>
8</h2>8 <tal:title content="context/title">News item title</tal:title>
99 </h2>
10<tal:summary condition="context/summary"10 </a>
11 tal:replace="structure context/summary/fmt:text-to-html" />11
12<p>12 <p class="registered">
13 <a tal:attributes="href string:${context/fmt:url}"13 Written for
14 >Permalink.</a>14 <tal:pillar replace="structure context/target/fmt:link" />
15 <tal:future condition="context/future">15 by
16 <img src="/@@/warning" title="Announcement is not yet public" />16 <tal:registrant replace="structure context/registrant/fmt:link" />.
17 <strong tal:condition="context/active">17 </p>
18 <tal:date_set condition="context/date_announced">18
19 This will be published on19 <tal:summary condition="context/summary"
20 <span tal:replace="context/date_announced/fmt:datetime" />20 tal:replace="structure context/summary/fmt:text-to-html" />
21 </tal:date_set>21 <p>
22 </strong>22 <tal:future condition="context/future">
23 </tal:future>23 <img src="/@@/warning" title="Announcement is not yet public." />
24 <strong tal:condition="not: context/active">24 <strong tal:condition="context/active">
25 [Retracted]25 <tal:date_set condition="context/date_announced">
26 </strong>26 This announcement will be published on
27 <strong tal:condition="not: context/date_announced">27 <span tal:replace="context/date_announced/fmt:datetime" />.
28 No publishing date set.28 </tal:date_set>
29 </strong>29 </strong>
30 <strong tal:condition="context/date_last_modified">30 </tal:future>
31 Updated31 <strong tal:condition="not: context/active">
32 <span tal:replace="context/date_last_modified/fmt:displaydate" />.32 <img src="/@@/info" title="Announcement has been retracted." />
33 </strong>33 Retracted.
34 <a tal:condition="context/url"34 </strong>
35 tal:attributes="href context/url">35 <strong tal:condition="not: context/date_announced">
36 <img src="/@@/link" alt="Link" /> Read more...</a>36 No publishing date set.
37</p>37 </strong>
38<p>38 <strong tal:condition="context/date_last_modified">
39 <tal:editor condition="context/required:launchpad.Edit">39 Updated
40 <img src="/@@/edit" alt="[Edit]" />40 <span tal:replace="context/date_last_modified/fmt:displaydate" />.
41 <a tal:attributes="href string:${context/fmt:url}/+edit"41 </strong>
42 >Edit this announcement.</a>42 <a tal:condition="context/url"
43 <a tal:condition="not: context/published"43 tal:attributes="href context/url">
44 tal:attributes="href string:${context/fmt:url}/+publish"44 <img src="/@@/link" alt="Link" /> Read more</a>
45 >Publish now.</a>45 </p>
46 <a tal:condition="context/active"46 </div>
47 tal:attributes="href string:${context/fmt:url}/+retract"47</div>
48 >Retract this announcement.</a>
49 <a tal:condition="not: context/active"
50 tal:attributes="href string:${context/fmt:url}/+delete"
51 >Permanently delete this announcement.</a>
52 <br />
53 </tal:editor>
54 Created for
55 <tal:pillar replace="structure context/target/fmt:link" />
56 <tal:date_created replace="context/date_created/fmt:displaydate" />
57 by
58 <tal:registrant replace="structure context/registrant/fmt:link" />
59</p>
6048
=== modified file 'lib/lp/registry/templates/hasannouncements-index.pt'
--- lib/lp/registry/templates/hasannouncements-index.pt 2009-07-17 17:59:07 +0000
+++ lib/lp/registry/templates/hasannouncements-index.pt 2009-08-17 20:36:01 +0000
@@ -3,53 +3,73 @@
3 xmlns:tal="http://xml.zope.org/namespaces/tal"3 xmlns:tal="http://xml.zope.org/namespaces/tal"
4 xmlns:metal="http://xml.zope.org/namespaces/metal"4 xmlns:metal="http://xml.zope.org/namespaces/metal"
5 xmlns:i18n="http://xml.zope.org/namespaces/i18n"5 xmlns:i18n="http://xml.zope.org/namespaces/i18n"
6 xml:lang="en"6 metal:use-macro="view/macro:page/main_side"
7 lang="en"7 i18n:domain="launchpad">
8 dir="ltr"8
9 metal:use-macro="view/macro:page/onecolumn"9 <metal:atom fill-slot="head_epilogue">
10 i18n:domain="launchpad"10 <link rel="alternate" type="application/atom+xml" tal:attributes="
11>11 href view/feed_url;
1212 title string:Announcements for ${context/displayname}" />
13<body>13 </metal:atom>
1414
15<metal:portlets fill-slot="portlets">15 <body>
16</metal:portlets>16 <tal:heading metal:fill-slot="heading">
1717 <h1>News and announcements</h1>
18<metal:atom fill-slot="head_epilogue">18 </tal:heading>
19 <link rel="alternate" type="application/atom+xml" tal:attributes="19 <div metal:fill-slot="main">
20 href view/feed_url;20 <p tal:condition="not: view/announcement_nav/batch/listlength">
21 title string:Announcements for ${context/displayname}" />21 There are no announcements for this project.
22</metal:atom>22 </p>
2323
24<p metal:fill-slot="help">24 <div tal:condition="view/announcement_nav/batch/listlength"
25 Project administrators can publish additional announcements, edit these25 id="announcements">
26 announcements or retract them.26 <tal:per_announcement
27</p>27 repeat="announcement view/announcement_nav/currentBatch"
2828 replace="structure announcement/@@+listing-detailed" />
29<div metal:fill-slot="main">29 </div>
3030 <div class="lesser"
31 <h1>News and announcements</h1>31 tal:content="structure view/announcement_nav/@@+navigation-links-lower"
3232 />
33 <p tal:condition="view/announcement_nav/batch/listlength">33 </div>
34 These announcements are available as an 34
35 <a tal:attributes="href view/feed_url">35 <tal:side metal:fill-slot="side"
36 <img src="/@@/rss" alt="" /> Atom/RSS feed</a>.36 define="announcements view/announcement_nav/currentBatch;
37 </p>37 overview_menu context/menu:overview">
3838
39 <p tal:condition="not: view/announcement_nav/batch/listlength">39 <tal:menu replace="structure view/@@+global-actions" />
40 There are no announcements for this project.40
41 </p>41 <div class="portlet">
4242 <h2>
43 <div tal:condition="view/announcement_nav/batch/listlength" id="announcements">43 <span style="float: right;">
44 <tal:per_announcement44 <a title="Atom 1.0 feed"
45 repeat="announcement view/announcement_nav/currentBatch"45 tal:attributes="href view/feed_url"><img src="/@@/rss.png"/></a>
46 replace="structure announcement/@@+listing-detailed" />46 </span>
47 </div>47 Announcements
4848 </h2>
49 <div class="lesser"49
50 tal:content="structure view/announcement_nav/@@+navigation-links-lower"50 <p tal:condition="not: view/announcement_nav/batch/listlength">
51 />51 <tal:name replace="context/displayname" /> has no announcements.
5252 </p>
53</div>53
54</body>54 <tal:announcements tal:condition="view/announcement_nav/batch/listlength">
55 <ul>
56 <li tal:repeat="announcement announcements">
57 <img src="/@@/warning" alt="[Not published]"
58 title="This is not yet a public announcement"
59 tal:condition="not: announcement/published" />
60 <a tal:attributes="href string:#${announcement/id}"
61 tal:content="announcement/title">
62 Announcement title
63 </a>
64 <strong
65 tal:condition="announcement/date_announced"
66 tal:content="announcement/date_announced/fmt:displaydate" />
67 <br />
68 <br />
69 </li>
70 </ul>
71 </tal:announcements>
72 </div>
73 </tal:side>
74 </body>
55</html>75</html>