30 |
30 |
31 from logilab.common.decorators import cached, cachedproperty |
31 from logilab.common.decorators import cached, cachedproperty |
32 from logilab.common.configuration import merge_options |
32 from logilab.common.configuration import merge_options |
33 |
33 |
34 from cubicweb import ConfigurationError |
34 from cubicweb import ConfigurationError |
35 from cubicweb.toolsutils import read_config |
|
36 from cubicweb.cwconfig import CubicWebConfiguration, register_persistent_options |
35 from cubicweb.cwconfig import CubicWebConfiguration, register_persistent_options |
37 |
36 |
38 |
37 |
39 _DATA_DIR = join(dirname(__file__), 'data') |
38 _DATA_DIR = join(dirname(__file__), 'data') |
40 |
39 |
41 |
40 |
42 register_persistent_options( ( |
41 register_persistent_options(( |
43 # site-wide only web ui configuration |
42 # site-wide only web ui configuration |
44 ('site-title', |
43 ('site-title', |
45 {'type' : 'string', 'default': 'unset title', |
44 {'type': 'string', 'default': 'unset title', |
46 'help': _('site title'), |
45 'help': _('site title'), |
47 'sitewide': True, 'group': 'ui', |
46 'sitewide': True, 'group': 'ui', |
48 }), |
47 }), |
49 ('main-template', |
48 ('main-template', |
50 {'type' : 'string', 'default': 'main-template', |
49 {'type': 'string', 'default': 'main-template', |
51 'help': _('id of main template used to render pages'), |
50 'help': _('id of main template used to render pages'), |
52 'sitewide': True, 'group': 'ui', |
51 'sitewide': True, 'group': 'ui', |
53 }), |
52 }), |
54 # user web ui configuration |
53 # user web ui configuration |
55 ('fckeditor', |
54 ('fckeditor', |
56 {'type' : 'yn', 'default': False, |
55 {'type': 'yn', 'default': False, |
57 'help': _('should html fields being edited using fckeditor (a HTML ' |
56 'help': _('should html fields being edited using fckeditor (a HTML ' |
58 'WYSIWYG editor). You should also select text/html as default ' |
57 'WYSIWYG editor). You should also select text/html as default ' |
59 'text format to actually get fckeditor.'), |
58 'text format to actually get fckeditor.'), |
60 'group': 'ui', |
59 'group': 'ui', |
61 }), |
60 }), |
62 # navigation configuration |
61 # navigation configuration |
63 ('page-size', |
62 ('page-size', |
64 {'type' : 'int', 'default': 40, |
63 {'type': 'int', 'default': 40, |
65 'help': _('maximum number of objects displayed by page of results'), |
64 'help': _('maximum number of objects displayed by page of results'), |
66 'group': 'navigation', |
65 'group': 'navigation', |
67 }), |
66 }), |
68 ('related-limit', |
67 ('related-limit', |
69 {'type' : 'int', 'default': 8, |
68 {'type': 'int', 'default': 8, |
70 'help': _('maximum number of related entities to display in the primary ' |
69 'help': _('maximum number of related entities to display in the primary ' |
71 'view'), |
70 'view'), |
72 'group': 'navigation', |
71 'group': 'navigation', |
73 }), |
72 }), |
74 ('combobox-limit', |
73 ('combobox-limit', |
75 {'type' : 'int', 'default': 20, |
74 {'type': 'int', 'default': 20, |
76 'help': _('maximum number of entities to display in related combo box'), |
75 'help': _('maximum number of entities to display in related combo box'), |
77 'group': 'navigation', |
76 'group': 'navigation', |
78 }), |
77 }), |
79 |
78 |
80 )) |
79 )) |
81 |
80 |
82 |
81 |
83 class BaseWebConfiguration(CubicWebConfiguration): |
82 class BaseWebConfiguration(CubicWebConfiguration): |
84 """Base class for web configurations""" |
83 """Base class for web configurations""" |
85 cubicweb_appobject_path = CubicWebConfiguration.cubicweb_appobject_path | set(['web.views']) |
84 cubicweb_appobject_path = CubicWebConfiguration.cubicweb_appobject_path | set(['web.views']) |
86 cube_appobject_path = CubicWebConfiguration.cube_appobject_path | set(['views']) |
85 cube_appobject_path = CubicWebConfiguration.cube_appobject_path | set(['views']) |
87 |
86 |
88 options = merge_options(CubicWebConfiguration.options + ( |
87 options = merge_options(CubicWebConfiguration.options + ( |
89 ('repository-uri', |
88 ('repository-uri', |
90 {'type' : 'string', |
89 {'type': 'string', |
91 'default': 'inmemory://', |
90 'default': 'inmemory://', |
92 'help': 'see `cubicweb.dbapi.connect` documentation for possible value', |
91 'help': 'see `cubicweb.dbapi.connect` documentation for possible value', |
93 'group': 'web', 'level': 2, |
92 'group': 'web', 'level': 2, |
94 }), |
93 }), |
95 ('use-uicache', |
94 ('use-uicache', |
96 {'type': 'yn', 'default': True, |
95 {'type': 'yn', 'default': True, |
97 'help': _('should css be compiled and store in uicache'), |
96 'help': _('should css be compiled and store in uicache'), |
98 'group': 'ui', 'level': 2, |
97 'group': 'ui', 'level': 2, |
99 }), |
98 }), |
100 ('anonymous-user', |
99 ('anonymous-user', |
101 {'type' : 'string', |
100 {'type': 'string', |
102 'default': None, |
101 'default': None, |
103 'help': 'login of the CubicWeb user account to use for anonymous user (if you want to allow anonymous)', |
102 'help': ('login of the CubicWeb user account to use for anonymous ' |
|
103 'user (if you want to allow anonymous)'), |
104 'group': 'web', 'level': 1, |
104 'group': 'web', 'level': 1, |
105 }), |
105 }), |
106 ('anonymous-password', |
106 ('anonymous-password', |
107 {'type' : 'string', |
107 {'type': 'string', |
108 'default': None, |
108 'default': None, |
109 'help': 'password of the CubicWeb user account to use for anonymous user, ' |
109 'help': 'password of the CubicWeb user account to use for anonymous user, ' |
110 'if anonymous-user is set', |
110 'if anonymous-user is set', |
111 'group': 'web', 'level': 1, |
111 'group': 'web', 'level': 1, |
112 }), |
112 }), |
113 ('query-log-file', |
113 ('query-log-file', |
114 {'type' : 'string', |
114 {'type': 'string', |
115 'default': None, |
115 'default': None, |
116 'help': 'web instance query log file', |
116 'help': 'web instance query log file', |
117 'group': 'web', 'level': 3, |
117 'group': 'web', 'level': 3, |
118 }), |
118 }), |
119 ('cleanup-anonymous-session-time', |
119 ('cleanup-anonymous-session-time', |
120 {'type' : 'time', |
120 {'type': 'time', |
121 'default': '5min', |
121 'default': '5min', |
122 'help': 'Same as cleanup-session-time but specific to anonymous ' |
122 'help': 'Same as cleanup-session-time but specific to anonymous ' |
123 'sessions. You can have a much smaller timeout here since it will be ' |
123 'sessions. You can have a much smaller timeout here since it will be ' |
124 'transparent to the user. Default to 5min.', |
124 'transparent to the user. Default to 5min.', |
125 'group': 'web', 'level': 3, |
125 'group': 'web', 'level': 3, |
157 'If served from a different domain, that domain should allow ' |
156 'If served from a different domain, that domain should allow ' |
158 'cross-origin requests.'), |
157 'cross-origin requests.'), |
159 'group': 'web', |
158 'group': 'web', |
160 }), |
159 }), |
161 ('auth-mode', |
160 ('auth-mode', |
162 {'type' : 'choice', |
161 {'type': 'choice', |
163 'choices' : ('cookie', 'http'), |
162 'choices': ('cookie', 'http'), |
164 'default': 'cookie', |
163 'default': 'cookie', |
165 'help': 'authentication mode (cookie / http)', |
164 'help': 'authentication mode (cookie / http)', |
166 'group': 'web', 'level': 3, |
165 'group': 'web', 'level': 3, |
167 }), |
166 }), |
168 ('realm', |
167 ('realm', |
169 {'type' : 'string', |
168 {'type': 'string', |
170 'default': 'cubicweb', |
169 'default': 'cubicweb', |
171 'help': 'realm to use on HTTP authentication mode', |
170 'help': 'realm to use on HTTP authentication mode', |
172 'group': 'web', 'level': 3, |
171 'group': 'web', 'level': 3, |
173 }), |
172 }), |
174 ('http-session-time', |
173 ('http-session-time', |
175 {'type' : 'time', |
174 {'type': 'time', |
176 'default': 0, |
175 'default': 0, |
177 'help': "duration of the cookie used to store session identifier. " |
176 'help': "duration of the cookie used to store session identifier. " |
178 "If 0, the cookie will expire when the user exist its browser. " |
177 "If 0, the cookie will expire when the user exist its browser. " |
179 "Should be 0 or greater than repository\'s session-time.", |
178 "Should be 0 or greater than repository\'s session-time.", |
180 'group': 'web', 'level': 2, |
179 'group': 'web', 'level': 2, |
181 }), |
180 }), |
182 ('submit-mail', |
181 ('submit-mail', |
183 {'type' : 'string', |
182 {'type': 'string', |
184 'default': None, |
183 'default': None, |
185 'help': ('Mail used as recipient to report bug in this instance, ' |
184 'help': ('Mail used as recipient to report bug in this instance, ' |
186 'if you want this feature on'), |
185 'if you want this feature on'), |
187 'group': 'web', 'level': 2, |
186 'group': 'web', 'level': 2, |
188 }), |
187 }), |
189 |
188 |
190 ('language-mode', |
189 ('language-mode', |
191 {'type' : 'choice', |
190 {'type': 'choice', |
192 'choices': ('http-negotiation', 'url-prefix', ''), |
191 'choices': ('http-negotiation', 'url-prefix', ''), |
193 'default': 'http-negotiation', |
192 'default': 'http-negotiation', |
194 'help': ('source for interface\'s language detection. ' |
193 'help': ('source for interface\'s language detection. ' |
195 'If set to "http-negotiation" the Accept-Language HTTP header will be used,' |
194 'If set to "http-negotiation" the Accept-Language HTTP header will be used,' |
196 ' if set to "url-prefix", the URL will be inspected for a short language prefix.'), |
195 ' if set to "url-prefix", the URL will be inspected for a' |
|
196 ' short language prefix.'), |
197 'group': 'web', 'level': 2, |
197 'group': 'web', 'level': 2, |
198 }), |
198 }), |
199 |
199 |
200 ('print-traceback', |
200 ('print-traceback', |
201 {'type' : 'yn', |
201 {'type': 'yn', |
202 'default': CubicWebConfiguration.mode != 'system', |
202 'default': CubicWebConfiguration.mode != 'system', |
203 'help': 'print the traceback on the error page when an error occurred', |
203 'help': 'print the traceback on the error page when an error occurred', |
204 'group': 'web', 'level': 2, |
204 'group': 'web', 'level': 2, |
205 }), |
205 }), |
206 |
206 |
207 ('captcha-font-file', |
207 ('captcha-font-file', |
208 {'type' : 'string', |
208 {'type': 'string', |
209 'default': join(_DATA_DIR, 'porkys.ttf'), |
209 'default': join(_DATA_DIR, 'porkys.ttf'), |
210 'help': 'True type font to use for captcha image generation (you \ |
210 'help': 'True type font to use for captcha image generation (you \ |
211 must have the python imaging library installed to use captcha)', |
211 must have the python imaging library installed to use captcha)', |
212 'group': 'web', 'level': 3, |
212 'group': 'web', 'level': 3, |
213 }), |
213 }), |
214 ('captcha-font-size', |
214 ('captcha-font-size', |
215 {'type' : 'int', |
215 {'type': 'int', |
216 'default': 25, |
216 'default': 25, |
217 'help': 'Font size to use for captcha image generation (you must \ |
217 'help': 'Font size to use for captcha image generation (you must \ |
218 have the python imaging library installed to use captcha)', |
218 have the python imaging library installed to use captcha)', |
219 'group': 'web', 'level': 3, |
219 'group': 'web', 'level': 3, |
220 }), |
220 }), |
221 |
221 |
222 ('concat-resources', |
222 ('concat-resources', |
223 {'type' : 'yn', |
223 {'type': 'yn', |
224 'default': False, |
224 'default': False, |
225 'help': 'use modconcat-like URLS to concat and serve JS / CSS files', |
225 'help': 'use modconcat-like URLS to concat and serve JS / CSS files', |
226 'group': 'web', 'level': 2, |
226 'group': 'web', 'level': 2, |
227 }), |
227 }), |
228 ('anonymize-jsonp-queries', |
228 ('anonymize-jsonp-queries', |
242 'default': None, |
242 'default': None, |
243 'help': 'The static data resource directory path.', |
243 'help': 'The static data resource directory path.', |
244 'group': 'web', 'level': 2, |
244 'group': 'web', 'level': 2, |
245 }), |
245 }), |
246 ('access-control-allow-origin', |
246 ('access-control-allow-origin', |
247 {'type' : 'csv', |
247 {'type': 'csv', |
248 'default': (), |
248 'default': (), |
249 'help':('comma-separated list of allowed origin domains or "*" for any domain'), |
249 'help': ('comma-separated list of allowed origin domains or "*" for any domain'), |
250 'group': 'web', 'level': 2, |
250 'group': 'web', 'level': 2, |
251 }), |
251 }), |
252 ('access-control-allow-methods', |
252 ('access-control-allow-methods', |
253 {'type' : 'csv', |
253 {'type': 'csv', |
254 'default': (), |
254 'default': (), |
255 'help': ('comma-separated list of allowed HTTP methods'), |
255 'help': ('comma-separated list of allowed HTTP methods'), |
256 'group': 'web', 'level': 2, |
256 'group': 'web', 'level': 2, |
257 }), |
257 }), |
258 ('access-control-max-age', |
258 ('access-control-max-age', |
259 {'type' : 'int', |
259 {'type': 'int', |
260 'default': None, |
260 'default': None, |
261 'help': ('maximum age of cross-origin resource sharing (in seconds)'), |
261 'help': ('maximum age of cross-origin resource sharing (in seconds)'), |
262 'group': 'web', 'level': 2, |
262 'group': 'web', 'level': 2, |
263 }), |
263 }), |
264 ('access-control-expose-headers', |
264 ('access-control-expose-headers', |
265 {'type' : 'csv', |
265 {'type': 'csv', |
266 'default': (), |
266 'default': (), |
267 'help':('comma-separated list of HTTP headers the application declare in response to a preflight request'), |
267 'help': ('comma-separated list of HTTP headers the application ' |
|
268 'declare in response to a preflight request'), |
268 'group': 'web', 'level': 2, |
269 'group': 'web', 'level': 2, |
269 }), |
270 }), |
270 ('access-control-allow-headers', |
271 ('access-control-allow-headers', |
271 {'type' : 'csv', |
272 {'type': 'csv', |
272 'default': (), |
273 'default': (), |
273 'help':('comma-separated list of HTTP headers the application may set in the response'), |
274 'help': ('comma-separated list of HTTP headers the application may set in the response'), |
274 'group': 'web', 'level': 2, |
275 'group': 'web', 'level': 2, |
275 }), |
276 }), |
276 )) |
277 )) |
277 |
278 |
278 def __init__(self, *args, **kwargs): |
279 def __init__(self, *args, **kwargs): |
279 super(WebConfiguration, self).__init__(*args, **kwargs) |
280 super(WebConfiguration, self).__init__(*args, **kwargs) |
280 self.uiprops = None |
281 self.uiprops = None |
281 self.datadir_url = None |
282 self.datadir_url = None |
401 uiprops.load(libuiprops) |
402 uiprops.load(libuiprops) |
402 for path in reversed([self.apphome] + self.cubes_path()): |
403 for path in reversed([self.apphome] + self.cubes_path()): |
403 self._load_ui_properties_file(uiprops, path) |
404 self._load_ui_properties_file(uiprops, path) |
404 self._load_ui_properties_file(uiprops, self.apphome) |
405 self._load_ui_properties_file(uiprops, self.apphome) |
405 datadir_url = uiprops.context['datadir_url'] |
406 datadir_url = uiprops.context['datadir_url'] |
406 if (datadir_url+'/cubicweb.old.css') in uiprops['STYLESHEETS']: |
407 if (datadir_url + '/cubicweb.old.css') in uiprops['STYLESHEETS']: |
407 warn('[3.20] cubicweb.old.css has been renamed back to cubicweb.css', |
408 warn('[3.20] cubicweb.old.css has been renamed back to cubicweb.css', |
408 DeprecationWarning) |
409 DeprecationWarning) |
409 idx = uiprops['STYLESHEETS'].index(datadir_url+'/cubicweb.old.css') |
410 idx = uiprops['STYLESHEETS'].index(datadir_url + '/cubicweb.old.css') |
410 uiprops['STYLESHEETS'][idx] = datadir_url+'/cubicweb.css' |
411 uiprops['STYLESHEETS'][idx] = datadir_url + '/cubicweb.css' |
411 if datadir_url+'/cubicweb.reset.css' in uiprops['STYLESHEETS']: |
412 if datadir_url + '/cubicweb.reset.css' in uiprops['STYLESHEETS']: |
412 warn('[3.20] cubicweb.reset.css is obsolete', DeprecationWarning) |
413 warn('[3.20] cubicweb.reset.css is obsolete', DeprecationWarning) |
413 uiprops['STYLESHEETS'].remove(datadir_url+'/cubicweb.reset.css') |
414 uiprops['STYLESHEETS'].remove(datadir_url + '/cubicweb.reset.css') |
414 cubicweb_js_url = datadir_url + '/cubicweb.js' |
415 cubicweb_js_url = datadir_url + '/cubicweb.js' |
415 if cubicweb_js_url not in uiprops['JAVASCRIPTS']: |
416 if cubicweb_js_url not in uiprops['JAVASCRIPTS']: |
416 uiprops['JAVASCRIPTS'].insert(0, cubicweb_js_url) |
417 uiprops['JAVASCRIPTS'].insert(0, cubicweb_js_url) |
417 |
418 |
418 def _load_ui_properties_file(self, uiprops, path): |
419 def _load_ui_properties_file(self, uiprops, path): |