4982.2.1
by Brad Crittenden
Working ZCML feeds directive |
1 |
= Feeds components = |
2 |
||
4898.3.65
by Elliot Murphy
More test cleanup on feeds doctest. |
3 |
`feeds` is a ZCML directive for handling feeds requests. The |
4982.2.1
by Brad Crittenden
Working ZCML feeds directive |
4 |
directive requires minimal ZCML configuration and relies on |
5 |
implementing view classes defining the `usedfor` and `name` class |
|
6 |
variables. |
|
7 |
||
8 |
Feeds are defined on the `FeedsLayer` layer. |
|
9 |
||
4898.3.65
by Elliot Murphy
More test cleanup on feeds doctest. |
10 |
|
4982.2.1
by Brad Crittenden
Working ZCML feeds directive |
11 |
== Demonstrating a feeds class == |
12 |
||
13 |
In order to demonstrate a feed class, we need to create an interface |
|
14 |
for the thing comprising the feed. Rather than use a standard |
|
15 |
Launchpad interface, we'll define one here. |
|
16 |
||
17 |
>>> from zope.interface import Interface, Attribute, implements |
|
14557.1.11
by Curtis Hovey
Moved feeds to lp.feeds. |
18 |
>>> from lp.services.feeds.tests.helper import ( |
5062.2.2
by Brad Crittenden
Changes due to review. |
19 |
... IThing, Thing, ThingFeedView) |
4982.2.1
by Brad Crittenden
Working ZCML feeds directive |
20 |
|
21 |
||
22 |
== ZCML for browser:feeds == |
|
23 |
||
4898.3.65
by Elliot Murphy
More test cleanup on feeds doctest. |
24 |
The zcml `browser:feeds` directive describes a feed view. |
4982.2.1
by Brad Crittenden
Working ZCML feeds directive |
25 |
|
26 |
>>> from zope.configuration import xmlconfig |
|
27 |
>>> zcmlcontext = xmlconfig.string(""" |
|
28 |
... <configure xmlns:browser="http://namespaces.zope.org/browser"> |
|
14600.2.2
by Curtis Hovey
Moved webapp to lp.services. |
29 |
... <include package="lp.services.webapp" file="meta.zcml" /> |
8521.3.10
by Gary Poster
address test failures found in last ec2test run |
30 |
... <include package="zope.app.zcmlfiles" file="meta.zcml" /> |
4982.2.1
by Brad Crittenden
Working ZCML feeds directive |
31 |
... <browser:feeds |
14557.1.11
by Curtis Hovey
Moved feeds to lp.feeds. |
32 |
... module="lp.services.feeds.tests.helper" |
4982.2.1
by Brad Crittenden
Working ZCML feeds directive |
33 |
... classes="ThingFeedView" |
34 |
... /> |
|
35 |
... </configure> |
|
36 |
... """) |
|
37 |
||
38 |
Get the view from a `thing` on 'thing-feed' for a request. |
|
39 |
||
40 |
>>> from zope.component import getMultiAdapter |
|
14600.2.2
by Curtis Hovey
Moved webapp to lp.services. |
41 |
>>> from lp.services.webapp.servers import LaunchpadTestRequest |
42 |
>>> from lp.services.webapp.testing import verifyObject |
|
4982.2.1
by Brad Crittenden
Working ZCML feeds directive |
43 |
|
44 |
>>> request = LaunchpadTestRequest() |
|
45 |
||
46 |
To successfully get a view, the lookup must be on an object that is an |
|
5062.2.2
by Brad Crittenden
Changes due to review. |
47 |
`IThing` and the view name must be one that is supported. If the |
4982.2.1
by Brad Crittenden
Working ZCML feeds directive |
48 |
view is not found a ComponentLookupError is raised. Also, the request |
49 |
must be in the FeedsLayer. |
|
50 |
||
51 |
The request we just created is not in the FeedsLayer, so the view will |
|
52 |
not be found. |
|
53 |
||
54 |
>>> thing = Thing('thing 1') |
|
55 |
>>> verifyObject(IThing, thing) |
|
56 |
True |
|
57 |
>>> feed_view = getMultiAdapter((thing, request), name='thing-feed.xml') |
|
58 |
Traceback (most recent call last): |
|
59 |
... |
|
60 |
ComponentLookupError: ... |
|
61 |
||
62 |
Set the layer on the request for all subsequent uses. |
|
63 |
||
14600.1.8
by Curtis Hovey
Move c.l.layers to lp. |
64 |
>>> from lp.layers import setFirstLayer, FeedsLayer |
4982.2.1
by Brad Crittenden
Working ZCML feeds directive |
65 |
>>> setFirstLayer(request, FeedsLayer) |
66 |
||
67 |
If the context object is not an IThing then the view will not be |
|
68 |
found. |
|
69 |
||
70 |
>>> thing = object() |
|
71 |
>>> verifyObject(IThing, thing) |
|
72 |
Traceback (most recent call last): |
|
73 |
... |
|
74 |
DoesNotImplement: ... |
|
75 |
>>> feed_view = getMultiAdapter((thing, request), name='thing-feed.atom') |
|
76 |
Traceback (most recent call last): |
|
77 |
... |
|
78 |
ComponentLookupError: ... |
|
79 |
||
80 |
If the name is not one of the supported names the view will not be |
|
81 |
found. |
|
82 |
||
83 |
>>> thing = Thing('thing 1') |
|
84 |
>>> verifyObject(IThing, thing) |
|
85 |
True |
|
86 |
>>> feed_view = getMultiAdapter((thing, request), name='thing-feed.xml') |
|
87 |
Traceback (most recent call last): |
|
88 |
... |
|
89 |
ComponentLookupError: ... |
|
90 |
||
91 |
If the thing is an IThing and the name is supported the view will be |
|
92 |
found, indicated by the absence of a ComponentLookupError. |
|
93 |
||
94 |
>>> thing = Thing('thing 1') |
|
95 |
>>> verifyObject(IThing, thing) |
|
96 |
True |
|
4898.3.65
by Elliot Murphy
More test cleanup on feeds doctest. |
97 |
>>> for name in ['thing-feed.atom', 'thing-feed.html']: |
4982.2.1
by Brad Crittenden
Working ZCML feeds directive |
98 |
... feed_view = getMultiAdapter((thing, request), name=name) |
4898.3.65
by Elliot Murphy
More test cleanup on feeds doctest. |
99 |
... print feed_view() |
100 |
a feed view on an IThing |
|
101 |
a feed view on an IThing |
|
102 |
||
5132.2.1
by Edwin Grubbs
Added configuration options and tests. |
103 |
== Feeds Configuration Options == |
104 |
||
105 |
The max_feed_cache_minutes and the max_bug_feed_cache_minutes |
|
106 |
configurations are provided to allow overriding the Expires |
|
107 |
and Cache-Control headers so that the feeds will be cached longer |
|
108 |
by browsers and the reverse-proxy in front of the feeds servers. |
|
109 |
||
14605.1.1
by Curtis Hovey
Moved canonical.config to lp.services. |
110 |
>>> from lp.services.config import config |
14606.4.2
by William Grant
merge canonical.lazr.feed into lp.services.feeds. |
111 |
>>> from lp.services.feeds.feed import FeedBase |
8523.3.1
by Gavin Panella
Bugs tree reorg after automated migration. |
112 |
>>> from lp.bugs.feed.bug import BugsFeedBase |
5132.2.1
by Edwin Grubbs
Added configuration options and tests. |
113 |
>>> config.launchpad.max_feed_cache_minutes |
114 |
60 |
|
115 |
>>> config.launchpad.max_bug_feed_cache_minutes |
|
116 |
30 |
|
117 |
>>> FeedBase.max_age |
|
118 |
3600 |
|
119 |
>>> BugsFeedBase.max_age |
|
120 |
1800 |
|
5132.2.3
by Edwin Grubbs
Made changes recommended by jamesh. |
121 |
>>> config.launchpad.max_feed_cache_minutes * 60 == FeedBase.max_age |
5132.2.1
by Edwin Grubbs
Added configuration options and tests. |
122 |
True |
5132.2.3
by Edwin Grubbs
Made changes recommended by jamesh. |
123 |
>>> (config.launchpad.max_bug_feed_cache_minutes * 60 |
124 |
... == BugsFeedBase.max_age) |
|
5132.2.1
by Edwin Grubbs
Added configuration options and tests. |
125 |
True |
4982.2.1
by Brad Crittenden
Working ZCML feeds directive |
126 |
|
5429.1.1
by Edwin Grubbs
Escaping html in atom feeds in order to get around IE7 not allowing |
127 |
|
128 |
== FeedTypedData class == |
|
129 |
||
130 |
The FeedTypedData class performs the appropriate escaping for data |
|
131 |
with a type of "text", "html", or "xhtml". The template is responsible |
|
132 |
for setting the "type" attribute in the <title> or <content> element. If |
|
133 |
no content type is specified, then "text" is assumed. |
|
134 |
||
135 |
Since plain text and html are not valid xml, "<", ">", and "&" must |
|
136 |
be escaped using xml entities such as "<". |
|
137 |
||
14606.4.2
by William Grant
merge canonical.lazr.feed into lp.services.feeds. |
138 |
>>> from lp.services.feeds.feed import FeedTypedData |
5429.1.1
by Edwin Grubbs
Escaping html in atom feeds in order to get around IE7 not allowing |
139 |
>>> text = FeedTypedData("<b> and and &") |
140 |
>>> text.content |
|
141 |
'<b> and &nbsp; and &amp;' |
|
142 |
>>> text2 = FeedTypedData("<b> and and &", content_type="text") |
|
143 |
>>> text2.content |
|
144 |
'<b> and &nbsp; and &amp;' |
|
145 |
>>> html = FeedTypedData("<b> and and &", content_type="html") |
|
146 |
>>> html.content |
|
147 |
'<b> and &nbsp; and &amp;' |
|
148 |
||
149 |
Since xhtml is valid xml, the "<" and ">" characters do not need to be |
|
150 |
escaped. However, xhtml supports many more entities than xml, and Internet |
|
151 |
Explorer 7 does not allow a DTD to be specified in feeds which prevents the |
|
152 |
xhtml entities from easily being registered in the xml document. Therefore, |
|
153 |
the xhtml entities will be converted to valid UTF-8. Since some simplistic |
|
5429.1.2
by Edwin Grubbs
Changed templates and HasAnnouncementsView to use the FeedsMixin |
154 |
feed readers may expect ascii, we prefer using "html" over "xhtml", however, |
155 |
we are testing xhtml encoding here in case we need it in the future. |
|
5429.1.1
by Edwin Grubbs
Escaping html in atom feeds in order to get around IE7 not allowing |
156 |
|
157 |
>>> xhtml = FeedTypedData("<b> and and &</b><hr/>", |
|
158 |
... content_type="xhtml") |
|
159 |
>>> xhtml.content |
|
9010.4.4
by Guilherme Salgado
Fix a couple tests that broke because of the way the new BeautifulSoup handles references |
160 |
u'<b> and \xa0 and &</b><hr />' |
5549.2.2
by Edwin Grubbs
Call validate_feed() in xx-branch-atom.txt and xx-announcements.txt |
161 |
|
162 |
||
163 |
== validate_feed() helper function == |
|
164 |
||
165 |
Pagetests can use the validate_feed() function to perform all the |
|
166 |
checks available at http://feedvalidator.org |
|
167 |
||
168 |
Occasionally, there will be suggestions from feedvalidator that we will |
|
169 |
ignore. For example, when the <title type="text"> element contains html, |
|
170 |
we want to view the html as opposed to having the title text formatted. |
|
5549.2.4
by Edwin Grubbs
feeds.txt wording fix |
171 |
Therefore, we won't set type="html" for the title element. |
5549.2.2
by Edwin Grubbs
Call validate_feed() in xx-branch-atom.txt and xx-announcements.txt |
172 |
|
173 |
>>> feed = """<?xml version="1.0" encoding="UTF-8"?> |
|
174 |
... <feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"> |
|
175 |
... <id>one</id> |
|
176 |
... <title>Bugs in Launchpad itself</title> |
|
177 |
... <link rel="self" href="http://foo.bar" /> |
|
178 |
... <updated>2006-05-19T06:37:40.344941+00:00</updated> |
|
179 |
... <entry> |
|
180 |
... <id>http://launchpad.dev/entry</id> |
|
181 |
... <author></author> |
|
182 |
... <updated>2007-05-19T06:37:40.344941+00:00</updated> |
|
183 |
... <title type="text"><b>hello</b></title> |
|
184 |
... <content type="html"><b>hello</b></content> |
|
185 |
... </entry> |
|
186 |
... </feed>""" |
|
14557.1.11
by Curtis Hovey
Moved feeds to lp.feeds. |
187 |
>>> from lp.services.feeds.tests.helper import validate_feed |
5549.2.2
by Edwin Grubbs
Call validate_feed() in xx-branch-atom.txt and xx-announcements.txt |
188 |
>>> validate_feed(feed, '/atom+xml', 'http://ubuntu.com') |
189 |
-------- Error: InvalidFullLink -------- |
|
190 |
Backupcolumn: 7 |
|
191 |
Backupline: 3 |
|
192 |
Column: 7 |
|
193 |
Element: id |
|
194 |
Line: 3 |
|
195 |
Parent: feed |
|
196 |
Value: one |
|
197 |
= |
|
198 |
1: <?xml version="1.0" encoding="UTF-8"?> |
|
199 |
2: <feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"> |
|
200 |
3: <id>one</id> |
|
201 |
: ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
202 |
4: <title>Bugs in Launchpad itself</title> |
|
203 |
5: <link rel="self" href="http://foo.bar" /> |
|
204 |
= |
|
205 |
-------- Error: MissingElement -------- |
|
206 |
Backupcolumn: 12 |
|
207 |
Backupline: 9 |
|
208 |
Column: 12 |
|
209 |
Element: name |
|
210 |
Line: 9 |
|
211 |
Parent: author |
|
212 |
= |
|
213 |
7: <entry> |
|
214 |
8: <id>http://launchpad.dev/entry</id> |
|
215 |
9: <author></author> |
|
216 |
: ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
217 |
10: <updated>2007-05-19T06:37:40.344941+00:00</updated> |
|
218 |
11: <title type="text"><b>hello</b></title> |
|
219 |
= |
|
220 |
-------- Warning: UnexpectedContentType -------- |
|
221 |
Contenttype: /atom+xml |
|
222 |
Type: Feeds |
|
223 |
-------- Warning: SelfDoesntMatchLocation -------- |
|
224 |
Backupcolumn: 41 |
|
225 |
Backupline: 5 |
|
226 |
Column: 41 |
|
227 |
Element: href |
|
228 |
Line: 5 |
|
229 |
Parent: feed |
|
230 |
Location: http://ubuntu.com |
|
231 |
= |
|
232 |
3: <id>one</id> |
|
233 |
4: <title>Bugs in Launchpad itself</title> |
|
234 |
5: <link rel="self" href="http://foo.bar" /> |
|
235 |
: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~ |
|
236 |
6: <updated>2006-05-19T06:37:40.344941+00:00</updated> |
|
237 |
7: <entry> |
|
238 |
= |
|
239 |
-------- Warning: ContainsUndeclaredHTML -------- |
|
240 |
Backupcolumn: 47 |
|
241 |
Backupline: 11 |
|
242 |
Column: 47 |
|
243 |
Element: title |
|
244 |
Line: 11 |
|
245 |
Parent: entry |
|
246 |
Value: b |
|
247 |
= |
|
248 |
9: <author></author> |
|
249 |
10: <updated>2007-05-19T06:37:40.344941+00:00</updated> |
|
250 |
11: <title type="text"><b>hello</b></title> |
|
251 |
: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~ |
|
252 |
12: <content type="html"><b>hello</b></content> |
|
253 |
13: </entry> |
|
254 |
= |