Merge lp:~aelkner/schooltool/cambodia_fixes into lp:schooltool/1.7

Proposed by Alan Elkner
Status: Rejected
Rejected by: Justas Sadzevičius
Proposed branch: lp:~aelkner/schooltool/cambodia_fixes
Merge into: lp:schooltool/1.7
Diff against target: 433 lines (+253/-16)
10 files modified
buildout.cfg (+5/-1)
src/schooltool/app/browser/ftests/setup.py (+2/-1)
src/schooltool/course/browser/section.py (+1/-1)
src/schooltool/email/browser/email.py (+4/-1)
src/schooltool/email/browser/ftests/__init__.py (+5/-0)
src/schooltool/email/browser/ftests/email.txt (+79/-8)
src/schooltool/email/browser/templates/email_form.pt (+113/-1)
src/schooltool/email/mail.py (+9/-3)
src/schooltool/skin/templates/widget_macros.pt (+33/-0)
src/schooltool/testing/analyze.py (+2/-0)
To merge this branch: bzr merge lp:~aelkner/schooltool/cambodia_fixes
Reviewer Review Type Date Requested Status
Justas Sadzevičius (community) Disapprove
Review via email: mp+20834@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Justas Sadzevičius (justas.sadzevicius) wrote :

Changes not needed anymore.

review: Disapprove

Unmerged revisions

2636. By Alan Elkner <aelkner@ubuntu>

changes needed for cambodia

2635. By Alan Elkner <aelkner@ubuntu>

created series of traversal adapters to allow access to messages and goals
updated security.txt tests, getting rid of XXX comments that were no longer needed
reversed order of evolve4 and evolve5 due to tricky persons_responsible get/set property
fixed permission to message and goal views to be schooltool.view as they should be
removed various security proxies to get to student data

2634. By Justas Sadzevičius

Merge Alan's widget macros.

2633. By Justas Sadzevičius

