Merge lp:~barry/launchpad/430068-person into lp:launchpad
- 430068-person
- Merge into devel
Status: | Merged |
---|---|
Merged at revision: | not available |
Proposed branch: | lp:~barry/launchpad/430068-person |
Merge into: | lp:launchpad |
Diff against target: | None lines |
To merge this branch: | bzr merge lp:~barry/launchpad/430068-person |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Curtis Hovey (community) | code and ui | Approve | |
Review via email:
|
Commit message
Description of the change
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Barry Warsaw (barry) wrote : | # |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Curtis Hovey (sinzui) wrote : | # |
Thanks for doing the extra clean up. This branch is fine to land as is.
> === modified file 'lib/lp/
> --- lib/lp/
> +++ lib/lp/
...
> +Code of Conduct registration problems
> +======
> +
> +Sample Person tries unsuccessfully to register a truncated code of conduct.
> +
> + >>> truncated_coc = read_file(
> + >>> browser.open('http://
> + >>> browser.
> + >>> browser.
> + >>> print_errors(
> + There is 1 error.
> + The signed text does not match the Code of Conduct. Make sure that you
> + signed the correct text (white space differences are acceptable).
> +
> +Sample Person tries unsuccessfully to register an old version of the code.
> +
> + >>> coc_version_1_0 = read_file(
> + >>> browser.
> + >>> browser.
> + >>> print_errors(
> + There is 1 error.
> + The signed text does not match the Code of Conduct. Make sure that you
> + signed the correct text (white space differences are acceptable).
These two tests should be view tests, but I think we can do that when we
add support for launchpad and U1 hacking.
...
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Barry Warsaw (barry) wrote : | # |
On Sep 16, 2009, at 03:47 PM, Curtis Hovey wrote:
>Review: Approve code and ui
>Thanks for doing the extra clean up. This branch is fine to land as is.
Thanks!
>> +Code of Conduct registration problems
>> +======
>> +
>> +Sample Person tries unsuccessfully to register a truncated code of conduct.
>> +
>> + >>> truncated_coc = read_file(
>> + >>> browser.open('http://
>> + >>> browser.
>> + >>> browser.
>> + >>> print_errors(
>> + There is 1 error.
>> + The signed text does not match the Code of Conduct. Make sure that you
>> + signed the correct text (white space differences are acceptable).
>> +
>> +Sample Person tries unsuccessfully to register an old version of the code.
>> +
>> + >>> coc_version_1_0 = read_file(
>> + >>> browser.
>> + >>> browser.
>> + >>> print_errors(
>> + There is 1 error.
>> + The signed text does not match the Code of Conduct. Make sure that you
>> + signed the correct text (white space differences are acceptable).
>
>These two tests should be view tests, but I think we can do that when we
>add support for launchpad and U1 hacking.
Agreed.
-Barry
Preview Diff
1 | === modified file 'lib/canonical/launchpad/pagetitles.py' |
2 | --- lib/canonical/launchpad/pagetitles.py 2009-09-15 10:05:14 +0000 |
3 | +++ lib/canonical/launchpad/pagetitles.py 2009-09-15 23:18:27 +0000 |
4 | @@ -314,8 +314,6 @@ |
5 | |
6 | codeofconduct_admin = 'Administer Codes of Conduct' |
7 | |
8 | -codeofconduct_index = ContextTitle('%s') |
9 | - |
10 | codeofconduct_list = 'Ubuntu Codes of Conduct' |
11 | |
12 | def contact_user(context, view): |
13 | @@ -704,8 +702,6 @@ |
14 | |
15 | person_packagebugs_search = person_packagebugs |
16 | |
17 | -person_participation = ContextTitle("Team participation by %s") |
18 | - |
19 | person_review = ContextDisplayName("Review %s") |
20 | |
21 | person_specfeedback = ContextDisplayName('Feature feedback requests for %s') |
22 | @@ -715,8 +711,6 @@ |
23 | person_translations_to_review = ContextDisplayName( |
24 | 'Translations for review by %s') |
25 | |
26 | -person_teamhierarchy = ContextDisplayName('Team hierarchy for %s') |
27 | - |
28 | pofile_index = ContextTitle(smartquote('Translation overview for "%s"')) |
29 | |
30 | def pofile_translate(context, view): |
31 | |
32 | === modified file 'lib/lp/registry/browser/codeofconduct.py' |
33 | --- lib/lp/registry/browser/codeofconduct.py 2009-08-18 17:15:10 +0000 |
34 | +++ lib/lp/registry/browser/codeofconduct.py 2009-09-15 20:20:20 +0000 |
35 | @@ -110,12 +110,14 @@ |
36 | return Link('../', text, icon='info') |
37 | |
38 | |
39 | -class CodeOfConductView: |
40 | +class CodeOfConductView(LaunchpadView): |
41 | """Simple view class for CoC page.""" |
42 | |
43 | - def __init__(self, context, request): |
44 | - self.context = context |
45 | - self.request = request |
46 | + @property |
47 | + def page_title(self): |
48 | + """See `LaunchpadView`.""" |
49 | + # This page has no breadcrumbs, nor should it. |
50 | + return self.context.title |
51 | |
52 | |
53 | class CodeOfConductDownloadView: |
54 | |
55 | === modified file 'lib/lp/registry/browser/configure.zcml' |
56 | --- lib/lp/registry/browser/configure.zcml 2009-09-15 16:26:15 +0000 |
57 | +++ lib/lp/registry/browser/configure.zcml 2009-09-15 22:55:30 +0000 |
58 | @@ -848,14 +848,18 @@ |
59 | name="+karma" |
60 | template="../templates/person-karma.pt"/> |
61 | </browser:pages> |
62 | + <browser:page |
63 | + for="lp.registry.interfaces.person.IPerson" |
64 | + permission="zope.Public" |
65 | + name="+participation" |
66 | + class="lp.registry.browser.person.PersonParticipationView" |
67 | + template="../templates/person-participation.pt" |
68 | + /> |
69 | <browser:pages |
70 | for="lp.registry.interfaces.person.IPerson" |
71 | permission="zope.Public" |
72 | class="lp.registry.browser.person.PersonView"> |
73 | <browser:page |
74 | - name="+participation" |
75 | - template="../templates/person-participation.pt"/> |
76 | - <browser:page |
77 | name="+sshkeys" |
78 | attribute="showSSHKeys"/> |
79 | <browser:page |
80 | @@ -1032,7 +1036,7 @@ |
81 | <browser:page |
82 | for="lp.registry.interfaces.person.IPerson" |
83 | permission="zope.Public" |
84 | - class="lp.registry.browser.person.PersonView" |
85 | + class="lp.registry.browser.team.TeamHierarchyView" |
86 | name="+teamhierarchy" |
87 | template="../templates/person-teamhierarchy.pt"/> |
88 | <browser:page |
89 | |
90 | === modified file 'lib/lp/registry/browser/person.py' |
91 | --- lib/lp/registry/browser/person.py 2009-09-15 19:28:54 +0000 |
92 | +++ lib/lp/registry/browser/person.py 2009-09-15 21:19:06 +0000 |
93 | @@ -6,8 +6,6 @@ |
94 | """Person-related view classes.""" |
95 | |
96 | __metaclass__ = type |
97 | - |
98 | - |
99 | __all__ = [ |
100 | 'BeginTeamClaimView', |
101 | 'BugSubscriberPackageBugsSearchListingView', |
102 | @@ -86,6 +84,7 @@ |
103 | 'archive_to_person', |
104 | ] |
105 | |
106 | + |
107 | import cgi |
108 | import copy |
109 | import itertools |
110 | @@ -239,6 +238,8 @@ |
111 | from lp.answers.interfaces.questioncollection import IQuestionSet |
112 | from lp.answers.interfaces.questionsperson import IQuestionsPerson |
113 | |
114 | +COMMASPACE = ', ' |
115 | + |
116 | |
117 | class RestrictedMembershipsPersonView(LaunchpadView): |
118 | """Secure access to team membership information for a person. |
119 | @@ -2831,17 +2832,6 @@ |
120 | assert self.user is not None |
121 | return self.user.findPathToTeam(self.context) |
122 | |
123 | - def indirect_teams_via(self): |
124 | - """Return a list of dictionaries, where each dictionary has a team |
125 | - in which the person is an indirect member, and a path to membership |
126 | - in that team. |
127 | - """ |
128 | - return [{'team': team, |
129 | - 'via': ', '.join( |
130 | - [viateam.displayname for viateam in |
131 | - self.context.findPathToTeam(team)[:-1]])} |
132 | - for team in self.context.teams_indirectly_participated_in] |
133 | - |
134 | def userIsParticipant(self): |
135 | """Return true if the user is a participant of this team. |
136 | |
137 | @@ -2975,6 +2965,31 @@ |
138 | return False |
139 | |
140 | |
141 | +class PersonParticipationView(LaunchpadView): |
142 | + """View for the ~person/+participation page.""" |
143 | + |
144 | + @property |
145 | + def label(self): |
146 | + return 'Team participation for ' + self.context.displayname |
147 | + |
148 | + @property |
149 | + def indirect_teams_via(self): |
150 | + """Information about indirect membership. |
151 | + |
152 | + :return: A list of dictionaries, where each dictionary has a team in |
153 | + which the person is an indirect member, and a path to membership in |
154 | + that team. |
155 | + :rtype: a list of dictionaries |
156 | + """ |
157 | + indirect_teams = [] |
158 | + for team in self.context.teams_indirectly_participated_in: |
159 | + via = COMMASPACE.join(viateam.displayname |
160 | + for viateam |
161 | + in self.context.findPathToTeam(team)[:-1]) |
162 | + indirect_teams.append(dict(team=team, via=via)) |
163 | + return indirect_teams |
164 | + |
165 | + |
166 | class EmailAddressVisibleState: |
167 | """The state of a person's email addresses w.r.t. the logged in user. |
168 | |
169 | @@ -3183,28 +3198,29 @@ |
170 | |
171 | |
172 | class PersonCodeOfConductEditView(LaunchpadView): |
173 | - |
174 | - def performCoCChanges(self): |
175 | - """Make changes to code-of-conduct signature records for this |
176 | - person. |
177 | - """ |
178 | + """View for the ~person/+codesofconduct pages.""" |
179 | + |
180 | + @property |
181 | + def label(self): |
182 | + """See `LaunchpadView`.""" |
183 | + return 'Codes of Conduct for ' + self.context.displayname |
184 | + |
185 | + def initialize(self): |
186 | + """See `LaunchpadView`.""" |
187 | + # Make changes to code-of-conduct signature records for this person. |
188 | sig_ids = self.request.form.get("DEACTIVATE_SIGNATURE") |
189 | |
190 | if sig_ids is not None: |
191 | sCoC_util = getUtility(ISignedCodeOfConductSet) |
192 | - |
193 | - # verify if we have multiple entries to deactive |
194 | + # Verify that we have multiple entries to deactive. |
195 | if not isinstance(sig_ids, list): |
196 | sig_ids = [sig_ids] |
197 | - |
198 | for sig_id in sig_ids: |
199 | sig_id = int(sig_id) |
200 | - # Deactivating signature |
201 | + # Deactivating signature. |
202 | comment = 'Deactivated by Owner' |
203 | sCoC_util.modifySignature(sig_id, self.user, comment, False) |
204 | |
205 | - return True |
206 | - |
207 | |
208 | class PersonEditWikiNamesView(LaunchpadView): |
209 | |
210 | |
211 | === modified file 'lib/lp/registry/browser/team.py' |
212 | --- lib/lp/registry/browser/team.py 2009-09-15 10:05:14 +0000 |
213 | +++ lib/lp/registry/browser/team.py 2009-09-15 22:55:30 +0000 |
214 | @@ -10,15 +10,17 @@ |
215 | 'TeamBrandingView', |
216 | 'TeamContactAddressView', |
217 | 'TeamEditView', |
218 | + 'TeamHierarchyView', |
219 | 'TeamMailingListConfigurationView', |
220 | 'TeamMailingListModerationView', |
221 | 'TeamMailingListSubscribersView', |
222 | + 'TeamMapData', |
223 | 'TeamMapView', |
224 | - 'TeamMapData', |
225 | 'TeamMemberAddView', |
226 | 'TeamPrivacyAdapter', |
227 | ] |
228 | |
229 | + |
230 | from urllib import quote |
231 | from datetime import datetime |
232 | import math |
233 | @@ -1106,3 +1108,31 @@ |
234 | 'content-type', 'application/xml;charset=utf-8') |
235 | body = LaunchpadView.render(self) |
236 | return body.encode('utf-8') |
237 | + |
238 | + |
239 | +class TeamHierarchyView(LaunchpadView): |
240 | + """View for ~team/+teamhierarchy page.""" |
241 | + |
242 | + @property |
243 | + def label(self): |
244 | + return 'Team relationships for ' + self.context.displayname |
245 | + |
246 | + @property |
247 | + def has_sub_teams(self): |
248 | + return self.context.sub_teams.count() > 0 |
249 | + |
250 | + @property |
251 | + def has_super_teams(self): |
252 | + return self.context.super_teams.count() > 0 |
253 | + |
254 | + @property |
255 | + def has_only_super_teams(self): |
256 | + return self.has_super_teams and not self.has_sub_teams |
257 | + |
258 | + @property |
259 | + def has_only_sub_teams(self): |
260 | + return not self.has_super_teams and self.has_sub_teams |
261 | + |
262 | + @property |
263 | + def has_relationships(self): |
264 | + return self.has_sub_teams or self.has_super_teams |
265 | |
266 | === added file 'lib/lp/registry/doc/team-hierarchy-views.txt' |
267 | --- lib/lp/registry/doc/team-hierarchy-views.txt 1970-01-01 00:00:00 +0000 |
268 | +++ lib/lp/registry/doc/team-hierarchy-views.txt 2009-09-15 22:55:30 +0000 |
269 | @@ -0,0 +1,100 @@ |
270 | +==================== |
271 | +Team hierarchy views |
272 | +==================== |
273 | + |
274 | +Team hierarchies are displayed via the ~team/+teamhierarchy page. By default, |
275 | +brand new teams have no relationships at all. |
276 | + |
277 | + >>> team = factory.makeTeam(displayname='Brand New Team') |
278 | + >>> view = create_initialized_view(team, '+teamhierarchy') |
279 | + >>> print view.label |
280 | + Team relationships for Brand New Team |
281 | + |
282 | + >>> view.has_relationships |
283 | + False |
284 | + >>> view.has_sub_teams |
285 | + False |
286 | + >>> view.has_super_teams |
287 | + False |
288 | + >>> view.has_only_sub_teams |
289 | + False |
290 | + >>> view.has_only_super_teams |
291 | + False |
292 | + |
293 | + |
294 | +Only sub-teams |
295 | +============== |
296 | + |
297 | +Guadamen is related to some other teams. |
298 | + |
299 | + >>> from lp.registry.interfaces.person import IPersonSet |
300 | + >>> person_set = getUtility(IPersonSet) |
301 | + |
302 | + >>> guadamen = person_set.getByName('guadamen') |
303 | + >>> view = create_initialized_view(guadamen, '+teamhierarchy') |
304 | + >>> print view.label |
305 | + Team relationships for GuadaMen |
306 | + >>> view.has_relationships |
307 | + True |
308 | + |
309 | +Guadamen has sub-teams... |
310 | + |
311 | + >>> view.has_sub_teams |
312 | + True |
313 | + |
314 | +...but no super teams. |
315 | + |
316 | + >>> view.has_super_teams |
317 | + False |
318 | + |
319 | +In other words, Guadamen has only sub-teams. |
320 | + |
321 | + >>> view.has_only_super_teams |
322 | + False |
323 | + |
324 | + >>> view.has_only_sub_teams |
325 | + True |
326 | + |
327 | + |
328 | +Only super-teams |
329 | +================ |
330 | + |
331 | +The Warty Gnome Team has only super-teams. |
332 | + |
333 | + >>> warty = person_set.getByName('warty-gnome') |
334 | + >>> view = create_initialized_view(warty, '+teamhierarchy') |
335 | + >>> print view.label |
336 | + Team relationships for Warty Gnome Team |
337 | + |
338 | + >>> view.has_super_teams |
339 | + True |
340 | + >>> view.has_sub_teams |
341 | + False |
342 | + >>> view.has_only_super_teams |
343 | + True |
344 | + >>> view.has_only_sub_teams |
345 | + False |
346 | + >>> view.has_relationships |
347 | + True |
348 | + |
349 | + |
350 | +Both super-teams and sub-teams |
351 | +============================== |
352 | + |
353 | +The Ubuntu Team has both sub-teams and super-teams. |
354 | + |
355 | + >>> ubuntu = person_set.getByName('ubuntu-team') |
356 | + >>> view = create_initialized_view(ubuntu, '+teamhierarchy') |
357 | + >>> print view.label |
358 | + Team relationships for Ubuntu Team |
359 | + |
360 | + >>> view.has_super_teams |
361 | + True |
362 | + >>> view.has_sub_teams |
363 | + True |
364 | + >>> view.has_only_super_teams |
365 | + False |
366 | + >>> view.has_only_sub_teams |
367 | + False |
368 | + >>> view.has_relationships |
369 | + True |
370 | |
371 | === added file 'lib/lp/registry/doc/xx-coc-views.txt' |
372 | --- lib/lp/registry/doc/xx-coc-views.txt 1970-01-01 00:00:00 +0000 |
373 | +++ lib/lp/registry/doc/xx-coc-views.txt 2009-09-15 20:20:20 +0000 |
374 | @@ -0,0 +1,12 @@ |
375 | +====================== |
376 | +Codes of conduct views |
377 | +====================== |
378 | + |
379 | +The PersonCodeOfConductEditView controls ~person/+codesofconduct. It displays |
380 | +the person's name in the page label. |
381 | + |
382 | + >>> login('admin@canonical.com') |
383 | + >>> geddy = factory.makePerson(displayname='Geddy Lee') |
384 | + >>> view = create_initialized_view(geddy, '+codesofconduct') |
385 | + >>> print view.label |
386 | + Codes of Conduct for Geddy Lee |
387 | |
388 | === modified file 'lib/lp/registry/stories/gpg-coc/02-signcoc.txt' |
389 | --- lib/lp/registry/stories/gpg-coc/02-signcoc.txt 2009-08-18 17:25:41 +0000 |
390 | +++ lib/lp/registry/stories/gpg-coc/02-signcoc.txt 2009-09-15 20:20:20 +0000 |
391 | @@ -1,72 +1,95 @@ |
392 | - First we check that Sample Person never signed a code of conduct. |
393 | - |
394 | - >>> browser.addHeader("Authorization", "Basic test@canonical.com:test") |
395 | - >>> browser.open("http://launchpad.dev/~name12/+codesofconduct") |
396 | - |
397 | - >>> "Sample Person has never signed" in browser.contents |
398 | - True |
399 | - |
400 | - |
401 | - First we define a helper function |
402 | - |
403 | - >>> import os.path |
404 | - >>> def filename_path(filename): |
405 | - ... return os.path.join(os.path.dirname(__file__), filename) |
406 | - ... |
407 | - |
408 | - Then we try to register a code of conduct with a truncated CoC: |
409 | - |
410 | - >>> filename = filename_path("truncated_coc.asc") |
411 | - >>> truncated_coc = open(filename).read() |
412 | - |
413 | - >>> browser.open("http://launchpad.dev/codeofconduct/1.0.1/+sign") |
414 | - >>> browser.getControl("Signed Code").value = truncated_coc |
415 | - >>> browser.getControl("Continue").click() |
416 | - |
417 | - >>> message = ( |
418 | - ... "The signed text does not match the Code of Conduct. Make sure that " |
419 | - ... "you signed the correct text (white space differences are acceptable") |
420 | - >>> message in browser.contents |
421 | - True |
422 | - |
423 | - We try to register an old version of the code (version 1.0) |
424 | - |
425 | - >>> filename = filename_path("10_coc.asc") |
426 | - >>> old_coc = open(filename).read() |
427 | - >>> browser.getControl("Signed Code").value = old_coc |
428 | - >>> browser.getControl("Continue").click() |
429 | - |
430 | - >>> message in browser.contents |
431 | - True |
432 | - |
433 | - If we try to access the old version page to sign it |
434 | - >>> browser.open("http://launchpad.dev/codeofconduct/1.0/+sign") |
435 | - |
436 | - We're presented with a link to the current code page |
437 | - >>> current_coc_link = browser.getLink("the current version") |
438 | - >>> current_coc_link.url |
439 | - 'http://launchpad.dev/codeofconduct/1.0.1' |
440 | - |
441 | - We navigate to the current Code page |
442 | - >>> current_coc_link.click() |
443 | - >>> browser.getLink("Sign it").click() |
444 | - >>> browser.url |
445 | - 'http://launchpad.dev/codeofconduct/1.0.1/+sign' |
446 | - |
447 | - |
448 | - Now we try to register the code of conduct, using an reformatted copy |
449 | - (leading spaces removed). |
450 | - |
451 | - >>> filename = filename_path("reformatted_101_coc.asc") |
452 | - >>> reformatted_coc = open(filename).read() |
453 | - >>> browser.getControl("Signed Code").value = reformatted_coc |
454 | - >>> browser.getControl("Continue").click() |
455 | - |
456 | - This succeeds because the words are the same and in the same order. |
457 | - |
458 | - >>> browser.url |
459 | - 'http://launchpad.dev/~name12/+codesofconduct' |
460 | - |
461 | - >>> browser.open("http://launchpad.dev/~name12/+codesofconduct") |
462 | - >>> "1024D/DFD20543" in browser.contents |
463 | - True |
464 | +========================= |
465 | +Signing a Code of Conduct |
466 | +========================= |
467 | + |
468 | +Sample person has never signed a code of conduct. |
469 | + |
470 | + >>> browser = setupBrowser(auth='Basic test@canonical.com:test') |
471 | + >>> browser.open('http://launchpad.dev/~name12/+codesofconduct') |
472 | + >>> print extract_text(find_main_content(browser.contents)) |
473 | + Codes of Conduct for Sample Person |
474 | + Sample Person +codesofconduct |
475 | + Launchpad records codes of conduct you sign as commitments to the |
476 | + principles of collaboration, tolerance and open communication that |
477 | + drive the open source community. |
478 | + Sample Person has never signed a code |
479 | + of conduct. |
480 | + See or sign new code of conduct releases |
481 | + |
482 | + # A helper function for reading a code-of-conduct file. |
483 | + >>> import os |
484 | + >>> def read_file(filename): |
485 | + ... path = os.path.join(os.path.dirname(__file__), filename) |
486 | + ... file_object = open(path) |
487 | + ... # Change this to a with-statement when we switch to Python 2.5. |
488 | + ... try: |
489 | + ... return file_object.read() |
490 | + ... finally: |
491 | + ... file_object.close() |
492 | + |
493 | + |
494 | +Code of Conduct registration problems |
495 | +===================================== |
496 | + |
497 | +Sample Person tries unsuccessfully to register a truncated code of conduct. |
498 | + |
499 | + >>> truncated_coc = read_file('truncated_coc.asc') |
500 | + >>> browser.open('http://launchpad.dev/codeofconduct/1.0.1/+sign') |
501 | + >>> browser.getControl('Signed Code').value = truncated_coc |
502 | + >>> browser.getControl('Continue').click() |
503 | + >>> print_errors(browser.contents) |
504 | + There is 1 error. |
505 | + The signed text does not match the Code of Conduct. Make sure that you |
506 | + signed the correct text (white space differences are acceptable). |
507 | + |
508 | +Sample Person tries unsuccessfully to register an old version of the code. |
509 | + |
510 | + >>> coc_version_1_0 = read_file('10_coc.asc') |
511 | + >>> browser.getControl('Signed Code').value = coc_version_1_0 |
512 | + >>> browser.getControl('Continue').click() |
513 | + >>> print_errors(browser.contents) |
514 | + There is 1 error. |
515 | + The signed text does not match the Code of Conduct. Make sure that you |
516 | + signed the correct text (white space differences are acceptable). |
517 | + |
518 | + |
519 | +Sample Person tries to access the old version page to sign it, and is informed |
520 | +that there is a new version available. |
521 | + |
522 | + >>> browser.open('http://launchpad.dev/codeofconduct/1.0/+sign') |
523 | + >>> browser.getLink('the current version').click() |
524 | + >>> print browser.url |
525 | + http://launchpad.dev/codeofconduct/1.0.1 |
526 | + |
527 | + >>> browser.getLink('Sign it').click() |
528 | + >>> print browser.url |
529 | + http://launchpad.dev/codeofconduct/1.0.1/+sign |
530 | + |
531 | + |
532 | +Code of Conduct registration |
533 | +============================ |
534 | + |
535 | +Sample Person registers the code of conduct, using a reformatted copy which |
536 | +has leading spaces removed. This succeeds because the words the same and |
537 | +appear in the same order. |
538 | + |
539 | + >>> reformatted_coc = read_file('reformatted_101_coc.asc') |
540 | + >>> browser.getControl('Signed Code').value = reformatted_coc |
541 | + >>> browser.getControl('Continue').click() |
542 | + >>> print browser.url |
543 | + http://launchpad.dev/~name12/+codesofconduct |
544 | + |
545 | +And now Sample Person's Codes of Conduct page shows that he's signed it. |
546 | + |
547 | + >>> browser.open('http://launchpad.dev/~name12/+codesofconduct') |
548 | + >>> print extract_text(find_main_content(browser.contents)) |
549 | + Codes of Conduct for Sample Person |
550 | + Sample Person +codesofconduct |
551 | + Launchpad records codes of conduct you sign as commitments to the |
552 | + principles of collaboration, tolerance and open communication that |
553 | + drive the open source community. |
554 | + Active signatures |
555 | + If you change your mind about agreeing to a code of conduct, |
556 | + you can deactivate your signature. |
557 | + 2009-09-15: digitally signed by Sample Person (1024D/DFD20543) |
558 | + ... |
559 | |
560 | === modified file 'lib/lp/registry/templates/person-codesofconduct.pt' |
561 | --- lib/lp/registry/templates/person-codesofconduct.pt 2009-07-17 17:59:07 +0000 |
562 | +++ lib/lp/registry/templates/person-codesofconduct.pt 2009-09-15 20:20:20 +0000 |
563 | @@ -3,81 +3,68 @@ |
564 | xmlns:tal="http://xml.zope.org/namespaces/tal" |
565 | xmlns:metal="http://xml.zope.org/namespaces/metal" |
566 | xmlns:i18n="http://xml.zope.org/namespaces/i18n" |
567 | - xml:lang="en" |
568 | - lang="en" |
569 | - dir="ltr" |
570 | - metal:use-macro="context/@@main_template/master" |
571 | + metal:use-macro="view/macro:page/main_only" |
572 | i18n:domain="launchpad" |
573 | -> |
574 | -<body> |
575 | - |
576 | -<div metal:fill-slot="main"> |
577 | - <h1>Code of conduct signatures</h1> |
578 | - |
579 | - <tal:changes condition="view/performCoCChanges" /> |
580 | - |
581 | - <p>Launchpad records codes of conduct you sign as commitments to the |
582 | - principles of collaboration, tolerance and open communication that |
583 | - drive the open source community.</p> |
584 | - |
585 | - <p tal:condition="not: context/signedcocs"> |
586 | - <tal:name replace="context/fmt:displayname"/> has never signed a code |
587 | - of conduct. |
588 | - </p> |
589 | - |
590 | - <div tal:condition="context/activesignatures"> |
591 | - <form name="coc" action="" method="post"> |
592 | - |
593 | - <h2>Active signatures</h2> |
594 | + > |
595 | + <body> |
596 | + <div metal:fill-slot="main"> |
597 | + <p>Launchpad records codes of conduct you |
598 | + sign as commitments to the principles of collaboration, tolerance and |
599 | + open communication that drive the open source community.</p> |
600 | + |
601 | + <p tal:condition="not: context/signedcocs"> |
602 | + <tal:name replace="context/fmt:displayname"/> has never signed a code |
603 | + of conduct. |
604 | + </p> |
605 | + |
606 | + <div tal:condition="context/activesignatures"> |
607 | + <form name="coc" action="" method="post"> |
608 | + <h2>Active signatures</h2> |
609 | <p>If you change your mind about agreeing to a code of conduct, |
610 | you can deactivate your signature.</p> |
611 | - <table> |
612 | - <tbody> |
613 | - <tr tal:repeat="sig context/activesignatures"> |
614 | - <td class="icon left"> |
615 | - <input |
616 | - type="checkbox" |
617 | - name="DEACTIVATE_SIGNATURE" |
618 | - tal:attributes="value sig/id; id string:code${sig/id}" |
619 | - /> |
620 | - </td> |
621 | - <td> |
622 | - <div> |
623 | - <label |
624 | - class="signature" |
625 | - tal:attributes="for string:code${sig/id}" |
626 | - tal:content="sig/displayname" |
627 | - >blah</label> |
628 | - </div> |
629 | - <pre |
630 | - class="discreet" |
631 | - tal:content="sig/signedcode" |
632 | - >SIGNATURE</pre> |
633 | - </td> |
634 | - </tr> |
635 | - </tbody> |
636 | - </table> |
637 | - <input type="submit" value="Deactivate"/> |
638 | - </form> |
639 | - </div> |
640 | - |
641 | - |
642 | - <div tal:condition="context/inactivesignatures"> |
643 | - |
644 | - <h2>Inactive signatures</h2> |
645 | - |
646 | - <p> |
647 | - Once <dfn>Inactive</dfn>, a signature can only be reactivated by a |
648 | - <a href="/~admins">Launchpad Administrator</a>. |
649 | - </p> |
650 | + <table> |
651 | + <tbody> |
652 | + <tr tal:repeat="sig context/activesignatures"> |
653 | + <td class="icon left"> |
654 | + <input |
655 | + type="checkbox" |
656 | + name="DEACTIVATE_SIGNATURE" |
657 | + tal:attributes="value sig/id; id string:code${sig/id}" |
658 | + /> |
659 | + </td> |
660 | + <td> |
661 | + <div> |
662 | + <label |
663 | + class="signature" |
664 | + tal:attributes="for string:code${sig/id}" |
665 | + tal:content="sig/displayname" |
666 | + >blah</label> |
667 | + </div> |
668 | + <pre |
669 | + class="discreet" |
670 | + tal:content="sig/signedcode" |
671 | + >SIGNATURE</pre> |
672 | + </td> |
673 | + </tr> |
674 | + </tbody> |
675 | + </table> |
676 | + <input type="submit" value="Deactivate"/> |
677 | + </form> |
678 | + </div> |
679 | + |
680 | + <div tal:condition="context/inactivesignatures"> |
681 | + <h2>Inactive signatures</h2> |
682 | + <p> |
683 | + Once <dfn>Inactive</dfn>, a signature can only be reactivated by a |
684 | + <a href="/~admins">Launchpad Administrator</a>. |
685 | + </p> |
686 | <ul> |
687 | <li tal:repeat="sig context/inactivesignatures" |
688 | tal:content="sig/displayname"/> |
689 | </ul> |
690 | + </div> |
691 | + |
692 | + <p><a href="/codeofconduct">See or sign new code of conduct releases</a></p> |
693 | </div> |
694 | - |
695 | - <p><a href="/codeofconduct">See or sign new code of conduct releases</a></p> |
696 | - |
697 | -</div> |
698 | -</body> |
699 | + </body> |
700 | </html> |
701 | |
702 | === modified file 'lib/lp/registry/templates/person-participation.pt' |
703 | --- lib/lp/registry/templates/person-participation.pt 2009-07-17 17:59:07 +0000 |
704 | +++ lib/lp/registry/templates/person-participation.pt 2009-09-15 21:16:37 +0000 |
705 | @@ -3,83 +3,60 @@ |
706 | xmlns:tal="http://xml.zope.org/namespaces/tal" |
707 | xmlns:metal="http://xml.zope.org/namespaces/metal" |
708 | xmlns:i18n="http://xml.zope.org/namespaces/i18n" |
709 | - xml:lang="en" |
710 | - lang="en" |
711 | - dir="ltr" |
712 | - metal:use-macro="context/@@main_template/master" |
713 | + metal:use-macro="view/macro:page/main_only" |
714 | i18n:domain="launchpad" |
715 | -> |
716 | + > |
717 | |
718 | <body> |
719 | - |
720 | -<div metal:fill-slot="help"> |
721 | - <p> |
722 | - Launchpad has a sophisticated system for managing teams, including the |
723 | - ability to create teams-of-teams. This page shows the teams that |
724 | - <span tal:replace="context/title">Foo Bar</span> is a member of. You can |
725 | - see the teams in which they are directly a member, and also the teams in |
726 | - which they have indirect membership. |
727 | - </p> |
728 | - <p> |
729 | - Indirect membership describes the case where a person is a member of a |
730 | - team, which is in turn a member of another team. The person will then be |
731 | - an indirect member of the other team. |
732 | - </p> |
733 | -</div> |
734 | - |
735 | -<metal:heading fill-slot="pageheading"> |
736 | - <h1>Team participation</h1> |
737 | -</metal:heading> |
738 | - |
739 | -<div metal:fill-slot="main" tal:define=" |
740 | - direct context/myactivememberships; |
741 | - indirect context/teams_indirectly_participated_in"> |
742 | - |
743 | - <p tal:condition="direct/count"> |
744 | - <span tal:replace="context/title">Foo Bar</span> |
745 | - is a member of the following teams: |
746 | - </p> |
747 | - <p tal:condition="not: direct/count"> |
748 | - <span tal:replace="context/title">Foo Bar</span> |
749 | - has not yet joined any teams. |
750 | - </p> |
751 | - |
752 | - <div class="left" tal:condition="direct/count"> |
753 | - <div class="portlet"> |
754 | - <h2>Direct membership</h2> |
755 | - <table id="participation"> |
756 | - <tal:loop repeat="membership context/myactivememberships"> |
757 | - <tr tal:replace="structure membership/@@+listing-simple" |
758 | - tal:condition="membership/team/@@+restricted-membership/userCanViewMembership" |
759 | - /> |
760 | - </tal:loop> |
761 | - </table> |
762 | - </div> |
763 | - </div> |
764 | - |
765 | - <div class="right" tal:condition="indirect/count"> |
766 | - <div class="portlet"> |
767 | - <h2>Indirect membership</h2> |
768 | - <table id="indirect participation"> |
769 | - <tal:loop repeat="team_via view/indirect_teams_via"> |
770 | - <tr tal:condition="team_via/team/@@+restricted-membership/userCanViewMembership"> |
771 | - <td><img tal:replace="structure team_via/team/image:icon" /> |
772 | - </td> |
773 | - <td> |
774 | - <div> |
775 | - <a tal:replace="structure team_via/team/fmt:link">Team name</a> |
776 | - </div> |
777 | - <div> |
778 | - Via |
779 | - <span tal:replace="team_via/via">guadamen</span>. |
780 | - </div> |
781 | - </td> |
782 | - </tr> |
783 | - </tal:loop> |
784 | - </table> |
785 | - </div> |
786 | - </div> |
787 | - |
788 | -</div> |
789 | + <div metal:fill-slot="main" |
790 | + tal:define="direct context/myactivememberships; |
791 | + indirect context/teams_indirectly_participated_in"> |
792 | + |
793 | + <p tal:condition="direct/count"> |
794 | + <span tal:replace="context/title">Foo Bar</span> |
795 | + is a member of the following teams: |
796 | + </p> |
797 | + <p tal:condition="not: direct/count"> |
798 | + <span tal:replace="context/title">Foo Bar</span> |
799 | + has not yet joined any teams. |
800 | + </p> |
801 | + |
802 | + <div class="left" tal:condition="direct/count"> |
803 | + <div class="portlet"> |
804 | + <h2>Direct membership</h2> |
805 | + <table id="participation"> |
806 | + <tal:loop repeat="membership context/myactivememberships"> |
807 | + <tr tal:replace="structure membership/@@+listing-simple" |
808 | + tal:condition="membership/team/@@+restricted-membership/userCanViewMembership" |
809 | + /> |
810 | + </tal:loop> |
811 | + </table> |
812 | + </div> |
813 | + </div> |
814 | + |
815 | + <div class="right" tal:condition="indirect/count"> |
816 | + <div class="portlet"> |
817 | + <h2>Indirect membership</h2> |
818 | + <table id="indirect participation"> |
819 | + <tal:loop repeat="team_via view/indirect_teams_via"> |
820 | + <tr tal:condition="team_via/team/@@+restricted-membership/userCanViewMembership"> |
821 | + <td><img tal:replace="structure team_via/team/image:icon" /> |
822 | + </td> |
823 | + <td> |
824 | + <div> |
825 | + <a tal:replace="structure team_via/team/fmt:link" |
826 | + >Team name</a> |
827 | + </div> |
828 | + <div> |
829 | + Via |
830 | + <span tal:replace="team_via/via">guadamen</span>. |
831 | + </div> |
832 | + </td> |
833 | + </tr> |
834 | + </tal:loop> |
835 | + </table> |
836 | + </div> |
837 | + </div> |
838 | + </div> |
839 | </body> |
840 | </html> |
841 | |
842 | === modified file 'lib/lp/registry/templates/person-teamhierarchy.pt' |
843 | --- lib/lp/registry/templates/person-teamhierarchy.pt 2009-07-17 17:59:07 +0000 |
844 | +++ lib/lp/registry/templates/person-teamhierarchy.pt 2009-09-15 22:55:30 +0000 |
845 | @@ -3,67 +3,54 @@ |
846 | xmlns:tal="http://xml.zope.org/namespaces/tal" |
847 | xmlns:metal="http://xml.zope.org/namespaces/metal" |
848 | xmlns:i18n="http://xml.zope.org/namespaces/i18n" |
849 | - xml:lang="en" |
850 | - lang="en" |
851 | - dir="ltr" |
852 | - metal:use-macro="context/@@main_template/master" |
853 | + metal:use-macro="view/macro:page/main_only" |
854 | i18n:domain="launchpad" |
855 | -> |
856 | + > |
857 | |
858 | <body> |
859 | - |
860 | -<div metal:fill-slot="main"> |
861 | - <h1> |
862 | - “<span tal:replace="context/displayname"> |
863 | - Foo</span>” team |
864 | - </h1> |
865 | - <h2>Relationship to other teams</h2> |
866 | - <tal:block define=" |
867 | - subteams context/sub_teams; |
868 | - superteams context/super_teams |
869 | - "> |
870 | - <p tal:condition="python: not subteams and not superteams"> |
871 | + <div metal:fill-slot="main"> |
872 | + <p tal:condition="not: view/has_relationships"> |
873 | None of the members of |
874 | “<span tal:replace="context/displayname"/>” |
875 | - are teams, |
876 | - and nor is it a member of any other team. |
877 | + are teams, nor is it a member of any other team. |
878 | </p> |
879 | - <p tal:condition="python: superteams and not subteams"> |
880 | + <p tal:condition="view/has_only_super_teams"> |
881 | None of the members of |
882 | “<span tal:replace="context/displayname"/>” |
883 | are teams. |
884 | </p> |
885 | - <tal:block condition="subteams"> |
886 | + <tal:block condition="view/has_sub_teams"> |
887 | <p> |
888 | These teams are members of |
889 | “<span tal:replace="context/displayname"/>”: |
890 | </p> |
891 | <ul id="subteams"> |
892 | - <tal:subteams repeat="team subteams"> |
893 | - <li tal:condition="team/@@+restricted-membership/userCanViewMembership"> |
894 | + <tal:subteams repeat="team context/sub_teams"> |
895 | + <li |
896 | + tal:condition="team/@@+restricted-membership/userCanViewMembership"> |
897 | <tal:link replace="structure team/fmt:link" /> |
898 | </li> |
899 | </tal:subteams> |
900 | - </ul> |
901 | + </ul> |
902 | </tal:block> |
903 | - <p tal:condition="python: subteams and not superteams"> |
904 | + <p tal:condition="view/has_only_sub_teams"> |
905 | “<span tal:replace="context/displayname"/>” |
906 | is not a member of any other team. |
907 | </p> |
908 | - <tal:block condition="superteams"> |
909 | + <tal:block condition="view/has_super_teams"> |
910 | <p> |
911 | “<span tal:replace="context/displayname"/>” |
912 | is a member of these teams: |
913 | </p> |
914 | <ul id="superteams"> |
915 | - <tal:superteams repeat="team superteams"> |
916 | - <li tal:condition="team/@@+restricted-membership/userCanViewMembership"> |
917 | + <tal:superteams repeat="team context/super_teams"> |
918 | + <li |
919 | + tal:condition="team/@@+restricted-membership/userCanViewMembership"> |
920 | <tal:link replace="structure team/fmt:link" /> |
921 | </li> |
922 | </tal:superteams> |
923 | </ul> |
924 | </tal:block> |
925 | - </tal:block> |
926 | -</div> |
927 | + </div> |
928 | </body> |
929 | </html> |
= Summary =
This branch converts three more pages to UI 3.0, the ~person/ +codesofconduct +participation page, and the ~person/ +teamhierarchy page.
page, the ~person/
I suck for letting this branch get over 800 lines.
== Proposed fix ==
Implement mostly mechanical changes to convert the relevant templates to UI
3.0.
== Pre-implementation notes ==
None really needed.
== Implementation details ==
In addition to the template changes, which were mostly mechanical and thus not
requiring a formal ui review, I cleaned up a lot of code and added some new
tests.
* Removed some obsolete pagetitles.py entries. tionView and yView. tionView. indirect_ teams_via to make it a property ConductEditView . Previously, the changes were made by anges() method called by placeholder TAL in the template.
* Made CodeOfConductView inherit from LaunchpadView so that it could be
simplified. I also added a page_title attribute to this view since it has
no breadcrumbs (nor should it; it isn't actually traversable from a core
content object).
* Split off the view code for the above templates into separate view
classes. The monolithic PersonView really sucks so it's better to have
smaller, more focused views. Added PersonParticipa
TeamHierarch
* Rewrote PersonParticipa
and to make the implementation more readable.
* Fixed the crufty way signature records are updated in
PersonCodeOf
performCoCCh
LaunchpadView supports an `initialize()` method, which makes much more
sense for performing this work.
* Added a bunch of convenience properties to TeamHierarchyView
* Cleaned up 02-signcoc.txt doctest, but unfortunately did not convert this
to an xx- random test.
== Tests ==
The new view tests:
% bin/test -vv -t team-hierarchy- views -t xx-coc-views
Regression testing the code of conduct signing stories:
% bin/test -vv -t gpg-coc
Regression testing the other template changes:
% bin/test -vv -m lp.registry -t stories
== Demo and Q/A ==
To view the new team hierarchy pages with various combinations of sub- and
super- team structure:
* http:// launchpad. dev/~warty- gnome/+ teamhierarchy launchpad. dev/~ubuntu- team/+teamhiera rchy launchpad. dev/~guadamen/ +teamhierarchy
* http://
* http://
To view the changes to the participation pages:
* http:// launchpad. dev/~name12/ +participation launchpad. dev/~name16/ +participation
* http://
To view the new code of conduct pages:
* http:// launchpad. dev/~name12/ +codesofconduct launchpad. dev/~no- priv/+codesofco nduct launchpad. dev/codeofcondu ct launchpad. dev/codeofcondu ct/1.0/ +sign launchpad. dev/codeofcondu ct/1.0. 1
* http://
* http://
* http://
* http://
= Launchpad lint =
Checking for conflicts. and issues in doctests and templates.
Running jslint, xmllint, pyflakes, and pylint.
Using normal rules.
Linting changed files: registry/ browser/ configure. zcml registry/ doc/team- hierarchy- views.txt registry/ doc/xx- coc-views. txt registry/ templates/ person- teamhierarchy. pt /launchpad/ pagetitles. py registry/ browser/ team.py registry/ browser/ codeofconduct. py registry/ templates/ person- codesofconduct. pt registry/ t...
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/canonical
lib/lp/
lib/lp/
lib/lp/
lib/lp/