Merge lp:~sinzui/launchpad/obsolete-add-edit into lp:launchpad

Proposed by Curtis Hovey
Status: Merged
Approved by: Paul Hummer
Approved revision: no longer in the source branch.
Merged at revision: 11711
Proposed branch: lp:~sinzui/launchpad/obsolete-add-edit
Merge into: lp:launchpad
Diff against target: 833 lines (+251/-446)
12 files modified
lib/canonical/launchpad/templates/launchpad-addform.pt (+0/-81)
lib/canonical/launchpad/templates/launchpad-editform.pt (+0/-104)
lib/canonical/launchpad/zcml/configure.zcml (+0/-2)
lib/canonical/launchpad/zcml/widgets.zcml (+0/-46)
lib/lp/app/browser/configure.zcml (+14/-0)
lib/lp/registry/browser/codeofconduct.py (+52/-118)
lib/lp/registry/browser/configure.zcml (+6/-18)
lib/lp/registry/browser/tests/test_codeofconduct.py (+149/-0)
lib/lp/registry/stories/gpg-coc/98-cocacknowledge.txt (+30/-29)
lib/lp/registry/templates/signedcodeofconduct-acknowledge.pt (+0/-16)
lib/lp/registry/templates/signedcodeofconduct-activate.pt (+0/-16)
lib/lp/registry/templates/signedcodeofconduct-deactivate.pt (+0/-16)
To merge this branch: bzr merge lp:~sinzui/launchpad/obsolete-add-edit
Reviewer Review Type Date Requested Status
Paul Hummer (community) Approve
Review via email: mp+38377@code.launchpad.net

Description of the change

This is my branch to remove addform and editform.

    lp:~sinzui/launchpad/obsolete-add-edit
    Diff size: 710
    Launchpad bug:
        https://bugs.launchpad.net/bugs/433074
        https://bugs.launchpad.net/bugs/414857
    Test command: ./bin/test -vv \
          -t coc -t codeofconduct
    Pre-implementation: no one
    Target release: 10.11

Remove addform and editform
---------------------------

These two templates are only used for their macros.

  lib/canonical/launchpad/templates/launchpad-addform.pt
  lib/canonical/launchpad/templates/launchpad-editform.pt

These are the last templates to use them.

    ./lib/lp/registry/templates/signedcodeofconduct-acknowledge.pt:11:
    ./lib/lp/registry/templates/signedcodeofconduct-activate.pt:11:
    ./lib/lp/registry/templates/signedcodeofconduct-deactivate.pt:11:

Rules
-----

    * Add tests for the existing behaviour
    * Convert the views to LaunchpadFormView
    * Update the ZCML to use the generic edit template

QA
--

As an admin, choose a user that has not signed the CoC to test with

    * Visit https://staging.launchpad.net/codeofconduct
    * Search for the user and verify he does has not signed the CoC.
    * Follow the register link.
    * Enter the user's name and choose Register.
    * Search for the user and view his signed CoC record.
    * Verify his CoC is active.
    * Choose to edit icon
    * Add a comment and choose Deactivate.
    * Verify the CoC now states it is inactive.
    * Choose to edit icon
    * Add a comment and choose Activate.
    * Verify the CoC now states it is active.

Lint
----

Linting changed files:
  lib/canonical/launchpad/zcml/widgets.zcml
  lib/lp/registry/browser/codeofconduct.py
  lib/lp/registry/browser/configure.zcml
  lib/lp/registry/browser/tests/test_codeofconduct.py
  lib/lp/registry/stories/gpg-coc/98-cocacknowledge.txt
       3: source has bad indentation.
      12: source has bad indentation.
      16: source exceeds 78 characters.
      16: source has bad indentation.
      23: source has bad indentation.
      32: source has bad indentation.

^ I can fix this after the review. The indentation changes will make the diff
difficult to read.

Test
----

    * lib/lp/registry/browser/tests/test_codeofconduct.py
      * Added tests for the signed CoC management views.
    * lib/lp/registry/stories/gpg-coc/98-cocacknowledge.txt
      * Updated the story to use the information the user sees.

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

    * lib/canonical/launchpad/zcml/widgets.zcml
      * Unregistered the deleted templates.
      * I could move the two remaining templates to lp/app and extract
        the last widget ZCML to lp/app/browser/configure.zcml to remove this
        file.
    * lib/lp/registry/browser/codeofconduct.py
      * Converted the AddView and EditView views into LaunchpadFormViews.
      * This looks like a 100% rewrite in the diff, but I made these changes
        using small refactorings. I am surprised I did this much.
    * lib/lp/registry/browser/configure.zcml
      * Replaced the add/edit ZCML with page ZCML.