Merge mail enhancments by Douglas:
Douglas Cerna 2010-02-15 Changed the SMTPDataError message id
Douglas Cerna 2010-02-03 Formatted email form notifications (#497492)
Douglas Cerna 2010-02-03 Handled SMTPDataError exceptions
Douglas Cerna 2010-01-31 Handled empty required fields in the Send Test view

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'buildout.cfg'
2--- buildout.cfg 2010-01-21 17:15:59 +0000
3+++ buildout.cfg 2010-03-06 21:34:21 +0000
4@@ -1,6 +1,10 @@
5 [buildout]
6 extends = base.cfg
7-develop = .
8+develop = . ../schooltool.lyceum.journal ../schooltool.intervention ../schooltool.gradebook
9
10 [package]
11 eggs = schooltool
12+ schooltool.gradebook
13+ schooltool.intervention
14+ schooltool.lyceum.journal
15+
16
17=== modified file 'src/schooltool/app/browser/ftests/setup.py'
18--- src/schooltool/app/browser/ftests/setup.py 2009-06-24 13:58:38 +0000
19+++ src/schooltool/app/browser/ftests/setup.py 2010-03-06 21:34:21 +0000
20@@ -81,7 +81,7 @@
21 manager.getLink('Resource', index=2).click()
22 assert title in manager.contents
23
24-def addCourse(title, schoolyear, description=""):
25+def addCourse(title, schoolyear, description="", credits=''):
26 """Add a course."""
27 manager = logInManager()
28 manager.getLink('Manage').click()
29@@ -91,6 +91,7 @@
30 manager.getLink('New Course').click()
31 manager.getControl('Title').value = title
32 manager.getControl('Description').value = description
33+ manager.getControl('Credits').value = credits
34 manager.getControl('Add').click()
35
36 def addSection(course, schoolyear, term, title=None, instructors=[], members=[]):
37
38=== modified file 'src/schooltool/course/browser/section.py'
39--- src/schooltool/course/browser/section.py 2010-01-19 12:09:22 +0000
40+++ src/schooltool/course/browser/section.py 2010-03-06 21:34:21 +0000
41@@ -304,12 +304,12 @@
42 terms = self.term_subform.terms
43 if course is None or not terms:
44 return None
45+ section.courses.add(removeSecurityProxy(course))
46
47 # add the section to the first term
48 sections = ISectionContainer(terms[0])
49 name = INameChooser(sections).chooseName('', section)
50 sections[name] = section
51- section.courses.add(removeSecurityProxy(course))
52
53 # overwrite section title.
54 section.title = "%s (%s)" % (course.title, section.__name__)
55
56=== modified file 'src/schooltool/email/browser/email.py'
57--- src/schooltool/email/browser/email.py 2009-10-19 12:32:19 +0000
58+++ src/schooltool/email/browser/email.py 2010-03-06 21:34:21 +0000
59@@ -487,7 +487,10 @@
60
61 @button.buttonAndHandler(_('Send'))
62 def handle_send_action(self, action):
63- data, some = self.extractData()
64+ data, errors = self.extractData()
65+ if errors:
66+ self.status = _('There were some errors.')
67+ return
68 from_address = data['from_address']
69 to_addresses = [address.strip()
70 for address in data['to_addresses'].split(',')]
71
72=== modified file 'src/schooltool/email/browser/ftests/__init__.py'
73--- src/schooltool/email/browser/ftests/__init__.py 2009-10-19 12:32:19 +0000
74+++ src/schooltool/email/browser/ftests/__init__.py 2010-03-06 21:34:21 +0000
75@@ -65,6 +65,11 @@
76 'addresses': 'foo@example.com, bar@example.com'})
77 return False
78
79+ # If fakes a unexpected data error
80+ if "bad data" in email.body:
81+ self.queue(email, 70, {'info': server_info})
82+ return False
83+
84 # It fakes a bad username for login
85 if self.container.username == 'wronguser':
86 self.queue(email, 40, {'info': server_info,
87
88=== modified file 'src/schooltool/email/browser/ftests/email.txt'
89--- src/schooltool/email/browser/ftests/email.txt 2009-12-24 15:25:47 +0000
90+++ src/schooltool/email/browser/ftests/email.txt 2010-03-06 21:34:21 +0000
91@@ -86,6 +86,13 @@
92 >>> manager.getControl('Hostname').value = 'localhost'
93 >>> manager.getControl('Apply').click()
94
95+We see a confirmation message:
96+
97+ >>> manager.printQuery('id("message")')
98+ <div id="message">
99+ <div class="summary">Data successfully updated.</div>
100+ </div>
101+
102 Note that just setting up the hostname for the SMTP server enables the
103 service:
104
105@@ -481,8 +488,8 @@
106 >>> manager.getControl('New Password', index=1).value = 'secret'
107 >>> manager.getControl('Confirm New Password').value = 'public'
108 >>> manager.getControl('Apply').click()
109- >>> manager.printQuery('//div[@class="status"]')
110- <div class="status">
111+ >>> manager.printQuery('id("message")')
112+ <div id="message">
113 <div class="summary">There were some errors.</div>
114 <ul class="errors"><li>
115 <div class="error">New passwords don't match</div>
116@@ -543,9 +550,49 @@
117 >>> manager.getControl('Username').value = 'rightuser'
118 >>> manager.getControl('Apply').click()
119
120-And Retry our lastest email:
121-
122- >>> manager.getLink('Queue (5 failed)').click()
123+And let's raise an unexpected data error:
124+
125+ >>> manager.getLink('Send Test').click()
126+ >>> manager.getControl('From').value = 'anotheraddress@example.com'
127+ >>> manager.getControl('To').value = 'agoodaddress@example.com'
128+ >>> manager.getControl('Subject').value = "This is bad"
129+ >>> manager.getControl('Body').value = 'This is bad data on the message'
130+ >>> manager.getControl('Send').click()
131+
132+ >>> manager.printQuery('//form/table[@class="data"]/tbody/tr[1]/td')
133+ <td>
134+ <input type="checkbox" name="delete.Email-6" id="delete.Email-6" /></td>
135+ <td>
136+ <a href="http://localhost/email/Email-6">anotheraddress@example.com</a>
137+ </td>
138+ <td>
139+ agoodaddress@example.com
140+ </td>
141+ <td>
142+ This is bad
143+ </td>
144+ <td>
145+ ...
146+ </td>
147+ <td>
148+ ...
149+ </td>
150+
151+ >>> manager.getLink('anotheraddress@example.com').click()
152+
153+ >>> # EMAIL STATUS
154+ >>> manager.printQuery('id("form-widgets-status-row")//label')
155+ <label for="form-widgets-status">
156+ <span>Email Status</span>
157+ </label>
158+ >>> manager.printQuery('id("form-widgets-status-row")/'
159+ ... 'div[@class="widget"]/span')
160+ <span id="form-widgets-status" class="..." style="color: red;">The server (localhost:25) replied that the message data was malformed</span>
161+ >>> manager.getControl('Cancel').click()
162+
163+Let's Retry one of our previous emails:
164+
165+ >>> manager.getLink('Queue (6 failed)').click()
166 >>> manager.getControl(name='delete.Email-5').value = True
167 >>> manager.getControl('Retry').click()
168
169@@ -554,9 +601,10 @@
170
171 >>> manager.printQuery('id("content-nav-group")/div[@class="content-nav"][1]')
172 <div class="content-nav">
173- <a href="http://localhost/email/index.html">Queue (4 failed)</a>
174+ <a href="http://localhost/email/index.html">Queue (5 failed)</a>
175 </div>
176 >>> manager.printQuery('//form/table[@class="data"]/tbody/tr/td[1]/input')
177+ <input type="checkbox" name="delete.Email-6" id="delete.Email-6" />
178 <input type="checkbox" name="delete.Email-4" id="delete.Email-4" />
179 <input type="checkbox" name="delete.Email-3" id="delete.Email-3" />
180 <input type="checkbox" name="delete.Email-2" id="delete.Email-2" />
181@@ -569,9 +617,10 @@
182
183 >>> manager.printQuery('id("content-nav-group")/div[@class="content-nav"][1]')
184 <div class="content-nav">
185- <a href="http://localhost/email/index.html">Queue (3 failed)</a>
186+ <a href="http://localhost/email/index.html">Queue (4 failed)</a>
187 </div>
188 >>> manager.printQuery('//form/table[@class="data"]/tbody/tr/td[1]/input')
189+ <input type="checkbox" name="delete.Email-6" id="delete.Email-6" />
190 <input type="checkbox" name="delete.Email-4" id="delete.Email-4" />
191 <input type="checkbox" name="delete.Email-3" id="delete.Email-3" />
192 <input type="checkbox" name="delete.Email" id="delete.Email" />
193@@ -591,7 +640,29 @@
194
195 >>> manager.printQuery('id("content-nav-group")/div[@class="content-nav"][1]')
196 <div class="content-nav">
197- <a href="http://localhost/email/index.html">Queue (1 failed)</a>
198+ <a href="http://localhost/email/index.html">Queue (2 failed)</a>
199 </div>
200 >>> manager.printQuery('//form/table[@class="data"]/tbody/tr/td[1]/input')
201+ <input type="checkbox" name="delete.Email-6" id="delete.Email-6" />
202 <input type="checkbox" name="delete.Email-3" id="delete.Email-3" />
203+
204+Now, let's handle empty values in the Send Test form:
205+
206+ >>> manager.getLink('Send Test').click()
207+ >>> manager.getControl('Send').click()
208+ >>> manager.printQuery('id("message")')
209+ <div id="message">
210+ <div class="summary">There were some errors.</div>
211+ <ul class="errors"><li>
212+ From:
213+ <div class="error">Required input is missing.</div>
214+ </li>
215+ <li>
216+ To:
217+ <div class="error">Required input is missing.</div>
218+ </li>
219+ <li>
220+ Body:
221+ <div class="error">Required input is missing.</div>
222+ </li>
223+ </ul></div>
224
225=== modified file 'src/schooltool/email/browser/templates/email_form.pt'
226--- src/schooltool/email/browser/templates/email_form.pt 2009-10-19 12:32:19 +0000
227+++ src/schooltool/email/browser/templates/email_form.pt 2010-03-06 21:34:21 +0000
228@@ -2,7 +2,119 @@
229 <body>
230 <metal:nothing metal:fill-slot="content-header" />
231 <metal:block metal:fill-slot="body">
232- <div metal:use-macro="macro:form" />
233+ <div id="message" tal:condition="view/status">
234+ <div class="summary" i18n:translate="" tal:content="view/status">
235+ Form status summary
236+ </div>
237+ <ul class="errors" tal:condition="view/widgets/errors">
238+ <li tal:repeat="error view/widgets/errors">
239+ <tal:block condition="error/widget">
240+ <span tal:replace="error/widget/label" />:
241+ </tal:block>
242+ <span tal:replace="structure error/render">Error Type</span>
243+ </li>
244+ </ul>
245+ </div>
246+ <form action="." method="post" enctype="multipart/form-data"
247+ class="standalone"
248+ metal:define-macro="form"
249+ tal:attributes="method view/method;
250+ enctype view/enctype;
251+ acceptCharset view/acceptCharset;
252+ accept view/accept;
253+ action view/action;
254+ name view/name;
255+ id view/id">
256+ <metal:subform define-macro="subform">
257+ <div class="viewspace" metal:define-slot="viewspace">
258+ <metal:label define-slot="label">
259+ <h3 metal:define-macro="label"
260+ tal:condition="view/label|nothing"
261+ tal:content="view/label">
262+ Form Label
263+ </h3>
264+ </metal:label>
265+ <metal:info define-slot="info">
266+ <div class="required-info"
267+ metal:define-macro="required-info">
268+ <!--<span class="required">*</span>
269+ &ndash; required -->
270+ </div>
271+ </metal:info>
272+ <div metal:define-slot="extra-info" tal:replace="nothing">
273+ </div>
274+ <div metal:define-slot="main">
275+ <metal:widget-rows define-macro="widget-rows">
276+ <fieldset>
277+ <tal:block repeat="widget view/widgets/values">
278+ <div id="" class="row"
279+ tal:attributes="id string:${widget/id}-row"
280+ tal:condition="python:widget.mode != 'hidden'">
281+ <metal:widget-row define-macro="widget-row">
282+ <div class="label">
283+ <label tal:attributes="for widget/id">
284+ <span i18n:translate=""
285+ tal:content="widget/label">label</span>
286+ <span class="required"
287+ tal:condition="widget/required">*</span>
288+ </label>
289+ </div>
290+ <p class="hint" tal:content="widget/field/description">Description of this field.</p>
291+ <div class="widget" tal:content="structure widget/render">
292+ <input type="text" size="24" value="" />
293+ </div>
294+ <div class="error"
295+ tal:condition="widget/error">
296+ <span tal:replace="structure widget/error/render">error</span>
297+ </div>
298+ </metal:widget-row>
299+ </div>
300+ <input type="hidden" value=""
301+ tal:condition="python:widget.mode == 'hidden'"
302+ tal:replace="structure widget/render" />
303+ </tal:block>
304+
305+ <div metal:define-slot="extra-widgets" tal:replace="nothing">
306+ </div>
307+
308+ </fieldset>
309+ </metal:widget-rows>
310+ <metal:groups define-macro="groups">
311+ <fieldset tal:condition="view/groups|nothing"
312+ tal:repeat="view view/groups">
313+ <legend tal:condition="view/label"
314+ tal:content="view/label">Label</legend>
315+ <metal:group-header define-slot="group-header">
316+ <div class="status"
317+ tal:condition="view/widgets/errors">
318+ <div metal:use-macro="template/macros/errors" />
319+ </div>
320+ </metal:group-header>
321+ <metal:group-rows define-slot="group-rows">
322+ <div metal:use-macro="template/macros/widget-rows" />
323+ </metal:group-rows>
324+ </fieldset>
325+ </metal:groups>
326+ </div>
327+ <metal:above-buttons define-slot="above-buttons">
328+ </metal:above-buttons>
329+ </div>
330+ <metal:buttons define-slot="buttons">
331+ <div metal:define-macro="buttons">
332+ <div class="buttons controls"
333+ metal:define-slot="bottom-buttons">
334+ <tal:block condition="view/actions|nothing">
335+ <input tal:repeat="action view/actions/values"
336+ tal:replace="structure action/render"
337+ />
338+ </tal:block>
339+ </div>
340+ </div>
341+ </metal:buttons>
342+ <metal:bottom define-slot="bottom">
343+ </metal:bottom>
344+ </metal:subform>
345+ </form>
346 </metal:block>
347 </body>
348 </html>
349
350=== modified file 'src/schooltool/email/mail.py'
351--- src/schooltool/email/mail.py 2010-01-19 12:09:22 +0000
352+++ src/schooltool/email/mail.py 2010-03-06 21:34:21 +0000
353@@ -56,6 +56,7 @@
354 50: _('The server (${info}) rejected the From address: ${from_address}'),
355 60: _('The server (${info}) rejected the following recipient addresses: '
356 '${addresses}'),
357+ 70: _('The server (${info}) replied that the message data was malformed'),
358 }
359
360
361@@ -197,9 +198,14 @@
362 'addresses': ', '.join(addresses)})
363 connection.quit()
364 return False
365- # XXX: SMTPDataError is not caught yet.
366- # For one, invalid recipient list may cause it (code 555)
367-
368+ except (smtplib.SMTPHeloError,), e:
369+ self.queue(email, 30, {'info': server_info})
370+ connection.quit()
371+ return False
372+ except (smtplib.SMTPDataError,), e:
373+ self.queue(email, 70, {'info': server_info})
374+ connection.quit()
375+ return False
376 if result:
377 addresses = [address for address in email.to_addresses
378 if address in result.keys()]
379
380=== modified file 'src/schooltool/skin/templates/widget_macros.pt'
381--- src/schooltool/skin/templates/widget_macros.pt 2007-11-14 18:47:28 +0000
382+++ src/schooltool/skin/templates/widget_macros.pt 2010-03-06 21:34:21 +0000
383@@ -20,6 +20,39 @@
384 </div>
385 </metal:block>
386
387+<metal:block define-macro="widget_split_row">
388+ <label for="field.name" title="The widget's hint" style="width: 20em"
389+ tal:condition="widget/label"
390+ tal:attributes="for widget/name; title widget/hint"
391+ tal:content="widget/label">The Label</label>
392+ <p class="hint" tal:condition="widget/hint" tal:content="widget/hint" />
393+ <div class="field">
394+ <input type="text" style="width:100%" tal:replace="structure widget" />
395+ <metal:block define-slot="extra" />
396+ </div>
397+ <div class="clear">&nbsp;</div>
398+ <div class="error" tal:define="error widget/error"
399+ tal:condition="error" tal:content="structure error">
400+ The Error
401+ </div>
402+</metal:block>
403+
404+<metal:block define-macro="widget_fieldset_row">
405+<fieldset>
406+ <legend tal:content="widget/label" />
407+ <p class="hint" tal:condition="widget/hint" tal:content="widget/hint" />
408+ <div class="field">
409+ <input type="text" style="width:100%" tal:replace="structure widget" />
410+ <metal:block define-slot="extra" />
411+ </div>
412+ <div class="clear">&nbsp;</div>
413+ <div class="error" tal:define="error widget/error"
414+ tal:condition="error" tal:content="structure error">
415+ The Error
416+ </div>
417+</fieldset>
418+</metal:block>
419+
420 <div class="field" metal:define-macro="checkbox_widget">
421 <input type="text" tal:replace="structure widget" />
422 <label tal:attributes="for widget/name"
423
424=== modified file 'src/schooltool/testing/analyze.py'
425--- src/schooltool/testing/analyze.py 2009-02-08 02:01:07 +0000
426+++ src/schooltool/testing/analyze.py 2010-03-06 21:34:21 +0000
427@@ -41,5 +41,7 @@
428 def printQuery(xpath, response):
429 """Helper function to print xpath query results on an html response"""
430 for result in queryHTML(xpath, response):
431+ lines = result.splitlines()
432+ result = '\n'.join([line for line in lines if line.strip()])
433 print result
434

Subscribers

People subscribed via source and target branches