Merge lp:~bac/launchpad/bug-514447-anon-api into lp:launchpad

Proposed by Brad Crittenden on 2010-02-08
Status: Merged
Approved by: Aaron Bentley on 2010-02-08
Approved revision: not available
Merged at revision: not available
Proposed branch: lp:~bac/launchpad/bug-514447-anon-api
Merge into: lp:launchpad
Diff against target: 189 lines (+40/-21)
5 files modified
lib/canonical/launchpad/security.py (+5/-0)
lib/lp/registry/configure.zcml (+8/-2)
lib/lp/registry/interfaces/distribution.py (+15/-17)
lib/lp/registry/interfaces/sourcepackage.py (+1/-1)
lib/lp/registry/stories/webservice/xx-distroseries.txt (+11/-1)
To merge this branch: bzr merge lp:~bac/launchpad/bug-514447-anon-api
Reviewer Review Type Date Requested Status
Aaron Bentley (community) 2010-02-08 Approve on 2010-02-08
Review via email: mp+18842@code.launchpad.net

Commit Message

Add security adapter so that distro.series can be seen via anonymous API access.

To post a comment you must log in.
Brad Crittenden (bac) wrote :

= Summary =

When anonymous API access was enabled the series data for distributions was returning
an empty list. The problem was reported as bug 514447 and was discovered to be the
same root cause as bug 515761.

== Proposed fix ==

Even though the distribution interface IDistributionPublic has no access restrictions
in the registry configure.zcml the series data was not authorized for launchpad.View.
 Creating a security adapter for IDistroSeries was required.

== Pre-implementation notes ==

Talks on IRC with Leonard and Jamal, who was fixing bug 515761.

== Implementation details ==

Create the new security adapter and test.

Also you'll see some drive-by cleanups including some annoying trailing whitespace
deletions (thanks emacs!).

Also you'll note an XXX comment in the code that I'll remove before landing. Jamal
created a new security adapter for anonymous access that I wanted to take advantage
of. Unfortunately his branch was delayed in landing (I am running it through ec2 at
the moment). When his branch lands I'll merge it in and delete the
'AnonymousAuthorization' class I've temporarily included in this branch.

== Tests ==

bin/test -vvm lp.registry -t xx-distroseries.txt

== Demo and Q/A ==

Use launchpadlib to do:

> ubuntu = lp.distributions['ubuntu']
> list(ubuntu.series)

If you run against edge you'll see all of the usual suspects. If you run against
launchpad.dev you'll see the four in the test data. You should definitely not get an
empty list.

= Launchpad lint =

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

Linting changed files:
  lib/canonical/launchpad/security.py
  lib/lp/registry/configure.zcml
  lib/lp/registry/interfaces/sourcepackage.py
  lib/lp/registry/interfaces/distribution.py
  lib/lp/registry/stories/webservice/xx-distroseries.txt

== Pylint notices ==

lib/lp/registry/interfaces/sourcepackage.py
    21: [F0401] Unable to import 'lazr.enum' (No module named enum)
    27: [F0401] Unable to import 'lazr.restful.fields' (No module named restful)
    28: [F0401] Unable to import 'lazr.restful.declarations' (No module named restful)
    187: [C0322, ISourcePackage.getBranch] Operator not preceded by a space
    vocabulary=DBEnumeratedType))
    ^

    @operation_returns_entry(Interface)
    @export_read_operation()
    def getBranch(pocket):
    205: [C0322, ISourcePackage.setBranch] Operator not preceded by a space
    vocabulary=DBEnumeratedType),
    ^
    branch=Reference(Interface, title=_("Branch"), required=False))
    @call_with(registrant=REQUEST_USER)
    @export_write_operation()
    def setBranch(pocket, branch, registrant):

lib/lp/registry/interfaces/distribution.py
    224: [C0301] Line too long (79/78)
    26: [F0401] Unable to import 'lazr.restful.fields' (No module named restful)
    27: [F0401] Unable to import 'lazr.restful.interface' (No module named restful)
    28: [F0401] Unable to import 'lazr.restful.declarations' (No module named restful)

