Merge lp:~jfb-tempo-consulting/unifield-web/us-812 into lp:unifield-web
- us-812
- Merge into trunk
Proposed by
jftempo
Status: | Merged |
---|---|
Merged at revision: | 4778 |
Proposed branch: | lp:~jfb-tempo-consulting/unifield-web/us-812 |
Merge into: | lp:unifield-web |
Diff against target: |
599 lines (+353/-29) 11 files modified
addons/openerp/controllers/actions.py (+20/-6) addons/openerp/controllers/database.py (+44/-11) addons/openerp/utils/serve_file.py (+142/-0) addons/openerp/utils/tools.py (+2/-1) doc/openerp-web-oc.cfg (+5/-0) doc/openerp-web-win.cfg (+93/-0) doc/openerp-web.cfg (+2/-1) openobject/__init__.py (+6/-3) openobject/commands.py (+32/-3) openobject/tools/_expose.py (+4/-2) setup.nsi (+3/-2) |
To merge this branch: | bzr merge lp:~jfb-tempo-consulting/unifield-web/us-812 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
UniField Reviewer Team | Pending | ||
Review via email: mp+283073@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'addons/openerp/controllers/actions.py' |
2 | --- addons/openerp/controllers/actions.py 2015-12-18 16:10:29 +0000 |
3 | +++ addons/openerp/controllers/actions.py 2016-01-19 10:40:01 +0000 |
4 | @@ -27,7 +27,7 @@ |
5 | import zlib |
6 | |
7 | import cherrypy |
8 | -from openerp.utils import rpc, common, expr_eval, TinyDict |
9 | +from openerp.utils import rpc, common, expr_eval, TinyDict, is_server_local, serve_file |
10 | |
11 | from form import Form |
12 | from openobject import tools |
13 | @@ -36,6 +36,7 @@ |
14 | from wizard import Wizard |
15 | import urllib |
16 | import re |
17 | +import os |
18 | |
19 | def execute_window(view_ids, model, res_id=False, domain=None, view_type='form', context=None, |
20 | mode='form,tree', name=None, target=None, limit=None, search_view=None, |
21 | @@ -127,17 +128,29 @@ |
22 | } |
23 | |
24 | def _print_data(data): |
25 | - |
26 | - if 'result' not in data: |
27 | + if 'result' not in data and 'path' not in data: |
28 | raise common.message(_('Error no report')) |
29 | |
30 | + cherrypy.response.headers['Content-Type'] = PRINT_FORMATS[data['format']] |
31 | if data.get('code','normal')=='zlib': |
32 | import zlib |
33 | content = zlib.decompress(base64.decodestring(data['result'])) |
34 | else: |
35 | + if not data.get('result') and data.get('path'): |
36 | + try: |
37 | + return serve_file.serve_file(data['path'], "application/x-download", 'attachment', delete=data.get('delete', False)) |
38 | + except Exception, e: |
39 | + cherrypy.response.headers['Content-Type'] = 'text/html' |
40 | + if 'Content-Disposition' in cherrypy.response.headers: |
41 | + del(cherrypy.response.headers['Content-Disposition']) |
42 | + raise common.warning(e) |
43 | + finally: |
44 | + if data.get('delete', False) and os.path.exists(data['path']): |
45 | + os.remove(data['path']) |
46 | +# return cherrypy.lib.static.serve_file(data['path'], "application/x-download", 'attachment') |
47 | + |
48 | content = base64.decodestring(data['result']) |
49 | |
50 | - cherrypy.response.headers['Content-Type'] = PRINT_FORMATS[data['format']] |
51 | return content |
52 | |
53 | def execute_report(name, **data): |
54 | @@ -162,6 +175,8 @@ |
55 | try: |
56 | ctx = dict(rpc.session.context) |
57 | ctx.update(datas.get('context', {})) |
58 | + if is_server_local(): |
59 | + ctx['report_fromfile'] = 1 |
60 | report_id = rpc.session.execute('report', 'report', name, ids, datas, ctx) |
61 | state = False |
62 | attempt = 0 |
63 | @@ -189,8 +204,7 @@ |
64 | if datas.get('force_attach'): |
65 | attachment = 'attachment;' |
66 | if background_id: |
67 | - bg_report = rpc.session.execute('object', 'execute', 'memory.background.report', 'write', [background_id], {'report_id': report_id, 'report_name': report_name}) |
68 | - |
69 | + bg_report = rpc.session.execute('object', 'execute', 'memory.background.report', 'write', [background_id], {'report_id': background_id, 'report_name': report_name}) |
70 | |
71 | while not state: |
72 | val = rpc.session.execute('report', 'report_get', report_id) |
73 | |
74 | === modified file 'addons/openerp/controllers/database.py' |
75 | --- addons/openerp/controllers/database.py 2015-05-28 10:07:02 +0000 |
76 | +++ addons/openerp/controllers/database.py 2016-01-19 10:40:01 +0000 |
77 | @@ -21,6 +21,7 @@ |
78 | import base64 |
79 | import re |
80 | import time |
81 | +import os |
82 | |
83 | import cherrypy |
84 | import formencode |
85 | @@ -31,7 +32,9 @@ |
86 | import openobject.errors |
87 | |
88 | from openerp import validators |
89 | -from openerp.utils import rpc, get_server_version |
90 | +from openerp.utils import rpc, get_server_version, is_server_local, serve_file |
91 | +from tempfile import NamedTemporaryFile |
92 | +import shutil |
93 | |
94 | def get_lang_list(): |
95 | langs = [('en_US', 'English (US)')] |
96 | @@ -94,14 +97,19 @@ |
97 | fields = [openobject.widgets.SelectField(name='dbname', options=get_db_list, label=_('Database:'), validator=validators.String(not_empty=True)), |
98 | openobject.widgets.PasswordField(name='password', label=_('Backup password:'), validator=formencode.validators.NotEmpty())] |
99 | |
100 | +class FileField(openobject.widgets.FileField): |
101 | + def adjust_value(self, value, **params): |
102 | + return False |
103 | + |
104 | class FormRestore(DBForm): |
105 | name = "restore" |
106 | string = _('Restore database') |
107 | action = '/openerp/database/do_restore' |
108 | submit_text = _('Restore') |
109 | - fields = [openobject.widgets.FileField(name="filename", label=_('File:')), |
110 | + fields = [FileField(name="filename", label=_('File:')), |
111 | openobject.widgets.PasswordField(name='password', label=_('Restore password:'), validator=formencode.validators.NotEmpty()), |
112 | openobject.widgets.TextField(name='dbname', label=_('New database name:'), validator=formencode.validators.NotEmpty(), readonly=1, attrs={'readonly': ''})] |
113 | + hidden_fields = [openobject.widgets.HiddenField(name='fpath', label=_('Path:'))] |
114 | |
115 | class FormPassword(DBForm): |
116 | name = "password" |
117 | @@ -245,15 +253,24 @@ |
118 | def do_backup(self, dbname, password, **kw): |
119 | self.msg = {} |
120 | try: |
121 | - res = rpc.session.execute_db('dump', password, dbname) |
122 | filename = [dbname, time.strftime('%Y%m%d-%H%M%S')] |
123 | version = get_server_version() |
124 | if version: |
125 | filename.append(version) |
126 | - if res: |
127 | - cherrypy.response.headers['Content-Type'] = "application/data" |
128 | - cherrypy.response.headers['Content-Disposition'] = 'filename="%s.dump"' % '-'.join(filename) |
129 | - return base64.decodestring(res) |
130 | + |
131 | + if is_server_local(): |
132 | + res = rpc.session.execute_db('dump_file', password, dbname) |
133 | + try: |
134 | + return serve_file.serve_file(res, "application/x-download", 'attachment', '%s.dump' % '-'.join(filename), delete=True) |
135 | + finally: |
136 | + if os.path.exists(res): |
137 | + os.remove(res) |
138 | + else: |
139 | + res = rpc.session.execute_db('dump', password, dbname) |
140 | + if res: |
141 | + cherrypy.response.headers['Content-Type'] = "application/data" |
142 | + cherrypy.response.headers['Content-Disposition'] = 'filename="%s.dump"' % '-'.join(filename) |
143 | + return base64.decodestring(res) |
144 | except openobject.errors.AccessDenied, e: |
145 | self.msg = {'message': _('Wrong password'), |
146 | 'title' : e.title} |
147 | @@ -293,14 +310,30 @@ |
148 | 'title': _('Error')} |
149 | return self.restore() |
150 | try: |
151 | - data = base64.encodestring(filename.file.read()) |
152 | - rpc.session.execute_db('restore', password, dbname, data) |
153 | + if is_server_local(): |
154 | + if not filename.filename and kw.get('fpath'): |
155 | + filename = kw.get('fpath') |
156 | + else: |
157 | + newfile = NamedTemporaryFile(delete=False) |
158 | + shutil.copyfileobj(filename.file, newfile) |
159 | + filename = newfile.name |
160 | + newfile.close() |
161 | + rpc.session.execute_db('restore_file', password, dbname, filename) |
162 | + else: |
163 | + data = base64.encodestring(filename.file.read()) |
164 | + rpc.session.execute_db('restore', password, dbname, data) |
165 | except openobject.errors.AccessDenied, e: |
166 | self.msg = {'message': _('Wrong password'), |
167 | 'title' : e.title} |
168 | + if hasattr(cherrypy.request, 'input_values') and filename: |
169 | + cherrypy.request.input_values['fpath'] = filename |
170 | return self.restore() |
171 | - except Exception: |
172 | - self.msg = {'message': _("Could not restore database")} |
173 | + except Exception, e: |
174 | + msg = _("Could not restore database") |
175 | + if isinstance(e, openobject.errors.TinyException): |
176 | + if 'Database already exists' in e.message: |
177 | + msg = _("Could not restore: database already exists") |
178 | + self.msg = {'message': msg} |
179 | return self.restore() |
180 | raise redirect('/openerp/login', db=dbname) |
181 | |
182 | |
183 | === added file 'addons/openerp/utils/serve_file.py' |
184 | --- addons/openerp/utils/serve_file.py 1970-01-01 00:00:00 +0000 |
185 | +++ addons/openerp/utils/serve_file.py 2016-01-19 10:40:01 +0000 |
186 | @@ -0,0 +1,142 @@ |
187 | +import mimetypes |
188 | +mimetypes.init() |
189 | +mimetypes.types_map['.dwg']='image/x-dwg' |
190 | +mimetypes.types_map['.ico']='image/x-icon' |
191 | + |
192 | +import os |
193 | +import re |
194 | +import stat |
195 | +import time |
196 | +import urllib |
197 | +import tempfile |
198 | +import cherrypy |
199 | +from cherrypy.lib import cptools, http, file_generator_limited |
200 | + |
201 | +def serve_file(path, content_type=None, disposition=None, name=None, delete=False): |
202 | + """Set status, headers, and body in order to serve the given file. |
203 | + |
204 | + The Content-Type header will be set to the content_type arg, if provided. |
205 | + If not provided, the Content-Type will be guessed by the file extension |
206 | + of the 'path' argument. |
207 | + |
208 | + If disposition is not None, the Content-Disposition header will be set |
209 | + to "<disposition>; filename=<name>". If name is None, it will be set |
210 | + to the basename of path. If disposition is None, no Content-Disposition |
211 | + header will be written. |
212 | + """ |
213 | + |
214 | + response = cherrypy.response |
215 | + |
216 | + # If path is relative, users should fix it by making path absolute. |
217 | + # That is, CherryPy should not guess where the application root is. |
218 | + # It certainly should *not* use cwd (since CP may be invoked from a |
219 | + # variety of paths). If using tools.static, you can make your relative |
220 | + # paths become absolute by supplying a value for "tools.static.root". |
221 | + if not os.path.isabs(path): |
222 | + raise ValueError("'%s' is not an absolute path." % path) |
223 | + |
224 | + try: |
225 | + st = os.stat(path) |
226 | + except OSError: |
227 | + raise cherrypy.NotFound() |
228 | + |
229 | + # Check if path is a directory. |
230 | + if stat.S_ISDIR(st.st_mode): |
231 | + # Let the caller deal with it as they like. |
232 | + raise cherrypy.NotFound() |
233 | + |
234 | + # Set the Last-Modified response header, so that |
235 | + # modified-since validation code can work. |
236 | + response.headers['Last-Modified'] = http.HTTPDate(st.st_mtime) |
237 | + cptools.validate_since() |
238 | + |
239 | + if content_type is None: |
240 | + # Set content-type based on filename extension |
241 | + ext = "" |
242 | + i = path.rfind('.') |
243 | + if i != -1: |
244 | + ext = path[i:].lower() |
245 | + content_type = mimetypes.types_map.get(ext, "text/plain") |
246 | + response.headers['Content-Type'] = content_type |
247 | + |
248 | + if disposition is not None: |
249 | + if name is None: |
250 | + name = os.path.basename(path) |
251 | + cd = '%s; filename="%s"' % (disposition, name) |
252 | + response.headers["Content-Disposition"] = cd |
253 | + |
254 | + # Set Content-Length and use an iterable (file object) |
255 | + # this way CP won't load the whole file in memory |
256 | + c_len = st.st_size |
257 | + if delete: |
258 | + flag = os.O_RDWR | os.O_EXCL |
259 | + if hasattr(os, 'O_BINARY'): |
260 | + flag |= os.O_BINARY |
261 | + if os.name == 'nt': |
262 | + flag |= os.O_TEMPORARY |
263 | + fd = os.open(path, flag) |
264 | + file = os.fdopen(fd, 'rb') |
265 | + bodyfile = file |
266 | + else: |
267 | + bodyfile = open(path, 'rb') |
268 | + |
269 | + # HTTP/1.0 didn't have Range/Accept-Ranges headers, or the 206 code |
270 | + if cherrypy.request.protocol >= (1, 1): |
271 | + response.headers["Accept-Ranges"] = "bytes" |
272 | + r = http.get_ranges(cherrypy.request.headers.get('Range'), c_len) |
273 | + if r == []: |
274 | + response.headers['Content-Range'] = "bytes */%s" % c_len |
275 | + message = "Invalid Range (first-byte-pos greater than Content-Length)" |
276 | + raise cherrypy.HTTPError(416, message) |
277 | + if r: |
278 | + if len(r) == 1: |
279 | + # Return a single-part response. |
280 | + start, stop = r[0] |
281 | + if stop > c_len: |
282 | + stop = c_len |
283 | + r_len = stop - start |
284 | + response.status = "206 Partial Content" |
285 | + response.headers['Content-Range'] = ("bytes %s-%s/%s" % |
286 | + (start, stop - 1, c_len)) |
287 | + response.headers['Content-Length'] = r_len |
288 | + bodyfile.seek(start) |
289 | + response.body = file_generator_limited(bodyfile, r_len) |
290 | + else: |
291 | + # Return a multipart/byteranges response. |
292 | + response.status = "206 Partial Content" |
293 | + import mimetools |
294 | + boundary = mimetools.choose_boundary() |
295 | + ct = "multipart/byteranges; boundary=%s" % boundary |
296 | + response.headers['Content-Type'] = ct |
297 | + if response.headers.has_key("Content-Length"): |
298 | + # Delete Content-Length header so finalize() recalcs it. |
299 | + del response.headers["Content-Length"] |
300 | + |
301 | + def file_ranges(): |
302 | + # Apache compatibility: |
303 | + yield "\r\n" |
304 | + |
305 | + for start, stop in r: |
306 | + yield "--" + boundary |
307 | + yield "\r\nContent-type: %s" % content_type |
308 | + yield ("\r\nContent-range: bytes %s-%s/%s\r\n\r\n" |
309 | + % (start, stop - 1, c_len)) |
310 | + bodyfile.seek(start) |
311 | + for chunk in file_generator_limited(bodyfile, stop-start): |
312 | + yield chunk |
313 | + yield "\r\n" |
314 | + # Final boundary |
315 | + yield "--" + boundary + "--" |
316 | + |
317 | + # Apache compatibility: |
318 | + yield "\r\n" |
319 | + response.body = file_ranges() |
320 | + else: |
321 | + response.headers['Content-Length'] = c_len |
322 | + response.body = bodyfile |
323 | + else: |
324 | + response.headers['Content-Length'] = c_len |
325 | + response.body = bodyfile |
326 | + response.stream = True |
327 | + return response.body |
328 | + |
329 | |
330 | === modified file 'addons/openerp/utils/tools.py' |
331 | --- addons/openerp/utils/tools.py 2011-06-30 13:58:31 +0000 |
332 | +++ addons/openerp/utils/tools.py 2016-01-19 10:40:01 +0000 |
333 | @@ -253,5 +253,6 @@ |
334 | def __deepcopy__(self, visit): |
335 | return self |
336 | |
337 | - |
338 | +def is_server_local(): |
339 | + return cherrypy.config.get('openerp.server.host') in ['127.0.0.1', 'localhost'] |
340 | # vim: ts=4 sts=4 sw=4 si et |
341 | |
342 | === added file 'doc/openerp-web-oc.cfg' |
343 | --- doc/openerp-web-oc.cfg 1970-01-01 00:00:00 +0000 |
344 | +++ doc/openerp-web-oc.cfg 2016-01-19 10:40:01 +0000 |
345 | @@ -0,0 +1,5 @@ |
346 | +[global] |
347 | + |
348 | +# Web tcp/port, default port is 8061 |
349 | +#server.socket_port = 8061 |
350 | + |
351 | |
352 | === added file 'doc/openerp-web-win.cfg' |
353 | --- doc/openerp-web-win.cfg 1970-01-01 00:00:00 +0000 |
354 | +++ doc/openerp-web-win.cfg 2016-01-19 10:40:01 +0000 |
355 | @@ -0,0 +1,93 @@ |
356 | +[global] |
357 | +server.environment = "development" |
358 | + |
359 | +# Some server parameters that you may want to tweak |
360 | +server.socket_host = "0.0.0.0" |
361 | +server.socket_port = 8061 |
362 | + |
363 | +# Sets the number of threads the server uses |
364 | +server.thread_pool = 40 |
365 | + |
366 | +tools.sessions.on = True |
367 | +tools.sessions.persistent = False |
368 | + |
369 | +# Simple code profiling |
370 | +server.profile_on = False |
371 | +server.profile_dir = "profile" |
372 | +# Max size: 10GB |
373 | +server.max_request_body_size = 10737418240 |
374 | +# disable monitor which raises an error at the end of the request |
375 | +engine.timeout_monitor.on = False |
376 | + |
377 | +# if this is part of a larger site, you can set the path |
378 | +# to the TurboGears instance here |
379 | +#server.webpath = "" |
380 | + |
381 | +# Set to True if you are deploying your App behind a proxy |
382 | +# e.g. Apache using mod_proxy |
383 | +#tools.proxy.on = True |
384 | + |
385 | +# If your proxy does not add the X-Forwarded-Host header, set |
386 | +# the following to the *public* host url. |
387 | +#tools.proxy.base = 'http://mydomain.com' |
388 | + |
389 | +# logging |
390 | +#log.screen = False |
391 | +#log.access_file = "/var/log/openerp-web/access.log" |
392 | +#log.error_file = "/var/log/openerp-web/error.log" |
393 | +log.error_file = "../ServerLog/openerp-web.log" |
394 | +log.access_level = "INFO" |
395 | +log.error_level = "INFO" |
396 | +# Replaces the cherrypy-created FileHandler by a TimedRotatingFileHandler, |
397 | +# requires that access_file and error_file be uncommented and set correctly |
398 | +# (they will be used to configure the rotating file handlers). |
399 | +# Value should be a dictionary providing TimedRotatingFileHandler's optional |
400 | +# arguments (any argument can be provided but `filename`). |
401 | +# See the documentation at http://docs.python.org/library/logging.handlers.html#logging.handlers.TimedRotatingFileHandler |
402 | +# for more informations on TimedRotatingFileHandler |
403 | +log.rotate = {'when' : 'D'} |
404 | + |
405 | +# Set to false to disable CSRF checks |
406 | +tools.csrf.on = True |
407 | + |
408 | +# replace builtin traceback tools by cgitb |
409 | +tools.log_tracebacks.on: False |
410 | +tools.cgitb.on: True |
411 | +# a default install can probably avoid logging those via cgitb as they're |
412 | +# available in the server log |
413 | +tools.cgitb.ignore=( |
414 | + openobject.errors.Concurrency, |
415 | + openobject.errors.TinyException) |
416 | + |
417 | +# if enable this force cookie to be sent over a secure channel 'ssl' |
418 | +# (make sure you site is reachable on https before activating this) |
419 | +#tools.secure_cookies.on = True |
420 | + |
421 | +# if enable for browse who understand this, the cookie will not be |
422 | +# readable by scripts, see: http://www.owasp.org/index.php/HttpOnly |
423 | +tools.httponly_cookies.on = True |
424 | + |
425 | +# fix support of cherrpy 3.1.2 tools.sessions.persistant = False |
426 | +tools.fix_312_session_persistent.on = True |
427 | + |
428 | +# OpenERP Server |
429 | +openerp.server.host = 'localhost' |
430 | +openerp.server.port = '8070' |
431 | +openerp.server.protocol = 'socket' |
432 | +openerp.server.timeout = 1800 |
433 | + |
434 | +# Web client settings |
435 | +[openerp-web] |
436 | +# filter dblists based on url pattern? |
437 | +# NONE: No Filter |
438 | +# EXACT: Exact Hostname |
439 | +# UNDERSCORE: Hostname_ |
440 | +# BOTH: Exact Hostname or Hostname_ |
441 | + |
442 | +dblist.filter = 'NONE' |
443 | + |
444 | +# whether to show Databases button on Login screen or not |
445 | +dbbutton.visible = True |
446 | + |
447 | +# will be applied on company logo |
448 | +company.url = '' |
449 | |
450 | === modified file 'doc/openerp-web.cfg' |
451 | --- doc/openerp-web.cfg 2015-10-01 08:55:14 +0000 |
452 | +++ doc/openerp-web.cfg 2016-01-19 10:40:01 +0000 |
453 | @@ -14,7 +14,8 @@ |
454 | # Simple code profiling |
455 | server.profile_on = False |
456 | server.profile_dir = "profile" |
457 | -server.max_request_body_size = 209715200 |
458 | +# Max size: 10GB |
459 | +server.max_request_body_size = 10737418240 |
460 | # disable monitor which raises an error at the end of the request |
461 | engine.timeout_monitor.on = False |
462 | |
463 | |
464 | === modified file 'openobject/__init__.py' |
465 | --- openobject/__init__.py 2011-06-22 09:35:20 +0000 |
466 | +++ openobject/__init__.py 2016-01-19 10:40:01 +0000 |
467 | @@ -128,8 +128,11 @@ |
468 | error_handler = handlers.TimedRotatingFileHandler(error_file, **rotate) |
469 | error_handler.setLevel(error_level) |
470 | log.error_log.addHandler(error_handler) |
471 | + log.error_file = '' |
472 | |
473 | # Make a new RotatingFileHandler for the access log. |
474 | - access_handler = handlers.TimedRotatingFileHandler(access_file, **rotate) |
475 | - access_handler.setLevel(access_level) |
476 | - log.access_log.addHandler(access_handler) |
477 | + if access_file: |
478 | + access_handler = handlers.TimedRotatingFileHandler(access_file, **rotate) |
479 | + access_handler.setLevel(access_level) |
480 | + log.access_log.addHandler(access_handler) |
481 | + log.access_file = '' |
482 | |
483 | === modified file 'openobject/commands.py' |
484 | --- openobject/commands.py 2013-02-04 11:48:01 +0000 |
485 | +++ openobject/commands.py 2016-01-19 10:40:01 +0000 |
486 | @@ -19,6 +19,15 @@ |
487 | |
488 | DISTRIBUTION_CONFIG = os.path.join('doc', 'openerp-web.cfg') |
489 | FROZEN_DISTRIBUTION_CONFIG = os.path.join('conf', 'openerp-web.cfg') |
490 | +OVERRIDE_CONFIG = os.path.join('conf', 'openerp-web-oc.cfg') |
491 | +def get_config_override_file(): |
492 | + if hasattr(sys, 'frozen'): |
493 | + configfile = os.path.join(openobject.paths.root(), OVERRIDE_CONFIG) |
494 | + if os.path.exists(configfile): |
495 | + return configfile |
496 | + |
497 | + return False |
498 | + |
499 | def get_config_file(): |
500 | if hasattr(sys, 'frozen'): |
501 | configfile = os.path.join(openobject.paths.root(), FROZEN_DISTRIBUTION_CONFIG) |
502 | @@ -37,6 +46,8 @@ |
503 | parser = OptionParser(version="%s" % (openobject.release.version)) |
504 | parser.add_option("-c", "--config", metavar="FILE", dest="config", |
505 | help="configuration file", default=get_config_file()) |
506 | + parser.add_option("--config-override", metavar="FILE", dest="config_override", |
507 | + help="override configuration file", default=get_config_override_file()) |
508 | parser.add_option("-a", "--address", help="host address, overrides server.socket_host") |
509 | parser.add_option("-p", "--port", help="port number, overrides server.socket_port") |
510 | parser.add_option("--openerp-host", dest="openerp_host", help="overrides openerp.server.host") |
511 | @@ -50,13 +61,26 @@ |
512 | if not os.path.exists(options.config): |
513 | raise ConfigurationError(_("Could not find configuration file: %s") % |
514 | options.config) |
515 | - |
516 | + |
517 | + error_config = False |
518 | app_config = as_dict(options.config) |
519 | - |
520 | + if options.config_override: |
521 | + try: |
522 | + over_config = as_dict(options.config_override) |
523 | + for section, value in over_config.iteritems(): |
524 | + app_config.setdefault(section, {}).update(value) |
525 | + except Exception, error_config: |
526 | + pass |
527 | openobject.configure(app_config) |
528 | + |
529 | + if error_config: |
530 | + cherrypy.log('Unable to parse %s\nError: %s' % (options.config_override, error_config), "ERROR") |
531 | + raise ConfigurationError(_("Unable to parse: %s") % |
532 | + options.config_override) |
533 | + |
534 | if options.static: |
535 | openobject.enable_static_paths() |
536 | - |
537 | + |
538 | if options.address: |
539 | cherrypy.config['server.socket_host'] = options.address |
540 | if options.port: |
541 | @@ -64,6 +88,11 @@ |
542 | cherrypy.config['server.socket_port'] = int(options.port) |
543 | except: |
544 | pass |
545 | + port = cherrypy.config.get('server.socket_port') |
546 | + if not isinstance(port, (int, long)) or port < 1 or port > 65535: |
547 | + cherrypy.log('Wrong configuration socket_port: %s' % (port,), "ERROR") |
548 | + raise ConfigurationError(_("Wrong configuration socket_port: %s") % |
549 | + port) |
550 | if options.openerp_host: |
551 | cherrypy.config['openerp.server.host'] = options.openerp_host |
552 | if options.openerp_port: |
553 | |
554 | === modified file 'openobject/tools/_expose.py' |
555 | --- openobject/tools/_expose.py 2011-01-20 18:50:26 +0000 |
556 | +++ openobject/tools/_expose.py 2016-01-19 10:40:01 +0000 |
557 | @@ -29,7 +29,8 @@ |
558 | from openobject import i18n |
559 | import _utils as utils |
560 | import resources |
561 | - |
562 | +import types |
563 | +import tempfile |
564 | |
565 | __all__ = ['load_template', 'render_template', 'expose', 'register_template_vars'] |
566 | |
567 | @@ -220,7 +221,8 @@ |
568 | jset.add(script) |
569 | |
570 | return render_template(_template, res).encode("utf-8") |
571 | - |
572 | + if isinstance(res, types.GeneratorType) and hasattr(res, '__name__') and res.__name__ == 'file_generator': |
573 | + return res |
574 | if not isinstance(res, basestring): |
575 | return unicode(res).encode("utf-8") |
576 | |
577 | |
578 | === modified file 'setup.nsi' |
579 | --- setup.nsi 2010-12-29 19:48:48 +0000 |
580 | +++ setup.nsi 2016-01-19 10:40:01 +0000 |
581 | @@ -151,7 +151,8 @@ |
582 | File "win32\stop.bat" |
583 | |
584 | SetOutPath "$INSTDIR\conf" |
585 | - File "/oname=openerp-web.cfg" ".\doc\openerp-web.cfg" |
586 | + File "/oname=openerp-web.cfg" ".\doc\openerp-web-win.cfg" |
587 | + File "/oname=openerp-web-oc.cfg" ".\doc\openerp-web-oc.cfg" |
588 | |
589 | !insertmacro MUI_STARTMENU_WRITE_BEGIN Application |
590 | ;Create shortcuts |
591 | @@ -159,7 +160,7 @@ |
592 | |
593 | CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Start OpenERP Web.lnk" "$INSTDIR\service\start.bat" |
594 | CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Stop OpenERP Web.lnk" "$INSTDIR\service\stop.bat" |
595 | - CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Edit Web Config.lnk" "notepad.exe" "$INSTDIR\conf\openerp-web.cfg" |
596 | + CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Edit Web Config.lnk" "notepad.exe" "$INSTDIR\conf\openerp-web-oc.cfg" |
597 | CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\uninstall.exe" |
598 | !insertmacro CreateInternetShortcut "$SMPROGRAMS\$STARTMENU_FOLDER\Forum" "http://www.openerp.com/forum" |
599 | !insertmacro CreateInternetShortcut "$SMPROGRAMS\$STARTMENU_FOLDER\Translation" "https://translations.launchpad.net/openobject" |