Merge lp:~michael.nelson/launchpad/409187-trivial-ui-fixes-for-p3a-access into lp:launchpad
- 409187-trivial-ui-fixes-for-p3a-access
- Merge into devel
Status: | Merged | ||||
---|---|---|---|---|---|
Merged at revision: | not available | ||||
Proposed branch: | lp:~michael.nelson/launchpad/409187-trivial-ui-fixes-for-p3a-access | ||||
Merge into: | lp:launchpad | ||||
Diff against target: |
932 lines 19 files modified
lib/canonical/launchpad/icing/style-3-0.css (+3/-0) lib/canonical/launchpad/javascript/soyuz/archivesubscribers_index.js (+54/-0) lib/canonical/launchpad/javascript/soyuz/tests/archivesubscribers_index.html (+46/-0) lib/canonical/launchpad/javascript/soyuz/tests/archivesubscribers_index.js (+147/-0) lib/canonical/launchpad/pagetitles.py (+0/-8) lib/lp/soyuz/browser/archivesubscription.py (+28/-3) lib/lp/soyuz/browser/distroarchseriesbinarypackage.py (+0/-9) lib/lp/soyuz/browser/tests/archivesubscription-views.txt (+23/-7) lib/lp/soyuz/browser/tests/test_breadcrumbs.py (+34/-0) lib/lp/soyuz/configure.zcml (+6/-1) lib/lp/soyuz/interfaces/archivesubscriber.py (+3/-0) lib/lp/soyuz/stories/ppa/xx-private-ppa-subscription-stories.txt (+3/-3) lib/lp/soyuz/stories/ppa/xx-private-ppa-subscriptions.txt (+1/-0) lib/lp/soyuz/templates/archive-subscriber-edit.pt (+0/-6) lib/lp/soyuz/templates/archive-subscribers.pt (+19/-13) lib/lp/soyuz/templates/person-archive-subscription.pt (+9/-14) lib/lp/soyuz/templates/person-archive-subscriptions.pt (+4/-8) lib/lp/soyuz/windmill/testing.py (+18/-0) lib/lp/soyuz/windmill/tests/test_archivesubscribersindex.py (+96/-0) |
||||
To merge this branch: | bzr merge lp:~michael.nelson/launchpad/409187-trivial-ui-fixes-for-p3a-access | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Graham Binns (community) | js | Approve | |
Barry Warsaw (community) | ui* | Approve | |
Guilherme Salgado (community) | Approve | ||
Review via email: mp+12035@code.launchpad.net |
Commit message
Description of the change
Michael Nelson (michael.nelson) wrote : | # |
Guilherme Salgado (salgado) wrote : | # |
Hi Michael,
Your changes look good. I have a few suggestions and I'd like somebody
else to review the JS changes, as I don't feel comfortable doing so.
review approve
> === modified file 'lib/lp/
> --- lib/lp/
> +++ lib/lp/
> @@ -9,6 +9,8 @@
>
> __all__ = [
> 'ArchiveSubscri
> + 'PersonalArchiv
> + 'PersonArchiveS
> 'PersonArchiveS
> 'traverse_
> ]
> @@ -34,10 +36,11 @@
> IArchiveAuthTok
> from lp.soyuz.
> IArchiveSubscri
> +from canonical.
> from canonical.
> action, custom_widget, LaunchpadFormView, LaunchpadEditFo
> from canonical.
> - canonical_url, LaunchpadView)
> + canonical_url, LaunchpadView, Navigation)
> from canonical.widgets import DateWidget
> from canonical.
>
> @@ -65,6 +68,20 @@
> """See `IPersonalArchi
> return "Access to %s" % self.archive.
>
> + @property
> + def title(self):
I know of page_title and label, which are used for this purpose, did you mean
one of them or am I not aware of this third one?
> + """Required for default headings in templates."""
> + return self.displayname
> +
> +
> +class PersonalArchive
> + """Navigation for `IPersonalArchi
> +
> + Without this, a breadcrumb will not be created for personal
> + archive subscription objects.
This is no longer needed, actually -- a fix for the bug (423898) is included
in my breadcrumbs branch that is on PQM now.
> + """
> + usedfor = IPersonalArchiv
> +
> def traverse_
> """Return the subscription for a subscriber to an archive."""
> subscription = None
> @@ -79,6 +96,14 @@
> return PersonalArchive
>
>
> +class PersonalArchive
> + """Builds a breadcrumb for `PersonalArchiv
> +
> + @property
> + def text(self):
> + return self.context.
You can use webapp.
of this adapter altogether. It'd be great if you could do a quick check for
other places where that generic adapter could replace other specific ones. :)
> +
> +
> class IArchiveSubscri
> """A custom interface for user interaction with archive subscriptions.
>
> === modified file 'lib/lp/
> --- lib/lp/
> +++ lib/lp/
> @@ -11,6 +11,8 @@
> from canonical.launc...
Barry Warsaw (barry) wrote : | # |
Looks very good, and the movie really helped! The only thing that's weird for me is leaving the date blank to mean never expire. There's no need to hold up the branch for this, so I'll just ramble a bit.
If possible, the date picker maybe should have a "Never expire" button. You'd use this both in the initial date choice but also if you then decide to extend a user's access to "forever". Also, if access never expires, it would be nice if the date field actually said that, instead of being blank.
With these changes, you'd be able to get rid of the helpful text explaining what a blank field means.
If you think these are worthwhile changes to make, file a bug and fix it later. But the ui as it is looks otherwise great.
Michael Nelson (michael.nelson) wrote : | # |
Guilherme Salgado wrote:
> Review: Approve
> Hi Michael,
>
> Your changes look good. I have a few suggestions and I'd like somebody
> else to review the JS changes, as I don't feel comfortable doing so.
>
Great, thanks Salgado.
> review approve
>
>> === modified file 'lib/lp/
>> --- lib/lp/
>> +++ lib/lp/
>> @@ -9,6 +9,8 @@
>>
>> __all__ = [
>> 'ArchiveSubscri
>> + 'PersonalArchiv
>> + 'PersonArchiveS
>> 'PersonArchiveS
>> 'traverse_
>> ]
>> @@ -34,10 +36,11 @@
>> IArchiveAuthTok
>> from lp.soyuz.
>> IArchiveSubscri
>> +from canonical.
>> from canonical.
>> action, custom_widget, LaunchpadFormView, LaunchpadEditFo
>> from canonical.
>> - canonical_url, LaunchpadView)
>> + canonical_url, LaunchpadView, Navigation)
>> from canonical.widgets import DateWidget
>> from canonical.
>>
>> @@ -65,6 +68,20 @@
>> """See `IPersonalArchi
>> return "Access to %s" % self.archive.
>>
>> + @property
>> + def title(self):
>
> I know of page_title and label, which are used for this purpose, did you mean
> one of them or am I not aware of this third one?
No, the helper class to which this belongs (PersonalArchiv
is used as the context for these views, and so like normal content
classes, it needs a title attribute for when the base template tries to
access context.title.
>
>> + """Required for default headings in templates."""
>> + return self.displayname
>> +
>> +
>> +class PersonalArchive
>> + """Navigation for `IPersonalArchi
>> +
>> + Without this, a breadcrumb will not be created for personal
>> + archive subscription objects.
>
> This is no longer needed, actually -- a fix for the bug (423898) is included
> in my breadcrumbs branch that is on PQM now.
Great, removed.
>
>> + """
>> + usedfor = IPersonalArchiv
>> +
>> def traverse_
>> """Return the subscription for a subscriber to an archive."""
>> subscription = None
>> @@ -79,6 +96,14 @@
>> return PersonalArchive
>>
>>
>> +class PersonalArchive
>> + """Builds a breadcrumb for `PersonalArchiv
>> +
>> + @property
>> + def text(self):
>> + return self.context.
>
> You can use webapp.
> of this adapter altogether. It'd be great if you could do a quick check for
> other places where that generic adapter could replace other speci...
1 | === added file 'lib/canonical/launchpad/javascript/soyuz/archivesubscribers_index.js' |
2 | --- lib/canonical/launchpad/javascript/soyuz/archivesubscribers_index.js 1970-01-01 00:00:00 +0000 |
3 | +++ lib/canonical/launchpad/javascript/soyuz/archivesubscribers_index.js 2009-09-29 07:26:40 +0000 |
4 | @@ -0,0 +1,54 @@ |
5 | +/* Copyright 2009 Canonical Ltd. This software is licensed under the |
6 | + * GNU Affero General Public License version 3 (see the file LICENSE). |
7 | + * |
8 | + * Enhancements for adding ppa subscribers. |
9 | + * |
10 | + * @module ArchiveSubscribersIndex |
11 | + * @requires event, node, oop |
12 | + */ |
13 | +YUI.add('soyuz.archivesubscribers_index', function(Y) { |
14 | + |
15 | +var soyuz = Y.namespace('soyuz'); |
16 | + |
17 | +/* |
18 | + * Setup the style and click handler for the add subscriber link. |
19 | + * |
20 | + * @method setup_archivesubscribers_index |
21 | + */ |
22 | +Y.soyuz.setup_archivesubscribers_index = function() { |
23 | + // If there are no errors then we hide the add-subscriber row and |
24 | + // potentially the whole table if there are no subscribers. |
25 | + if (Y.Lang.isNull(Y.get('p.error.message'))) { |
26 | + |
27 | + // Hide the add-subscriber row. |
28 | + var add_subscriber_row = Y.get( |
29 | + '#archive-subscribers .add-subscriber'); |
30 | + add_subscriber_row.setStyle('display', 'none'); |
31 | + |
32 | + // If there are no subscribers, then hide the complete section. |
33 | + var subscribers = Y.get('#subscribers'); |
34 | + if (Y.Lang.isObject(Y.get('#no-subscribers'))) { |
35 | + subscribers.setStyle('display', 'none'); |
36 | + } |
37 | + } |
38 | + |
39 | + // Add a link to open the add-subscriber row. |
40 | + var placeholder = Y.get('#add-subscriber-placeholder'); |
41 | + placeholder.set( |
42 | + 'innerHTML', |
43 | + '<a class="js-action sprite add" href="#">Add access</a>'); |
44 | + |
45 | + // Unfortunately we can't use the lazr slider, as it uses display:block |
46 | + // which breaks table rows (they use display:table-row). |
47 | + function show_add_subscriber(e) { |
48 | + e.preventDefault(); |
49 | + subscribers.setStyle('display', 'block'); |
50 | + add_subscriber_row.setStyle('display', 'table-row'); |
51 | + } |
52 | + |
53 | + Y.on('click', show_add_subscriber, |
54 | + '#add-subscriber-placeholder a'); |
55 | +}; |
56 | + |
57 | +}, '0.1', {requires: ['oop', 'node', 'event']}); |
58 | + |
59 | |
60 | === added file 'lib/canonical/launchpad/javascript/soyuz/tests/archivesubscribers_index.html' |
61 | --- lib/canonical/launchpad/javascript/soyuz/tests/archivesubscribers_index.html 1970-01-01 00:00:00 +0000 |
62 | +++ lib/canonical/launchpad/javascript/soyuz/tests/archivesubscribers_index.html 2009-09-29 09:28:33 +0000 |
63 | @@ -0,0 +1,46 @@ |
64 | +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> |
65 | +<html> |
66 | + <head> |
67 | + <title>Launchpad ArchiveSubscriberIndex</title> |
68 | + |
69 | + <!-- YUI 3.0 Setup --> |
70 | + <script type="text/javascript" src="../../../icing/yui/current/build/yui/yui.js"></script> |
71 | + <link rel="stylesheet" href="../../../icing/yui/current/build/cssreset/reset.css"/> |
72 | + <link rel="stylesheet" href="../../../icing/yui/current/build/cssfonts/fonts.css"/> |
73 | + <link rel="stylesheet" href="../../../icing/yui/current/build/cssbase/base.css"/> |
74 | + <link rel="stylesheet" href="../../test.css" /> |
75 | + |
76 | + <!-- The module under test --> |
77 | + <script type="text/javascript" src="../archivesubscribers_index.js"></script> |
78 | + |
79 | + <!-- The test suite --> |
80 | + <script type="text/javascript" src="archivesubscribers_index.js"></script> |
81 | +</head> |
82 | +<body class="yui-skin-sam"> |
83 | + <h1>Testing the ArchiveSubscribersIndex javascript</h1> |
84 | + |
85 | + <h2>Errors</h2> |
86 | + <div id="errors"> |
87 | + </div> |
88 | + |
89 | + <h2>Add subscriber place-holder</h2> |
90 | + <div id="add-subscriber-placeholder"> |
91 | + </div> |
92 | + |
93 | + <h2>Subscribers</h2> |
94 | + <div id="subscribers"> |
95 | + <table id="archive-subscribers"> |
96 | + <thead> |
97 | + <tr> |
98 | + <th>Name</th> |
99 | + <th>Expires</th> |
100 | + <th colspan="2">Comment</th> |
101 | + </tr> |
102 | + </thead> |
103 | + <tbody> |
104 | + </tbody> |
105 | + </table> |
106 | + </div> |
107 | + <div id="log"></div> |
108 | +</body> |
109 | +</html> |
110 | |
111 | === added file 'lib/canonical/launchpad/javascript/soyuz/tests/archivesubscribers_index.js' |
112 | --- lib/canonical/launchpad/javascript/soyuz/tests/archivesubscribers_index.js 1970-01-01 00:00:00 +0000 |
113 | +++ lib/canonical/launchpad/javascript/soyuz/tests/archivesubscribers_index.js 2009-09-29 09:28:33 +0000 |
114 | @@ -0,0 +1,134 @@ |
115 | +/* Copyright 2009 Canonical Ltd. This software is licensed under the |
116 | + GNU Affero General Public License version 3 (see the file LICENSE). */ |
117 | + |
118 | +YUI({ |
119 | + base: '../../../icing/yui/current/build/', |
120 | + filter: 'raw', |
121 | + combine: false |
122 | + }).use( |
123 | + 'yuitest', 'console', 'soyuz.archivesubscribers_index', function(Y) { |
124 | + |
125 | +var Assert = Y.Assert; // For easy access to isTrue(), etc. |
126 | + |
127 | +var suite = new Y.Test.Suite("ArchiveSubscriber Tests"); |
128 | + |
129 | +suite.add(new Y.Test.Case({ |
130 | + |
131 | + name: 'add-subscriber', |
132 | + |
133 | + setUp: function() { |
134 | + this.add_subscriber_placeholder = Y.get( |
135 | + '#add-subscriber-placeholder'); |
136 | + this.archive_subscribers_table_body = Y.get( |
137 | + '#archive-subscribers').query('tbody'); |
138 | + this.error_div = Y.get('#errors'); |
139 | + this.subscribers_div = Y.get('#subscribers'); |
140 | + |
141 | + |
142 | + // Ensure there are no errors displayed. |
143 | + this.error_div.set('innerHTML', ''); |
144 | + |
145 | + // Ensure the add subscriber place-holder is empty. |
146 | + this.add_subscriber_placeholder.set('innerHTML', ''); |
147 | + |
148 | + // Ensure the table has the correct structure. |
149 | + this.archive_subscribers_table_body.set( |
150 | + 'innerHTML', [ |
151 | + '<tr class="add-subscriber">', |
152 | + '<td>New 1</td>', |
153 | + '<td>New 2</td>', |
154 | + '<td>New 3</td>', |
155 | + '<td>Add</td>', |
156 | + '</tr>', |
157 | + '<tr>', |
158 | + '<td>Existing 1</td>', |
159 | + '<td>Existing 2</td>', |
160 | + '<td>Existing 3</td>', |
161 | + '<td>Edit</td>', |
162 | + '</tr>' |
163 | + ].join('')); |
164 | + |
165 | + this.add_subscriber_row = Y.get( |
166 | + '#archive-subscribers .add-subscriber'); |
167 | + }, |
168 | + |
169 | + test_add_row_displayed_by_default: function() { |
170 | + Assert.areEqual( |
171 | + 'table-row', this.add_subscriber_row.getStyle('display'), |
172 | + 'The add subscriber row degrades to display without js.'); |
173 | + }, |
174 | + |
175 | + test_subscribers_displayed_by_default: function() { |
176 | + Assert.areEqual( |
177 | + 'block', this.subscribers_div.getStyle('display'), |
178 | + 'The subscribers section is displayed by default without js.'); |
179 | + }, |
180 | + |
181 | + test_add_row_hidden_after_setup: function() { |
182 | + Y.soyuz.setup_archivesubscribers_index(); |
183 | + Assert.areEqual( |
184 | + 'none', this.add_subscriber_row.getStyle('display'), |
185 | + 'The add subscriber row is hidden during setup.'); |
186 | + }, |
187 | + |
188 | + test_subscribers_section_displayed_after_setup: function() { |
189 | + Y.soyuz.setup_archivesubscribers_index(); |
190 | + Assert.areEqual( |
191 | + 'block', this.subscribers_div.getStyle('display'), |
192 | + 'The subscribers div normally remains displayed after setup.'); |
193 | + }, |
194 | + |
195 | + test_subscribers_section_hidden_when_no_subscribers: function() { |
196 | + // Add a paragraph with the no-subscribers id. |
197 | + this.error_div.set('innerHTML', '<p id="no-subscribers">blah</p>'); |
198 | + Y.soyuz.setup_archivesubscribers_index(); |
199 | + Assert.areEqual( |
200 | + 'none', this.subscribers_div.getStyle('display'), |
201 | + 'The subscribers div is hidden when no subscribers yet.'); |
202 | + }, |
203 | + |
204 | + test_add_row_displayed_when_errors_present: function() { |
205 | + // Add an error paragraph. |
206 | + this.error_div.set('innerHTML', '<p class="error message">Blah</p>'); |
207 | + Y.soyuz.setup_archivesubscribers_index(); |
208 | + Assert.areEqual( |
209 | + 'table-row', this.add_subscriber_row.getStyle('display'), |
210 | + 'The add subscriber row is displayed if there are errors ' + |
211 | + 'present.'); |
212 | + }, |
213 | + |
214 | + test_add_access_link_added_after_setup: function() { |
215 | + Y.soyuz.setup_archivesubscribers_index(); |
216 | + Assert.areEqual( |
217 | + '<a class="js-action sprite add" href="#">Add access</a>', |
218 | + this.add_subscriber_placeholder.get('innerHTML'), |
219 | + "The 'Add access' link is created during setup.") |
220 | + }, |
221 | + |
222 | + test_click_add_access_displays_add_row: function() { |
223 | + Y.soyuz.setup_archivesubscribers_index(); |
224 | + var link_node = this.add_subscriber_placeholder.query('a'); |
225 | + Assert.areEqual( |
226 | + 'Add access', link_node.get('innerHTML')); |
227 | + |
228 | + Y.Event.simulate(Y.Node.getDOMNode(link_node), 'click'); |
229 | + |
230 | + Assert.areEqual( |
231 | + 'table-row', this.add_subscriber_row.getStyle('display'), |
232 | + "The add subscriber row is displayed after clicking " + |
233 | + "'Add access'"); |
234 | + } |
235 | +})); |
236 | + |
237 | +Y.Test.Runner.add(suite); |
238 | + |
239 | +var yconsole = new Y.Console({ |
240 | + newestOnTop: false |
241 | +}); |
242 | +yconsole.render('#log'); |
243 | + |
244 | +Y.on('domready', function() { |
245 | + Y.Test.Runner.run(); |
246 | +}); |
247 | + |
248 | +}); |
249 | |
250 | === modified file 'lib/lp/soyuz/browser/archivesubscription.py' |
251 | --- lib/lp/soyuz/browser/archivesubscription.py 2009-09-14 08:08:51 +0000 |
252 | +++ lib/lp/soyuz/browser/archivesubscription.py 2009-09-29 07:21:40 +0000 |
253 | @@ -9,7 +9,6 @@ |
254 | |
255 | __all__ = [ |
256 | 'ArchiveSubscribersView', |
257 | - 'PersonalArchiveSubscriptionBreadcrumb', |
258 | 'PersonArchiveSubscriptionView', |
259 | 'PersonArchiveSubscriptionsView', |
260 | 'traverse_archive_subscription_for_subscriber' |
261 | @@ -74,14 +73,6 @@ |
262 | return self.displayname |
263 | |
264 | |
265 | -class PersonalArchiveSubscriptionNavigation(Navigation): |
266 | - """Navigation for `IPersonalArchiveSubscription`. |
267 | - |
268 | - Without this, a breadcrumb will not be created for personal |
269 | - archive subscription objects. |
270 | - """ |
271 | - usedfor = IPersonalArchiveSubscription |
272 | - |
273 | def traverse_archive_subscription_for_subscriber(subscriber, archive_id): |
274 | """Return the subscription for a subscriber to an archive.""" |
275 | subscription = None |
276 | @@ -96,14 +87,6 @@ |
277 | return PersonalArchiveSubscription(subscriber, archive) |
278 | |
279 | |
280 | -class PersonalArchiveSubscriptionBreadcrumb(Breadcrumb): |
281 | - """Builds a breadcrumb for `PersonalArchiveSubscription`.""" |
282 | - |
283 | - @property |
284 | - def text(self): |
285 | - return self.context.displayname |
286 | - |
287 | - |
288 | class IArchiveSubscriberUI(Interface): |
289 | """A custom interface for user interaction with archive subscriptions. |
290 | |
291 | |
292 | === modified file 'lib/lp/soyuz/browser/configure.zcml' |
293 | --- lib/lp/soyuz/browser/configure.zcml 2009-09-28 13:56:17 +0000 |
294 | +++ lib/lp/soyuz/browser/configure.zcml 2009-09-29 07:21:40 +0000 |
295 | @@ -520,9 +520,6 @@ |
296 | <browser:defaultView |
297 | for="lp.soyuz.interfaces.archivesubscriber.IPersonalArchiveSubscription" |
298 | name="+index"/> |
299 | - <browser:navigation |
300 | - module="lp.soyuz.browser.archivesubscription" |
301 | - classes="PersonalArchiveSubscriptionNavigation"/> |
302 | <browser:defaultView |
303 | for="lp.soyuz.interfaces.distributionsourcepackagerelease.IDistributionSourcePackageRelease" |
304 | name="+index"/> |
305 | |
306 | === modified file 'lib/lp/soyuz/browser/distroarchseriesbinarypackage.py' |
307 | --- lib/lp/soyuz/browser/distroarchseriesbinarypackage.py 2009-09-03 15:17:24 +0000 |
308 | +++ lib/lp/soyuz/browser/distroarchseriesbinarypackage.py 2009-09-29 07:21:40 +0000 |
309 | @@ -4,7 +4,6 @@ |
310 | __metaclass__ = type |
311 | |
312 | __all__ = [ |
313 | - 'DistroArchSeriesBinaryPackageBreadcrumb', |
314 | 'DistroArchSeriesBinaryPackageNavigation', |
315 | 'DistroArchSeriesBinaryPackageView', |
316 | ] |
317 | @@ -16,14 +15,6 @@ |
318 | from canonical.lazr.utils import smartquote |
319 | |
320 | |
321 | -class DistroArchSeriesBinaryPackageBreadcrumb(Breadcrumb): |
322 | - """A breadcrumb for `DistroArchSeriesBinaryPackage`.""" |
323 | - |
324 | - @property |
325 | - def text(self): |
326 | - return self.context.name |
327 | - |
328 | - |
329 | class DistroArchSeriesBinaryPackageOverviewMenu(ApplicationMenu): |
330 | |
331 | usedfor = IDistroArchSeriesBinaryPackage |
332 | |
333 | === modified file 'lib/lp/soyuz/browser/tests/test_breadcrumbs.py' |
334 | --- lib/lp/soyuz/browser/tests/test_breadcrumbs.py 2009-09-11 10:52:54 +0000 |
335 | +++ lib/lp/soyuz/browser/tests/test_breadcrumbs.py 2009-09-29 07:21:40 +0000 |
336 | @@ -76,7 +76,6 @@ |
337 | owner, self.ppa) |
338 | |
339 | def test_personal_archive_subscription(self): |
340 | - |
341 | self.traversed_objects = [ |
342 | self.root, self.ppa.owner, self.personal_archive_subscription] |
343 | subscription_url = canonical_url(self.personal_archive_subscription) |
344 | |
345 | === modified file 'lib/lp/soyuz/configure.zcml' |
346 | --- lib/lp/soyuz/configure.zcml 2009-09-24 08:17:04 +0000 |
347 | +++ lib/lp/soyuz/configure.zcml 2009-09-29 07:21:40 +0000 |
348 | @@ -582,7 +582,7 @@ |
349 | <adapter |
350 | for="lp.soyuz.interfaces.distroarchseriesbinarypackage.IDistroArchSeriesBinaryPackage" |
351 | provides="canonical.launchpad.webapp.interfaces.IBreadcrumb" |
352 | - factory="lp.soyuz.browser.distroarchseriesbinarypackage.DistroArchSeriesBinaryPackageBreadcrumb" |
353 | + factory="canonical.launchpad.webapp.breadcrumb.NameBreadcrumb" |
354 | permission="zope.Public" /> |
355 | |
356 | <!-- PublishedPackage --> |
357 | @@ -650,7 +650,7 @@ |
358 | <adapter |
359 | provides="canonical.launchpad.webapp.interfaces.IBreadcrumb" |
360 | for="lp.soyuz.interfaces.archivesubscriber.IPersonalArchiveSubscription" |
361 | - factory="lp.soyuz.browser.archivesubscription.PersonalArchiveSubscriptionBreadcrumb" |
362 | + factory="canonical.launchpad.webapp.breadcrumb.DisplaynameBreadcrumb" |
363 | permission="zope.Public"/> |
364 | <subscriber |
365 | for="lp.soyuz.interfaces.archivesubscriber.IArchiveSubscriber |
366 | |
367 | === modified file 'lib/lp/soyuz/templates/archive-subscribers.pt' |
368 | --- lib/lp/soyuz/templates/archive-subscribers.pt 2009-09-18 08:09:23 +0000 |
369 | +++ lib/lp/soyuz/templates/archive-subscribers.pt 2009-09-29 07:21:40 +0000 |
370 | @@ -10,6 +10,11 @@ |
371 | <metal:block fill-slot="head_epilogue"> |
372 | <metal:yui-dependencies |
373 | use-macro="context/@@launchpad_widget_macros/yui2calendar-dependencies" /> |
374 | + |
375 | + <tal:devmode condition="devmode"> |
376 | + <script type="text/javascript" |
377 | + tal:attributes="src string:${lp_js}/soyuz/archivesubscribers_index.js"></script> |
378 | + </tal:devmode> |
379 | </metal:block> |
380 | |
381 | <div metal:fill-slot="main"> |
382 | @@ -92,51 +97,12 @@ |
383 | </table> |
384 | </form> |
385 | </div><!-- class="portlet" --> |
386 | + <script type="text/javascript" id="setup-archivesubscribers-index"> |
387 | + YUI().use('soyuz.archivesubscribers_index', function(Y) { |
388 | + Y.soyuz.setup_archivesubscribers_index(); |
389 | + }); |
390 | + </script> |
391 | </div> |
392 | - <script type="text/javascript"> |
393 | -YUI({ |
394 | - base: '../../lib/yui/current/build/', |
395 | - filter: 'raw' |
396 | - }).use('node', 'event', 'lazr.effects', function(Y) { |
397 | - |
398 | - // If there are no errors then we hide the add-subscriber row and |
399 | - // potentially the whole table if there are no subscribers. |
400 | - if (Y.Lang.isNull(Y.get('p.error.message'))) { |
401 | - |
402 | - // Hide the add-subscriber row. |
403 | - var add_subscriber_row = Y.get( |
404 | - '#archive-subscribers .add-subscriber'); |
405 | - add_subscriber_row.setStyle('display', 'none'); |
406 | - |
407 | - // If there are no subscribers, then hide the complete section. |
408 | - var subscribers = Y.get('#subscribers'); |
409 | - if (Y.Lang.isObject(Y.get('#no-subscribers'))) { |
410 | - subscribers.setStyle('display', 'none'); |
411 | - } |
412 | - } |
413 | - |
414 | - // Add a link to open the add-subscriber row. |
415 | - var placeholder = Y.get('#add-subscriber-placeholder'); |
416 | - placeholder.set( |
417 | - 'innerHTML', '<a class="js-action sprite add" href="#" />'); |
418 | - var add_subscriber_node = Y.get("#add-subscriber-placeholder a"); |
419 | - add_subscriber_node.set('innerHTML', 'Add access'); |
420 | - |
421 | - // Unfortunately we can't use the lazr slider, as it uses display:block |
422 | - // which breaks table rows (they use display:table-row). |
423 | - function show_add_subscriber(e) { |
424 | - e.preventDefault(); |
425 | - subscribers.setStyle('display', 'block'); |
426 | - add_subscriber_row.setStyle('display', 'table-row'); |
427 | - } |
428 | - |
429 | - Y.on('click', show_add_subscriber, |
430 | - '#add-subscriber-placeholder a'); |
431 | - |
432 | -}); |
433 | - </script> |
434 | - |
435 | - |
436 | </div> |
437 | </body> |
438 | </html> |
439 | |
440 | === added directory 'lib/lp/soyuz/windmill' |
441 | === added file 'lib/lp/soyuz/windmill/__init__.py' |
442 | === added file 'lib/lp/soyuz/windmill/testing.py' |
443 | --- lib/lp/soyuz/windmill/testing.py 1970-01-01 00:00:00 +0000 |
444 | +++ lib/lp/soyuz/windmill/testing.py 2009-09-29 12:09:39 +0000 |
445 | @@ -0,0 +1,18 @@ |
446 | +# Copyright 2009 Canonical Ltd. This software is licensed under the |
447 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
448 | + |
449 | +"""Soyuz-specific testing infrastructure for Windmill.""" |
450 | + |
451 | +__metaclass__ = type |
452 | +__all__ = [ |
453 | + 'SoyuzWindmillLayer', |
454 | + ] |
455 | + |
456 | + |
457 | +from canonical.testing.layers import BaseWindmillLayer |
458 | + |
459 | + |
460 | +class SoyuzWindmillLayer(BaseWindmillLayer): |
461 | + """Layer for Soyuz Windmill tests.""" |
462 | + |
463 | + base_url = 'http://launchpad.dev:8085/' |
464 | |
465 | === added directory 'lib/lp/soyuz/windmill/tests' |
466 | === added file 'lib/lp/soyuz/windmill/tests/__init__.py' |
467 | === added file 'lib/lp/soyuz/windmill/tests/test_archivesubscribersindex.py' |
468 | --- lib/lp/soyuz/windmill/tests/test_archivesubscribersindex.py 1970-01-01 00:00:00 +0000 |
469 | +++ lib/lp/soyuz/windmill/tests/test_archivesubscribersindex.py 2009-09-29 12:09:39 +0000 |
470 | @@ -0,0 +1,96 @@ |
471 | +# Copyright 2009 Canonical Ltd. This software is licensed under the |
472 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
473 | + |
474 | +"""Test for the archive subscribers index page..""" |
475 | + |
476 | +__metaclass__ = type |
477 | +__all__ = [] |
478 | + |
479 | +import transaction |
480 | +import unittest |
481 | + |
482 | +from windmill.authoring import WindmillTestClient |
483 | + |
484 | +from zope.component import getUtility |
485 | + |
486 | +from canonical.launchpad.ftests import login, logout |
487 | +from canonical.launchpad.windmill.testing.lpuser import LaunchpadUser |
488 | +from lp.registry.interfaces.distribution import IDistributionSet |
489 | +from lp.soyuz.windmill.testing import SoyuzWindmillLayer |
490 | +from lp.testing import TestCaseWithFactory |
491 | + |
492 | +WAIT_PAGELOAD = u'30000' |
493 | +WAIT_ELEMENT_COMPLETE = u'30000' |
494 | +WAIT_CHECK_CHANGE = u'1000' |
495 | +ADD_ACCESS_LINK = u'//a[@class="js-action sprite add"]' |
496 | +CHOOSE_SUBSCRIBER_LINK = u'//a[@id="show-widget-field-subscriber"]' |
497 | +SUBSCRIBER_SEARCH_FIELD = ( |
498 | + u'//div[@id="yui-pretty-overlay-modal"]//input[@name="search"]') |
499 | +SUBSCRIBER_SEARCH_BUTTON = u'//div[@id="yui-pretty-overlay-modal"]//button' |
500 | +FIRST_SUBSCRIBER_RESULT = ( |
501 | + u'//div[@id="yui-pretty-overlay-modal"]' |
502 | + '//span[@class="yui-picker-result-title"]') |
503 | + |
504 | + |
505 | +class TestArchiveSubscribersIndex(TestCaseWithFactory): |
506 | + |
507 | + layer = SoyuzWindmillLayer |
508 | + |
509 | + def setUp(self): |
510 | + """Create a private PPA.""" |
511 | + super(TestArchiveSubscribersIndex, self).setUp() |
512 | + |
513 | + user = self.factory.makePerson( |
514 | + name='joe-bloggs', email='joe@example.com', password='joe', |
515 | + displayname='Joe Bloggs') |
516 | + ubuntu = getUtility(IDistributionSet)['ubuntu'] |
517 | + self.ppa = self.factory.makeArchive( |
518 | + owner=user, name='myppa', distribution=ubuntu) |
519 | + |
520 | + login('foo.bar@canonical.com') |
521 | + self.ppa.private = True |
522 | + self.ppa.buildd_secret = 'secret' |
523 | + logout() |
524 | + transaction.commit() |
525 | + |
526 | + self.lpuser = LaunchpadUser( |
527 | + 'Joe Bloggs', 'joe@example.com', 'joe') |
528 | + |
529 | + def test_add_subscriber(self): |
530 | + """Test adding a private PPA subscriber..""" |
531 | + client = WindmillTestClient('Adding private PPA subscribers.') |
532 | + |
533 | + self.lpuser.ensure_login(client) |
534 | + |
535 | + client.open(url='http://launchpad.dev:8085/~joe-bloggs/' |
536 | + '+archive/myppa/+subscriptions') |
537 | + client.waits.forPageLoad(timeout=WAIT_PAGELOAD) |
538 | + |
539 | + # Click on the JS add access action. |
540 | + client.waits.forElement(xpath=ADD_ACCESS_LINK) |
541 | + client.click(xpath=ADD_ACCESS_LINK) |
542 | + |
543 | + # Open the picker, search for 'launchpad' and choose the first |
544 | + # result |
545 | + client.click(xpath=CHOOSE_SUBSCRIBER_LINK) |
546 | + client.type(xpath=SUBSCRIBER_SEARCH_FIELD, text='launchpad') |
547 | + client.click(xpath=SUBSCRIBER_SEARCH_BUTTON) |
548 | + |
549 | + client.waits.forElement(xpath=FIRST_SUBSCRIBER_RESULT) |
550 | + client.click(xpath=FIRST_SUBSCRIBER_RESULT) |
551 | + |
552 | + # Add the new subscriber. |
553 | + client.click(id='field.actions.add') |
554 | + client.waits.forPageLoad(timeout=WAIT_PAGELOAD) |
555 | + |
556 | + # And verify that the correct informational message is displayed. |
557 | + # It would be nice if we could use ... here. |
558 | + client.asserts.assertText( |
559 | + xpath=u'//div[@class="informational message"]', |
560 | + validator='You have granted access for Launchpad Developers ' |
561 | + 'to install software from PPA named myppa for Joe ' |
562 | + 'Bloggs. Members of Launchpad Developers will be ' |
563 | + 'notified of the access via email.') |
564 | + |
565 | +def test_suite(): |
566 | + return unittest.TestLoader().loadTestsFromName(__name__) |
Graham Binns (gmb) wrote : | # |
Approved with the changes requested in IRC w.r.t comments in the tests.
Preview Diff
1 | === modified file 'lib/canonical/launchpad/icing/style-3-0.css' |
2 | --- lib/canonical/launchpad/icing/style-3-0.css 2009-09-23 10:29:52 +0000 |
3 | +++ lib/canonical/launchpad/icing/style-3-0.css 2009-09-30 14:18:17 +0000 |
4 | @@ -366,6 +366,9 @@ |
5 | vertical-align: bottom; |
6 | } |
7 | |
8 | +form { |
9 | + margin-bottom: 1em; |
10 | +} |
11 | form h1 { |
12 | margin-bottom: 1em; |
13 | } |
14 | |
15 | === added file 'lib/canonical/launchpad/javascript/soyuz/archivesubscribers_index.js' |
16 | --- lib/canonical/launchpad/javascript/soyuz/archivesubscribers_index.js 1970-01-01 00:00:00 +0000 |
17 | +++ lib/canonical/launchpad/javascript/soyuz/archivesubscribers_index.js 2009-09-30 14:18:17 +0000 |
18 | @@ -0,0 +1,54 @@ |
19 | +/* Copyright 2009 Canonical Ltd. This software is licensed under the |
20 | + * GNU Affero General Public License version 3 (see the file LICENSE). |
21 | + * |
22 | + * Enhancements for adding ppa subscribers. |
23 | + * |
24 | + * @module ArchiveSubscribersIndex |
25 | + * @requires event, node, oop |
26 | + */ |
27 | +YUI.add('soyuz.archivesubscribers_index', function(Y) { |
28 | + |
29 | +var soyuz = Y.namespace('soyuz'); |
30 | + |
31 | +/* |
32 | + * Setup the style and click handler for the add subscriber link. |
33 | + * |
34 | + * @method setup_archivesubscribers_index |
35 | + */ |
36 | +Y.soyuz.setup_archivesubscribers_index = function() { |
37 | + // If there are no errors then we hide the add-subscriber row and |
38 | + // potentially the whole table if there are no subscribers. |
39 | + if (Y.Lang.isNull(Y.get('p.error.message'))) { |
40 | + |
41 | + // Hide the add-subscriber row. |
42 | + var add_subscriber_row = Y.get( |
43 | + '#archive-subscribers .add-subscriber'); |
44 | + add_subscriber_row.setStyle('display', 'none'); |
45 | + |
46 | + // If there are no subscribers, then hide the complete section. |
47 | + var subscribers = Y.get('#subscribers'); |
48 | + if (Y.Lang.isObject(Y.get('#no-subscribers'))) { |
49 | + subscribers.setStyle('display', 'none'); |
50 | + } |
51 | + } |
52 | + |
53 | + // Add a link to open the add-subscriber row. |
54 | + var placeholder = Y.get('#add-subscriber-placeholder'); |
55 | + placeholder.set( |
56 | + 'innerHTML', |
57 | + '<a class="js-action sprite add" href="#">Add access</a>'); |
58 | + |
59 | + // Unfortunately we can't use the lazr slider, as it uses display:block |
60 | + // which breaks table rows (they use display:table-row). |
61 | + function show_add_subscriber(e) { |
62 | + e.preventDefault(); |
63 | + subscribers.setStyle('display', 'block'); |
64 | + add_subscriber_row.setStyle('display', 'table-row'); |
65 | + } |
66 | + |
67 | + Y.on('click', show_add_subscriber, |
68 | + '#add-subscriber-placeholder a'); |
69 | +}; |
70 | + |
71 | +}, '0.1', {requires: ['oop', 'node', 'event']}); |
72 | + |
73 | |
74 | === added file 'lib/canonical/launchpad/javascript/soyuz/tests/archivesubscribers_index.html' |
75 | --- lib/canonical/launchpad/javascript/soyuz/tests/archivesubscribers_index.html 1970-01-01 00:00:00 +0000 |
76 | +++ lib/canonical/launchpad/javascript/soyuz/tests/archivesubscribers_index.html 2009-09-30 14:18:17 +0000 |
77 | @@ -0,0 +1,46 @@ |
78 | +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> |
79 | +<html> |
80 | + <head> |
81 | + <title>Launchpad ArchiveSubscriberIndex</title> |
82 | + |
83 | + <!-- YUI 3.0 Setup --> |
84 | + <script type="text/javascript" src="../../../icing/yui/current/build/yui/yui.js"></script> |
85 | + <link rel="stylesheet" href="../../../icing/yui/current/build/cssreset/reset.css"/> |
86 | + <link rel="stylesheet" href="../../../icing/yui/current/build/cssfonts/fonts.css"/> |
87 | + <link rel="stylesheet" href="../../../icing/yui/current/build/cssbase/base.css"/> |
88 | + <link rel="stylesheet" href="../../test.css" /> |
89 | + |
90 | + <!-- The module under test --> |
91 | + <script type="text/javascript" src="../archivesubscribers_index.js"></script> |
92 | + |
93 | + <!-- The test suite --> |
94 | + <script type="text/javascript" src="archivesubscribers_index.js"></script> |
95 | +</head> |
96 | +<body class="yui-skin-sam"> |
97 | + <h1>Testing the ArchiveSubscribersIndex javascript</h1> |
98 | + |
99 | + <h2>Errors</h2> |
100 | + <div id="errors"> |
101 | + </div> |
102 | + |
103 | + <h2>Add subscriber place-holder</h2> |
104 | + <div id="add-subscriber-placeholder"> |
105 | + </div> |
106 | + |
107 | + <h2>Subscribers</h2> |
108 | + <div id="subscribers"> |
109 | + <table id="archive-subscribers"> |
110 | + <thead> |
111 | + <tr> |
112 | + <th>Name</th> |
113 | + <th>Expires</th> |
114 | + <th colspan="2">Comment</th> |
115 | + </tr> |
116 | + </thead> |
117 | + <tbody> |
118 | + </tbody> |
119 | + </table> |
120 | + </div> |
121 | + <div id="log"></div> |
122 | +</body> |
123 | +</html> |
124 | |
125 | === added file 'lib/canonical/launchpad/javascript/soyuz/tests/archivesubscribers_index.js' |
126 | --- lib/canonical/launchpad/javascript/soyuz/tests/archivesubscribers_index.js 1970-01-01 00:00:00 +0000 |
127 | +++ lib/canonical/launchpad/javascript/soyuz/tests/archivesubscribers_index.js 2009-09-30 14:18:17 +0000 |
128 | @@ -0,0 +1,147 @@ |
129 | +/* Copyright 2009 Canonical Ltd. This software is licensed under the |
130 | + GNU Affero General Public License version 3 (see the file LICENSE). */ |
131 | + |
132 | +YUI({ |
133 | + base: '../../../icing/yui/current/build/', |
134 | + filter: 'raw', |
135 | + combine: false |
136 | + }).use( |
137 | + 'yuitest', 'console', 'soyuz.archivesubscribers_index', function(Y) { |
138 | + |
139 | +var Assert = Y.Assert; // For easy access to isTrue(), etc. |
140 | + |
141 | +var suite = new Y.Test.Suite("ArchiveSubscriber Tests"); |
142 | + |
143 | +suite.add(new Y.Test.Case({ |
144 | + |
145 | + name: 'add-subscriber', |
146 | + |
147 | + setUp: function() { |
148 | + this.add_subscriber_placeholder = Y.get( |
149 | + '#add-subscriber-placeholder'); |
150 | + this.archive_subscribers_table_body = Y.get( |
151 | + '#archive-subscribers').query('tbody'); |
152 | + this.error_div = Y.get('#errors'); |
153 | + this.subscribers_div = Y.get('#subscribers'); |
154 | + |
155 | + |
156 | + // Ensure there are no errors displayed. |
157 | + this.error_div.set('innerHTML', ''); |
158 | + |
159 | + // Ensure the add subscriber place-holder is empty. |
160 | + this.add_subscriber_placeholder.set('innerHTML', ''); |
161 | + |
162 | + // Ensure the table has the correct structure. |
163 | + this.archive_subscribers_table_body.set( |
164 | + 'innerHTML', [ |
165 | + '<tr class="add-subscriber">', |
166 | + '<td>New 1</td>', |
167 | + '<td>New 2</td>', |
168 | + '<td>New 3</td>', |
169 | + '<td>Add</td>', |
170 | + '</tr>', |
171 | + '<tr>', |
172 | + '<td>Existing 1</td>', |
173 | + '<td>Existing 2</td>', |
174 | + '<td>Existing 3</td>', |
175 | + '<td>Edit</td>', |
176 | + '</tr>' |
177 | + ].join('')); |
178 | + |
179 | + this.add_subscriber_row = Y.get( |
180 | + '#archive-subscribers .add-subscriber'); |
181 | + }, |
182 | + |
183 | + test_add_row_displayed_by_default: function() { |
184 | + // The add subscriber row is displayed when the JS is not run. |
185 | + Assert.areEqual( |
186 | + 'table-row', this.add_subscriber_row.getStyle('display'), |
187 | + 'The add subscriber row should display when the js is not run.'); |
188 | + }, |
189 | + |
190 | + test_subscribers_displayed_by_default: function() { |
191 | + // The subscribers section is displayed when the js is not run. |
192 | + Assert.areEqual( |
193 | + 'block', this.subscribers_div.getStyle('display'), |
194 | + 'The subscribers section should display without js.'); |
195 | + }, |
196 | + |
197 | + test_add_row_hidden_after_setup: function() { |
198 | + // The add subscriber row is hidden during setup. |
199 | + Y.soyuz.setup_archivesubscribers_index(); |
200 | + Assert.areEqual( |
201 | + 'none', this.add_subscriber_row.getStyle('display'), |
202 | + 'The add subscriber row should be hidden during setup.'); |
203 | + }, |
204 | + |
205 | + test_subscribers_section_displayed_after_setup: function() { |
206 | + // The subscribers div normally remains displayed after setup. |
207 | + Y.soyuz.setup_archivesubscribers_index(); |
208 | + Assert.areEqual( |
209 | + 'block', this.subscribers_div.getStyle('display'), |
210 | + 'The subscribers div should remain displayed after setup.'); |
211 | + }, |
212 | + |
213 | + test_subscribers_section_hidden_when_no_subscribers: function() { |
214 | + // The subscribers div is hidden when there are no subscribers. |
215 | + |
216 | + // Add a paragraph with the no-subscribers id. |
217 | + this.error_div.set('innerHTML', '<p id="no-subscribers">blah</p>'); |
218 | + Y.soyuz.setup_archivesubscribers_index(); |
219 | + Assert.areEqual( |
220 | + 'none', this.subscribers_div.getStyle('display'), |
221 | + 'The subscribers div should be hidden when there are ' + |
222 | + 'no subscribers.'); |
223 | + }, |
224 | + |
225 | + test_add_row_displayed_when_errors_present: function() { |
226 | + // The add subscriber row is not hidden if there are validation |
227 | + // errors. |
228 | + |
229 | + // Add an error paragraph. |
230 | + this.error_div.set('innerHTML', '<p class="error message">Blah</p>'); |
231 | + Y.soyuz.setup_archivesubscribers_index(); |
232 | + Assert.areEqual( |
233 | + 'table-row', this.add_subscriber_row.getStyle('display'), |
234 | + 'The add subscriber row should not be hidden if there are ' + |
235 | + 'errors present.'); |
236 | + }, |
237 | + |
238 | + test_add_access_link_added_after_setup: function() { |
239 | + // The 'Add access' link is created during setup. |
240 | + |
241 | + Y.soyuz.setup_archivesubscribers_index(); |
242 | + Assert.areEqual( |
243 | + '<a class="js-action sprite add" href="#">Add access</a>', |
244 | + this.add_subscriber_placeholder.get('innerHTML'), |
245 | + "The 'Add access' link should be created during setup.") |
246 | + }, |
247 | + |
248 | + test_click_add_access_displays_add_row: function() { |
249 | + // The add subscriber row is displayed after clicking 'Add access'. |
250 | + Y.soyuz.setup_archivesubscribers_index(); |
251 | + var link_node = this.add_subscriber_placeholder.query('a'); |
252 | + Assert.areEqual( |
253 | + 'Add access', link_node.get('innerHTML')); |
254 | + |
255 | + Y.Event.simulate(Y.Node.getDOMNode(link_node), 'click'); |
256 | + |
257 | + Assert.areEqual( |
258 | + 'table-row', this.add_subscriber_row.getStyle('display'), |
259 | + "The add subscriber row should be displayed after clicking " + |
260 | + "'Add access'"); |
261 | + } |
262 | +})); |
263 | + |
264 | +Y.Test.Runner.add(suite); |
265 | + |
266 | +var yconsole = new Y.Console({ |
267 | + newestOnTop: false |
268 | +}); |
269 | +yconsole.render('#log'); |
270 | + |
271 | +Y.on('domready', function() { |
272 | + Y.Test.Runner.run(); |
273 | +}); |
274 | + |
275 | +}); |
276 | |
277 | === modified file 'lib/canonical/launchpad/pagetitles.py' |
278 | --- lib/canonical/launchpad/pagetitles.py 2009-09-23 14:58:12 +0000 |
279 | +++ lib/canonical/launchpad/pagetitles.py 2009-09-30 14:18:17 +0000 |
280 | @@ -128,10 +128,6 @@ |
281 | |
282 | archive_edit_dependencies = ContextDisplayName('Edit dependencies for %s') |
283 | |
284 | -archive_subscriber_edit = ContextDisplayName('Edit %s') |
285 | - |
286 | -archive_subscribers = ContextDisplayName('Manage access to %s') |
287 | - |
288 | bazaar_all_branches = 'All branches in the Launchpad Bazaar' |
289 | |
290 | bazaar_index = 'Launchpad Branches' |
291 | @@ -562,10 +558,6 @@ |
292 | |
293 | people_requestmerge_multiple = 'Merge Launchpad accounts' |
294 | |
295 | -person_archive_subscription = ContextDisplayName('%s') |
296 | - |
297 | -person_archive_subscriptions = 'Private PPA access' |
298 | - |
299 | person_answer_contact_for = ContextDisplayName( |
300 | 'Projects for which %s is an answer contact') |
301 | |
302 | |
303 | === modified file 'lib/lp/soyuz/browser/archivesubscription.py' |
304 | --- lib/lp/soyuz/browser/archivesubscription.py 2009-08-12 08:40:41 +0000 |
305 | +++ lib/lp/soyuz/browser/archivesubscription.py 2009-09-30 14:18:17 +0000 |
306 | @@ -9,6 +9,7 @@ |
307 | |
308 | __all__ = [ |
309 | 'ArchiveSubscribersView', |
310 | + 'PersonArchiveSubscriptionView', |
311 | 'PersonArchiveSubscriptionsView', |
312 | 'traverse_archive_subscription_for_subscriber' |
313 | ] |
314 | @@ -34,10 +35,11 @@ |
315 | IArchiveAuthTokenSet) |
316 | from lp.soyuz.interfaces.archivesubscriber import ( |
317 | IArchiveSubscriberSet, IPersonalArchiveSubscription) |
318 | +from canonical.launchpad.webapp.breadcrumb import Breadcrumb |
319 | from canonical.launchpad.webapp.launchpadform import ( |
320 | action, custom_widget, LaunchpadFormView, LaunchpadEditFormView) |
321 | from canonical.launchpad.webapp.publisher import ( |
322 | - canonical_url, LaunchpadView) |
323 | + canonical_url, LaunchpadView, Navigation) |
324 | from canonical.widgets import DateWidget |
325 | from canonical.widgets.popup import PersonPickerWidget |
326 | |
327 | @@ -65,6 +67,12 @@ |
328 | """See `IPersonalArchiveSubscription`.""" |
329 | return "Access to %s" % self.archive.displayname |
330 | |
331 | + @property |
332 | + def title(self): |
333 | + """Required for default headings in templates.""" |
334 | + return self.displayname |
335 | + |
336 | + |
337 | def traverse_archive_subscription_for_subscriber(subscriber, archive_id): |
338 | """Return the subscription for a subscriber to an archive.""" |
339 | subscription = None |
340 | @@ -111,6 +119,11 @@ |
341 | custom_widget('subscriber', PersonPickerWidget, |
342 | header="Select the subscriber") |
343 | |
344 | + @property |
345 | + def label(self): |
346 | + """Return a label for the view's main heading.""" |
347 | + return "Manage access to " + self.context.title |
348 | + |
349 | def initialize(self): |
350 | """Ensure that we are dealing with a private archive.""" |
351 | # If this archive is not private, then we should not be |
352 | @@ -210,6 +223,11 @@ |
353 | custom_widget('description', TextWidget, displayWidth=40) |
354 | custom_widget('date_expires', CustomWidgetFactory(DateWidget)) |
355 | |
356 | + @property |
357 | + def label(self): |
358 | + """Return a label for the view's main heading.""" |
359 | + return "Edit " + self.context.displayname |
360 | + |
361 | def validate_update_subscription(self, action, data): |
362 | """Ensure that the date of expiry is not in the past.""" |
363 | form.getWidgetsData(self.widgets, 'field', data) |
364 | @@ -241,12 +259,12 @@ |
365 | self.context.subscriber.displayname) |
366 | self.request.response.addNotification(notification) |
367 | |
368 | - @action(u'Cancel access', name='cancel') |
369 | + @action(u'Revoke access', name='cancel') |
370 | def cancel_subscription(self, action, data): |
371 | """Cancel the context subscription.""" |
372 | self.context.cancel(self.user) |
373 | |
374 | - notification = "You have cancelled %s's subscription to %s." % ( |
375 | + notification = "You have revoked %s's access to %s." % ( |
376 | self.context.subscriber.displayname, |
377 | self.context.archive.displayname) |
378 | self.request.response.addNotification(notification) |
379 | @@ -265,6 +283,8 @@ |
380 | class PersonArchiveSubscriptionsView(LaunchpadView): |
381 | """A view for displaying a persons archive subscriptions.""" |
382 | |
383 | + label = "Private PPA access" |
384 | + |
385 | @cachedproperty |
386 | def subscriptions_with_tokens(self): |
387 | """Return all the persons archive subscriptions with the token |
388 | @@ -294,6 +314,11 @@ |
389 | tokens. |
390 | """ |
391 | |
392 | + @property |
393 | + def label(self): |
394 | + """Return the label for the view's main heading.""" |
395 | + return self.context.title |
396 | + |
397 | def initialize(self): |
398 | """Process any posted actions.""" |
399 | super(PersonArchiveSubscriptionView, self).initialize() |
400 | |
401 | === modified file 'lib/lp/soyuz/browser/distroarchseriesbinarypackage.py' |
402 | --- lib/lp/soyuz/browser/distroarchseriesbinarypackage.py 2009-09-03 15:17:24 +0000 |
403 | +++ lib/lp/soyuz/browser/distroarchseriesbinarypackage.py 2009-09-30 14:18:17 +0000 |
404 | @@ -4,7 +4,6 @@ |
405 | __metaclass__ = type |
406 | |
407 | __all__ = [ |
408 | - 'DistroArchSeriesBinaryPackageBreadcrumb', |
409 | 'DistroArchSeriesBinaryPackageNavigation', |
410 | 'DistroArchSeriesBinaryPackageView', |
411 | ] |
412 | @@ -16,14 +15,6 @@ |
413 | from canonical.lazr.utils import smartquote |
414 | |
415 | |
416 | -class DistroArchSeriesBinaryPackageBreadcrumb(Breadcrumb): |
417 | - """A breadcrumb for `DistroArchSeriesBinaryPackage`.""" |
418 | - |
419 | - @property |
420 | - def text(self): |
421 | - return self.context.name |
422 | - |
423 | - |
424 | class DistroArchSeriesBinaryPackageOverviewMenu(ApplicationMenu): |
425 | |
426 | usedfor = IDistroArchSeriesBinaryPackage |
427 | |
428 | === modified file 'lib/lp/soyuz/browser/tests/archivesubscription-views.txt' |
429 | --- lib/lp/soyuz/browser/tests/archivesubscription-views.txt 2009-08-13 19:03:36 +0000 |
430 | +++ lib/lp/soyuz/browser/tests/archivesubscription-views.txt 2009-09-30 14:18:17 +0000 |
431 | @@ -30,11 +30,16 @@ |
432 | >>> transaction.commit() |
433 | >>> logout() |
434 | |
435 | +The view includes a label property. |
436 | + |
437 | + >>> login('celso.providelo@canonical.com') |
438 | + >>> view = create_initialized_view(cprov.archive, name="+subscriptions") |
439 | + >>> print view.label |
440 | + Manage access to PPA for Celso Providelo |
441 | + |
442 | Initially the view does not display any subscribers, as can be seen |
443 | using the has_subscriptions property: |
444 | |
445 | - >>> login('celso.providelo@canonical.com') |
446 | - >>> view = create_initialized_view(cprov.archive, name="+subscriptions") |
447 | >>> view.has_subscriptions |
448 | False |
449 | |
450 | @@ -166,8 +171,8 @@ |
451 | |
452 | == ArchiveSubscriptionEditView == |
453 | |
454 | -The ArchiveSubscriptionEditView presents the expiry and description ready |
455 | -for editing, together with Update and Cancel actions: |
456 | +The ArchiveSubsriptionEditView includes a view label for the views main |
457 | +title. |
458 | |
459 | >>> login('celso.providelo@canonical.com') |
460 | >>> from lp.soyuz.interfaces.archivesubscriber import ( |
461 | @@ -175,12 +180,18 @@ |
462 | >>> spiv_subscription = getUtility(IArchiveSubscriberSet).getByArchive( |
463 | ... cprov.archive).one() |
464 | >>> view = create_initialized_view(spiv_subscription, name="+edit") |
465 | + >>> print view.label |
466 | + Edit Andrew Bennetts's access to PPA for Celso Providelo |
467 | + |
468 | +The ArchiveSubscriptionEditView presents the expiry and description ready |
469 | +for editing, together with Update and Cancel actions: |
470 | + |
471 | >>> view.field_names |
472 | ['date_expires', 'description'] |
473 | >>> for action in view.actions: |
474 | ... print action.label |
475 | Save |
476 | - Cancel access |
477 | + Revoke access |
478 | |
479 | The ArchiveSubscriptionEditView has a next_url helper property. |
480 | |
481 | @@ -241,7 +252,7 @@ |
482 | |
483 | >>> for notification in view.request.notifications: |
484 | ... print notification.message |
485 | - You have cancelled Andrew Bennetts's subscription to PPA for |
486 | + You have revoked Andrew Bennetts's access to PPA for |
487 | Celso Providelo. |
488 | |
489 | Just uncancel the subscription before continuing on. |
490 | @@ -306,13 +317,18 @@ |
491 | This view displays a single subscription of a person, as well as the |
492 | corresponding token information. |
493 | |
494 | -Initially the subscription does not have an active token: |
495 | +The view includes a label to denifen its main heading. |
496 | |
497 | >>> from lp.soyuz.browser.archivesubscription import ( |
498 | ... PersonalArchiveSubscription) |
499 | >>> spiv_subscription = PersonalArchiveSubscription( |
500 | ... spiv_subscription.subscriber, spiv_subscription.archive) |
501 | >>> view = create_initialized_view(spiv_subscription, name="+index") |
502 | + >>> print view.label |
503 | + Access to PPA for Celso Providelo |
504 | + |
505 | +Initially the subscription does not have an active token: |
506 | + |
507 | >>> print view.active_token |
508 | None |
509 | |
510 | |
511 | === modified file 'lib/lp/soyuz/browser/tests/test_breadcrumbs.py' |
512 | --- lib/lp/soyuz/browser/tests/test_breadcrumbs.py 2009-09-02 16:32:06 +0000 |
513 | +++ lib/lp/soyuz/browser/tests/test_breadcrumbs.py 2009-09-30 14:18:17 +0000 |
514 | @@ -11,6 +11,8 @@ |
515 | from canonical.launchpad.webapp.tests.breadcrumbs import ( |
516 | BaseBreadcrumbTestCase) |
517 | from lp.registry.interfaces.distribution import IDistributionSet |
518 | +from lp.soyuz.browser.archivesubscription import PersonalArchiveSubscription |
519 | +from lp.testing import login, login_person |
520 | |
521 | |
522 | class TestDistroArchSeriesBreadcrumb(BaseBreadcrumbTestCase): |
523 | @@ -55,5 +57,37 @@ |
524 | self.assertEquals(texts[-1], "0.1-1") |
525 | |
526 | |
527 | +class TestArchiveSubscriptionBreadcrumb(BaseBreadcrumbTestCase): |
528 | + |
529 | + def setUp(self): |
530 | + super(TestArchiveSubscriptionBreadcrumb, self).setUp() |
531 | + |
532 | + # Create a private ppa |
533 | + self.ppa = self.factory.makeArchive() |
534 | + login('foo.bar@canonical.com') |
535 | + self.ppa.private = True |
536 | + self.ppa.buildd_secret = 'secret' |
537 | + |
538 | + owner = self.ppa.owner |
539 | + login_person(owner) |
540 | + self.ppa_subscription = self.ppa.newSubscription(owner, owner) |
541 | + self.ppa_token = self.ppa.newAuthToken(owner) |
542 | + self.personal_archive_subscription = PersonalArchiveSubscription( |
543 | + owner, self.ppa) |
544 | + |
545 | + def test_personal_archive_subscription(self): |
546 | + self.traversed_objects = [ |
547 | + self.root, self.ppa.owner, self.personal_archive_subscription] |
548 | + subscription_url = canonical_url(self.personal_archive_subscription) |
549 | + |
550 | + urls = self._getBreadcrumbsURLs( |
551 | + subscription_url, self.traversed_objects) |
552 | + texts = self._getBreadcrumbsTexts( |
553 | + subscription_url, self.traversed_objects) |
554 | + |
555 | + self.assertEquals(subscription_url, urls[-1]) |
556 | + self.assertEquals( |
557 | + "Access to %s" % self.ppa.displayname, texts[-1]) |
558 | + |
559 | def test_suite(): |
560 | return unittest.TestLoader().loadTestsFromName(__name__) |
561 | |
562 | === modified file 'lib/lp/soyuz/configure.zcml' |
563 | --- lib/lp/soyuz/configure.zcml 2009-09-04 18:18:39 +0000 |
564 | +++ lib/lp/soyuz/configure.zcml 2009-09-30 14:18:17 +0000 |
565 | @@ -582,7 +582,7 @@ |
566 | <adapter |
567 | for="lp.soyuz.interfaces.distroarchseriesbinarypackage.IDistroArchSeriesBinaryPackage" |
568 | provides="canonical.launchpad.webapp.interfaces.IBreadcrumb" |
569 | - factory="lp.soyuz.browser.distroarchseriesbinarypackage.DistroArchSeriesBinaryPackageBreadcrumb" |
570 | + factory="canonical.launchpad.webapp.breadcrumb.NameBreadcrumb" |
571 | permission="zope.Public" /> |
572 | |
573 | <!-- PublishedPackage --> |
574 | @@ -647,6 +647,11 @@ |
575 | for="lp.soyuz.interfaces.archivesubscriber.IArchiveSubscriber" |
576 | provides="lp.soyuz.browser.archivesubscription.IArchiveSubscriberUI" |
577 | factory="lp.soyuz.browser.archivesubscription.archive_subscription_ui_adapter"/> |
578 | + <adapter |
579 | + provides="canonical.launchpad.webapp.interfaces.IBreadcrumb" |
580 | + for="lp.soyuz.interfaces.archivesubscriber.IPersonalArchiveSubscription" |
581 | + factory="canonical.launchpad.webapp.breadcrumb.DisplaynameBreadcrumb" |
582 | + permission="zope.Public"/> |
583 | <subscriber |
584 | for="lp.soyuz.interfaces.archivesubscriber.IArchiveSubscriber |
585 | lazr.lifecycle.interfaces.IObjectCreatedEvent" |
586 | |
587 | === modified file 'lib/lp/soyuz/interfaces/archivesubscriber.py' |
588 | --- lib/lp/soyuz/interfaces/archivesubscriber.py 2009-07-17 00:26:05 +0000 |
589 | +++ lib/lp/soyuz/interfaces/archivesubscriber.py 2009-09-30 14:18:17 +0000 |
590 | @@ -185,3 +185,6 @@ |
591 | |
592 | displayname = TextLine(title=_("Subscription displayname"), |
593 | required=False) |
594 | + |
595 | + title = TextLine(title=_("Subscription title"), |
596 | + required=False) |
597 | |
598 | === modified file 'lib/lp/soyuz/stories/ppa/xx-private-ppa-subscription-stories.txt' |
599 | --- lib/lp/soyuz/stories/ppa/xx-private-ppa-subscription-stories.txt 2009-08-13 19:03:36 +0000 |
600 | +++ lib/lp/soyuz/stories/ppa/xx-private-ppa-subscription-stories.txt 2009-09-30 14:18:17 +0000 |
601 | @@ -176,7 +176,7 @@ |
602 | |
603 | >>> for msg in get_feedback_messages(cprov_browser.contents): |
604 | ... print msg |
605 | - You have cancelled Launchpad Developers's subscription to PPA |
606 | + You have revoked Launchpad Developers's access to PPA |
607 | for Celso Providelo. |
608 | |
609 | |
610 | @@ -242,10 +242,10 @@ |
611 | >>> regeneration_info = find_tag_by_id( |
612 | ... joe_browser.contents, 'regenerate_token') |
613 | >>> print(extract_text(regeneration_info)) |
614 | - Password security |
615 | + Reset password |
616 | If you believe... |
617 | + Reset password |
618 | Note: after ... |
619 | - Generate new password |
620 | |
621 | When Joe clicks on the 'Generate new personal subscription' link then |
622 | the page is redisplayed with new sources.list entries and a notification. |
623 | |
624 | === modified file 'lib/lp/soyuz/stories/ppa/xx-private-ppa-subscriptions.txt' |
625 | --- lib/lp/soyuz/stories/ppa/xx-private-ppa-subscriptions.txt 2009-08-13 19:03:36 +0000 |
626 | +++ lib/lp/soyuz/stories/ppa/xx-private-ppa-subscriptions.txt 2009-09-30 14:18:17 +0000 |
627 | @@ -54,6 +54,7 @@ |
628 | ... |
629 | http://launchpad.dev/+icing/.../build/lp/calendar.js |
630 | http://launchpad.dev/+icing/.../yui_2.7.0b/build/calendar/assets/skins/sam/calendar.css |
631 | + ... |
632 | |
633 | Initially there are no subscriptions for a newly privatized PPA (although, |
634 | this may need to change, to add the owner/team). A heading is displayed |
635 | |
636 | === modified file 'lib/lp/soyuz/templates/archive-subscriber-edit.pt' |
637 | --- lib/lp/soyuz/templates/archive-subscriber-edit.pt 2009-08-05 10:02:22 +0000 |
638 | +++ lib/lp/soyuz/templates/archive-subscriber-edit.pt 2009-09-30 14:18:17 +0000 |
639 | @@ -12,12 +12,6 @@ |
640 | use-macro="context/@@launchpad_widget_macros/yui2calendar-dependencies" /> |
641 | </metal:block> |
642 | |
643 | - <div metal:fill-slot="heading"> |
644 | - <h1 tal:content="CONTEXTS/fmt:pagetitle"> |
645 | - Edit access for Joe Smith |
646 | - </h1> |
647 | - </div> |
648 | - |
649 | <div metal:fill-slot="main"> |
650 | <div class="top-portlet"> |
651 | <p>You can update the expiry or description for the granted access, |
652 | |
653 | === modified file 'lib/lp/soyuz/templates/archive-subscribers.pt' |
654 | --- lib/lp/soyuz/templates/archive-subscribers.pt 2009-08-05 10:02:22 +0000 |
655 | +++ lib/lp/soyuz/templates/archive-subscribers.pt 2009-09-30 14:18:17 +0000 |
656 | @@ -10,24 +10,26 @@ |
657 | <metal:block fill-slot="head_epilogue"> |
658 | <metal:yui-dependencies |
659 | use-macro="context/@@launchpad_widget_macros/yui2calendar-dependencies" /> |
660 | + |
661 | + <tal:devmode condition="devmode"> |
662 | + <script type="text/javascript" |
663 | + tal:attributes="src string:${lp_js}/soyuz/archivesubscribers_index.js"></script> |
664 | + </tal:devmode> |
665 | </metal:block> |
666 | |
667 | - <div metal:fill-slot="heading"> |
668 | - <h1 tal:content="CONTEXTS/fmt:pagetitle"> |
669 | - Manage access to Blah PPA |
670 | - </h1> |
671 | - </div> |
672 | <div metal:fill-slot="main"> |
673 | <div class="top-portlet"> |
674 | <p>You can grant access to people or teams to install software |
675 | from your PPA. |
676 | </p> |
677 | |
678 | - <div class="subscribers"> |
679 | - <p tal:condition="not: view/has_subscriptions" id="no-subscribers"> |
680 | - No one has access to install software from this PPA. |
681 | - </p> |
682 | - |
683 | + <p tal:condition="not: view/has_subscriptions" id="no-subscribers"> |
684 | + No one has access to install software from this PPA. |
685 | + </p> |
686 | + |
687 | + <div id="add-subscriber-placeholder"></div> |
688 | + |
689 | + <div id="subscribers"> |
690 | <p class="error message" tal:condition="view/errors" |
691 | tal:content="view/error_count" /> |
692 | |
693 | @@ -44,13 +46,13 @@ |
694 | id="archive-subscribers" class="listing"> |
695 | <thead> |
696 | <tr class="archive_subscriber_row"> |
697 | - <th>Name</th> |
698 | + <th style="width:30%">Name</th> |
699 | <th>Expires</th> |
700 | <th colspan="2">Comment</th> |
701 | </tr> |
702 | </thead> |
703 | <tbody> |
704 | - <tr> |
705 | + <tr class="add-subscriber" style="background-color:#eeeeff;"> |
706 | <tal:single-row-form define="widgets widgets|view/widgets" |
707 | repeat="widget widgets"> |
708 | |
709 | @@ -95,8 +97,12 @@ |
710 | </table> |
711 | </form> |
712 | </div><!-- class="portlet" --> |
713 | + <script type="text/javascript" id="setup-archivesubscribers-index"> |
714 | + YUI().use('soyuz.archivesubscribers_index', function(Y) { |
715 | + Y.soyuz.setup_archivesubscribers_index(); |
716 | + }); |
717 | + </script> |
718 | </div> |
719 | - |
720 | </div> |
721 | </body> |
722 | </html> |
723 | |
724 | === modified file 'lib/lp/soyuz/templates/person-archive-subscription.pt' |
725 | --- lib/lp/soyuz/templates/person-archive-subscription.pt 2009-08-05 10:02:22 +0000 |
726 | +++ lib/lp/soyuz/templates/person-archive-subscription.pt 2009-09-30 14:18:17 +0000 |
727 | @@ -8,12 +8,6 @@ |
728 | > |
729 | <body> |
730 | |
731 | - <div metal:fill-slot="heading"> |
732 | - <h1 tal:content="CONTEXTS/fmt:pagetitle"> |
733 | - Access to Joe Smith's private archive |
734 | - </h1> |
735 | - </div> |
736 | - |
737 | <div metal:fill-slot="main"> |
738 | |
739 | <tal:activate condition="not: view/active_token"> |
740 | @@ -54,22 +48,23 @@ |
741 | </div> <!-- signing-key --> |
742 | </div> |
743 | <div id="regenerate_token" class="portlet" style="clear:both"> |
744 | - <h2>Password security</h2> |
745 | + <h2>Reset password</h2> |
746 | <p>If you believe the security of your password for this access |
747 | - has been compromised, you can generate a new one. After you've |
748 | + has been compromised, you reset your password. After you've |
749 | requested a new password, you'll see new "sources.list" entries |
750 | on this page. You'll need to update them on your computer. |
751 | </p> |
752 | - <p>Note: after requesting a new password for your personal |
753 | - access — and updating your sources.list with the new |
754 | - entries — you may need to wait for up to ten minutes before |
755 | - you can download using the new password. |
756 | - </p> |
757 | <form action="" method="post"> |
758 | <button type="submit" name="regenerate" value="1"> |
759 | - Generate new password |
760 | + Reset password |
761 | </button> |
762 | </form> |
763 | + <p class="discreet"> |
764 | + Note: after resetting the password for your personal |
765 | + access — and updating your sources.list with the new |
766 | + entries — you may need to wait for up to ten minutes before |
767 | + you can download using the new password. |
768 | + </p> |
769 | </div> |
770 | </tal:active> |
771 | </div> |
772 | |
773 | === modified file 'lib/lp/soyuz/templates/person-archive-subscriptions.pt' |
774 | --- lib/lp/soyuz/templates/person-archive-subscriptions.pt 2009-08-05 10:02:22 +0000 |
775 | +++ lib/lp/soyuz/templates/person-archive-subscriptions.pt 2009-09-30 14:18:17 +0000 |
776 | @@ -7,24 +7,20 @@ |
777 | i18n:domain="launchpad" |
778 | > |
779 | <body> |
780 | - <div metal:fill-slot="heading"> |
781 | - <h1 tal:content="CONTEXTS/fmt:pagetitle"> |
782 | - Private PPA access |
783 | - </h1> |
784 | - </div> |
785 | |
786 | <div metal:fill-slot="main"> |
787 | <div class="top-portlet"> |
788 | <tal:has_subscriptions condition="view/subscriptions_with_tokens"> |
789 | <div id="current_subscriptions"> |
790 | - <p>Here's a list of all the private archives to which you have |
791 | - been granted access. |
792 | + <p>All the private archives to which you have |
793 | + been granted access are listed below. |
794 | </p> |
795 | <table summary="CONTEXTS/fmt:pagetitle" id="archive-subscriptions" |
796 | - class="listing"> |
797 | + class="listing" style="width:70%"> |
798 | <thead> |
799 | <tr class="archive-subscription-row"> |
800 | <th>Archive</th> |
801 | + <th></th> |
802 | </tr> |
803 | </thead> |
804 | <tbody> |
805 | |
806 | === added directory 'lib/lp/soyuz/windmill' |
807 | === added file 'lib/lp/soyuz/windmill/__init__.py' |
808 | === added file 'lib/lp/soyuz/windmill/testing.py' |
809 | --- lib/lp/soyuz/windmill/testing.py 1970-01-01 00:00:00 +0000 |
810 | +++ lib/lp/soyuz/windmill/testing.py 2009-09-30 14:18:17 +0000 |
811 | @@ -0,0 +1,18 @@ |
812 | +# Copyright 2009 Canonical Ltd. This software is licensed under the |
813 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
814 | + |
815 | +"""Soyuz-specific testing infrastructure for Windmill.""" |
816 | + |
817 | +__metaclass__ = type |
818 | +__all__ = [ |
819 | + 'SoyuzWindmillLayer', |
820 | + ] |
821 | + |
822 | + |
823 | +from canonical.testing.layers import BaseWindmillLayer |
824 | + |
825 | + |
826 | +class SoyuzWindmillLayer(BaseWindmillLayer): |
827 | + """Layer for Soyuz Windmill tests.""" |
828 | + |
829 | + base_url = 'http://launchpad.dev:8085/' |
830 | |
831 | === added directory 'lib/lp/soyuz/windmill/tests' |
832 | === added file 'lib/lp/soyuz/windmill/tests/__init__.py' |
833 | === added file 'lib/lp/soyuz/windmill/tests/test_archivesubscribersindex.py' |
834 | --- lib/lp/soyuz/windmill/tests/test_archivesubscribersindex.py 1970-01-01 00:00:00 +0000 |
835 | +++ lib/lp/soyuz/windmill/tests/test_archivesubscribersindex.py 2009-09-30 14:18:17 +0000 |
836 | @@ -0,0 +1,96 @@ |
837 | +# Copyright 2009 Canonical Ltd. This software is licensed under the |
838 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
839 | + |
840 | +"""Test for the archive subscribers index page..""" |
841 | + |
842 | +__metaclass__ = type |
843 | +__all__ = [] |
844 | + |
845 | +import transaction |
846 | +import unittest |
847 | + |
848 | +from windmill.authoring import WindmillTestClient |
849 | + |
850 | +from zope.component import getUtility |
851 | + |
852 | +from canonical.launchpad.ftests import login, logout |
853 | +from canonical.launchpad.windmill.testing.lpuser import LaunchpadUser |
854 | +from lp.registry.interfaces.distribution import IDistributionSet |
855 | +from lp.soyuz.windmill.testing import SoyuzWindmillLayer |
856 | +from lp.testing import TestCaseWithFactory |
857 | + |
858 | +WAIT_PAGELOAD = u'30000' |
859 | +WAIT_ELEMENT_COMPLETE = u'30000' |
860 | +WAIT_CHECK_CHANGE = u'1000' |
861 | +ADD_ACCESS_LINK = u'//a[@class="js-action sprite add"]' |
862 | +CHOOSE_SUBSCRIBER_LINK = u'//a[@id="show-widget-field-subscriber"]' |
863 | +SUBSCRIBER_SEARCH_FIELD = ( |
864 | + u'//div[@id="yui-pretty-overlay-modal"]//input[@name="search"]') |
865 | +SUBSCRIBER_SEARCH_BUTTON = u'//div[@id="yui-pretty-overlay-modal"]//button' |
866 | +FIRST_SUBSCRIBER_RESULT = ( |
867 | + u'//div[@id="yui-pretty-overlay-modal"]' |
868 | + '//span[@class="yui-picker-result-title"]') |
869 | + |
870 | + |
871 | +class TestArchiveSubscribersIndex(TestCaseWithFactory): |
872 | + |
873 | + layer = SoyuzWindmillLayer |
874 | + |
875 | + def setUp(self): |
876 | + """Create a private PPA.""" |
877 | + super(TestArchiveSubscribersIndex, self).setUp() |
878 | + |
879 | + user = self.factory.makePerson( |
880 | + name='joe-bloggs', email='joe@example.com', password='joe', |
881 | + displayname='Joe Bloggs') |
882 | + ubuntu = getUtility(IDistributionSet)['ubuntu'] |
883 | + self.ppa = self.factory.makeArchive( |
884 | + owner=user, name='myppa', distribution=ubuntu) |
885 | + |
886 | + login('foo.bar@canonical.com') |
887 | + self.ppa.private = True |
888 | + self.ppa.buildd_secret = 'secret' |
889 | + logout() |
890 | + transaction.commit() |
891 | + |
892 | + self.lpuser = LaunchpadUser( |
893 | + 'Joe Bloggs', 'joe@example.com', 'joe') |
894 | + |
895 | + def test_add_subscriber(self): |
896 | + """Test adding a private PPA subscriber..""" |
897 | + client = WindmillTestClient('Adding private PPA subscribers.') |
898 | + |
899 | + self.lpuser.ensure_login(client) |
900 | + |
901 | + client.open(url='http://launchpad.dev:8085/~joe-bloggs/' |
902 | + '+archive/myppa/+subscriptions') |
903 | + client.waits.forPageLoad(timeout=WAIT_PAGELOAD) |
904 | + |
905 | + # Click on the JS add access action. |
906 | + client.waits.forElement(xpath=ADD_ACCESS_LINK) |
907 | + client.click(xpath=ADD_ACCESS_LINK) |
908 | + |
909 | + # Open the picker, search for 'launchpad' and choose the first |
910 | + # result |
911 | + client.click(xpath=CHOOSE_SUBSCRIBER_LINK) |
912 | + client.type(xpath=SUBSCRIBER_SEARCH_FIELD, text='launchpad') |
913 | + client.click(xpath=SUBSCRIBER_SEARCH_BUTTON) |
914 | + |
915 | + client.waits.forElement(xpath=FIRST_SUBSCRIBER_RESULT) |
916 | + client.click(xpath=FIRST_SUBSCRIBER_RESULT) |
917 | + |
918 | + # Add the new subscriber. |
919 | + client.click(id='field.actions.add') |
920 | + client.waits.forPageLoad(timeout=WAIT_PAGELOAD) |
921 | + |
922 | + # And verify that the correct informational message is displayed. |
923 | + # It would be nice if we could use ... here. |
924 | + client.asserts.assertText( |
925 | + xpath=u'//div[@class="informational message"]', |
926 | + validator='You have granted access for Launchpad Developers ' |
927 | + 'to install software from PPA named myppa for Joe ' |
928 | + 'Bloggs. Members of Launchpad Developers will be ' |
929 | + 'notified of the access via email.') |
930 | + |
931 | +def test_suite(): |
932 | + return unittest.TestLoader().loadTestsFromName(__name__) |
= Summary =
This branch deals with a number of UI issues related to private PPA
subscriptions. Please refer tot bug 409187 for the details.
== Proposed fix ==
== Pre-implementation notes ==
All before-after screenshots and notes are on bug 409187, as well as a
screencast of the new interaction.
== Implementation details ==
I have not added a windmill test for the new interaction yet, but will
do soon. If I need to do it now I will, but otherwise I'll focus on
blueprint templates for the rest of today.
== Tests ==
bin/test -vv -t archivesubscrip tion-views. txt -t criptionBreadcr umb -t stories/ppa
TestArchiveSubs
== Demo and Q/A ==
For screenshots/casts, see bug 409187.
To demo locally, run the following in a harness:
ppa = getUtility( IPersonSet) .getByName( 'cprov' ).archive transaction. commit( )
ppa.private = True
ppa.buildd_secret = 'blah'
import transaction;
and then navigate to: /launchpad. dev/~cprov/ +archive/ ppa
https:/
Click on 'Manage access', add yourself (Celso) and others. Try editing.
Next go to: /launchpad. dev/~cprov and click on 'View your private ppa
https:/
subscriptions'. Click on the subscription listed there etc.
For QA, the soyuz-team ppa can be used.
= Launchpad lint =
Checking for conflicts. and issues in doctests and templates.
Running jslint, xmllint, pyflakes, and pylint.
Using normal rules.
Linting changed files: soyuz/templates /person- archive- subscriptions. pt soyuz/templates /archive- subscribers. pt /launchpad/ pagetitles. py soyuz/templates /person- archive- subscription. pt soyuz/browser/ tests/test_ breadcrumbs. py soyuz/browser/ tests/archivesu bscription- views.txt soyuz/interface s/archivesubscr iber.py soyuz/configure .zcml soyuz/stories/ ppa/xx- private- ppa-subscriptio n-stories. txt /launchpad/ icing/style- 3-0.css soyuz/browser/ archivesubscrip tion.py soyuz/browser/ configure. zcml soyuz/templates /archive- subscriber- edit.pt
lib/lp/
lib/lp/
lib/canonical
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/canonical
lib/lp/
lib/lp/
lib/lp/
== Pylint notices ==
lib/lp/ soyuz/interface s/archivesubscr iber.py declarations' (No module fields' (No module named
20: [F0401] Unable to import 'lazr.enum' (No module named enum)
26: [F0401] Unable to import 'lazr.restful.
named restful)
27: [F0401] Unable to import 'lazr.restful.
restful)
--
Michael