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
=== modified file 'lib/lp/registry/browser/__init__.py'
--- lib/lp/registry/browser/__init__.py 2010-09-21 04:21:16 +0000
+++ lib/lp/registry/browser/__init__.py 2010-09-23 17:41:09 +0000
@@ -6,6 +6,7 @@
6__metaclass__ = type6__metaclass__ = type
77
8__all__ = [8__all__ = [
9 'BaseRdfView',
9 'get_status_counts',10 'get_status_counts',
10 'MilestoneOverlayMixin',11 'MilestoneOverlayMixin',
11 'RegistryEditFormView',12 'RegistryEditFormView',
@@ -256,3 +257,30 @@
256 @action("Change", name='change')257 @action("Change", name='change')
257 def change_action(self, action, data):258 def change_action(self, action, data):
258 self.updateContextFromData(data)259 self.updateContextFromData(data)
260
261
262class BaseRdfView:
263 """A view that sets its mime-type to application/rdf+xml."""
264
265 template = None
266 filename = None
267
268 def __init__(self, context, request):
269 self.context = context
270 self.request = request
271
272 def __call__(self):
273 """Render RDF output, and return it as a string encoded in UTF-8.
274
275 Render the page template to produce RDF output.
276 The return value is string data encoded in UTF-8.
277
278 As a side-effect, HTTP headers are set for the mime type
279 and filename for download."""
280 self.request.response.setHeader('Content-Type', 'application/rdf+xml')
281 self.request.response.setHeader(
282 'Content-Disposition', 'attachment; filename=%s.rdf' % (
283 self.filename))
284 unicodedata = self.template()
285 encodeddata = unicodedata.encode('utf-8')
286 return encodeddata
259287
=== modified file 'lib/lp/registry/browser/person.py'
--- lib/lp/registry/browser/person.py 2010-09-21 16:06:38 +0000
+++ lib/lp/registry/browser/person.py 2010-09-23 17:41:09 +0000
@@ -242,6 +242,7 @@
242from lp.code.browser.sourcepackagerecipelisting import HasRecipesMenuMixin242from lp.code.browser.sourcepackagerecipelisting import HasRecipesMenuMixin
243from lp.code.errors import InvalidNamespace243from lp.code.errors import InvalidNamespace
244from lp.code.interfaces.branchnamespace import IBranchNamespaceSet244from lp.code.interfaces.branchnamespace import IBranchNamespaceSet
245from lp.registry.browser import BaseRdfView
245from lp.registry.browser.branding import BrandingChangeView246from lp.registry.browser.branding import BrandingChangeView
246from lp.registry.browser.mailinglists import enabled_with_active_mailing_list247from lp.registry.browser.mailinglists import enabled_with_active_mailing_list
247from lp.registry.browser.menu import (248from lp.registry.browser.menu import (
@@ -1611,28 +1612,15 @@
1611 self.preferredemail = email1612 self.preferredemail = email
16121613
16131614
1614class PersonRdfView:1615class PersonRdfView(BaseRdfView):
1615 """A view that embeds PersonRdfContentsView in a standalone page."""1616 """A view that embeds PersonRdfContentsView in a standalone page."""
16161617
1617 template = ViewPageTemplateFile(1618 template = ViewPageTemplateFile(
1618 '../templates/person-rdf.pt')1619 '../templates/person-rdf.pt')
16191620
1620 def __call__(self):1621 @property
1621 """Render RDF output, and return it as a string encoded in UTF-8.1622 def filename(self):
16221623 return self.context.name
1623 Render the page template to produce RDF output.
1624 The return value is string data encoded in UTF-8.
1625
1626 As a side-effect, HTTP headers are set for the mime type
1627 and filename for download."""
1628 self.request.response.setHeader('content-type',
1629 'application/rdf+xml')
1630 self.request.response.setHeader('Content-Disposition',
1631 'attachment; filename=%s.rdf' %
1632 self.context.name)
1633 unicodedata = self.template()
1634 encodeddata = unicodedata.encode('utf-8')
1635 return encodeddata
16361624
16371625
1638class PersonRdfContentsView:1626class PersonRdfContentsView:
@@ -1649,30 +1637,6 @@
1649 self.context = context1637 self.context = context
1650 self.request = request1638 self.request = request
16511639
1652 def buildMemberData(self):
1653 members = []
1654 members_by_id = {}
1655 raw_members = list(self.context.allmembers)
1656 if not raw_members:
1657 # Empty teams have nothing to offer.
1658 return []
1659 personset = getUtility(IPersonSet)
1660 personset.cacheBrandingForPeople(raw_members)
1661 for member in raw_members:
1662 decorated_member = PersonWithKeysAndPreferredEmail(member)
1663 members.append(decorated_member)
1664 members_by_id[member.id] = decorated_member
1665 sshkeyset = getUtility(ISSHKeySet)
1666 gpgkeyset = getUtility(IGPGKeySet)
1667 emailset = getUtility(IEmailAddressSet)
1668 for key in sshkeyset.getByPeople(members):
1669 members_by_id[key.personID].addSSHKey(key)
1670 for key in gpgkeyset.getGPGKeysForPeople(members):
1671 members_by_id[key.ownerID].addGPGKey(key)
1672 for email in emailset.getPreferredEmailForPeople(members):
1673 members_by_id[email.person.id].setPreferredEmail(email)
1674 return members
1675
1676 def __call__(self):1640 def __call__(self):
1677 """Render RDF output.1641 """Render RDF output.
16781642
16791643
=== modified file 'lib/lp/registry/browser/product.py'
--- lib/lp/registry/browser/product.py 2010-09-22 22:51:48 +0000
+++ lib/lp/registry/browser/product.py 2010-09-23 17:41:09 +0000
@@ -155,6 +155,7 @@
155from lp.bugs.interfaces.bugtask import RESOLVED_BUGTASK_STATUSES155from lp.bugs.interfaces.bugtask import RESOLVED_BUGTASK_STATUSES
156from lp.code.browser.branchref import BranchRef156from lp.code.browser.branchref import BranchRef
157from lp.code.browser.sourcepackagerecipelisting import HasRecipesMenuMixin157from lp.code.browser.sourcepackagerecipelisting import HasRecipesMenuMixin
158from lp.registry.browser import BaseRdfView
158from lp.registry.browser.announcement import HasAnnouncementsView159from lp.registry.browser.announcement import HasAnnouncementsView
159from lp.registry.browser.branding import BrandingChangeView160from lp.registry.browser.branding import BrandingChangeView
160from lp.registry.browser.distribution import UsesLaunchpadMixin161from lp.registry.browser.distribution import UsesLaunchpadMixin
@@ -1406,7 +1407,7 @@
1406 def setUpFields(self):1407 def setUpFields(self):
1407 super(ProductConfigureBase, self).setUpFields()1408 super(ProductConfigureBase, self).setUpFields()
1408 if self.usage_fieldname is not None:1409 if self.usage_fieldname is not None:
1409 # The usage fields are shared among pillars. But when referring to1410 # The usage fields are shared among pillars. But when referring to
1410 # an individual object in Launchpad it is better to call it by its1411 # an individual object in Launchpad it is better to call it by its
1411 # real name, i.e. 'project' instead of 'pillar'.1412 # real name, i.e. 'project' instead of 'pillar'.
1412 usage_field = self.form_fields.get(self.usage_fieldname)1413 usage_field = self.form_fields.get(self.usage_fieldname)
@@ -1730,31 +1731,15 @@
1730 page_title = label1731 page_title = label
17311732
17321733
1733class ProductRdfView:1734class ProductRdfView(BaseRdfView):
1734 """A view that sets its mime-type to application/rdf+xml"""1735 """A view that sets its mime-type to application/rdf+xml"""
17351736
1736 template = ViewPageTemplateFile(1737 template = ViewPageTemplateFile(
1737 '../templates/product-rdf.pt')1738 '../templates/product-rdf.pt')
17381739
1739 def __init__(self, context, request):1740 @property
1740 self.context = context1741 def filename(self):
1741 self.request = request1742 return self.context.name
1742
1743 def __call__(self):
1744 """Render RDF output, and return it as a string encoded in UTF-8.
1745
1746 Render the page template to produce RDF output.
1747 The return value is string data encoded in UTF-8.
1748
1749 As a side-effect, HTTP headers are set for the mime type
1750 and filename for download."""
1751 self.request.response.setHeader('Content-Type', 'application/rdf+xml')
1752 self.request.response.setHeader('Content-Disposition',
1753 'attachment; filename=%s.rdf' %
1754 self.context.name)
1755 unicodedata = self.template()
1756 encodeddata = unicodedata.encode('utf-8')
1757 return encodeddata
17581743
17591744
1760class Icon:1745class Icon:
17611746
=== modified file 'lib/lp/registry/browser/productrelease.py'
--- lib/lp/registry/browser/productrelease.py 2010-08-20 20:31:18 +0000
+++ lib/lp/registry/browser/productrelease.py 2010-09-23 17:41:09 +0000
@@ -50,6 +50,7 @@
50from canonical.lazr.utils import smartquote50from canonical.lazr.utils import smartquote
51from canonical.widgets import DateTimeWidget51from canonical.widgets import DateTimeWidget
52from lp.registry.browser import (52from lp.registry.browser import (
53 BaseRdfView,
53 MilestoneOverlayMixin,54 MilestoneOverlayMixin,
54 RegistryDeleteViewMixin,55 RegistryDeleteViewMixin,
55 )56 )
@@ -256,33 +257,17 @@
256 return canonical_url(self.context)257 return canonical_url(self.context)
257258
258259
259class ProductReleaseRdfView(object):260class ProductReleaseRdfView(BaseRdfView):
260 """A view that sets its mime-type to application/rdf+xml"""261 """A view that sets its mime-type to application/rdf+xml"""
261262
262 template = ViewPageTemplateFile('../templates/productrelease-rdf.pt')263 template = ViewPageTemplateFile('../templates/productrelease-rdf.pt')
263264
264 def __init__(self, context, request):265 @property
265 self.context = context266 def filename(self):
266 self.request = request267 return '%s-%s-%s' % (
267268 self.context.product.name,
268 def __call__(self):269 self.context.productseries.name,
269 """Render RDF output, and return it as a string encoded in UTF-8.270 self.context.version)
270
271 Render the page template to produce RDF output.
272 The return value is string data encoded in UTF-8.
273
274 As a side-effect, HTTP headers are set for the mime type
275 and filename for download."""
276 self.request.response.setHeader('Content-Type', 'application/rdf+xml')
277 self.request.response.setHeader(
278 'Content-Disposition',
279 'attachment; filename=%s-%s-%s.rdf' % (
280 self.context.product.name,
281 self.context.productseries.name,
282 self.context.version))
283 unicodedata = self.template()
284 encodeddata = unicodedata.encode('utf-8')
285 return encodeddata
286271
287272
288class ProductReleaseAddDownloadFileView(LaunchpadFormView):273class ProductReleaseAddDownloadFileView(LaunchpadFormView):
289274
=== modified file 'lib/lp/registry/browser/productseries.py'
--- lib/lp/registry/browser/productseries.py 2010-09-15 13:25:01 +0000
+++ lib/lp/registry/browser/productseries.py 2010-09-23 17:41:09 +0000
@@ -119,6 +119,7 @@
119 ICodeImportSet,119 ICodeImportSet,
120 )120 )
121from lp.registry.browser import (121from lp.registry.browser import (
122 BaseRdfView,
122 MilestoneOverlayMixin,123 MilestoneOverlayMixin,
123 RegistryDeleteViewMixin,124 RegistryDeleteViewMixin,
124 StatusCount,125 StatusCount,
@@ -1259,32 +1260,15 @@
1259 self.next_url = canonical_url(self.context)1260 self.next_url = canonical_url(self.context)
12601261
12611262
1262class ProductSeriesRdfView(object):1263class ProductSeriesRdfView(BaseRdfView):
1263 """A view that sets its mime-type to application/rdf+xml"""1264 """A view that sets its mime-type to application/rdf+xml"""
12641265
1265 template = ViewPageTemplateFile(1266 template = ViewPageTemplateFile(
1266 '../templates/productseries-rdf.pt')1267 '../templates/productseries-rdf.pt')
12671268
1268 def __init__(self, context, request):1269 @property
1269 self.context = context1270 def filename(self):
1270 self.request = request1271 return '%s-%s' % (self.context.product.name, self.context.name)
1271
1272 def __call__(self):
1273 """Render RDF output, and return it as a string encoded in UTF-8.
1274
1275 Render the page template to produce RDF output.
1276 The return value is string data encoded in UTF-8.
1277
1278 As a side-effect, HTTP headers are set for the mime type
1279 and filename for download."""
1280 self.request.response.setHeader('Content-Type', 'application/rdf+xml')
1281 self.request.response.setHeader('Content-Disposition',
1282 'attachment; filename=%s-%s.rdf' % (
1283 self.context.product.name,
1284 self.context.name))
1285 unicodedata = self.template()
1286 encodeddata = unicodedata.encode('utf-8')
1287 return encodeddata
12881272
12891273
1290class ProductSeriesFileBugRedirect(LaunchpadView):1274class ProductSeriesFileBugRedirect(LaunchpadView):
12911275
=== modified file 'lib/lp/registry/browser/project.py'
--- lib/lp/registry/browser/project.py 2010-08-24 10:45:57 +0000
+++ lib/lp/registry/browser/project.py 2010-09-23 17:41:09 +0000
@@ -72,6 +72,7 @@
72from lp.blueprints.browser.specificationtarget import (72from lp.blueprints.browser.specificationtarget import (
73 HasSpecificationsMenuMixin,73 HasSpecificationsMenuMixin,
74 )74 )
75from lp.registry.browser import BaseRdfView
75from lp.registry.browser.announcement import HasAnnouncementsView76from lp.registry.browser.announcement import HasAnnouncementsView
76from lp.registry.browser.branding import BrandingChangeView77from lp.registry.browser.branding import BrandingChangeView
77from lp.registry.browser.menu import (78from lp.registry.browser.menu import (
@@ -592,31 +593,15 @@
592 field_names = ['icon', 'logo', 'mugshot']593 field_names = ['icon', 'logo', 'mugshot']
593594
594595
595class ProjectRdfView(object):596class ProjectRdfView(BaseRdfView):
596 """A view that sets its mime-type to application/rdf+xml"""597 """A view that sets its mime-type to application/rdf+xml"""
597598
598 template = ViewPageTemplateFile(599 template = ViewPageTemplateFile(
599 '../templates/project-rdf.pt')600 '../templates/project-rdf.pt')
600601
601 def __init__(self, context, request):602 @property
602 self.context = context603 def filename(self):
603 self.request = request604 return '%s-project' % self.context.name
604
605 def __call__(self):
606 """Render RDF output, and return it as a string encoded in UTF-8.
607
608 Render the page template to produce RDF output.
609 The return value is string data encoded in UTF-8.
610
611 As a side-effect, HTTP headers are set for the mime type
612 and filename for download."""
613 self.request.response.setHeader('Content-Type', 'application/rdf+xml')
614 self.request.response.setHeader(
615 'Content-Disposition',
616 'attachment; filename=%s-project.rdf' % self.context.name)
617 unicodedata = self.template()
618 encodeddata = unicodedata.encode('utf-8')
619 return encodeddata
620605
621606
622class ProjectAddQuestionView(QuestionAddView):607class ProjectAddQuestionView(QuestionAddView):
623608
=== modified file 'lib/lp/registry/stories/person/xx-person-rdf.txt'
--- lib/lp/registry/stories/person/xx-person-rdf.txt 2009-08-13 19:03:36 +0000
+++ lib/lp/registry/stories/person/xx-person-rdf.txt 2010-09-23 17:41:09 +0000
@@ -80,33 +80,14 @@
80 <foaf:name>testing Spanish team</foaf:name>80 <foaf:name>testing Spanish team</foaf:name>
81 <foaf:nick>testing-spanish-team</foaf:nick>81 <foaf:nick>testing-spanish-team</foaf:nick>
82 <foaf:member>82 <foaf:member>
83 <foaf:Person>83 <lp:specifiedAt rdf:resource="/~carlos/+rdf"/>
84 <foaf:name>Carlos Perell\xf3 Mar\xedn</foaf:name>84 </foaf:member>
85 <foaf:nick>carlos</foaf:nick>85 <foaf:member>
86 <foaf:mbox_sha1sum>BCB3DF72647D7B136A3C33005318D63974179452</foaf:mbox_sha1sum>86 <lp:specifiedAt rdf:resource="/~name16/+rdf"/>
87 </foaf:Person>87 </foaf:member>
88 </foaf:member>88 <foaf:member>
89 <foaf:member>89 <lp:specifiedAt rdf:resource="/~mark/+rdf"/>
90 <foaf:Person>90 </foaf:member>
91 <foaf:name>Foo Bar</foaf:name>
92 <foaf:nick>name16</foaf:nick>
93 <foaf:mbox_sha1sum>D248D2313390766929B6CEC214BD9B640F5EA7E7</foaf:mbox_sha1sum>
94 <wot:hasKey>
95 <wot:PubKey>
96 <wot:hex_id>12345678</wot:hex_id>
97 ...
98 </wot:PubKey>
99 </wot:hasKey>
100 </foaf:Person>
101 </foaf:member>
102 <foaf:member>
103 <foaf:Person>
104 <foaf:name>Mark Shuttleworth</foaf:name>
105 <foaf:nick>mark</foaf:nick>
106 <foaf:img rdf:resource="http://.../logo.png"/>
107 <foaf:img rdf:resource="http://.../mugshot.png"/>
108 <foaf:mbox_sha1sum>3CB9B47B0C0ADC68633D899805A9ADDF0045F922</foaf:mbox_sha1sum>
109 <lp:sshPubKey>AAAAB3NzaC1kc3MAAABBAL5VoWG5sy3CnLYeOw47L8m9A15hA/PzdX2u0B7c2Z1ktFPcEaEuKbLqKVSkXpYm7YwKj9y88A9Qm61CdvI0c50AAAAVAKGY0YON9dEFH3DzeVYHVEBGFGfVAAAAQCoe0RhBcefm4YiyQVwMAxwTlgySTk7FSk6GZ95EZ5Q8/OTdViTaalvGXaRIsBdaQamHEBB+Vek/VpnF1UGGm8YAAABAaCXDl0r1k93JhnMdF0ap4UJQ2/NnqCyoE8Xd5KdUWWwqwGdMzqB1NOeKN6ladIAXRggLc2E00UsnUXh3GE3Rgw==</lp:sshPubKey>
110 ...91 ...
111 </foaf:Group>92 </foaf:Group>
112 </rdf:RDF>93 </rdf:RDF>
@@ -116,17 +97,13 @@
11697
117Note how ascii and non-ascii names are rendered properly:98Note how ascii and non-ascii names are rendered properly:
11899
100 >>> anon_browser.open("http://launchpad.dev/~carlos/+rdf")
119 >>> from BeautifulSoup import BeautifulSoup, SoupStrainer101 >>> from BeautifulSoup import BeautifulSoup, SoupStrainer
120 >>> strainer = SoupStrainer(['foaf:name'])102 >>> strainer = SoupStrainer(['foaf:name'])
121 >>> soup = BeautifulSoup(anon_browser.contents, parseOnlyThese=strainer)103 >>> soup = BeautifulSoup(anon_browser.contents, parseOnlyThese=strainer)
122 >>> for tag in soup:104 >>> for tag in soup:
123 ... tag.renderContents()105 ... tag.renderContents()
124 'testing Spanish team'
125 'Carlos Perell\xc3\xb3 Mar\xc3\xadn'106 'Carlos Perell\xc3\xb3 Mar\xc3\xadn'
126 'Foo Bar'
127 'Mark Shuttleworth'
128 'Miroslav Kure'
129 'Valentina Commissari'
130107
131If the team has no active members no <foaf:member> elements will be108If the team has no active members no <foaf:member> elements will be
132present:109present:
@@ -150,17 +127,3 @@
150 <foaf:nick>name21</foaf:nick>127 <foaf:nick>name21</foaf:nick>
151 </foaf:Group>128 </foaf:Group>
152 </rdf:RDF>129 </rdf:RDF>
153
154The pages still work fine for teams whose members have not set up
155mugshots or images for them:
156
157 >>> anon_browser.open("http://launchpad.dev/~name18/+rdf")
158 >>> strainer = SoupStrainer(['foaf:member'])
159 >>> soup = BeautifulSoup(anon_browser.contents, parseOnlyThese=strainer)
160 >>> len(soup)
161 6
162 >>> strainer = SoupStrainer(['foaf:img'])
163 >>> soup = BeautifulSoup(anon_browser.contents, parseOnlyThese=strainer)
164 >>> len(soup)
165 0
166
167130
=== modified file 'lib/lp/registry/stories/product/xx-product-rdf.txt'
--- lib/lp/registry/stories/product/xx-product-rdf.txt 2009-06-12 16:36:02 +0000
+++ lib/lp/registry/stories/product/xx-product-rdf.txt 2010-09-23 17:41:09 +0000
@@ -13,12 +13,7 @@
13 <lp:title>Mozilla Firefox</lp:title>13 <lp:title>Mozilla Firefox</lp:title>
14 ...14 ...
15 <lp:owner>15 <lp:owner>
16 <foaf:Person>16 <lp:specifiedAt rdf:resource="/~name12/+rdf"/>
17 <foaf:name>Sample Person</foaf:name>
18 <foaf:nick>name12</foaf:nick>
19 <foaf:mbox_sha1sum>AF55D387F22F761CB32EC2A9C81F66220452C081</foaf:mbox_sha1sum>
20 <lp:sshPubKey>AAAAB3NzaC1kc3MAAA...SG1gBOiI=</lp:sshPubKey>
21 </foaf:Person>
22 </lp:owner>17 </lp:owner>
23 ...18 ...
24 </lp:Product>19 </lp:Product>
2520
=== modified file 'lib/lp/registry/stories/project/xx-project-rdf.txt'
--- lib/lp/registry/stories/project/xx-project-rdf.txt 2009-06-12 16:36:02 +0000
+++ lib/lp/registry/stories/project/xx-project-rdf.txt 2010-09-23 17:41:09 +0000
@@ -13,12 +13,7 @@
13 <lp:title>The Mozilla Project</lp:title>13 <lp:title>The Mozilla Project</lp:title>
14 ...14 ...
15 <lp:owner>15 <lp:owner>
16 <foaf:Person>16 <lp:specifiedAt rdf:resource="/~name12/+rdf"/>
17 <foaf:name>Sample Person</foaf:name>
18 <foaf:nick>name12</foaf:nick>
19 <foaf:mbox_sha1sum>AF55D387F22F761CB32EC2A9C81F66220452C081</foaf:mbox_sha1sum>
20 <lp:sshPubKey>AAAAB3NzaC1kc3MAAA...SG1gBOiI=</lp:sshPubKey>
21 </foaf:Person>
22 </lp:owner>17 </lp:owner>
23 ...18 ...
24 </lp:Project>19 </lp:Project>
2520
=== modified file 'lib/lp/registry/templates/person-rdf-contents.pt'
--- lib/lp/registry/templates/person-rdf-contents.pt 2010-03-11 16:09:29 +0000
+++ lib/lp/registry/templates/person-rdf-contents.pt 2010-09-23 17:41:09 +0000
@@ -5,7 +5,6 @@
5 xmlns:lp="https://launchpad.net/rdf/launchpad#"5 xmlns:lp="https://launchpad.net/rdf/launchpad#"
6 xmlns:wot="http://xmlns.com/wot/0.1/">6 xmlns:wot="http://xmlns.com/wot/0.1/">
7 <tal:is-person condition="not:context/isTeam" define="person context">7 <tal:is-person condition="not:context/isTeam" define="person context">
8 <metal:display-person define-macro="display_person">
9 <foaf:Person>8 <foaf:Person>
10 <foaf:name tal:content="person/displayname">Display Name</foaf:name>9 <foaf:name tal:content="person/displayname">Display Name</foaf:name>
11 <foaf:nick tal:content="person/name">Nick name</foaf:nick>10 <foaf:nick tal:content="person/name">Nick name</foaf:nick>
@@ -30,7 +29,6 @@
30 <lp:sshPubKey tal:content="sshkey/keytext"></lp:sshPubKey>29 <lp:sshPubKey tal:content="sshkey/keytext"></lp:sshPubKey>
31 </tal:sshkeys>30 </tal:sshkeys>
32 </foaf:Person>31 </foaf:Person>
33 </metal:display-person>
34 </tal:is-person>32 </tal:is-person>
35 <tal:public tal:condition="context/name|nothing">33 <tal:public tal:condition="context/name|nothing">
36 <foaf:Group tal:condition="context/isTeam">34 <foaf:Group tal:condition="context/isTeam">
@@ -44,8 +42,9 @@
44 tal:attributes="rdf:resource context/logo/http_url" />42 tal:attributes="rdf:resource context/logo/http_url" />
45 <foaf:img tal:condition="context/mugshot"43 <foaf:img tal:condition="context/mugshot"
46 tal:attributes="rdf:resource context/mugshot/http_url" />44 tal:attributes="rdf:resource context/mugshot/http_url" />
47 <foaf:member tal:repeat="person view/buildMemberData">45 <foaf:member tal:repeat="person context/allmembers">
48 <metal:display-person use-macro="template/macros/display_person" />46 <lp:specifiedAt tal:attributes="rdf:resource
47 string:${person/fmt:url}/+rdf" />
49 </foaf:member>48 </foaf:member>
50 </foaf:Group>49 </foaf:Group>
51 </tal:public>50 </tal:public>
5251
=== modified file 'lib/lp/registry/templates/product-rdf.pt'
--- lib/lp/registry/templates/product-rdf.pt 2009-10-26 18:40:04 +0000
+++ lib/lp/registry/templates/product-rdf.pt 2010-09-23 17:41:09 +0000
@@ -23,7 +23,7 @@
23 </lp:description>23 </lp:description>
24 <lp:creationDate tal:content="context/datecreated/fmt:datetime">24 <lp:creationDate tal:content="context/datecreated/fmt:datetime">
25 1970-01-01 00:00:0025 1970-01-01 00:00:00
26 </lp:creationDate> 26 </lp:creationDate>
27 <lp:homepage tal:attributes="rdf:resource context/homepageurl" />27 <lp:homepage tal:attributes="rdf:resource context/homepageurl" />
28 <lp:wiki tal:condition="context/wikiurl"28 <lp:wiki tal:condition="context/wikiurl"
29 tal:attributes="rdf:resource context/wikiurl" />29 tal:attributes="rdf:resource context/wikiurl" />
@@ -55,7 +55,10 @@
55 string:${context/fmt:url}/${series/name}/+rdf" />55 string:${context/fmt:url}/${series/name}/+rdf" />
56 </lp:ProductSeries>56 </lp:ProductSeries>
57 </lp:series>57 </lp:series>
58 <lp:owner tal:content="structure context/owner/@@+rdf-contents/template" />58 <lp:owner>
59 <lp:specifiedAt tal:attributes="rdf:resource
60 string:${context/owner/fmt:url}/+rdf" />
61 </lp:owner>
59 <lp:status tal:condition="context/active">Active</lp:status>62 <lp:status tal:condition="context/active">Active</lp:status>
60 <lp:status tal:condition="not:context/active">Inactive</lp:status>63 <lp:status tal:condition="not:context/active">Inactive</lp:status>
61 </lp:Product>64 </lp:Product>
6265
=== modified file 'lib/lp/registry/templates/productrelease-rdf.pt'
--- lib/lp/registry/templates/productrelease-rdf.pt 2009-07-17 17:59:07 +0000
+++ lib/lp/registry/templates/productrelease-rdf.pt 2010-09-23 17:41:09 +0000
@@ -24,13 +24,16 @@
24 </lp:changelog>24 </lp:changelog>
25 <lp:creationDate tal:content="context/datecreated/fmt:datetime">25 <lp:creationDate tal:content="context/datecreated/fmt:datetime">
26 1970-01-01 00:00:0026 1970-01-01 00:00:00
27 </lp:creationDate> 27 </lp:creationDate>
28 <lp:inProductSeries>28 <lp:inProductSeries>
29 <lp:ProductSeries>29 <lp:ProductSeries>
30 <lp:specifiedAt tal:attributes="rdf:resource30 <lp:specifiedAt tal:attributes="rdf:resource
31 string:${context/product/fmt:url}/${context/productseries/name}/+rdf" />31 string:${context/product/fmt:url}/${context/productseries/name}/+rdf" />
32 </lp:ProductSeries>32 </lp:ProductSeries>
33 </lp:inProductSeries>33 </lp:inProductSeries>
34 <lp:owner tal:content="structure context/owner/@@+rdf-contents/template" />34 <lp:owner>
35 <lp:specifiedAt tal:attributes="rdf:resource
36 string:${context/owner/fmt:url}/+rdf" />
37 </lp:owner>
35 </lp:ProductRelease>38 </lp:ProductRelease>
36</rdf:RDF>39</rdf:RDF>
3740
=== modified file 'lib/lp/registry/templates/project-rdf.pt'
--- lib/lp/registry/templates/project-rdf.pt 2009-07-17 17:59:07 +0000
+++ lib/lp/registry/templates/project-rdf.pt 2010-09-23 17:41:09 +0000
@@ -23,7 +23,7 @@
23 </lp:description>23 </lp:description>
24 <lp:creationDate tal:content="context/datecreated/fmt:datetime">24 <lp:creationDate tal:content="context/datecreated/fmt:datetime">
25 1970-01-01 00:00:0025 1970-01-01 00:00:00
26 </lp:creationDate> 26 </lp:creationDate>
27 <lp:homepage tal:attributes="rdf:resource context/homepageurl" />27 <lp:homepage tal:attributes="rdf:resource context/homepageurl" />
28 <lp:wiki tal:condition="context/wikiurl"28 <lp:wiki tal:condition="context/wikiurl"
29 tal:attributes="rdf:resource context/wikiurl" />29 tal:attributes="rdf:resource context/wikiurl" />
@@ -41,7 +41,10 @@
41 string:${product/fmt:url}/+rdf" />41 string:${product/fmt:url}/+rdf" />
42 </lp:Product>42 </lp:Product>
43 </lp:product>43 </lp:product>
44 <lp:owner tal:content="structure context/owner/@@+rdf-contents/template" />44 <lp:owner>
45 <lp:specifiedAt tal:attributes="rdf:resource
46 string:${context/owner/fmt:url}/+rdf" />
47 </lp:owner>
45 <lp:status tal:condition="context/active">Active</lp:status>48 <lp:status tal:condition="context/active">Active</lp:status>
46 <lp:status tal:condition="not:context/active">Inactive</lp:status>49 <lp:status tal:condition="not:context/active">Inactive</lp:status>
47 </lp:Project>50 </lp:Project>