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

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

Issue 29984580: Issue 4413 - Merge formmail.py and formmail2.py (Closed) Base URL: https://hg.adblockplus.org/sitescripts/
Patch Set: Start the README Created Jan. 18, 2019, 12:44 a.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
(Empty)
1 # This file is part of the Adblock Plus web scripts,
2 # Copyright (C) 2006-present eyeo GmbH
3 #
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
6 # published by the Free Software Foundation.
7 #
8 # Adblock Plus is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
12 #
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/>.
15
16 from __future__ import print_function
17
18 import os
19 import sys
20 import datetime
21 import traceback
22 import collections
23 from csv import DictWriter, DictReader
24
25 import jinja2
26
27 from sitescripts.utils import (get_config, sendMail, encode_email_address,
28 get_template)
29 from sitescripts.web import registerUrlHandler, form_handler
30
31
32 def get_config_items():
33 config = get_config()
34 default_keys = set(config.defaults())
35 for name, value in config.items('formmail2'):
36 if name not in default_keys:
37 yield name, value
38
39
40 def store_value(conf_dict, path, value):
41 head, tail = path[0], path[1:]
42 if head not in conf_dict:
43 conf_dict[head] = collections.OrderedDict()
44 if tail:
45 store_value(conf_dict[head], tail, value)
46 else:
47 conf_dict[head].value = value
48
49
50 def conf_parse(conf_items):
51 conf_dict = collections.OrderedDict()
52 for key, value in conf_items:
53 path = key.split('.')
54 store_value(conf_dict, path, value)
55 return conf_dict
56
57
58 def make_error(spec, check_type, default_message):
59 if check_type in spec:
60 return spec[check_type].value
61 return default_message
62
63
64 def log_formfield_error(parameters, log_path):
65 err_file = os.path.basename(log_path) + '_error'
66 err_path = os.path.join(os.path.dirname(log_path), err_file)
67 if os.path.isfile(err_path):
68 with open(err_path, 'a') as error_log:
69 writer = DictWriter(error_log, fieldnames=parameters.keys())
70 writer.writerow(parameters)
71 raise Exception('Field names have changed, error log '
72 'appended to ' + err_path)
73 with open(err_path, 'w') as error_log:
74 writer = DictWriter(error_log, fieldnames=parameters.keys())
75 writer.writeheader()
76 writer.writerow(parameters)
77 raise Exception('Field names have changed, error log '
78 'written to ' + err_path)
79
80
81 def log_formdata(params, path):
82 if os.path.isfile(path):
83 with open(path, 'ab+') as formlog:
84 formlog.seek(0)
85 reader = DictReader(formlog)
86 if reader.fieldnames != params.keys():
87 log_formfield_error(params, path)
88 formlog.seek(os.SEEK_END)
89 writer = DictWriter(formlog, fieldnames=params.keys())
90 writer.writerow(params)
91 return
92 with open(path, 'w') as new_formlog:
93 writer = DictWriter(new_formlog, fieldnames=params.keys())
94 writer.writeheader()
95 writer.writerow(params)
96 return
97
98
99 def validate_fields(fields, params):
100 errors = []
101 for field, spec in fields.items():
102 if 'mandatory' in spec.value and field not in params:
103 errors.append(make_error(spec, 'mandatory',
104 'No {} entered'.format(field)))
105 if 'email' in spec.value and field in params:
106 try:
107 params[field] = encode_email_address(params[field])
108 except ValueError:
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))
114 return errors
115
116
117 def make_handler(name, config):
118 try:
119 url = config['url'].value
120 except (KeyError, AttributeError):
121 raise Exception('No URL configured for form handler: ' + name)
122 try:
123 template = config['template'].value
124 get_template(template, autoescape=False)
125 except (KeyError, AttributeError):
126 raise Exception('No template configured for form handler: ' + name)
127 except jinja2.TemplateNotFound:
128 raise Exception('Template not found at: ' + template)
129 try:
130 fields = config['fields']
131 for field, spec in fields.items():
132 spec.value = {s.strip() for s in spec.value.split(',')}
133 except KeyError:
134 raise Exception('No fields configured for form handler: ' + name)
135 if len(fields) == 0:
136 raise Exception('No fields configured for form handler: ' + name)
137
138 @form_handler
139 def handler(environ, start_response, params):
140 response_headers = [('Content-Type', 'text/plain; charset=utf-8')]
141 errors = validate_fields(fields, params)
142 if errors:
143 start_response('400 Bad Request', response_headers)
144 return '\n'.join(errors)
145 time = datetime.datetime.now()
146 template_args = {
147 'time': time,
148 'fields': {field: params.get(field, '') for field in fields},
149 }
150 try:
151 sendMail(template, template_args)
152 except:
153 print(traceback.print_exc(), file=sys.stderr)
154 start_response('500 Server Error', response_headers)
155 return ''
156 finally:
157 if 'csv_log' in config:
158 params = {field: params.get(field, '').encode('utf8')
159 for field in fields}
160 params['time'] = time
161 log_formdata(params, config['csv_log'].value)
162 start_response('200 OK', response_headers)
163 return ''
164
165 return url, handler
166
167
168 conf_dict = conf_parse(get_config_items())
169 for name, config in conf_dict.items():
170 url, handler = make_handler(name, config)
171 registerUrlHandler(url, handler)
OLDNEW

Powered by Google App Engine
This is Rietveld