Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Delta Between Two Patch Sets: sitescripts/formmail/web/formmail2.py

Issue 29374647: Issue 4814 - Adds csv log to formmail2 (Closed) Base URL: https://hg.adblockplus.org/sitescripts
Left Patch Set: Created March 18, 2017, 4:13 p.m.
Right Patch Set: Created March 23, 2017, 6:50 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « sitescripts/formmail/test/test_formmail2.py ('k') | tox.ini » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 # This file is part of the Adblock Plus web scripts, 1 # This file is part of the Adblock Plus web scripts,
2 # Copyright (C) 2006-2016 Eyeo GmbH 2 # Copyright (C) 2006-2017 eyeo GmbH
3 # 3 #
4 # Adblock Plus is free software: you can redistribute it and/or modify 4 # Adblock Plus is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License version 3 as 5 # it under the terms of the GNU General Public License version 3 as
6 # published by the Free Software Foundation. 6 # published by the Free Software Foundation.
7 # 7 #
8 # Adblock Plus is distributed in the hope that it will be useful, 8 # Adblock Plus is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details. 11 # GNU General Public License for more details.
12 # 12 #
13 # You should have received a copy of the GNU General Public License 13 # You should have received a copy of the GNU General Public License
14 # along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. 14 # along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
15
16 from __future__ import print_function
17
15 import os 18 import os
19 import sys
16 import datetime 20 import datetime
21 import traceback
17 import collections 22 import collections
18 from csv import DictWriter, DictReader 23 from csv import DictWriter, DictReader
24
25 import jinja2
19 26
20 from sitescripts.utils import (get_config, sendMail, encode_email_address, 27 from sitescripts.utils import (get_config, sendMail, encode_email_address,
21 get_template) 28 get_template)
22 from sitescripts.web import registerUrlHandler, form_handler 29 from sitescripts.web import registerUrlHandler, form_handler
23 30
24 31
25 def get_config_items(): 32 def get_config_items():
26 config = get_config() 33 config = get_config()
27 default_keys = set(config.defaults()) 34 default_keys = set(config.defaults())
28 for name, value in config.items('formmail2'): 35 for name, value in config.items('formmail2'):
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
69 writer.writerow(parameters) 76 writer.writerow(parameters)
70 raise Exception('Field names have changed, error log ' 77 raise Exception('Field names have changed, error log '
71 'written to ' + err_path) 78 'written to ' + err_path)
72 79
73 80
74 def log_formdata(params, path): 81 def log_formdata(params, path):
75 if os.path.isfile(path): 82 if os.path.isfile(path):
76 with open(path, 'ab+') as formlog: 83 with open(path, 'ab+') as formlog:
77 formlog.seek(0) 84 formlog.seek(0)
78 reader = DictReader(formlog) 85 reader = DictReader(formlog)
79 if reader.fieldnames != params.keys(): 86 if reader.fieldnames != params.keys():
Jon Sonesen 2017/03/22 09:23:30 I think this is incorrect, after some local testin
Jon Sonesen 2017/03/22 14:28:21 Done.
80 log_formfield_error(params, path) 87 log_formfield_error(params, path)
81 formlog.seek(os.SEEK_END) 88 formlog.seek(os.SEEK_END)
82 writer = DictWriter(formlog, fieldnames=params.keys()) 89 writer = DictWriter(formlog, fieldnames=params.keys())
83 writer.writerow(params) 90 writer.writerow(params)
84 return 91 return
85 with open(path, 'w') as new_formlog: 92 with open(path, 'w') as new_formlog:
86 writer = DictWriter(new_formlog, fieldnames=params.keys()) 93 writer = DictWriter(new_formlog, fieldnames=params.keys())
87 writer.writeheader() 94 writer.writeheader()
88 writer.writerow(params) 95 writer.writerow(params)
89 return 96 return
90 97
91 98
92 def validate_fields(fields, params): 99 def validate_fields(fields, params):
93 errors = [] 100 errors = []
94 for field, spec in fields.items(): 101 for field, spec in fields.items():
95 if 'mandatory' in spec.value: 102 if 'mandatory' in spec.value and field not in params:
96 if field not in params.keys():
97 errors.append(make_error(spec, 'mandatory', 103 errors.append(make_error(spec, 'mandatory',
98 'No {} entered'.format(field))) 104 'No {} entered'.format(field)))
99 if 'email' in spec.value and field in params.keys(): 105 if 'email' in spec.value and field in params:
100 try: 106 try:
101 params[field] = encode_email_address(params[field]) 107 params[field] = encode_email_address(params[field])
102 except ValueError: 108 except ValueError:
103 errors.append(make_error(spec, 'email', 'Invalid email')) 109 errors.append(make_error(spec, 'email', 'Invalid email'))
110
111 unexpected_fields = ' '.join(set(params.keys()) - set(fields.keys()))
112 if unexpected_fields:
113 errors.append('Unexpected field/fields: ' + str(unexpected_fields))
104 return errors 114 return errors
105 115
106 116
107 def make_handler(name, config): 117 def make_handler(name, config):
108 try: 118 try:
109 url = config['url'].value 119 url = config['url'].value
110 except (KeyError, AttributeError): 120 except (KeyError, AttributeError):
111 raise Exception('No URL configured for form handler: ' + name) 121 raise Exception('No URL configured for form handler: ' + name)
112 try: 122 try:
113 template = config['template'].value 123 template = config['template'].value
114 get_template(template, autoescape=False) 124 get_template(template, autoescape=False)
115 except (KeyError, AttributeError): 125 except (KeyError, AttributeError):
116 raise Exception('No template configured for form handler: ' + name) 126 raise Exception('No template configured for form handler: ' + name)
127 except (jinja2.TemplateNotFound):
128 raise Exception('Template not found at: ' + template)
117 try: 129 try:
118 fields = config['fields'] 130 fields = config['fields']
119 for field, spec in fields.items(): 131 for field, spec in fields.items():
120 spec.value = {s.strip() for s in spec.value.split(',')} 132 spec.value = {s.strip() for s in spec.value.split(',')}
121 except KeyError: 133 except KeyError:
122 raise Exception('No fields configured for form handler: ' + name) 134 raise Exception('No fields configured for form handler: ' + name)
123 if len(fields) == 0: 135 if len(fields) == 0:
124 raise Exception('No fields configured for form handler: ' + name) 136 raise Exception('No fields configured for form handler: ' + name)
125 137
126 @form_handler 138 @form_handler
127 def handler(environ, start_response, params): 139 def handler(environ, start_response, params):
128 response_headers = [('Content-Type', 'text/plain; charset=utf-8')] 140 response_headers = [('Content-Type', 'text/plain; charset=utf-8')]
129 errors = validate_fields(fields, params) 141 errors = validate_fields(fields, params)
130 if errors: 142 if errors:
131 start_response('400 Bad Request', response_headers) 143 start_response('400 Bad Request', response_headers)
132 return '\n'.join(errors) 144 return '\n'.join(errors)
133 time = datetime.datetime.now() 145 time = datetime.datetime.now()
134 template_args = { 146 template_args = {
135 'time': time, 147 'time': time,
136 'fields': {field: params.get(field, '') for field in fields} 148 'fields': {field: params.get(field, '') for field in fields}
137 } 149 }
138 try: 150 try:
139 sendMail(template, template_args) 151 sendMail(template, template_args)
140 except: 152 except:
153 print(traceback.print_exc(), file=sys.stderr)
141 start_response('500 Server Error', response_headers) 154 start_response('500 Server Error', response_headers)
Vasily Kuznetsov 2017/03/21 14:00:35 I wonder if we could log the stacktrace here someh
Jon Sonesen 2017/03/22 14:28:21 Done.
142 return '' 155 return ''
143 finally: 156 finally:
144 if 'csv_log' in config: 157 if 'csv_log' in config:
145 params = {field: params.get(field, '').encode('utf8') 158 params = {field: params.get(field, '').encode('utf8')
146 for field in fields} 159 for field in fields}
147 params['time'] = time 160 params['time'] = time
148 log_formdata(params, config['csv_log'].value) 161 log_formdata(params, config['csv_log'].value)
149 start_response('200 OK', response_headers) 162 start_response('200 OK', response_headers)
150 return '' 163 return ''
151 164
152 return url, handler 165 return url, handler
153 166
154 167
155 conf_dict = conf_parse(get_config_items()) 168 conf_dict = conf_parse(get_config_items())
156 for name, config in conf_dict.items(): 169 for name, config in conf_dict.items():
157 url, handler = make_handler(name, config) 170 url, handler = make_handler(name, config)
158 registerUrlHandler(url, handler) 171 registerUrlHandler(url, handler)
LEFTRIGHT

Powered by Google App Engine
This is Rietveld