Aaron Bentley (abentley) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/canonical/launchpad/security.py'
2--- lib/canonical/launchpad/security.py 2010-02-04 23:18:16 +0000
3+++ lib/canonical/launchpad/security.py 2010-02-08 20:33:22 +0000
4@@ -813,6 +813,11 @@
5 user.in_admin)
6
7
8+class ViewDistroSeries(AnonymousAuthorization):
9+ """Anyone can view a DistroSeries."""
10+ usedfor = IDistroSeries
11+
12+
13 class SeriesDrivers(AuthorizationBase):
14 """Drivers can approve or decline features and target bugs.
15
16
17=== modified file 'lib/lp/registry/configure.zcml'
18--- lib/lp/registry/configure.zcml 2010-01-27 19:06:49 +0000
19+++ lib/lp/registry/configure.zcml 2010-02-08 20:33:22 +0000
20@@ -1375,7 +1375,13 @@
21 interface="lp.registry.interfaces.distribution.IDistributionDriverRestricted"/>
22 <require
23 permission="launchpad.Edit"
24- set_attributes="displayname title summary description translation_focus translationgroup translationpermission driver members owner security_contact mirror_admin homepage_content icon logo mugshot enable_bug_expiration bug_reporting_guidelines official_blueprints official_malone official_rosetta official_answers official_bug_tags"/>
25+ set_attributes="displayname title summary description
26+ translation_focus translationgroup translationpermission
27+ driver members owner security_contact mirror_admin
28+ homepage_content icon logo mugshot enable_bug_expiration
29+ bug_reporting_guidelines official_blueprints
30+ official_malone official_rosetta official_answers
31+ official_bug_tags"/>
32 <require
33 permission="launchpad.TranslationsAdmin"
34 set_attributes="language_pack_admin"/>
35@@ -1701,7 +1707,7 @@
36 </securedutility>
37
38 <!-- StructuralSubscription -->
39-
40+
41 <class
42 class="lp.registry.model.structuralsubscription.StructuralSubscription">
43 <allow
44
45=== modified file 'lib/lp/registry/interfaces/distribution.py'
46--- lib/lp/registry/interfaces/distribution.py 2010-02-01 19:48:57 +0000
47+++ lib/lp/registry/interfaces/distribution.py 2010-02-08 20:33:22 +0000
48@@ -166,8 +166,7 @@
49 description=_("The distro's owner."), required=True))
50 date_created = exported(
51 Datetime(title=_('Date created'),
52- description=_("The date this distribution was registered.")),
53- exported_as='date_created')
54+ description=_("The date this distribution was registered.")))
55 driver = exported(
56 PublicPersonChoice(
57 title=_("Driver"),
58@@ -210,9 +209,8 @@
59 series = exported(
60 CollectionField(
61 title=_("DistroSeries inside this Distribution"),
62- # Really IDistroSeries, see below.
63- value_type=Reference(schema=Interface)),
64- exported_as="series")
65+ # Really IDistroSeries, see _schema_circular_imports.py.
66+ value_type=Reference(schema=Interface)))
67 architectures = List(
68 title=_("DistroArchSeries inside this Distribution"))
69 bugCounter = Attribute("The distro bug counter")
70@@ -223,7 +221,7 @@
71 # properties
72 currentseries = exported(
73 Reference(
74- Interface, # Really IDistroSeries, see below
75+ Interface, # Really IDistroSeries, see _schema_circular_imports.py.
76 title=_("Current series"),
77 description=_(
78 "The current development series of this distribution. "
79@@ -253,14 +251,15 @@
80 main_archive = exported(
81 Reference(
82 title=_('Distribution Main Archive.'), readonly=True,
83- schema=Interface)) # Really IArchive, circular import fix below.
84+ # Really IArchive, see _schema_circular_imports.py.
85+ schema=Interface))
86
87 all_distro_archives = exported(
88 CollectionField(
89 title=_("A sequence of the distribution's non-PPA Archives."),
90 readonly=True, required=False,
91 value_type=Reference(schema=Interface)),
92- # Really Iarchive, circular import fix below.
93+ # Really IArchive, see _schema_circular_imports.py.
94 exported_as='archives')
95
96 all_distro_archive_ids = Attribute(
97@@ -291,7 +290,7 @@
98 def __iter__():
99 """Iterate over the series for this distribution."""
100
101- # Really IDistroSeries, see below
102+ # Really IDistroSeries, see _schema_circular_imports.py.
103 @operation_returns_collection_of(Interface)
104 @export_operation_as(name="getDevelopmentSeries")
105 @export_read_operation()
106@@ -300,7 +299,8 @@
107
108 @operation_parameters(
109 name_or_version=TextLine(title=_("Name or version"), required=True))
110- @operation_returns_entry(Interface) # Really IDistroSeries, see below
111+ # Really IDistroSeries, see _schema_circular_imports.py.
112+ @operation_returns_entry(Interface)
113 @export_read_operation()
114 def getSeries(name_or_version):
115 """Return the series with the name or version given.
116@@ -330,7 +330,8 @@
117
118 @operation_parameters(
119 name=TextLine(title=_("Package name"), required=True))
120- # Really returns IDistributionSourcePackage, see below.
121+ # Really returns IDistributionSourcePackage, see
122+ # _schema_circular_imports.py.
123 @operation_returns_entry(Interface)
124 @export_read_operation()
125 def getSourcePackage(name):
126@@ -402,12 +403,13 @@
127 @operation_parameters(
128 text=TextLine(title=_("Source package name substring match"),
129 required=True))
130- # Really returns IDistributionSourcePackage, see below.
131+ # Really returns IDistributionSourcePackage, see
132+ # _schema_circular_imports.py.
133 @operation_returns_collection_of(Interface)
134 @export_read_operation()
135 def searchSourcePackages(text):
136 """Search for source packages that correspond to the given text.
137-
138+
139 This method just decorates the result of searchSourcePackageCaches()
140 to return DistributionSourcePackages.
141 """
142@@ -597,7 +599,3 @@
143 Exception.__init__(
144 self, "Partner archive for distro '%s' not found"
145 % (distribution.name,))
146-
147-
148-# Monkey patching to fix circular imports done in
149-# _schema_circular_imports.py
150
151=== modified file 'lib/lp/registry/interfaces/sourcepackage.py'
152--- lib/lp/registry/interfaces/sourcepackage.py 2009-11-24 23:12:23 +0000
153+++ lib/lp/registry/interfaces/sourcepackage.py 2010-02-08 20:33:22 +0000
154@@ -94,7 +94,7 @@
155 vocabulary="ProductSeries",
156 schema=Interface,
157 description=_(
158- "The registered project series that this source package. "
159+ "The registered project series that this source package "
160 "is based on. This series may be the same as the one that "
161 "earlier versions of this source packages were based on.")))
162
163
164=== modified file 'lib/lp/registry/stories/webservice/xx-distroseries.txt'
165--- lib/lp/registry/stories/webservice/xx-distroseries.txt 2009-09-09 13:19:41 +0000
166+++ lib/lp/registry/stories/webservice/xx-distroseries.txt 2010-02-08 20:33:22 +0000
167@@ -18,6 +18,17 @@
168 http://.../ubuntu/hoary
169 http://.../ubuntu/warty
170
171+The series are available to the anonymous API user too:
172+
173+ >>> all_series = anon_webservice.get(
174+ ... ubuntu['series_collection_link']).jsonBody()
175+ >>> for entry in all_series['entries']:
176+ ... print entry['self_link']
177+ http://.../ubuntu/breezy-autotest
178+ http://.../ubuntu/grumpy
179+ http://.../ubuntu/hoary
180+ http://.../ubuntu/warty
181+
182 Via the current series:
183
184 >>> current_series = webservice.get(
185@@ -84,4 +95,3 @@
186 ...
187 Location: http://.../ubuntu/+milestone/alpha1
188 ...
189-