Merge lp:~sinzui/launchpad/rdf-links-0 into lp:launchpad

Proposed by Curtis Hovey
Status: Merged
Merged at revision: 11630
Proposed branch: lp:~sinzui/launchpad/rdf-links-0
Merge into: lp:launchpad
Diff against target: 549 lines (+86/-194)
13 files modified
lib/lp/registry/browser/__init__.py (+28/-0)
lib/lp/registry/browser/person.py (+5/-41)
lib/lp/registry/browser/product.py (+6/-21)
lib/lp/registry/browser/productrelease.py (+8/-23)
lib/lp/registry/browser/productseries.py (+5/-21)
lib/lp/registry/browser/project.py (+5/-20)
lib/lp/registry/stories/person/xx-person-rdf.txt (+9/-46)
lib/lp/registry/stories/product/xx-product-rdf.txt (+1/-6)
lib/lp/registry/stories/project/xx-project-rdf.txt (+1/-6)
lib/lp/registry/templates/person-rdf-contents.pt (+3/-4)
lib/lp/registry/templates/product-rdf.pt (+5/-2)
lib/lp/registry/templates/productrelease-rdf.pt (+5/-2)
lib/lp/registry/templates/project-rdf.pt (+5/-2)
To merge this branch: bzr merge lp:~sinzui/launchpad/rdf-links-0
Reviewer Review Type Date Requested Status
Abel Deuring (community) code Approve
Review via email: mp+36475@code.launchpad.net

Description of the change

This is my branch to reduce the work performed in +rdf views to prevent
timeouts.

    lp:~sinzui/launchpad/rdf-links-0
    Diff size: 550
    Launchpad bug:
          https://bugs.launchpad.net/bugs/360699
          https://bugs.launchpad.net/bugs/30793
    Test command: ./bin/test -vv \
          -t stories/.*rdf
    Pre-implementation: lifeless
    Target release: 10.10

Reduce the work performed in +rdf views to prevent timeouts
-----------------------------------------------------------

The example project RDF that times out are those owned by large teams. The
template uses a macro that renders the personal data for each member. Though
the method is optimised for a small team, it sill never scale to a large
team. Instead of using the macro to expand the owner, use a reference to the
person/team's rdf entry.

This problem is larger than to reported oopses. Project pages are indexed by
bots following links. The RDF for the owning teams also times out if you
try to access it; the link in in the head, not body of the page.

This branch also introduces a base class for RDF views because the
implementations are identical except for template and filename.

Rules
-----

    * Update the RDF templates to include a reference to owner instead
      embedding personal data.
    * Remove the method that tries to collect team member information since
      it will not be used

    ADDENDUM
    * Extract a base class for the RDF views. Each subclass must provide
      a template and a filename.

QA
--

    * Visit https://edge.launchpad.net/bughelper-data/+rdf
    * Verify the page does not timeout
    * Visit https://edge.launchpad.net/~bugsquad/+rdf
    * Verify the page does not timeout

Lint
----

Linting changed files:
  lib/lp/registry/browser/__init__.py
  lib/lp/registry/browser/person.py
  lib/lp/registry/browser/product.py
  lib/lp/registry/browser/productrelease.py
  lib/lp/registry/browser/productseries.py
  lib/lp/registry/browser/project.py
  lib/lp/registry/stories/person/xx-person-rdf.txt
  lib/lp/registry/stories/product/xx-product-rdf.txt
  lib/lp/registry/stories/project/xx-project-rdf.txt
  lib/lp/registry/templates/person-rdf-contents.pt
  lib/lp/registry/templates/product-rdf.pt
  lib/lp/registry/templates/productrelease-rdf.pt
  lib/lp/registry/templates/project-rdf.pt

^ Lint reports a lot in indentation and line length issues un the rdf tests.
I will fix these after the review because the fix will make it appear that
I changed the entire file.

Test
----

Updated the tests to verify that members are referenced as resources instead
of being embedded.

    * lib/lp/registry/stories/product/xx-product-rdf.txt
    * lib/lp/registry/stories/project/xx-project-rdf.txt
    * lib/lp/registry/stories/person/xx-person-rdf.txt
      * Updated the ascii test to use carlos directly since he is not embedded
        in the team RDF.
      * Removed the embedded member in team test for mugshots. The image
        tests for users continue to work.

Implementation
--------------

