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

Side by Side Diff: sitescripts/formmail/web/formmail2.py

Issue 29374647: Issue 4814 - Adds csv log to formmail2 (Closed) Base URL: https://hg.adblockplus.org/sitescripts
Patch Set: Created March 23, 2017, 2:33 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
OLDNEW
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-2017 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 from __future__ import print_function
Sebastian Noack 2017/03/23 15:27:58 Nit: There should be a blank line above.
Jon Sonesen 2017/03/23 18:42:16 Done.
15 16
17 import os
18 import sys
16 import datetime 19 import datetime
20 import traceback
17 import collections 21 import collections
22 from csv import DictWriter, DictReader
23
24 import jinja2
18 25
19 from sitescripts.utils import (get_config, sendMail, encode_email_address, 26 from sitescripts.utils import (get_config, sendMail, encode_email_address,
20 get_template) 27 get_template)
21 from sitescripts.web import registerUrlHandler, form_handler 28 from sitescripts.web import registerUrlHandler, form_handler
22 29
23 30
24 def get_config_items(): 31 def get_config_items():
25 config = get_config() 32 config = get_config()
26 default_keys = set(config.defaults()) 33 default_keys = set(config.defaults())
27 for name, value in config.items('formmail2'): 34 for name, value in config.items('formmail2'):
(...skipping 18 matching lines...) Expand all
46 store_value(conf_dict, path, value) 53 store_value(conf_dict, path, value)
47 return conf_dict 54 return conf_dict
48 55
49 56
50 def make_error(spec, check_type, default_message): 57 def make_error(spec, check_type, default_message):
51 if check_type in spec: 58 if check_type in spec:
52 return spec[check_type].value 59 return spec[check_type].value
53 return default_message 60 return default_message
54 61
55 62
63 def log_formfield_error(parameters, log_path):
64 err_file = os.path.basename(log_path) + '_error'
65 err_path = os.path.join(os.path.dirname(log_path), err_file)
66 if os.path.isfile(err_path):
67 with open(err_path, 'a') as error_log:
68 writer = DictWriter(error_log, fieldnames=parameters.keys())
69 writer.writerow(parameters)
70 raise Exception('Field names have changed, error log '
71 'appended to ' + err_path)
72 with open(err_path, 'w') as error_log:
73 writer = DictWriter(error_log, fieldnames=parameters.keys())
74 writer.writeheader()
75 writer.writerow(parameters)
76 raise Exception('Field names have changed, error log '
77 'written to ' + err_path)
78
79
80 def log_formdata(params, path):
81 if os.path.isfile(path):
82 with open(path, 'ab+') as formlog:
83 formlog.seek(0)
84 reader = DictReader(formlog)
85 if reader.fieldnames != params.keys():
86 log_formfield_error(params, path)
87 formlog.seek(os.SEEK_END)
88 writer = DictWriter(formlog, fieldnames=params.keys())
89 writer.writerow(params)
90 return
91 with open(path, 'w') as new_formlog:
92 writer = DictWriter(new_formlog, fieldnames=params.keys())
93 writer.writeheader()
94 writer.writerow(params)
95 return
96
97
98 def validate_fields(fields, params):
99 errors = []
100 for field, spec in fields.items():
101 if 'mandatory' in spec.value and field not in params:
102 errors.append(make_error(spec, 'mandatory',
103 'No {} entered'.format(field)))
104 if 'email' in spec.value and field in params:
105 try:
106 params[field] = encode_email_address(params[field])
107 except ValueError:
108 errors.append(make_error(spec, 'email', 'Invalid email'))
109
110 unexpected_fields = ' '.join(set(params.keys()) - set(fields.keys()))
111 if unexpected_fields:
112 errors.append('Unexpected field/fields: ' + str(unexpected_fields))
113 return errors
114
115
56 def make_handler(name, config): 116 def make_handler(name, config):
57 try: 117 try:
58 url = config['url'].value 118 url = config['url'].value
59 except (KeyError, AttributeError): 119 except (KeyError, AttributeError):
60 raise Exception('No URL configured for form handler: ' + name) 120 raise Exception('No URL configured for form handler: ' + name)
61 try: 121 try:
62 template = config['template'].value 122 template = config['template'].value
63 get_template(template, autoescape=False) 123 get_template(template, autoescape=False)
64 except (KeyError, AttributeError): 124 except (KeyError, AttributeError):
65 raise Exception('No template configured for form handler: ' + name) 125 raise Exception('No template configured for form handler: ' + name)
126 except (jinja2.TemplateNotFound):
127 raise Exception('Template not found at: ' + template)
66 try: 128 try:
67 fields = config['fields'] 129 fields = config['fields']
68 for field, spec in fields.items(): 130 for field, spec in fields.items():
69 spec.value = {s.strip() for s in spec.value.split(',')} 131 spec.value = {s.strip() for s in spec.value.split(',')}
70 except KeyError: 132 except KeyError:
71 raise Exception('No fields configured for form handler: ' + name) 133 raise Exception('No fields configured for form handler: ' + name)
72 if len(fields) == 0: 134 if len(fields) == 0:
73 raise Exception('No fields configured for form handler: ' + name) 135 raise Exception('No fields configured for form handler: ' + name)
74 136
75 @form_handler 137 @form_handler
76 def handler(environ, start_response, params): 138 def handler(environ, start_response, params):
77 response_headers = [('Content-Type', 'text/plain; charset=utf-8')] 139 response_headers = [('Content-Type', 'text/plain; charset=utf-8')]
78 errors = [] 140 errors = validate_fields(fields, params)
79 for field, spec in fields.items():
80 if 'mandatory' in spec.value:
81 if field not in params.keys():
82 errors.append(make_error(spec, 'mandatory',
83 'No {} entered'.format(field)))
84 if 'email' in spec.value and field in params.keys():
85 try:
86 params[field] = encode_email_address(params[field])
87 except ValueError:
88 errors.append(make_error(spec, 'email', 'Invalid email'))
89 if errors: 141 if errors:
90 start_response('400 Bad Request', response_headers) 142 start_response('400 Bad Request', response_headers)
91 return '\n'.join(errors) 143 return '\n'.join(errors)
92 144 time = datetime.datetime.now()
93 template_args = { 145 template_args = {
94 'time': datetime.datetime.now(), 146 'time': time,
95 'fields': {field: params.get(field, '') for field in fields} 147 'fields': {field: params.get(field, '') for field in fields}
96 } 148 }
97 sendMail(template, template_args) 149 try:
150 sendMail(template, template_args)
151 except:
152 print(traceback.print_exc(), file=sys.stderr)
153 start_response('500 Server Error', response_headers)
154 return ''
155 finally:
156 if 'csv_log' in config:
157 params = {field: params.get(field, '').encode('utf8')
158 for field in fields}
159 params['time'] = time
160 log_formdata(params, config['csv_log'].value)
98 start_response('200 OK', response_headers) 161 start_response('200 OK', response_headers)
99 return '' 162 return ''
100 163
101 return url, handler 164 return url, handler
102 165
103 166
104 conf_dict = conf_parse(get_config_items()) 167 conf_dict = conf_parse(get_config_items())
105 for name, config in conf_dict.items(): 168 for name, config in conf_dict.items():
106 url, handler = make_handler(name, config) 169 url, handler = make_handler(name, config)
107 registerUrlHandler(url, handler) 170 registerUrlHandler(url, handler)
OLDNEW

Powered by Google App Engine
This is Rietveld