Put CDN configuration variables in environnement.py.
[infos-pratiques:etalage.git] / etalage / environment.py
1 # -*- coding: utf-8 -*-
2
3
4 # Etalage -- Open Data POIs portal
5 # By: Emmanuel Raviart <eraviart@easter-eggs.com>
6 #
7 # Copyright (C) 2011, 2012 Easter-eggs
8 # http://gitorious.org/infos-pratiques/etalage
9 #
10 # This file is part of Etalage.
11 #
12 # Etalage is free software; you can redistribute it and/or modify
13 # it under the terms of the GNU Affero General Public License as
14 # published by the Free Software Foundation, either version 3 of the
15 # License, or (at your option) any later version.
16 #
17 # Etalage is distributed in the hope that it will be useful,
18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 # GNU Affero General Public License for more details.
21 #
22 # You should have received a copy of the GNU Affero General Public License
23 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
24
25
26 """Environment configuration"""
27
28
29 from ConfigParser import SafeConfigParser
30 import logging
31 import os
32 import sys
33 import urlparse
34
35 from biryani import strings
36 import mako.lookup
37 import pkg_resources
38 import pymongo
39 from suq import monpyjama
40 from etalage import ramdb
41
42 import etalage
43 from . import conv, model, templates
44
45
46 app_dir = os.path.dirname(os.path.abspath(__file__))
47
48
49 def load_environment(global_conf, app_conf):
50     """Configure the application environment."""
51     conf = etalage.conf  # Empty dictionary
52     conf.update(strings.deep_decode(global_conf))
53     conf.update(strings.deep_decode(app_conf))
54     conf.update(conv.check(conv.struct(
55         {
56             'app_conf': conv.set_value(app_conf),
57             'app_dir': conv.set_value(app_dir),
58             'autocompleter_territories_kinds': conv.pipe(
59                 conv.function(lambda kinds: kinds.split()),
60                 conv.uniform_sequence(
61                     conv.test_in(model.Territory.public_kinds),
62                     constructor = lambda kinds: sorted(set(kinds)),
63                     ),
64                 conv.default([
65                     # u'AbstractCommuneOfFrance',
66                     u'ArrondissementOfCommuneOfFrance',
67                     u'ArrondissementOfFrance',
68                     u'AssociatedCommuneOfFrance',
69                     # u'CantonalFractionOfCommuneOfFrance',
70                     u'CantonOfFrance',
71                     u'CommuneOfFrance',
72                     # u'Country',
73                     u'DepartmentOfFrance',
74                     u'IntercommunalityOfFrance',
75                     # u'InternationalOrganization',
76                     u'MetropoleOfCountry',
77                     u'Mountain',
78                     u'OverseasCollectivityOfFrance',
79                     u'PaysOfFrance',
80                     u'RegionalNatureParkOfFrance',
81                     u'RegionOfFrance',
82                     # u'Special',
83                     u'UrbanAreaOfFrance',
84                     u'UrbanTransportsPerimeterOfFrance',
85                     ]),
86                 ),
87             'brand_name': conv.default(u'Comarquage.fr'),
88             'brand_url': conv.default(u'http://www.comarquage.fr/'),
89             'cache_dir': conv.default(os.path.join(os.path.dirname(app_dir), 'cache')),
90             'categories_collection': conv.default('categories'),
91             'cdn_url': conv.default('http://localhost:7000'),
92             'custom_static_files_dir': conv.default(None),
93             'custom_templates_dir': conv.default(None),
94             'data_updates_collection': conv.default('data_updates'),
95             'data_email': conv.pipe(
96                 conv.function(lambda lines: lines.split(u',')),
97                 conv.uniform_sequence(
98                         conv.input_to_email,
99                     ),
100                 ),
101             'database': conv.default('souk'),
102             'debug': conv.pipe(conv.guess_bool, conv.default(False)),
103             'default_filter': conv.input_to_filter,
104             'default_tab': conv.pipe(
105                 conv.cleanup_line,
106                 conv.test_in(['carte', 'liste']),
107                 conv.default('carte'),
108                 ),
109             'gadget-integration.js': conv.default(urlparse.urljoin('http://localhost:7002/', 'integration.js')),
110             'global_conf': conv.set_value(global_conf),
111             'hide_directory': conv.pipe(conv.guess_bool, conv.default(False)),
112             'hide_export': conv.pipe(conv.guess_bool, conv.default(False)),
113             'hide_gadget': conv.pipe(conv.guess_bool, conv.default(False)),
114             'hide_map': conv.pipe(conv.guess_bool, conv.default(False)),
115             'hide_minisite': conv.pipe(conv.guess_bool, conv.default(False)),
116             'i18n_dir': conv.default(os.path.join(app_dir, 'i18n')),
117             'i18n_dir_by_plugin_name': conv.set_value(None),  # set by plugins below
118             'ignored_fields': conv.pipe(
119                 conv.function(lambda lines: lines.split(u'\n')),
120                 conv.uniform_sequence(conv.pipe(
121                     conv.function(lambda line: line.split(None, 1)),
122                     conv.uniform_sequence(conv.input_to_slug),
123                     conv.function(lambda seq: dict(zip(['id', 'name'], seq))),
124                     )),
125                 conv.id_name_dict_list_to_ignored_fields,
126                 ),
127             'log_level': conv.pipe(
128                 conv.default('WARNING'),
129                 conv.function(lambda log_level: getattr(logging, log_level.upper())),
130                 ),
131             'organism_types_collection': conv.default('organism_types'),
132             'package_name': conv.default('etalage'),
133             'pois_collection': conv.default('pois'),
134             'plugins_conf_file': conv.default(None),
135             'realm': conv.default(u'Etalage'),
136             'require_subscription': conv.pipe(conv.guess_bool, conv.default(False)),
137             'reset_on_poi_update': conv.pipe(conv.guess_bool, conv.default(False)),
138             # Whether this application serves its own static files.
139             'static_files': conv.pipe(conv.guess_bool, conv.default(True)),
140             'static_files_dir': conv.default(os.path.join(app_dir, 'static')),
141             'territories_collection': conv.default('territories'),
142             'territories_kinds': conv.pipe(
143                 conv.function(lambda kinds: kinds.split()),
144                 conv.uniform_sequence(
145                     conv.test_in(model.Territory.public_kinds),
146                     constructor = lambda kinds: sorted(set(kinds)),
147                     ),
148                 conv.default([
149                     # u'AbstractCommuneOfFrance',
150                     u'ArrondissementOfCommuneOfFrance',
151                     u'ArrondissementOfFrance',
152                     u'AssociatedCommuneOfFrance',
153                     # u'CantonalFractionOfCommuneOfFrance',
154                     u'CantonOfFrance',
155                     u'CommuneOfFrance',
156                     # u'Country',
157                     u'DepartmentOfFrance',
158                     u'IntercommunalityOfFrance',
159                     # u'InternationalOrganization',
160                     u'MetropoleOfCountry',
161                     u'Mountain',
162                     u'OverseasCollectivityOfFrance',
163                     u'PaysOfFrance',
164                     u'RegionalNatureParkOfFrance',
165                     u'RegionOfFrance',
166                     # u'Special',
167                     u'UrbanAreaOfFrance',
168                     u'UrbanTransportsPerimeterOfFrance',
169                     ]),
170                 ),
171             'theme_field': conv.pipe(
172                 conv.function(lambda line: line.split(None, 1)),
173                 conv.uniform_sequence(conv.input_to_slug),
174                 conv.function(lambda seq: dict(zip(['id', 'name'], seq))),
175                 conv.default(dict(id = 'organism-type')),
176                 ),
177             'tile_layers': conv.pipe(
178                 conv.function(eval),
179                 conv.function(strings.deep_decode),
180                 conv.test_isinstance(list),
181                 conv.uniform_sequence(
182                     conv.pipe(
183                         conv.test_isinstance(dict),
184                         conv.struct(dict(
185                             attribution = conv.pipe(
186                                 conv.test_isinstance(basestring),
187                                 conv.not_none,
188                                 ),
189                             name = conv.pipe(
190                                 conv.test_isinstance(basestring),
191                                 conv.not_none,
192                                 ),
193                             subdomains = conv.test_isinstance(basestring),
194                             url = conv.pipe(
195                                 conv.test_isinstance(basestring),
196                                 conv.make_input_to_url(full = True),
197                                 conv.not_none,
198                                 ),
199                             )),
200                         ),
201                     ),
202                 conv.not_none,
203                 ),
204             },
205         default = 'drop',
206         keep_none_values = True,
207         ))(conf))
208
209     # CDN configuration
210     conf.update(conv.check(conv.struct(
211         {
212             'bootstrap.css': conv.default(urlparse.urljoin(conf['cdn_url'], '/bootstrap/2.2.1/css/bootstrap.min.css')),
213             'bootstrap.js': conv.default(urlparse.urljoin(conf['cdn_url'], '/bootstrap/2.2.1/js/bootstrap.min.js')),
214             'bootstrap-responsive.css': conv.default(
215                 urlparse.urljoin(conf['cdn_url'], '/bootstrap/2.2.1/css/bootstrap-responsive.min.css')
216                 ),
217             'easyxdm.js': conv.default(urlparse.urljoin(conf['cdn_url'], '/easyxdm/2.4.15/easyXDM.min.js')),
218             'easyxdm.swf': conv.default(urlparse.urljoin(conf['cdn_url'], '/easyxdm/2.4.15/easyxdm.swf')),
219             'jquery.js': conv.default(urlparse.urljoin(conf['cdn_url'], '/jquery/jquery-1.7.1.min.js')),
220             'jquery-ui.css': conv.default(
221                 urlparse.urljoin(conf['cdn_url'], '/jquery-ui/1.8.16/themes/smoothness/jquery-ui.css')
222                 ),
223             'jquery-ui.js': conv.default(urlparse.urljoin(conf['cdn_url'], '/jquery-ui/1.8.16/jquery-ui.min.js')),
224             'json2.js': conv.default(urlparse.urljoin(conf['cdn_url'], '/easyxdm/2.4.15/json2.js')),
225             'leaflet.css': conv.default(urlparse.urljoin(conf['cdn_url'], '/leaflet/git-v0.4.5-0-165e50f/leaflet.css')),
226             'leaflet.ie.css': conv.default(urlparse.urljoin(conf['cdn_url'], '/leaflet/git-v0.4.5-0-165e50f/leaflet.ie.css')),
227             'leaflet.js': conv.default(urlparse.urljoin(conf['cdn_url'], '/leaflet/git-v0.4.5-0-165e50f/leaflet.js')),
228             'pie.js': conv.default(urlparse.urljoin(conf['cdn_url'], '/css3pie/1.0beta5/PIE.js')),
229             'prettify.js': conv.default(urlparse.urljoin(conf['cdn_url'], '/google-code-prettify/187/prettify.js')),
230             'images.markers.url': conv.default(urlparse.urljoin(conf['cdn_url'], '/images/markers/')),
231             'images.misc.url': conv.default(urlparse.urljoin(conf['cdn_url'], '/images/misc/')),
232             },
233         default = conv.noop,
234         ))(conf))
235
236     # Configure logging.
237     logging.basicConfig(level = conf['log_level'], stream = sys.stdout)
238
239     errorware = conf.setdefault('errorware', {})
240     errorware['debug'] = conf['debug']
241     if not errorware['debug']:
242         errorware['error_email'] = conf['email_to']
243         errorware['error_log'] = conf.get('error_log', None)
244         errorware['error_message'] = conf.get('error_message', 'An internal server error occurred')
245         errorware['error_subject_prefix'] = conf.get('error_subject_prefix', 'Etalage Error: ')
246         errorware['from_address'] = conf['from_address']
247         errorware['smtp_server'] = conf.get('smtp_server', 'localhost')
248
249     # Connect to MongoDB database.
250     monpyjama.Wrapper.db = model.db = pymongo.Connection()[conf['database']]
251
252     # Initialize plugins.
253     if conf['plugins_conf_file'] is not None:
254         plugins_conf = SafeConfigParser(dict(here = os.path.dirname(conf['plugins_conf_file'])))
255         plugins_conf.read(conf['plugins_conf_file'])
256         conf['i18n_dir_by_plugin_name'] = {}
257         for section in plugins_conf.sections():
258             plugin_accessor = plugins_conf.get(section, 'use')
259             plugin_constructor = pkg_resources.EntryPoint.parse('constructor = {0}'.format(plugin_accessor)).load(
260                 require = False)
261             plugin_constructor(plugins_conf, section)
262             plugin_package_name = plugins_conf.get(section, 'package_name')
263             if plugin_package_name is not None:
264                 plugin_i18n_dir = plugins_conf.get(section, 'i18n_dir')
265                 if plugin_i18n_dir is not None:
266                     conf['i18n_dir_by_plugin_name'][plugin_package_name] = plugin_i18n_dir
267
268     # Initialize ramdb database from MongoDB.
269     ramdb.load()
270
271     # Create the Mako TemplateLookup, with the default auto-escaping.
272     templates_dirs = []
273     if conf['custom_templates_dir']:
274         templates_dirs.append(conf['custom_templates_dir'])
275     templates_dirs.append(os.path.join(app_dir, 'templates'))
276     templates.lookup = mako.lookup.TemplateLookup(
277         default_filters = ['h'],
278         directories = templates_dirs,
279 #        error_handler = handle_mako_error,
280         input_encoding = 'utf-8',
281         module_directory = os.path.join(conf['cache_dir'], 'templates'),
282 #        strict_undefined = True,
283         )