Updated the templates to reference the person/team instead of embedding
the person/member's information. Remove trailing whitespace from some
templates and removed the definition of the macro used to expand members.

    * lib/lp/registry/templates/product-rdf.pt
    * lib/lp/registry/templates/productrelease-rdf.pt
    * lib/lp/registry/templates/project-rdf.pt
    * lib/lp/registry/templates/person-rdf-contents.pt

Extracted BaseRdfView view and updated the views to inherit. The existing
tests verify the filename and content types.

    * lib/lp/registry/browser/__init__.py
    * lib/lp/registry/browser/product.py
    * lib/lp/registry/browser/productrelease.py
    * lib/lp/registry/browser/productseries.py
    * lib/lp/registry/browser/project.py
    * lib/lp/registry/browser/person.py
      * Also removed buildMemberData() which is not needed.

To post a comment you must log in.
Revision history for this message
Abel Deuring (adeuring) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/registry/browser/__init__.py'
2--- lib/lp/registry/browser/__init__.py 2010-09-21 04:21:16 +0000
3+++ lib/lp/registry/browser/__init__.py 2010-09-23 17:41:09 +0000
4@@ -6,6 +6,7 @@
5 __metaclass__ = type
6
7 __all__ = [
8+ 'BaseRdfView',
9 'get_status_counts',
10 'MilestoneOverlayMixin',
11 'RegistryEditFormView',
12@@ -256,3 +257,30 @@
13 @action("Change", name='change')
14 def change_action(self, action, data):
15 self.updateContextFromData(data)
16+
17+
18+class BaseRdfView:
19+ """A view that sets its mime-type to application/rdf+xml."""
20+
21+ template = None
22+ filename = None
23+
24+ def __init__(self, context, request):
25+ self.context = context
26+ self.request = request
27+
28+ def __call__(self):
29+ """Render RDF output, and return it as a string encoded in UTF-8.
30+
31+ Render the page template to produce RDF output.
32+ The return value is string data encoded in UTF-8.
33+
34+ As a side-effect, HTTP headers are set for the mime type
35+ and filename for download."""
36+ self.request.response.setHeader('Content-Type', 'application/rdf+xml')
37+ self.request.response.setHeader(
38+ 'Content-Disposition', 'attachment; filename=%s.rdf' % (
39+ self.filename))
40+ unicodedata = self.template()
41+ encodeddata = unicodedata.encode('utf-8')
42+ return encodeddata
43
44=== modified file 'lib/lp/registry/browser/person.py'
45--- lib/lp/registry/browser/person.py 2010-09-21 16:06:38 +0000
46+++ lib/lp/registry/browser/person.py 2010-09-23 17:41:09 +0000
47@@ -242,6 +242,7 @@
48 from lp.code.browser.sourcepackagerecipelisting import HasRecipesMenuMixin
49 from lp.code.errors import InvalidNamespace
50 from lp.code.interfaces.branchnamespace import IBranchNamespaceSet
51+from lp.registry.browser import BaseRdfView
52 from lp.registry.browser.branding import BrandingChangeView
53 from lp.registry.browser.mailinglists import enabled_with_active_mailing_list
54 from lp.registry.browser.menu import (
55@@ -1611,28 +1612,15 @@
56 self.preferredemail = email
57
58
59-class PersonRdfView:
60+class PersonRdfView(BaseRdfView):
61 """A view that embeds PersonRdfContentsView in a standalone page."""
62
63 template = ViewPageTemplateFile(
64 '../templates/person-rdf.pt')
65
66- def __call__(self):
67- """Render RDF output, and return it as a string encoded in UTF-8.
68-
69- Render the page template to produce RDF output.
70- The return value is string data encoded in UTF-8.
71-
72- As a side-effect, HTTP headers are set for the mime type
73- and filename for download."""
74- self.request.response.setHeader('content-type',
75- 'application/rdf+xml')
76- self.request.response.setHeader('Content-Disposition',
77- 'attachment; filename=%s.rdf' %
78- self.context.name)
79- unicodedata = self.template()
80- encodeddata = unicodedata.encode('utf-8')
81- return encodeddata
82+ @property
83+ def filename(self):
84+ return self.context.name
85
86
87 class PersonRdfContentsView:
88@@ -1649,30 +1637,6 @@
89 self.context = context
90 self.request = request
91
92- def buildMemberData(self):
93- members = []
94- members_by_id = {}
95- raw_members = list(self.context.allmembers)
96- if not raw_members:
97- # Empty teams have nothing to offer.
98- return []
99- personset = getUtility(IPersonSet)
100- personset.cacheBrandingForPeople(raw_members)
101- for member in raw_members:
102- decorated_member = PersonWithKeysAndPreferredEmail(member)
103- members.append(decorated_member)
104- members_by_id[member.id] = decorated_member
105- sshkeyset = getUtility(ISSHKeySet)
106- gpgkeyset = getUtility(IGPGKeySet)
107- emailset = getUtility(IEmailAddressSet)
108- for key in sshkeyset.getByPeople(members):
109- members_by_id[key.personID].addSSHKey(key)
110- for key in gpgkeyset.getGPGKeysForPeople(members):
111- members_by_id[key.ownerID].addGPGKey(key)
112- for email in emailset.getPreferredEmailForPeople(members):
113- members_by_id[email.person.id].setPreferredEmail(email)
114- return members
115-
116 def __call__(self):
117 """Render RDF output.
118
119
120=== modified file 'lib/lp/registry/browser/product.py'
121--- lib/lp/registry/browser/product.py 2010-09-22 22:51:48 +0000
122+++ lib/lp/registry/browser/product.py 2010-09-23 17:41:09 +0000
123@@ -155,6 +155,7 @@
124 from lp.bugs.interfaces.bugtask import RESOLVED_BUGTASK_STATUSES
125 from lp.code.browser.branchref import BranchRef
126 from lp.code.browser.sourcepackagerecipelisting import HasRecipesMenuMixin
127+from lp.registry.browser import BaseRdfView
128 from lp.registry.browser.announcement import HasAnnouncementsView
129 from lp.registry.browser.branding import BrandingChangeView
130 from lp.registry.browser.distribution import UsesLaunchpadMixin
131@@ -1406,7 +1407,7 @@
132 def setUpFields(self):
133 super(ProductConfigureBase, self).setUpFields()
134 if self.usage_fieldname is not None:
135- # The usage fields are shared among pillars. But when referring to
136+ # The usage fields are shared among pillars. But when referring to
137 # an individual object in Launchpad it is better to call it by its
138 # real name, i.e. 'project' instead of 'pillar'.
139 usage_field = self.form_fields.get(self.usage_fieldname)
140@@ -1730,31 +1731,15 @@
141 page_title = label
142
143
144-class ProductRdfView:
145+class ProductRdfView(BaseRdfView):
146 """A view that sets its mime-type to application/rdf+xml"""
147
148 template = ViewPageTemplateFile(
149 '../templates/product-rdf.pt')
150
151- def __init__(self, context, request):
152- self.context = context
153- self.request = request
154-
155- def __call__(self):
156- """Render RDF output, and return it as a string encoded in UTF-8.
157-
158- Render the page template to produce RDF output.
159- The return value is string data encoded in UTF-8.
160-
161- As a side-effect, HTTP headers are set for the mime type
162- and filename for download."""
163- self.request.response.setHeader('Content-Type', 'application/rdf+xml')
164- self.request.response.setHeader('Content-Disposition',
165- 'attachment; filename=%s.rdf' %
166- self.context.name)
167- unicodedata = self.template()
168- encodeddata = unicodedata.encode('utf-8')
169- return encodeddata
170+ @property
171+ def filename(self):
172+ return self.context.name
173
174
175 class Icon:
176
177=== modified file 'lib/lp/registry/browser/productrelease.py'
178--- lib/lp/registry/browser/productrelease.py 2010-08-20 20:31:18 +0000
179+++ lib/lp/registry/browser/productrelease.py 2010-09-23 17:41:09 +0000
180@@ -50,6 +50,7 @@
181 from canonical.lazr.utils import smartquote
182 from canonical.widgets import DateTimeWidget
183 from lp.registry.browser import (
184+ BaseRdfView,
185 MilestoneOverlayMixin,
186 RegistryDeleteViewMixin,
187 )
188@@ -256,33 +257,17 @@
189 return canonical_url(self.context)
190
191
192-class ProductReleaseRdfView(object):
193+class ProductReleaseRdfView(BaseRdfView):
194 """A view that sets its mime-type to application/rdf+xml"""
195
196 template = ViewPageTemplateFile('../templates/productrelease-rdf.pt')
197
198- def __init__(self, context, request):
199- self.context = context
200- self.request = request
201-
202- def __call__(self):
203- """Render RDF output, and return it as a string encoded in UTF-8.
204-
205- Render the page template to produce RDF output.
206- The return value is string data encoded in UTF-8.
207-
208- As a side-effect, HTTP headers are set for the mime type
209- and filename for download."""
210- self.request.response.setHeader('Content-Type', 'application/rdf+xml')
211- self.request.response.setHeader(
212- 'Content-Disposition',
213- 'attachment; filename=%s-%s-%s.rdf' % (
214- self.context.product.name,
215- self.context.productseries.name,
216- self.context.version))
217- unicodedata = self.template()
218- encodeddata = unicodedata.encode('utf-8')
219- return encodeddata
220+ @property
221+ def filename(self):
222+ return '%s-%s-%s' % (
223+ self.context.product.name,
224+ self.context.productseries.name,
225+ self.context.version)
226
227
228 class ProductReleaseAddDownloadFileView(LaunchpadFormView):
229
230=== modified file 'lib/lp/registry/browser/productseries.py'
231--- lib/lp/registry/browser/productseries.py 2010-09-15 13:25:01 +0000
232+++ lib/lp/registry/browser/productseries.py 2010-09-23 17:41:09 +0000
233@@ -119,6 +119,7 @@
234 ICodeImportSet,
235 )
236 from lp.registry.browser import (
237+ BaseRdfView,
238 MilestoneOverlayMixin,
239 RegistryDeleteViewMixin,
240 StatusCount,
241@@ -1259,32 +1260,15 @@
242 self.next_url = canonical_url(self.context)
243
244
245-class ProductSeriesRdfView(object):
246+class ProductSeriesRdfView(BaseRdfView):
247 """A view that sets its mime-type to application/rdf+xml"""
248
249 template = ViewPageTemplateFile(
250 '../templates/productseries-rdf.pt')
251
252- def __init__(self, context, request):
253- self.context = context
254- self.request = request
255-
256- def __call__(self):
257- """Render RDF output, and return it as a string encoded in UTF-8.
258-
259- Render the page template to produce RDF output.
260- The return value is string data encoded in UTF-8.
261-
262- As a side-effect, HTTP headers are set for the mime type
263- and filename for download."""
264- self.request.response.setHeader('Content-Type', 'application/rdf+xml')
265- self.request.response.setHeader('Content-Disposition',
266- 'attachment; filename=%s-%s.rdf' % (
267- self.context.product.name,
268- self.context.name))
269- unicodedata = self.template()
270- encodeddata = unicodedata.encode('utf-8')
271- return encodeddata
272+ @property
273+ def filename(self):
274+ return '%s-%s' % (self.context.product.name, self.context.name)
275
276
277 class ProductSeriesFileBugRedirect(LaunchpadView):
278
279=== modified file 'lib/lp/registry/browser/project.py'
280--- lib/lp/registry/browser/project.py 2010-08-24 10:45:57 +0000
281+++ lib/lp/registry/browser/project.py 2010-09-23 17:41:09 +0000
282@@ -72,6 +72,7 @@
283 from lp.blueprints.browser.specificationtarget import (
284 HasSpecificationsMenuMixin,
285 )
286+from lp.registry.browser import BaseRdfView
287 from lp.registry.browser.announcement import HasAnnouncementsView
288 from lp.registry.browser.branding import BrandingChangeView
289 from lp.registry.browser.menu import (
290@@ -592,31 +593,15 @@
291 field_names = ['icon', 'logo', 'mugshot']
292
293
294-class ProjectRdfView(object):
295+class ProjectRdfView(BaseRdfView):
296 """A view that sets its mime-type to application/rdf+xml"""
297
298 template = ViewPageTemplateFile(
299 '../templates/project-rdf.pt')
300
301- def __init__(self, context, request):
302- self.context = context
303- self.request = request
304-
305- def __call__(self):
306- """Render RDF output, and return it as a string encoded in UTF-8.
307-
308- Render the page template to produce RDF output.
309- The return value is string data encoded in UTF-8.
310-
311- As a side-effect, HTTP headers are set for the mime type
312- and filename for download."""
313- self.request.response.setHeader('Content-Type', 'application/rdf+xml')
314- self.request.response.setHeader(
315- 'Content-Disposition',
316- 'attachment; filename=%s-project.rdf' % self.context.name)
317- unicodedata = self.template()
318- encodeddata = unicodedata.encode('utf-8')
319- return encodeddata
320+ @property
321+ def filename(self):
322+ return '%s-project' % self.context.name
323
324
325 class ProjectAddQuestionView(QuestionAddView):
326
327=== modified file 'lib/lp/registry/stories/person/xx-person-rdf.txt'
328--- lib/lp/registry/stories/person/xx-person-rdf.txt 2009-08-13 19:03:36 +0000
329+++ lib/lp/registry/stories/person/xx-person-rdf.txt 2010-09-23 17:41:09 +0000
330@@ -80,33 +80,14 @@
331 <foaf:name>testing Spanish team</foaf:name>
332 <foaf:nick>testing-spanish-team</foaf:nick>
333 <foaf:member>
334- <foaf:Person>
335- <foaf:name>Carlos Perell\xf3 Mar\xedn</foaf:name>
336- <foaf:nick>carlos</foaf:nick>
337- <foaf:mbox_sha1sum>BCB3DF72647D7B136A3C33005318D63974179452</foaf:mbox_sha1sum>
338- </foaf:Person>
339- </foaf:member>
340- <foaf:member>
341- <foaf:Person>
342- <foaf:name>Foo Bar</foaf:name>
343- <foaf:nick>name16</foaf:nick>
344- <foaf:mbox_sha1sum>D248D2313390766929B6CEC214BD9B640F5EA7E7</foaf:mbox_sha1sum>
345- <wot:hasKey>
346- <wot:PubKey>
347- <wot:hex_id>12345678</wot:hex_id>
348- ...
349- </wot:PubKey>
350- </wot:hasKey>
351- </foaf:Person>
352- </foaf:member>
353- <foaf:member>
354- <foaf:Person>
355- <foaf:name>Mark Shuttleworth</foaf:name>
356- <foaf:nick>mark</foaf:nick>
357- <foaf:img rdf:resource="http://.../logo.png"/>
358- <foaf:img rdf:resource="http://.../mugshot.png"/>
359- <foaf:mbox_sha1sum>3CB9B47B0C0ADC68633D899805A9ADDF0045F922</foaf:mbox_sha1sum>
360- <lp:sshPubKey>AAAAB3NzaC1kc3MAAABBAL5VoWG5sy3CnLYeOw47L8m9A15hA/PzdX2u0B7c2Z1ktFPcEaEuKbLqKVSkXpYm7YwKj9y88A9Qm61CdvI0c50AAAAVAKGY0YON9dEFH3DzeVYHVEBGFGfVAAAAQCoe0RhBcefm4YiyQVwMAxwTlgySTk7FSk6GZ95EZ5Q8/OTdViTaalvGXaRIsBdaQamHEBB+Vek/VpnF1UGGm8YAAABAaCXDl0r1k93JhnMdF0ap4UJQ2/NnqCyoE8Xd5KdUWWwqwGdMzqB1NOeKN6ladIAXRggLc2E00UsnUXh3GE3Rgw==</lp:sshPubKey>
361+ <lp:specifiedAt rdf:resource="/~carlos/+rdf"/>
362+ </foaf:member>
363+ <foaf:member>
364+ <lp:specifiedAt rdf:resource="/~name16/+rdf"/>
365+ </foaf:member>
366+ <foaf:member>
367+ <lp:specifiedAt rdf:resource="/~mark/+rdf"/>
368+ </foaf:member>
369 ...
370 </foaf:Group>
371 </rdf:RDF>
372@@ -116,17 +97,13 @@
373
374 Note how ascii and non-ascii names are rendered properly:
375
376+ >>> anon_browser.open("http://launchpad.dev/~carlos/+rdf")
377 >>> from BeautifulSoup import BeautifulSoup, SoupStrainer
378 >>> strainer = SoupStrainer(['foaf:name'])
379 >>> soup = BeautifulSoup(anon_browser.contents, parseOnlyThese=strainer)
380 >>> for tag in soup:
381 ... tag.renderContents()
382- 'testing Spanish team'
383 'Carlos Perell\xc3\xb3 Mar\xc3\xadn'
384- 'Foo Bar'
385- 'Mark Shuttleworth'
386- 'Miroslav Kure'
387- 'Valentina Commissari'
388
389 If the team has no active members no <foaf:member> elements will be
390 present:
391@@ -150,17 +127,3 @@
392 <foaf:nick>name21</foaf:nick>
393 </foaf:Group>
394 </rdf:RDF>
395-
396-The pages still work fine for teams whose members have not set up
397-mugshots or images for them:
398-
399- >>> anon_browser.open("http://launchpad.dev/~name18/+rdf")
400- >>> strainer = SoupStrainer(['foaf:member'])
401- >>> soup = BeautifulSoup(anon_browser.contents, parseOnlyThese=strainer)
402- >>> len(soup)
403- 6
404- >>> strainer = SoupStrainer(['foaf:img'])
405- >>> soup = BeautifulSoup(anon_browser.contents, parseOnlyThese=strainer)
406- >>> len(soup)
407- 0
408-
409
410=== modified file 'lib/lp/registry/stories/product/xx-product-rdf.txt'
411--- lib/lp/registry/stories/product/xx-product-rdf.txt 2009-06-12 16:36:02 +0000
412+++ lib/lp/registry/stories/product/xx-product-rdf.txt 2010-09-23 17:41:09 +0000
413@@ -13,12 +13,7 @@
414 <lp:title>Mozilla Firefox</lp:title>
415 ...
416 <lp:owner>
417- <foaf:Person>
418- <foaf:name>Sample Person</foaf:name>
419- <foaf:nick>name12</foaf:nick>
420- <foaf:mbox_sha1sum>AF55D387F22F761CB32EC2A9C81F66220452C081</foaf:mbox_sha1sum>
421- <lp:sshPubKey>AAAAB3NzaC1kc3MAAA...SG1gBOiI=</lp:sshPubKey>
422- </foaf:Person>
423+ <lp:specifiedAt rdf:resource="/~name12/+rdf"/>
424 </lp:owner>
425 ...
426 </lp:Product>
427
428=== modified file 'lib/lp/registry/stories/project/xx-project-rdf.txt'
429--- lib/lp/registry/stories/project/xx-project-rdf.txt 2009-06-12 16:36:02 +0000
430+++ lib/lp/registry/stories/project/xx-project-rdf.txt 2010-09-23 17:41:09 +0000
431@@ -13,12 +13,7 @@
432 <lp:title>The Mozilla Project</lp:title>
433 ...
434 <lp:owner>
435- <foaf:Person>
436- <foaf:name>Sample Person</foaf:name>
437- <foaf:nick>name12</foaf:nick>
438- <foaf:mbox_sha1sum>AF55D387F22F761CB32EC2A9C81F66220452C081</foaf:mbox_sha1sum>
439- <lp:sshPubKey>AAAAB3NzaC1kc3MAAA...SG1gBOiI=</lp:sshPubKey>
440- </foaf:Person>
441+ <lp:specifiedAt rdf:resource="/~name12/+rdf"/>
442 </lp:owner>
443 ...
444 </lp:Project>
445
446=== modified file 'lib/lp/registry/templates/person-rdf-contents.pt'
447--- lib/lp/registry/templates/person-rdf-contents.pt 2010-03-11 16:09:29 +0000
448+++ lib/lp/registry/templates/person-rdf-contents.pt 2010-09-23 17:41:09 +0000
449@@ -5,7 +5,6 @@
450 xmlns:lp="https://launchpad.net/rdf/launchpad#"
451 xmlns:wot="http://xmlns.com/wot/0.1/">
452 <tal:is-person condition="not:context/isTeam" define="person context">
453- <metal:display-person define-macro="display_person">
454 <foaf:Person>
455 <foaf:name tal:content="person/displayname">Display Name</foaf:name>
456 <foaf:nick tal:content="person/name">Nick name</foaf:nick>
457@@ -30,7 +29,6 @@
458 <lp:sshPubKey tal:content="sshkey/keytext"></lp:sshPubKey>
459 </tal:sshkeys>
460 </foaf:Person>
461- </metal:display-person>
462 </tal:is-person>
463 <tal:public tal:condition="context/name|nothing">
464 <foaf:Group tal:condition="context/isTeam">
465@@ -44,8 +42,9 @@
466 tal:attributes="rdf:resource context/logo/http_url" />
467 <foaf:img tal:condition="context/mugshot"
468 tal:attributes="rdf:resource context/mugshot/http_url" />
469- <foaf:member tal:repeat="person view/buildMemberData">
470- <metal:display-person use-macro="template/macros/display_person" />
471+ <foaf:member tal:repeat="person context/allmembers">
472+ <lp:specifiedAt tal:attributes="rdf:resource
473+ string:${person/fmt:url}/+rdf" />
474 </foaf:member>
475 </foaf:Group>
476 </tal:public>
477
478=== modified file 'lib/lp/registry/templates/product-rdf.pt'
479--- lib/lp/registry/templates/product-rdf.pt 2009-10-26 18:40:04 +0000
480+++ lib/lp/registry/templates/product-rdf.pt 2010-09-23 17:41:09 +0000
481@@ -23,7 +23,7 @@
482 </lp:description>
483 <lp:creationDate tal:content="context/datecreated/fmt:datetime">
484 1970-01-01 00:00:00
485- </lp:creationDate>
486+ </lp:creationDate>
487 <lp:homepage tal:attributes="rdf:resource context/homepageurl" />
488 <lp:wiki tal:condition="context/wikiurl"
489 tal:attributes="rdf:resource context/wikiurl" />
490@@ -55,7 +55,10 @@
491 string:${context/fmt:url}/${series/name}/+rdf" />
492 </lp:ProductSeries>
493 </lp:series>
494- <lp:owner tal:content="structure context/owner/@@+rdf-contents/template" />
495+ <lp:owner>
496+ <lp:specifiedAt tal:attributes="rdf:resource
497+ string:${context/owner/fmt:url}/+rdf" />
498+ </lp:owner>
499 <lp:status tal:condition="context/active">Active</lp:status>
500 <lp:status tal:condition="not:context/active">Inactive</lp:status>
501 </lp:Product>
502
503=== modified file 'lib/lp/registry/templates/productrelease-rdf.pt'
504--- lib/lp/registry/templates/productrelease-rdf.pt 2009-07-17 17:59:07 +0000
505+++ lib/lp/registry/templates/productrelease-rdf.pt 2010-09-23 17:41:09 +0000
506@@ -24,13 +24,16 @@
507 </lp:changelog>
508 <lp:creationDate tal:content="context/datecreated/fmt:datetime">
509 1970-01-01 00:00:00
510- </lp:creationDate>
511+ </lp:creationDate>
512 <lp:inProductSeries>
513 <lp:ProductSeries>
514 <lp:specifiedAt tal:attributes="rdf:resource
515 string:${context/product/fmt:url}/${context/productseries/name}/+rdf" />
516 </lp:ProductSeries>
517 </lp:inProductSeries>
518- <lp:owner tal:content="structure context/owner/@@+rdf-contents/template" />
519+ <lp:owner>
520+ <lp:specifiedAt tal:attributes="rdf:resource
521+ string:${context/owner/fmt:url}/+rdf" />
522+ </lp:owner>
523 </lp:ProductRelease>
524 </rdf:RDF>
525
526=== modified file 'lib/lp/registry/templates/project-rdf.pt'
527--- lib/lp/registry/templates/project-rdf.pt 2009-07-17 17:59:07 +0000
528+++ lib/lp/registry/templates/project-rdf.pt 2010-09-23 17:41:09 +0000
529@@ -23,7 +23,7 @@
530 </lp:description>
531 <lp:creationDate tal:content="context/datecreated/fmt:datetime">
532 1970-01-01 00:00:00
533- </lp:creationDate>
534+ </lp:creationDate>
535 <lp:homepage tal:attributes="rdf:resource context/homepageurl" />
536 <lp:wiki tal:condition="context/wikiurl"
537 tal:attributes="rdf:resource context/wikiurl" />
538@@ -41,7 +41,10 @@
539 string:${product/fmt:url}/+rdf" />
540 </lp:Product>
541 </lp:product>
542- <lp:owner tal:content="structure context/owner/@@+rdf-contents/template" />
543+ <lp:owner>
544+ <lp:specifiedAt tal:attributes="rdf:resource
545+ string:${context/owner/fmt:url}/+rdf" />
546+ </lp:owner>
547 <lp:status tal:condition="context/active">Active</lp:status>
548 <lp:status tal:condition="not:context/active">Inactive</lp:status>
549 </lp:Project>