To post a comment you must log in.
Revision history for this message
Paul Hummer (rockstar) wrote :

The best kind of code to review is the kind that's getting removed. :) Thanks for sorting out some more tech debt.

Please fix the indentation issues raised by lint. Thank you for thinking of your reviewer when you saw those lint issues.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== removed file 'lib/canonical/launchpad/templates/launchpad-addform.pt'
2--- lib/canonical/launchpad/templates/launchpad-addform.pt 2009-09-18 20:25:59 +0000
3+++ lib/canonical/launchpad/templates/launchpad-addform.pt 1970-01-01 00:00:00 +0000
4@@ -1,81 +0,0 @@
5-<html
6- xmlns="http://www.w3.org/1999/xhtml"
7- xmlns:tal="http://xml.zope.org/namespaces/tal"
8- xmlns:metal="http://xml.zope.org/namespaces/metal"
9- metal:use-macro="view/macro:page/main_only"
10->
11- <body>
12-
13- <div metal:fill-slot="main">
14-
15- <div tal:condition="nothing">
16- This file is a modified version of zope/app/form/browser/add.pt for use
17- in the Launchpad system. You should not edit this file, but rather use
18- it as the default_template attribute of your addform. You create your
19- own template for the specific addform, called table-add.pt for example,
20- which is the template which uses this one.
21- </div>
22-
23- <div metal:define-macro="addform">
24-
25- <form action="."
26- tal:attributes="action request/URL"
27- method="post"
28- enctype="multipart/form-data"
29- accept-charset="UTF-8">
30-
31- <div metal:define-macro="formbody">
32-
33- <h1
34- tal:condition="view/label"
35- tal:content="view/label"
36- metal:define-slot="heading"
37- >Add Something</h1>
38-
39- <p metal:define-slot="extra_info" tal:replace="nothing">
40- This is the description of the add form.
41- This text will be in bold, beneath the title of the add form,
42- and should explain a little bit about the form.
43- </p>
44-
45- <p class="error message"
46- tal:define="status view/update"
47- tal:condition="status"
48- tal:content="status" />
49-
50- <div class="row"
51- metal:define-slot="extra_top"
52- tal:replace="nothing">
53- <div>Extra top</div>
54- <div><input type="text" style="width:100%" /></div>
55- </div>
56-
57- <div metal:use-macro="context/@@launchpad_widget_macros/launchpad_widget_rows" />
58-
59- <div class="row"
60- metal:define-slot="extra_bottom"
61- tal:replace="nothing">
62- <div>Extra bottom</div>
63- <div class="field"><input type="text" style="width:100%" /></div>
64- </div>
65-
66- </div>
67- <div class="actions">
68- <input type="submit"
69- value="Add"
70- name="UPDATE_SUBMIT" />
71- </div>
72-
73- <div class="row"
74- metal:define-slot="extra_buttons"
75- tal:replace="nothing">
76- </div>
77-
78- </form>
79- </div>
80-
81- </div>
82- </body>
83-
84-</html>
85-
86
87=== removed file 'lib/canonical/launchpad/templates/launchpad-editform.pt'
88--- lib/canonical/launchpad/templates/launchpad-editform.pt 2009-09-18 20:25:59 +0000
89+++ lib/canonical/launchpad/templates/launchpad-editform.pt 1970-01-01 00:00:00 +0000
90@@ -1,104 +0,0 @@
91-<html
92- xmlns="http://www.w3.org/1999/xhtml"
93- xmlns:tal="http://xml.zope.org/namespaces/tal"
94- xmlns:metal="http://xml.zope.org/namespaces/metal"
95- metal:use-macro="view/macro:page/main_only"
96->
97- <body>
98-
99- <div metal:fill-slot="main">
100-
101- <div tal:condition="nothing">
102- This file is a modified version of zope/app/form/browser/edit.pt for use
103- in the Launchpad system. You should not edit this file, but rather use
104- it from your custom editform. You create your own template for the
105- specific editform, called table-edit.pt for example, which is the template
106- which uses this one.</div>
107-
108- <div metal:define-macro="editform">
109-
110- <h1
111- tal:condition="view/label"
112- tal:content="view/label"
113- >Edit something</h1>
114-
115- <form action="." tal:attributes="action request/URL" method="post"
116- enctype="multipart/form-data">
117-
118- <div metal:define-macro="formbody">
119-
120- <p class="informational message"
121- tal:define="status view/update"
122- tal:condition="status"
123- tal:content="status" />
124-
125- <tal:errors
126- define="errors view/errors|nothing;
127- num_errors view/errors/count:len"
128- condition="errors"
129- >
130- <p tal:condition="python: num_errors == 1" class="error message">
131- There is a problem with the information you entered.
132- Please fix it and try again.
133- </p>
134- <p tal:condition="python: num_errors > 1" class="error message">
135- There are
136- <tal:errors replace="num_errors">6</tal:errors>
137- problems with the information you entered.
138- Please fix them and try again.
139- </p>
140- </tal:errors>
141-
142- <p class="error message"
143- tal:repeat="top_of_page_error view/top_of_page_errors|nothing"
144- tal:content="structure top_of_page_error">
145- Schema validation errors.
146- </p>
147-
148- <div metal:define-slot="extra_info"
149- class="documentDescription"
150- tal:replace="nothing">
151- This is where a document heading paragraph can be inserted. In
152- your actual customised editform, you can fill-slot this with
153- a descriptive paragraph.
154- </div>
155-
156- <div class="row"
157- metal:define-slot="extra_top" tal:replace="nothing">
158- <div>Extra top</div>
159- <div class="field"><input type="text" style="width:100%" /></div>
160- </div>
161-
162- <div metal:use-macro="context/@@launchpad_widget_macros/launchpad_widget_rows" />
163-
164- <div class="separator"></div>
165-
166- <div class="row"
167- metal:define-slot="extra_bottom" tal:replace="nothing">
168- <div>Extra bottom</div>
169- <div class="field"><input type="text" style="width:100%" /></div>
170- </div>
171-
172- </div>
173-
174- <div class="actions">
175- <input
176- type="submit"
177- name="UPDATE_SUBMIT"
178- value="Change"
179- />
180- </div>
181-
182- <div class="row" metal:define-slot="extra_buttons"
183- tal:replace="nothing">
184- </div>
185-
186- <div class="separator"></div>
187-
188- </form>
189-
190- </div>
191- </div>
192-
193- </body>
194-</html>
195
196=== modified file 'lib/canonical/launchpad/zcml/configure.zcml'
197--- lib/canonical/launchpad/zcml/configure.zcml 2010-09-30 23:21:35 +0000
198+++ lib/canonical/launchpad/zcml/configure.zcml 2010-10-15 01:29:43 +0000
199@@ -29,8 +29,6 @@
200 <include file="temporaryblobstorage.zcml" />
201 <include file="webservice.zcml" />
202
203- <include file="widgets.zcml" />
204-
205 <!-- System homepages -->
206
207 <!-- Event configuration -->
208
209=== removed file 'lib/canonical/launchpad/zcml/widgets.zcml'
210--- lib/canonical/launchpad/zcml/widgets.zcml 2009-07-13 18:15:02 +0000
211+++ lib/canonical/launchpad/zcml/widgets.zcml 1970-01-01 00:00:00 +0000
212@@ -1,46 +0,0 @@
213-<!-- Copyright 2009 Canonical Ltd. This software is licensed under the
214- GNU Affero General Public License version 3 (see the file LICENSE).
215--->
216-
217-<configure
218- xmlns="http://namespaces.zope.org/zope"
219- xmlns:browser="http://namespaces.zope.org/browser"
220- xmlns:i18n="http://namespaces.zope.org/i18n"
221- i18n_domain="launchpad">
222-
223- <!-- Launchpad Add and Edit Form METAL
224- These templates can be used by any of the add or edit forms
225- in Launchpad -->
226- <browser:page
227- for="*"
228- name="launchpad_addform"
229- layer="canonical.launchpad.layers.LaunchpadLayer"
230- permission="zope.Public"
231- template="../templates/launchpad-addform.pt"
232- />
233-
234- <browser:page
235- for="*"
236- name="launchpad_editform"
237- layer="canonical.launchpad.layers.LaunchpadLayer"
238- permission="zope.Public"
239- template="../templates/launchpad-editform.pt"
240- />
241-
242- <browser:page
243- for="*"
244- name="launchpad_form"
245- layer="canonical.launchpad.layers.LaunchpadLayer"
246- permission="zope.Public"
247- template="../templates/launchpad-form.pt"
248- />
249-
250- <browser:page
251- for="*"
252- name="launchpad_widget_macros"
253- layer="canonical.launchpad.layers.LaunchpadLayer"
254- permission="zope.Public"
255- template="../templates/launchpad-widget-macros.pt"
256- />
257-
258-</configure>
259
260=== modified file 'lib/lp/app/browser/configure.zcml'
261--- lib/lp/app/browser/configure.zcml 2010-10-03 15:30:06 +0000
262+++ lib/lp/app/browser/configure.zcml 2010-10-15 01:29:43 +0000
263@@ -22,6 +22,20 @@
264 />
265 <browser:page
266 for="*"
267+ name="launchpad_form"
268+ layer="canonical.launchpad.layers.LaunchpadLayer"
269+ permission="zope.Public"
270+ template="../templates/launchpad-form.pt"
271+ />
272+ <browser:page
273+ for="*"
274+ name="launchpad_widget_macros"
275+ layer="canonical.launchpad.layers.LaunchpadLayer"
276+ permission="zope.Public"
277+ template="../templates/launchpad-widget-macros.pt"
278+ />
279+ <browser:page
280+ for="*"
281 name="+related-pages"
282 class="canonical.launchpad.browser.launchpad.NavigationMenuTabs"
283 template="../templates/navigationmenu-related-pages.pt"
284
285=== renamed file 'lib/canonical/launchpad/templates/launchpad-form.pt' => 'lib/lp/app/templates/launchpad-form.pt'
286=== renamed file 'lib/canonical/launchpad/templates/launchpad-widget-macros.pt' => 'lib/lp/app/templates/launchpad-widget-macros.pt'
287=== modified file 'lib/lp/registry/browser/codeofconduct.py'
288--- lib/lp/registry/browser/codeofconduct.py 2010-08-20 20:31:18 +0000
289+++ lib/lp/registry/browser/codeofconduct.py 2010-10-15 01:29:43 +0000
290@@ -23,10 +23,6 @@
291 'SignedCodeOfConductDeactiveView',
292 ]
293
294-from zope.app.form.browser.add import (
295- AddView,
296- EditView,
297- )
298 from zope.component import getUtility
299
300 from canonical.launchpad.webapp import (
301@@ -49,7 +45,6 @@
302 ISignedCodeOfConduct,
303 ISignedCodeOfConductSet,
304 )
305-from lp.registry.interfaces.person import IPerson
306
307
308 class SignedCodeOfConductSetNavigation(GetitemNavigation):
309@@ -197,38 +192,24 @@
310 return coc_set[coc_conf.currentrelease]
311
312
313-class SignedCodeOfConductAckView(AddView):
314+class SignedCodeOfConductAckView(LaunchpadFormView):
315 """Acknowledge a Paper Submitted CoC."""
316-
317- def __init__(self, context, request):
318- self.context = context
319- self.request = request
320- self.bag = getUtility(ILaunchBag)
321- self._nextURL = '.'
322- self.page_title = self.label
323- AddView.__init__(self, context, request)
324-
325- def createAndAdd(self, data):
326+ schema = ISignedCodeOfConduct
327+ field_names = ['owner']
328+ label = 'Register a code of conduct signature'
329+ page_title = label
330+
331+ @property
332+ def next_url(self):
333+ return canonical_url(self.context)
334+
335+ cancel_url = next_url
336+
337+ @action('Register', name='add')
338+ def createAndAdd(self, action, data):
339 """Verify and Add the Acknowledge SignedCoC entry."""
340- kw = {}
341-
342- for key, value in data.items():
343- kw[str(key)] = value
344-
345- # XXX cprov 2005-03-23:
346- # rename unused key:value
347- kw['user'] = kw['owner']
348- del kw['owner']
349-
350- recipient = getUtility(ILaunchBag).user
351- kw['recipient'] = recipient
352-
353- # use utility to store it in the database
354- sCoC_util = getUtility(ISignedCodeOfConductSet)
355- sCoC_util.acknowledgeSignature(**kw)
356-
357- def nextURL(self):
358- return self._nextURL
359+ self.context.acknowledgeSignature(
360+ user=data['owner'], recipient=self.user)
361
362
363 class SignedCodeOfConductView:
364@@ -265,86 +246,39 @@
365 return True
366
367
368-# XXX: salgado, bug=414861, 2009-08-17: This view must be converted to a
369-# LaunchpadFormView and define a 'cancel_url' so that the form gets a cancel
370-# link.
371-class SignedCodeOfConductActiveView(EditView):
372- """Active a SignedCodeOfConduct Entry.
373- When activating a signature:
374- * Grant a new admincomment,
375- * store the recipient,
376- * set active.
377- """
378-
379- def __init__(self, context, request):
380- self.context = context
381- self.request = request
382- self.page_title = self.label
383- EditView.__init__(self, context, request)
384-
385- def changed(self):
386- admincomment = self.request.form.get('field.admincomment')
387-
388- if admincomment:
389- # No verification is needed since this page is protected by
390- # lp.Admin
391- recipient = IPerson(self.request.principal, None)
392- kw = {}
393- kw['recipient'] = recipient
394- kw['admincomment'] = admincomment
395- kw['sign_id'] = self.context.id
396- kw['state'] = True
397-
398- # use utility to active it in the database
399- sCoC_util = getUtility(ISignedCodeOfConductSet)
400- sCoC_util.modifySignature(**kw)
401-
402- # now redirect to view the SignedCoC
403- self.request.response.redirect(self.request.URL[-1])
404-
405- # XXX: cprov 2005-02-26:
406- # How to proceed with no admincomment ?
407-
408-
409-# XXX: salgado, bug=414857, 2009-08-17: This view must be converted to a
410-# LaunchpadFormView and define a 'cancel_url' so that the form gets a cancel
411-# link.
412-class SignedCodeOfConductDeactiveView(EditView):
413- """Deactive a SignedCodeOfConduct Entry.
414- When deactivating a signature:
415- * Grant admincomment,
416- * store recipient,
417- * clear active.
418- """
419-
420- def __init__(self, context, request):
421- self.context = context
422- self.request = request
423- self.page_title = self.label
424- EditView.__init__(self, context, request)
425-
426- def changed(self):
427- admincomment = self.request.form.get('field.admincomment')
428-
429- if admincomment:
430- # No verification is needed since this page is protected by
431- # lp.Edit
432- recipient = IPerson(self.request.principal, None)
433-
434- kw = {}
435- kw['recipient'] = recipient
436- kw['admincomment'] = admincomment
437- kw['sign_id'] = self.context.id
438- kw['state'] = False
439-
440- # use utility to active it in the database
441- sCoC_util = getUtility(ISignedCodeOfConductSet)
442- sCoC_util.modifySignature(**kw)
443-
444- # now redirect to view the SignedCoC
445- self.request.response.redirect(self.request.URL[-1])
446-
447-
448- # XXX: cprov 2005-02-26:
449- # How to proceed with no admincomment ?
450-
451+class SignedCodeOfConductActiveView(LaunchpadFormView):
452+ """Active a SignedCodeOfConduct Entry."""
453+ schema = ISignedCodeOfConduct
454+ field_names = ['admincomment']
455+ label = 'Activate code of conduct signature'
456+ page_title = label
457+ state = True
458+
459+ @property
460+ def next_url(self):
461+ return canonical_url(self.context)
462+
463+ cancel_url = next_url
464+
465+ def _change(self, action, data):
466+ admincomment = data['admincomment']
467+ sCoC_util = getUtility(ISignedCodeOfConductSet)
468+ sCoC_util.modifySignature(
469+ sign_id=self.context.id, recipient=self.user,
470+ admincomment=admincomment, state=self.state)
471+ self.request.response.redirect(self.next_url)
472+
473+ @action('Activate', name='change')
474+ def activate(self, action, data):
475+ self._change(action, data)
476+
477+
478+class SignedCodeOfConductDeactiveView(SignedCodeOfConductActiveView):
479+ """Deactivate a SignedCodeOfConduct Entry."""
480+ label = 'Deactivate code of conduct signature'
481+ page_title = label
482+ state = False
483+
484+ @action('Deactivate', name='change')
485+ def deactivate(self, action, data):
486+ self._change(action, data)
487
488=== modified file 'lib/lp/registry/browser/configure.zcml'
489--- lib/lp/registry/browser/configure.zcml 2010-10-14 20:20:47 +0000
490+++ lib/lp/registry/browser/configure.zcml 2010-10-15 01:29:43 +0000
491@@ -256,26 +256,18 @@
492 template="../templates/signedcodeofconduct-index.pt"
493 name="+index"/>
494 </browser:pages>
495- <browser:editform
496+ <browser:page
497 name="+activate"
498 for="lp.registry.interfaces.codeofconduct.ISignedCodeOfConduct"
499- schema="lp.registry.interfaces.codeofconduct.ISignedCodeOfConduct"
500 class="lp.registry.browser.codeofconduct.SignedCodeOfConductActiveView"
501- label="Activate code of conduct signature"
502- fields="admincomment"
503 permission="launchpad.Admin"
504- template="../templates/signedcodeofconduct-activate.pt">
505- </browser:editform>
506- <browser:editform
507+ template="../../app/templates/generic-edit.pt" />
508+ <browser:page
509 name="+deactivate"
510 for="lp.registry.interfaces.codeofconduct.ISignedCodeOfConduct"
511- schema="lp.registry.interfaces.codeofconduct.ISignedCodeOfConduct"
512 class="lp.registry.browser.codeofconduct.SignedCodeOfConductDeactiveView"
513- label="Deactivate code of conduct signature"
514- fields="admincomment"
515 permission="launchpad.Admin"
516- template="../templates/signedcodeofconduct-deactivate.pt">
517- </browser:editform>
518+ template="../../app/templates/generic-edit.pt" />
519 <browser:url
520 for="lp.registry.interfaces.codeofconduct.ISignedCodeOfConductSet"
521 path_expression="string:console"
522@@ -298,16 +290,12 @@
523 permission="launchpad.Admin"
524 template="../templates/codeofconduct-admin.pt"
525 name="+index"/>
526- <browser:addform
527+ <browser:page
528 name="+new"
529 for="lp.registry.interfaces.codeofconduct.ISignedCodeOfConductSet"
530- schema="lp.registry.interfaces.codeofconduct.ISignedCodeOfConduct"
531- label="Register a code of conduct signature"
532- fields="owner"
533 class="lp.registry.browser.codeofconduct.SignedCodeOfConductAckView"
534 permission="launchpad.Admin"
535- template="../templates/signedcodeofconduct-acknowledge.pt">
536- </browser:addform>
537+ template="../../app/templates/generic-edit.pt" />
538 </facet>
539 <browser:url
540 for="lp.registry.interfaces.irc.IIrcID"
541
542=== added file 'lib/lp/registry/browser/tests/test_codeofconduct.py'
543--- lib/lp/registry/browser/tests/test_codeofconduct.py 1970-01-01 00:00:00 +0000
544+++ lib/lp/registry/browser/tests/test_codeofconduct.py 2010-10-15 01:29:43 +0000
545@@ -0,0 +1,149 @@
546+# Copyright 2010 Canonical Ltd. This software is licensed under the
547+# GNU Affero General Public License version 3 (see the file LICENSE).
548+
549+"""Tests for Code of Conduct views."""
550+
551+__metaclass__ = type
552+
553+from zope.component import getUtility
554+
555+from canonical.testing.layers import DatabaseFunctionalLayer
556+from lp.registry.interfaces.codeofconduct import ISignedCodeOfConductSet
557+from lp.registry.model.codeofconduct import SignedCodeOfConduct
558+from lp.testing import (
559+ login_celebrity,
560+ TestCaseWithFactory,
561+ )
562+from lp.testing.views import create_initialized_view
563+
564+
565+class TestSignedCodeOfConductAckView(TestCaseWithFactory):
566+
567+ layer = DatabaseFunctionalLayer
568+
569+ def setUp(self):
570+ super(TestSignedCodeOfConductAckView, self).setUp()
571+ self.signed_coc_set = getUtility(ISignedCodeOfConductSet)
572+ self.owner = self.factory.makePerson()
573+ self.admin = login_celebrity('admin')
574+
575+ def test_view_properties(self):
576+ view = create_initialized_view(self.signed_coc_set, name="+new")
577+ self.assertEqual(
578+ 'Register a code of conduct signature', view.label)
579+ self.assertEqual(view.label, view.page_title)
580+ self.assertEqual(['owner'], view.field_names)
581+ url = 'http://launchpad.dev/codeofconduct/console'
582+ self.assertEqual(url, view.next_url)
583+ self.assertEqual(url, view.cancel_url)
584+
585+ def test_register_coc_signed_on_paper(self):
586+ form = {
587+ 'field.owner': self.owner.name,
588+ 'field.actions.add': 'Register',
589+ }
590+ view = create_initialized_view(
591+ self.signed_coc_set, name="+new", form=form,
592+ principal=self.admin)
593+ self.assertEqual([], view.errors)
594+ results = self.signed_coc_set.searchByUser(self.owner.id)
595+ self.assertEqual(1, results.count())
596+ signed_coc = results[0]
597+ self.assertEqual(self.admin, signed_coc.recipient)
598+
599+
600+class SignCodeOfConductTestCase(TestCaseWithFactory):
601+
602+ layer = DatabaseFunctionalLayer
603+
604+ def setUp(self):
605+ super(SignCodeOfConductTestCase, self).setUp()
606+ user = self.factory.makePerson()
607+ gpg_key = self.factory.makeGPGKey(user)
608+ self.signed_coc = self.sign_coc(user, gpg_key)
609+ self.admin = login_celebrity('admin')
610+
611+ def sign_coc(self, user, gpg_key):
612+ """Return a SignedCodeOfConduct using dummy text."""
613+ signed_coc = SignedCodeOfConduct(
614+ owner=user, signingkey=gpg_key,
615+ signedcode="Dummy CoC signed text.", active=True)
616+ return signed_coc
617+
618+ def verify_common_view_properties(self, view):
619+ self.assertEqual(['admincomment'], view.field_names)
620+ self.assertEqual(
621+ view.page_title, view.label)
622+ url = 'http://launchpad.dev/codeofconduct/console/%d' % (
623+ self.signed_coc.id)
624+ self.assertEqual(url, view.next_url)
625+ self.assertEqual(url, view.cancel_url)
626+
627+ def verify_admincomment_required(self, action_name, view_name):
628+ # Empty comments are not permitted for any state change.
629+ form = {
630+ 'field.admincomment': '',
631+ 'field.actions.change': action_name,
632+ }
633+ view = create_initialized_view(
634+ self.signed_coc, name=view_name, form=form,
635+ principal=self.admin)
636+ self.assertEqual(1, len(view.errors))
637+ self.assertEqual('admincomment', view.errors[0].field_name)
638+
639+
640+class TestSignedCodeOfConductActiveView(SignCodeOfConductTestCase):
641+
642+ def test_view_properties(self):
643+ self.signed_coc.active = False
644+ view = create_initialized_view(self.signed_coc, name="+activate")
645+ self.assertEqual(
646+ 'Activate code of conduct signature', view.label)
647+ self.assertTrue(view.state)
648+ self.verify_common_view_properties(view)
649+
650+ def test_activate(self):
651+ self.signed_coc.active = False
652+ form = {
653+ 'field.admincomment': 'The user is sorry.',
654+ 'field.actions.change': 'Activate',
655+ }
656+ view = create_initialized_view(
657+ self.signed_coc, name="+activate", form=form,
658+ principal=self.admin)
659+ self.assertEqual([], view.errors)
660+ self.assertTrue(self.signed_coc.active)
661+ self.assertEqual(self.admin, self.signed_coc.recipient)
662+ self.assertEqual(
663+ 'The user is sorry.', self.signed_coc.admincomment)
664+
665+ def test_admincomment_required(self):
666+ self.verify_admincomment_required('Activate', '+activate')
667+
668+
669+class TestSignedCodeOfConductDeactiveView(SignCodeOfConductTestCase):
670+
671+ def test_view_properties(self):
672+ self.signed_coc.active = True
673+ view = create_initialized_view(self.signed_coc, name="+deactivate")
674+ self.assertEqual(
675+ 'Deactivate code of conduct signature', view.label)
676+ self.assertFalse(view.state)
677+ self.verify_common_view_properties(view)
678+
679+ def test_deactivate(self):
680+ self.signed_coc.active = True
681+ form = {
682+ 'field.admincomment': 'The user is bad.',
683+ 'field.actions.change': 'Deactivate',
684+ }
685+ view = create_initialized_view(
686+ self.signed_coc, name="+deactivate", form=form,
687+ principal=self.admin)
688+ self.assertEqual([], view.errors)
689+ self.assertFalse(self.signed_coc.active)
690+ self.assertEqual(
691+ 'The user is bad.', self.signed_coc.admincomment)
692+
693+ def test_admincomment_required(self):
694+ self.verify_admincomment_required('Deactivate', '+deactivate')
695
696=== modified file 'lib/lp/registry/stories/gpg-coc/98-cocacknowledge.txt'
697--- lib/lp/registry/stories/gpg-coc/98-cocacknowledge.txt 2009-08-18 14:17:32 +0000
698+++ lib/lp/registry/stories/gpg-coc/98-cocacknowledge.txt 2010-10-15 01:29:43 +0000
699@@ -1,41 +1,42 @@
700 Check to see no CoC signature is registered for Mark:
701
702- >>> admin_browser.open('http://localhost:9000/codeofconduct/console')
703- >>> admin_browser.getControl(name='searchfor').value = ["all"]
704- >>> admin_browser.getControl(name='name').value = "mark"
705- >>> admin_browser.getControl(name='search').click()
706- >>> "No signatures found." in admin_browser.contents
707- True
708+ >>> admin_browser.open('http://localhost:9000/codeofconduct/console')
709+ >>> admin_browser.getControl(name='searchfor').value = ["all"]
710+ >>> admin_browser.getControl(name='name').value = "mark"
711+ >>> admin_browser.getControl(name='search').click()
712+ >>> "No signatures found." in admin_browser.contents
713+ True
714
715 Perform Acknowledge process as Foo bar person:
716
717- >>> admin_browser.open('http://localhost:9000/codeofconduct/console/+new')
718- >>> admin_browser.title
719- 'Register a code of conduct signature'
720+ >>> admin_browser.open('http://localhost:9000/codeofconduct/console/+new')
721+ >>> admin_browser.title
722+ 'Register a code of conduct signature'
723
724- >>> admin_browser.getControl(name='field.owner').value = "mark@example.com"
725- >>> admin_browser.getControl(name='UPDATE_SUBMIT').click()
726- >>> admin_browser.url
727- 'http://localhost:9000/codeofconduct/console/'
728+ >>> admin_browser.getControl(
729+ ... name='field.owner').value = "mark@example.com"
730+ >>> admin_browser.getControl('Register').click()
731+ >>> admin_browser.url
732+ 'http://localhost:9000/codeofconduct/console'
733
734 Ensure the CoC was acknowledge by searching in the CoC Admin Console:
735
736- >>> admin_browser.open('http://launchpad.dev/codeofconduct/console')
737- >>> admin_browser.getControl(name='searchfor').value = ["all"]
738- >>> admin_browser.getControl(name='name').value = "mark"
739- >>> admin_browser.getControl(name='search').click()
740- >>> print extract_text(find_tag_by_id(admin_browser.contents, 'matches'))
741- Mark ... paper submission accepted by Foo Bar [ACTIVE]
742+ >>> admin_browser.open('http://launchpad.dev/codeofconduct/console')
743+ >>> admin_browser.getControl(name='searchfor').value = ["all"]
744+ >>> admin_browser.getControl(name='name').value = "mark"
745+ >>> admin_browser.getControl(name='search').click()
746+ >>> print extract_text(find_tag_by_id(admin_browser.contents, 'matches'))
747+ Mark ... paper submission accepted by Foo Bar [ACTIVE]
748
749 Test if the advertisement email was sent:
750
751- >>> import email
752- >>> from lp.services.mail import stub
753- >>> from_addr, to_addrs, raw_msg = stub.test_emails.pop()
754- >>> msg = email.message_from_string(raw_msg)
755- >>> print msg.get_payload(decode=True)
756- <BLANKLINE>
757- ...
758- User: 'Mark Shuttleworth'
759- Paper Submitted acknowledge by Foo Bar
760- ...
761+ >>> import email
762+ >>> from lp.services.mail import stub
763+ >>> from_addr, to_addrs, raw_msg = stub.test_emails.pop()
764+ >>> msg = email.message_from_string(raw_msg)
765+ >>> print msg.get_payload(decode=True)
766+ <BLANKLINE>
767+ ...
768+ User: 'Mark Shuttleworth'
769+ Paper Submitted acknowledge by Foo Bar
770+ ...
771
772=== removed file 'lib/lp/registry/templates/signedcodeofconduct-acknowledge.pt'
773--- lib/lp/registry/templates/signedcodeofconduct-acknowledge.pt 2009-08-17 15:36:10 +0000
774+++ lib/lp/registry/templates/signedcodeofconduct-acknowledge.pt 1970-01-01 00:00:00 +0000
775@@ -1,16 +0,0 @@
776-<html
777- xmlns="http://www.w3.org/1999/xhtml"
778- xmlns:tal="http://xml.zope.org/namespaces/tal"
779- xmlns:metal="http://xml.zope.org/namespaces/metal"
780- xmlns:i18n="http://xml.zope.org/namespaces/i18n"
781- metal:use-macro="view/macro:page/locationless"
782- i18n:domain="launchpad"
783->
784- <body>
785- <div metal:fill-slot="main">
786- <div metal:use-macro="context/@@launchpad_addform/addform"/>
787- </div>
788- </body>
789- </html>
790-
791-
792
793=== removed file 'lib/lp/registry/templates/signedcodeofconduct-activate.pt'
794--- lib/lp/registry/templates/signedcodeofconduct-activate.pt 2009-08-17 15:36:10 +0000
795+++ lib/lp/registry/templates/signedcodeofconduct-activate.pt 1970-01-01 00:00:00 +0000
796@@ -1,16 +0,0 @@
797-<html
798- xmlns="http://www.w3.org/1999/xhtml"
799- xmlns:tal="http://xml.zope.org/namespaces/tal"
800- xmlns:metal="http://xml.zope.org/namespaces/metal"
801- xmlns:i18n="http://xml.zope.org/namespaces/i18n"
802- metal:use-macro="view/macro:page/locationless"
803- i18n:domain="launchpad"
804->
805- <body>
806- <div metal:fill-slot="main">
807- <div metal:use-macro="context/@@launchpad_editform/editform"/>
808- </div>
809- </body>
810- </html>
811-
812-
813
814=== removed file 'lib/lp/registry/templates/signedcodeofconduct-deactivate.pt'
815--- lib/lp/registry/templates/signedcodeofconduct-deactivate.pt 2009-08-17 15:36:10 +0000
816+++ lib/lp/registry/templates/signedcodeofconduct-deactivate.pt 1970-01-01 00:00:00 +0000
817@@ -1,16 +0,0 @@
818-<html
819- xmlns="http://www.w3.org/1999/xhtml"
820- xmlns:tal="http://xml.zope.org/namespaces/tal"
821- xmlns:metal="http://xml.zope.org/namespaces/metal"
822- xmlns:i18n="http://xml.zope.org/namespaces/i18n"
823- metal:use-macro="view/macro:page/locationless"
824- i18n:domain="launchpad"
825->
826- <body>
827- <div metal:fill-slot="main">
828- <div metal:use-macro="context/@@launchpad_editform/editform"/>
829- </div>
830- </body>
831- </html>
832-
833-