launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #03735
[Merge] lp:~wallyworld/launchpad/irc-nickname-formatter into lp:launchpad
Ian Booth has proposed merging lp:~wallyworld/launchpad/irc-nickname-formatter into lp:launchpad.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
Bug #787650 in Launchpad itself: "Add an IRC nick formatter"
https://bugs.launchpad.net/launchpad/+bug/787650
For more details, see:
https://code.launchpad.net/~wallyworld/launchpad/irc-nickname-formatter/+merge/62237
Add a tales irc nick formatter
== Implementation ==
Pretty straightforward. Add a new IRCNicknameFormatterAPI class. It supports the following traversals:
/fmt:displayname
/fmt:formatted_displayname
The displayname returns straight text "fred on irc.freenode.net" and is what will be required for rendering on the picker later.
The formatted_displayname returns html markup, and is equivalent to what is rendered on a user's home page now, except that it says "... on ..." instead of "... on network...". The person contact details portlet has been updated to use the new formatter.
== Tests ==
Add new TestIRCNicknameFormatterAPI test case to test_tales.py
== Lint ==
Checking for conflicts and issues in changed files.
Linting changed files:
lib/lp/app/browser/configure.zcml
lib/lp/app/browser/tales.py
lib/lp/app/tests/test_tales.py
lib/lp/registry/templates/person-portlet-contact-details.pt
--
https://code.launchpad.net/~wallyworld/launchpad/irc-nickname-formatter/+merge/62237
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~wallyworld/launchpad/irc-nickname-formatter into lp:launchpad.
=== modified file 'lib/lp/app/browser/configure.zcml'
--- lib/lp/app/browser/configure.zcml 2011-03-09 20:39:15 +0000
+++ lib/lp/app/browser/configure.zcml 2011-05-25 05:15:57 +0000
@@ -273,6 +273,13 @@
/>
<adapter
+ for="lp.registry.interfaces.irc.IIrcID"
+ provides="zope.traversing.interfaces.IPathAdapter"
+ factory="lp.app.browser.tales.IRCNicknameFormatterAPI"
+ name="fmt"
+ />
+
+ <adapter
for="datetime.timedelta"
provides="zope.traversing.interfaces.IPathAdapter"
factory="lp.app.browser.tales.DurationFormatterAPI"
=== modified file 'lib/lp/app/browser/tales.py'
--- lib/lp/app/browser/tales.py 2011-03-27 22:53:50 +0000
+++ lib/lp/app/browser/tales.py 2011-05-25 05:15:57 +0000
@@ -4,6 +4,7 @@
# pylint: disable-msg=C0103,W0613,R0911,F0401
#
"""Implementation of the lp: htmlform: fmt: namespaces in TALES."""
+from textwrap import dedent
__metaclass__ = type
@@ -497,7 +498,7 @@
# We are interested in the default value (param2).
result = ''
for nm in self.allowed_names:
- if name.startswith(nm+":"):
+ if name.startswith(nm + ":"):
name_parts = name.split(":")
name = name_parts[0]
if len(name_parts) > 2:
@@ -2051,7 +2052,7 @@
delta = abs(delta)
days = delta.days
hours = delta.seconds / 3600
- minutes = (delta.seconds - (3600*hours)) / 60
+ minutes = (delta.seconds - (3600 * hours)) / 60
seconds = delta.seconds % 60
result = ''
if future:
@@ -2129,7 +2130,7 @@
parts = []
minutes, seconds = divmod(self._duration.seconds, 60)
hours, minutes = divmod(minutes, 60)
- seconds = seconds + (float(self._duration.microseconds) / 10**6)
+ seconds = seconds + (float(self._duration.microseconds) / 10 ** 6)
if self._duration.days > 0:
if self._duration.days == 1:
parts.append('%d day' % self._duration.days)
@@ -2175,7 +2176,7 @@
# including the decimal part.
seconds = self._duration.days * (3600 * 24)
seconds += self._duration.seconds
- seconds += (float(self._duration.microseconds) / 10**6)
+ seconds += (float(self._duration.microseconds) / 10 ** 6)
# First we'll try to calculate an approximate number of
# seconds up to a minute. We'll start by defining a sorted
@@ -2655,3 +2656,24 @@
return getattr(self, name)(furtherPath)
except AttributeError:
raise TraversalError(name)
+
+
+class IRCNicknameFormatterAPI(ObjectFormatterAPI):
+ """Adapter from IrcID objects to a formatted string."""
+
+ implements(ITraversable)
+
+ traversable_names = {
+ 'displayname': 'displayname',
+ 'formatted_displayname': 'formatted_displayname',
+ }
+
+ def displayname(self, view_name=None):
+ return "%s on %s" % (self._context.nickname, self._context.network)
+
+ def formatted_displayname(self, view_name=None):
+ return dedent("""\
+ <strong>%s</strong>
+ <span class="discreet"> on </span>
+ <strong>%s</strong>
+ """ % (self._context.nickname, self._context.network))
=== modified file 'lib/lp/app/tests/test_tales.py'
--- lib/lp/app/tests/test_tales.py 2011-04-21 01:44:06 +0000
+++ lib/lp/app/tests/test_tales.py 2011-05-25 05:15:57 +0000
@@ -5,7 +5,10 @@
from lxml import html
-from zope.component import getAdapter
+from zope.component import (
+ getAdapter,
+ getUtility
+ )
from zope.traversing.interfaces import (
IPathAdapter,
TraversalError,
@@ -19,6 +22,7 @@
format_link,
PersonFormatterAPI,
)
+from lp.registry.interfaces.irc import IIrcIDSet
from lp.testing import (
test_tales,
TestCaseWithFactory,
@@ -141,7 +145,8 @@
# The rendering of an object's link ignores any specified default
# value which would be used in the case where the object were None.
person = self.factory.makePerson()
- person_link = test_tales('person/fmt:link::default value', person=person)
+ person_link = test_tales(
+ 'person/fmt:link::default value', person=person)
self.assertEqual(PersonFormatterAPI(person).link(None), person_link)
person_link = test_tales(
'person/fmt:link:bugs:default value', person=person)
@@ -264,3 +269,29 @@
extra = ['1', '2']
self.assertEqual('', traverse('shorten', extra))
self.assertEqual(['1'], extra)
+
+
+class TestIRCNicknameFormatterAPI(TestCaseWithFactory):
+ """Tests for IRCNicknameFormatterAPI"""
+
+ layer = DatabaseFunctionalLayer
+
+ def test_nick_displayname(self):
+ person = self.factory.makePerson(name='fred')
+ ircset = getUtility(IIrcIDSet)
+ ircID = ircset.new(person, "irc.canonical.com", "fred")
+ self.assertEqual(
+ 'fred on irc.canonical.com',
+ test_tales('nick/fmt:displayname', nick=ircID))
+
+ def test_nick_formatted_displayname(self):
+ person = self.factory.makePerson(name='fred')
+ ircset = getUtility(IIrcIDSet)
+ ircID = ircset.new(person, "irc.canonical.com", "fred")
+ expected_html = test_tales(
+ 'nick/fmt:formatted_displayname', nick=ircID)
+ self.assertEquals(
+ u'<strong>fred</strong>\n'
+ '<span class="discreet"> on </span>\n'
+ '<strong>irc.canonical.com</strong>\n',
+ expected_html)
=== modified file 'lib/lp/registry/templates/person-portlet-contact-details.pt'
--- lib/lp/registry/templates/person-portlet-contact-details.pt 2010-12-01 22:05:51 +0000
+++ lib/lp/registry/templates/person-portlet-contact-details.pt 2011-05-25 05:15:57 +0000
@@ -134,9 +134,7 @@
<a tal:replace="structure overview_menu/editircnicknames/fmt:icon" />
</dt>
<dd tal:repeat="ircnick context/ircnicknames">
- <strong tal:content="ircnick/nickname"/>
- <span class="discreet">on network</span>
- <strong tal:content="ircnick/network" />
+ <span tal:replace="structure ircnick/fmt:formatted_displayname"/>
</dd>
<dd tal:condition="not: context/ircnicknames">
No IRC nicknames registered.