Merge lp:~elachuni/ubuntu-webcatalog/deploy into lp:ubuntu-webcatalog
- deploy
- Merge into trunk
Proposed by
Anthony Lenton
Status: | Merged | ||||||||
---|---|---|---|---|---|---|---|---|---|
Approved by: | Łukasz Czyżykowski | ||||||||
Approved revision: | no longer in the source branch. | ||||||||
Merged at revision: | 22 | ||||||||
Proposed branch: | lp:~elachuni/ubuntu-webcatalog/deploy | ||||||||
Merge into: | lp:ubuntu-webcatalog | ||||||||
Diff against target: |
749 lines (+437/-167) 13 files modified
.bzrignore (+3/-0) debian/control (+8/-1) django_project/config/main.cfg (+98/-0) django_project/settings.py (+24/-156) django_project/urls.py (+8/-0) fabtasks/bootstrap.py (+32/-0) fabtasks/upgrade_from_package.py (+4/-3) requirements.txt (+8/-3) setup.py (+20/-4) src/webcatalog/context_processors.py (+26/-0) src/webcatalog/middleware/exception.py (+127/-0) src/webcatalog/schema.py (+61/-0) src/webcatalog/wsgi.py (+18/-0) |
||||||||
To merge this branch: | bzr merge lp:~elachuni/ubuntu-webcatalog/deploy | ||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Canonical ISD hackers | Pending | ||
Review via email: mp+65276@code.launchpad.net |
Commit message
Added several infrastructure modules and classes.
Description of the change
Overview
========
This branch adds standard ISD modules and classes, prepping for a deployment.
Details
=======
Integration for the following was added in this branch:
- (django-)configglue
- django-preflight
- django-adminaudit
- django-pgtools
- Google analytics
- django_openid_auth (for admin authentication)
- wsgi-oops
To post a comment you must log in.
Revision history for this message
Łukasz Czyżykowski (lukasz-czyzykowski) wrote : | # |
Revision history for this message
ISD Branch Mangler (isd-branches-mangler) wrote : | # |
There are additional revisions which have not been approved in review. Please seek review and approval of these new revisions.
- 22. By Anthony Lenton
-
[r=lukasz-
czyzykowski] Added several infrastructure modules and classes.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file '.bzrignore' |
2 | --- .bzrignore 2011-06-07 17:27:12 +0000 |
3 | +++ .bzrignore 2011-06-21 11:33:32 +0000 |
4 | @@ -1,8 +1,11 @@ |
5 | webcatalog.db |
6 | src/ubuntu_webcatalog.egg-info/ |
7 | virtualenv/ |
8 | +django_project/adminaudit |
9 | +django_project/django_openid_auth |
10 | django_project/local_settings.py |
11 | django_project/static/ |
12 | django_project/media_root_dev/* |
13 | .backup |
14 | tags |
15 | +branches/ |
16 | |
17 | === modified file 'debian/control' |
18 | --- debian/control 2011-06-17 15:33:40 +0000 |
19 | +++ debian/control 2011-06-21 11:33:32 +0000 |
20 | @@ -18,6 +18,13 @@ |
21 | python-django (>> 1.2.4), |
22 | python-imaging, |
23 | python-configglue (>> 0.9.1), |
24 | - python-django-configglue (>> 0.3) |
25 | + python-django-configglue (>> 0.3), |
26 | + python-django-preflight, |
27 | + python-django-adminaudit, |
28 | + python-django-pgtools, |
29 | + python-django-south, |
30 | + python-django-openid-auth, |
31 | + python-wsgi-oops, |
32 | + python-apt |
33 | Description: Ubuntu Web Catalog |
34 | Providing web access to the Ubuntu Software Center. |
35 | |
36 | === added directory 'django_project/config' |
37 | === added file 'django_project/config/main.cfg' |
38 | --- django_project/config/main.cfg 1970-01-01 00:00:00 +0000 |
39 | +++ django_project/config/main.cfg 2011-06-21 11:33:32 +0000 |
40 | @@ -0,0 +1,98 @@ |
41 | +[__noschema__] |
42 | +hostname = webcatalog.staging.ubuntu.com |
43 | + |
44 | +[django] |
45 | +authentication_backends = django_openid_auth.auth.OpenIDBackend |
46 | + django.contrib.auth.backends.ModelBackend |
47 | + |
48 | +databases = django_databases |
49 | +logging = django_logging |
50 | + |
51 | +debug = true |
52 | +media_root = django_project/media_root_dev/ |
53 | + |
54 | +installed_apps = django.contrib.auth |
55 | + django.contrib.contenttypes |
56 | + django.contrib.sessions |
57 | + django.contrib.sites |
58 | + django.contrib.messages |
59 | + django.contrib.staticfiles |
60 | + django.contrib.markup |
61 | + adminaudit |
62 | + django.contrib.admin |
63 | + django_openid_auth |
64 | + django_configglue |
65 | + webcatalog |
66 | + south |
67 | + preflight |
68 | + pgtools |
69 | +login_url = /openid/login/ |
70 | +managers = %(admins)s |
71 | +middleware_classes = django.middleware.common.CommonMiddleware |
72 | + django.contrib.sessions.middleware.SessionMiddleware |
73 | + django.middleware.csrf.CsrfViewMiddleware |
74 | + django.contrib.auth.middleware.AuthenticationMiddleware |
75 | + django.contrib.messages.middleware.MessageMiddleware |
76 | + webcatalog.middleware.exception.LogExceptionMiddleware |
77 | +fixture_dirs = |
78 | + |
79 | +secret_key = eepu9Av5ixage9ahhodovahfaiFoorodahf6keip3eichaeW9f |
80 | +template_debug = %(debug)s |
81 | +time_zone = Europe/London |
82 | +media_url = /site_media/ |
83 | +use_etags = true |
84 | + |
85 | +template_context_processors = django.contrib.auth.context_processors.auth |
86 | + django.core.context_processors.debug |
87 | + django.core.context_processors.i18n |
88 | + django.core.context_processors.media |
89 | + django.core.context_processors.static |
90 | + django.contrib.messages.context_processors.messages |
91 | + webcatalog.context_processors.google_analytics_id |
92 | + |
93 | +template_dirs = django_project/templates/ |
94 | +static_root = ./django_project/static/ |
95 | +static_url = /assets/ |
96 | + |
97 | +# Django-1.1 backwards compatibility |
98 | +database_engine = sqlite3 |
99 | +database_name = webcatalog.db |
100 | + |
101 | + |
102 | +[django_databases] |
103 | +default = default_database |
104 | + |
105 | +[default_database] |
106 | +engine = sqlite3 |
107 | +name = webcatalog.db |
108 | + |
109 | +[django_logging] |
110 | +loggers = django_loggers |
111 | +version = 1 |
112 | +disable_existing_loggers = False |
113 | + |
114 | +[django_loggers] |
115 | + |
116 | +[openid] |
117 | +openid_sso_server_url = https://login.staging.ubuntu.com |
118 | +openid_create_users = true |
119 | +openid_update_details_from_sreg = true |
120 | +openid_launchpad_teams_mapping = openid_team_mapping |
121 | + |
122 | + |
123 | +[openid_team_mapping] |
124 | +# Structure here is: LP Team = Django Group |
125 | +canonical-isd-hackers = admin |
126 | +canonical-losas = admin |
127 | + |
128 | +[oops] |
129 | +oops_dir = /srv/%(hostname)s/staging-logs/www-oops |
130 | + |
131 | +[webcatalog] |
132 | +serve_site_media = True |
133 | +sca_api_url = https://sc.staging.ubuntu.com/api/2.0/ |
134 | +disk_apt_cache_location = /tmp/webcat_cache |
135 | + |
136 | +[google] |
137 | +google_analytics_id = UA-1018242-24 |
138 | + |
139 | |
140 | === modified file 'django_project/settings.py' |
141 | --- django_project/settings.py 2011-06-17 17:48:07 +0000 |
142 | +++ django_project/settings.py 2011-06-21 11:33:32 +0000 |
143 | @@ -1,156 +1,24 @@ |
144 | -# Django settings for django_project project. |
145 | - |
146 | -DEBUG = True |
147 | -TEMPLATE_DEBUG = DEBUG |
148 | - |
149 | -ADMINS = ( |
150 | - # ('Your Name', 'your_email@example.com'), |
151 | -) |
152 | - |
153 | -MANAGERS = ADMINS |
154 | - |
155 | -DATABASES = { |
156 | - 'default': { |
157 | - 'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'. |
158 | - 'NAME': 'webcatalog.db', # Or path to database file if using sqlite3. |
159 | - 'USER': '', # Not used with sqlite3. |
160 | - 'PASSWORD': '', # Not used with sqlite3. |
161 | - 'HOST': '', # Set to empty string for localhost. Not used with sqlite3. |
162 | - 'PORT': '', # Set to empty string for default. Not used with sqlite3. |
163 | - } |
164 | -} |
165 | - |
166 | -# Local time zone for this installation. Choices can be found here: |
167 | -# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name |
168 | -# although not all choices may be available on all operating systems. |
169 | -# On Unix systems, a value of None will cause Django to use the same |
170 | -# timezone as the operating system. |
171 | -# If running in a Windows environment this must be set to the same as your |
172 | -# system time zone. |
173 | -TIME_ZONE = 'America/Chicago' |
174 | - |
175 | -# Language code for this installation. All choices can be found here: |
176 | -# http://www.i18nguy.com/unicode/language-identifiers.html |
177 | -LANGUAGE_CODE = 'en-us' |
178 | - |
179 | -SITE_ID = 1 |
180 | - |
181 | -# If you set this to False, Django will make some optimizations so as not |
182 | -# to load the internationalization machinery. |
183 | -USE_I18N = True |
184 | - |
185 | -# If you set this to False, Django will not format dates, numbers and |
186 | -# calendars according to the current locale |
187 | -USE_L10N = True |
188 | - |
189 | -# Absolute filesystem path to the directory that will hold user-uploaded files. |
190 | -# Example: "/home/media/media.lawrence.com/media/" |
191 | -MEDIA_ROOT = './django_project/media_root_dev/' |
192 | - |
193 | -# URL that handles the media served from MEDIA_ROOT. Make sure to use a |
194 | -# trailing slash. |
195 | -# Examples: "http://media.lawrence.com/media/", "http://example.com/media/" |
196 | -MEDIA_URL = '/site_media/' |
197 | - |
198 | -# Absolute path to the directory static files should be collected to. |
199 | -# Don't put anything in this directory yourself; store your static files |
200 | -# in apps' "static/" subdirectories and in STATICFILES_DIRS. |
201 | -# Example: "/home/media/media.lawrence.com/static/" |
202 | -STATIC_ROOT = './django_project/static/' |
203 | - |
204 | -# URL prefix for static files. |
205 | -# Example: "http://media.lawrence.com/static/" |
206 | -STATIC_URL = '/assets/' |
207 | - |
208 | -# URL prefix for admin static files -- CSS, JavaScript and images. |
209 | -# Make sure to use a trailing slash. |
210 | -# Examples: "http://foo.com/static/admin/", "/static/admin/". |
211 | -ADMIN_MEDIA_PREFIX = '/assets/admin/' |
212 | - |
213 | -# Additional locations of static files |
214 | -STATICFILES_DIRS = ( |
215 | - # Put strings here, like "/home/html/static" or "C:/www/django/static". |
216 | - # Always use forward slashes, even on Windows. |
217 | - # Don't forget to use absolute paths, not relative paths. |
218 | -) |
219 | - |
220 | -# List of finder classes that know how to find static files in |
221 | -# various locations. |
222 | -STATICFILES_FINDERS = ( |
223 | - 'django.contrib.staticfiles.finders.FileSystemFinder', |
224 | - 'django.contrib.staticfiles.finders.AppDirectoriesFinder', |
225 | -# 'django.contrib.staticfiles.finders.DefaultStorageFinder', |
226 | -) |
227 | - |
228 | -# Make this unique, and don't share it with anybody. |
229 | -SECRET_KEY = '5t7w7uzf&_^goikwn)!g3lmn07gw7x&193uvs#irw4h=1#*%%-' |
230 | - |
231 | -# List of callables that know how to import templates from various sources. |
232 | -TEMPLATE_LOADERS = ( |
233 | - 'django.template.loaders.filesystem.Loader', |
234 | - 'django.template.loaders.app_directories.Loader', |
235 | -# 'django.template.loaders.eggs.Loader', |
236 | -) |
237 | - |
238 | -MIDDLEWARE_CLASSES = ( |
239 | - 'django.middleware.common.CommonMiddleware', |
240 | - 'django.contrib.sessions.middleware.SessionMiddleware', |
241 | - 'django.middleware.csrf.CsrfViewMiddleware', |
242 | - 'django.contrib.auth.middleware.AuthenticationMiddleware', |
243 | - 'django.contrib.messages.middleware.MessageMiddleware', |
244 | -) |
245 | - |
246 | -ROOT_URLCONF = 'django_project.urls' |
247 | - |
248 | -TEMPLATE_DIRS = ( |
249 | - './django_project/templates', |
250 | -) |
251 | - |
252 | -INSTALLED_APPS = ( |
253 | - 'django.contrib.auth', |
254 | - 'django.contrib.contenttypes', |
255 | - 'django.contrib.sessions', |
256 | - 'django.contrib.sites', |
257 | - 'django.contrib.messages', |
258 | - 'django.contrib.staticfiles', |
259 | - 'django.contrib.admin', |
260 | - 'south', |
261 | - 'webcatalog', |
262 | -) |
263 | - |
264 | -# A sample logging configuration. The only tangible logging |
265 | -# performed by this configuration is to send an email to |
266 | -# the site admins on every HTTP 500 error. |
267 | -# See http://docs.djangoproject.com/en/dev/topics/logging for |
268 | -# more details on how to customize your logging configuration. |
269 | -LOGGING = { |
270 | - 'version': 1, |
271 | - 'disable_existing_loggers': False, |
272 | - 'handlers': { |
273 | - 'mail_admins': { |
274 | - 'level': 'ERROR', |
275 | - 'class': 'django.utils.log.AdminEmailHandler' |
276 | - } |
277 | - }, |
278 | - 'loggers': { |
279 | - 'django.request': { |
280 | - 'handlers': ['mail_admins'], |
281 | - 'level': 'ERROR', |
282 | - 'propagate': True, |
283 | - }, |
284 | - } |
285 | -} |
286 | - |
287 | -######################## |
288 | -# Ubuntu Web Catalog specific settings: |
289 | -######################## |
290 | - |
291 | -# Strictly for use in our dev environment: |
292 | -SERVE_SITE_MEDIA = True |
293 | -SCA_API_URL = 'https://sc.staging.ubuntu.com/api/2.0/' |
294 | -DISK_APT_CACHE_LOCATION = '/tmp/webcat_cache' |
295 | - |
296 | -try: |
297 | - from local_settings import * |
298 | -except ImportError: |
299 | - pass |
300 | +from __future__ import absolute_import |
301 | + |
302 | +import os.path |
303 | + |
304 | +from configglue.pyschema import SchemaConfigParser |
305 | +from django_configglue.utils import update_settings |
306 | + |
307 | +from webcatalog.schema import WebCatalogSchema |
308 | + |
309 | + |
310 | +# get absolute path for config files |
311 | +current_dir = os.path.dirname(os.path.abspath(__file__)) |
312 | +config_files = map(lambda x: os.path.join(current_dir, x), |
313 | + ['config/main.cfg', '../../local_config/local.cfg', |
314 | + 'local.cfg']) |
315 | + |
316 | +# parse config files |
317 | +parser = SchemaConfigParser(WebCatalogSchema()) |
318 | +parser.read(config_files) |
319 | +update_settings(parser, locals()) |
320 | + |
321 | +# keep parser reference |
322 | +__CONFIGGLUE_PARSER__ = parser |
323 | + |
324 | |
325 | === removed directory 'django_project/templates' |
326 | === modified file 'django_project/urls.py' |
327 | --- django_project/urls.py 2011-05-06 15:03:41 +0000 |
328 | +++ django_project/urls.py 2011-06-21 11:33:32 +0000 |
329 | @@ -15,15 +15,23 @@ |
330 | # You should have received a copy of the GNU Affero General Public License |
331 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
332 | |
333 | +import preflight |
334 | +import adminaudit |
335 | from django.conf.urls.defaults import patterns, include, url |
336 | from django.conf import settings |
337 | from django.contrib import admin |
338 | +from django.views.generic.simple import redirect_to |
339 | |
340 | admin.autodiscover() |
341 | +preflight.autodiscover() |
342 | +adminaudit.audit_install() |
343 | |
344 | urlpatterns = patterns('', |
345 | url(r'^cat/', include('webcatalog.urls')), |
346 | url(r'^admin/', include(admin.site.urls)), |
347 | + (r'^preflight/$', include('preflight.urls')), |
348 | + url(r'^$', redirect_to, {'url': '/cat/'}), |
349 | + |
350 | ) |
351 | |
352 | if settings.SERVE_SITE_MEDIA: |
353 | |
354 | === modified file 'fabtasks/bootstrap.py' |
355 | --- fabtasks/bootstrap.py 2011-05-06 21:00:11 +0000 |
356 | +++ fabtasks/bootstrap.py 2011-06-21 11:33:32 +0000 |
357 | @@ -52,13 +52,45 @@ |
358 | if not os.path.exists(link_name): |
359 | os.symlink(os.path.abspath(source), link_name) |
360 | |
361 | +def _get_or_pull_bzr_branch(repo, name, revision=None): |
362 | + if revision is None: |
363 | + revision = "" |
364 | + else: |
365 | + revision = "--revision={0}".format(revision) |
366 | + if not os.path.exists("branches"): |
367 | + os.mkdir('branches') |
368 | + branch_path = os.path.join("branches", name) |
369 | + if os.path.exists(branch_path): |
370 | + local("rm -r {0}".format(branch_path)) |
371 | + local("bzr branch {0} {1} {2}".format( |
372 | + revision, repo, branch_path), capture=False) |
373 | + |
374 | +def pull_required_branches(): |
375 | + _get_or_pull_bzr_branch( |
376 | + "lp:django-adminaudit", |
377 | + "django-adminaudit") |
378 | + _symlink( |
379 | + "branches/django-adminaudit/adminaudit", |
380 | + "django_project/adminaudit") |
381 | + _get_or_pull_bzr_branch( |
382 | + "lp:~django-openid-auth/django-openid-auth/trunk", |
383 | + "django-openid-auth", |
384 | + revision=79) |
385 | + _symlink( |
386 | + "branches/django-openid-auth/django_openid_auth", |
387 | + "django_project/django_openid_auth") |
388 | |
389 | def bootstrap(): |
390 | virtualenv_create() |
391 | install_requirements() |
392 | + pull_required_branches() |
393 | |
394 | |
395 | def clean(): |
396 | + local("rm -rf branches/") |
397 | local("rm -rf virtualenv/") |
398 | local("rm -rf src/ubuntu_webcatalog.egg-info") |
399 | local("rm -f webcatalog.db") |
400 | + links = ("adminaudit", "django_openid_auth") |
401 | + for link in links: |
402 | + local("rm -f django_project/{0}".format(link)) |
403 | |
404 | === modified file 'fabtasks/upgrade_from_package.py' |
405 | --- fabtasks/upgrade_from_package.py 2011-04-05 02:19:30 +0000 |
406 | +++ fabtasks/upgrade_from_package.py 2011-06-21 11:33:32 +0000 |
407 | @@ -69,7 +69,7 @@ |
408 | recipe = dedent("""\ |
409 | # bzr-builder format 0.2 deb-version {debupstream}-0~{revno}+{time} |
410 | .""") |
411 | - recipe_path = os.path.join(build_dir, 'rnr.recipe') |
412 | + recipe_path = os.path.join(build_dir, 'uwc.recipe') |
413 | with open(recipe_path, 'w+') as recipe_file: |
414 | recipe_file.write(recipe) |
415 | |
416 | @@ -92,7 +92,7 @@ |
417 | |
418 | def migrate_database(config_dir=None): |
419 | if config_dir is None: |
420 | - # By default, the rnr config directory is assumed to be |
421 | + # By default, the uwc config directory is assumed to be |
422 | # /home/username/django_project. |
423 | config_dir = 'django_project' |
424 | run(config_dir + '/manage.py syncdb --migrate') |
425 | @@ -133,7 +133,8 @@ |
426 | run("cp %s/local.cfg %s" % (backup_dir, config_dir)) |
427 | else: |
428 | # Create a local.cfg on the server from our template. |
429 | - local_file, local_path = tempfile.mkstemp() |
430 | + local_fd, local_path = tempfile.mkstemp() |
431 | + local_file = os.fdopen(local_fd, 'w') |
432 | local_file.write(LOCAL_CONFIG) |
433 | local_file.close() |
434 | put(local_path, "%s/local.cfg" % config_dir) |
435 | |
436 | === modified file 'requirements.txt' |
437 | --- requirements.txt 2011-06-17 14:44:34 +0000 |
438 | +++ requirements.txt 2011-06-21 11:33:32 +0000 |
439 | @@ -1,7 +1,12 @@ |
440 | +configglue==0.10 |
441 | +coverage |
442 | django |
443 | +django-configglue==0.4 |
444 | +-e bzr+http://bazaar.launchpad.net/~canonical-isd-hackers/django-pgtools/trunk |
445 | +django-preflight |
446 | mock |
447 | +PIL |
448 | +python-debian |
449 | +python-openid |
450 | setuptools |
451 | south |
452 | -python-debian |
453 | -PIL |
454 | -coverage |
455 | |
456 | === modified file 'setup.py' |
457 | --- setup.py 2011-04-05 02:19:30 +0000 |
458 | +++ setup.py 2011-06-21 11:33:32 +0000 |
459 | @@ -1,5 +1,24 @@ |
460 | +import os |
461 | from setuptools import setup, find_packages |
462 | |
463 | +def find_packages_data(start_dir): |
464 | + packages = {} |
465 | + for package_name in os.listdir(start_dir): |
466 | + package_dir = os.path.join(start_dir, package_name) |
467 | + if os.path.exists(os.path.join(package_dir, '__init__.py')): |
468 | + files = [] |
469 | + packages[package_name] = files |
470 | + for dirpath, dirnames, filenames in os.walk(package_dir): |
471 | + dirpath = dirpath[len(package_dir) + 1:] |
472 | + for filename in filenames: |
473 | + ext = os.path.splitext(filename)[1] |
474 | + if ext not in ('.py', '.pyc', '.pyo'): |
475 | + file_path = os.path.join(dirpath, filename) |
476 | + full_file_path = os.path.join(package_dir, file_path) |
477 | + if os.path.isfile(full_file_path): |
478 | + files.append(file_path) |
479 | + return packages |
480 | + |
481 | setup( |
482 | name = "ubuntu-webcatalog", |
483 | version = "0.1", |
484 | @@ -18,9 +37,6 @@ |
485 | 'django', |
486 | 'south', |
487 | ], |
488 | - package_data = { |
489 | - 'webcatalog': [ |
490 | - ], |
491 | - }, |
492 | + package_data = find_packages_data('src'), |
493 | ) |
494 | |
495 | |
496 | === added file 'src/webcatalog/context_processors.py' |
497 | --- src/webcatalog/context_processors.py 1970-01-01 00:00:00 +0000 |
498 | +++ src/webcatalog/context_processors.py 2011-06-21 11:33:32 +0000 |
499 | @@ -0,0 +1,26 @@ |
500 | +# -*- coding: utf-8 -*- |
501 | +# This file is part of the Ubuntu Web Catalog |
502 | +# Copyright (C) 2011 Canonical Ltd. |
503 | +# |
504 | +# This program is free software: you can redistribute it and/or modify |
505 | +# it under the terms of the GNU Affero General Public License as |
506 | +# published by the Free Software Foundation, either version 3 of the |
507 | +# License, or (at your option) any later version. |
508 | +# |
509 | +# This program is distributed in the hope that it will be useful, |
510 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
511 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
512 | +# GNU Affero General Public License for more details. |
513 | +# |
514 | +# You should have received a copy of the GNU Affero General Public License |
515 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
516 | + |
517 | +"""Context processors web catalog app.""" |
518 | + |
519 | +from django.conf import settings |
520 | + |
521 | +def google_analytics_id(request): |
522 | + """Adds the google analytics id to the context if it's present.""" |
523 | + return { |
524 | + 'google_analytics_id': getattr(settings, 'GOOGLE_ANALYTICS_ID', None), |
525 | + } |
526 | |
527 | === added directory 'src/webcatalog/middleware' |
528 | === added file 'src/webcatalog/middleware/__init__.py' |
529 | === added file 'src/webcatalog/middleware/exception.py' |
530 | --- src/webcatalog/middleware/exception.py 1970-01-01 00:00:00 +0000 |
531 | +++ src/webcatalog/middleware/exception.py 2011-06-21 11:33:32 +0000 |
532 | @@ -0,0 +1,127 @@ |
533 | +# -*- coding: utf-8 -*- |
534 | +# This file is part of the Ubuntu Web Catalog |
535 | +# Copyright (C) 2011 Canonical Ltd. |
536 | +# |
537 | +# This program is free software: you can redistribute it and/or modify |
538 | +# it under the terms of the GNU Affero General Public License as |
539 | +# published by the Free Software Foundation, either version 3 of the |
540 | +# License, or (at your option) any later version. |
541 | +# |
542 | +# This program is distributed in the hope that it will be useful, |
543 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
544 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
545 | +# GNU Affero General Public License for more details. |
546 | +# |
547 | +# You should have received a copy of the GNU Affero General Public License |
548 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
549 | + |
550 | +"""Exception logging middleware for the web catalog app.""" |
551 | + |
552 | +import logging |
553 | +import re |
554 | +import sys |
555 | +import traceback |
556 | + |
557 | +from django.conf import settings |
558 | +from django.db import connection |
559 | +from django.views import debug |
560 | +from django.views.debug import ExceptionReporter |
561 | + |
562 | +default_hidden_settings = \ |
563 | + 'SECRET|PASSWORD|PROFANITIES_LIST|PRIVATE|secret|password|private' |
564 | +hidden_settings = getattr(settings, 'HIDDEN_SETTINGS', default_hidden_settings) |
565 | +debug.HIDDEN_SETTINGS = re.compile(hidden_settings) |
566 | + |
567 | + |
568 | +class SanitizedExceptionReporter(ExceptionReporter): |
569 | + def __init__(self, request, exc_type, exc_value, tb, is_email=None): |
570 | + request = self.sanitize_request(request) |
571 | + ExceptionReporter.__init__(self, request, |
572 | + exc_type, exc_value, tb) |
573 | + |
574 | + def get_traceback_frames(self): |
575 | + # This method is taken from Django's views.debug.ExceptionReporter. |
576 | + # Please see the license file in the third-party/django directory. |
577 | + frames = [] |
578 | + tb = self.tb |
579 | + while tb is not None: |
580 | + # support for __traceback_hide__ which is used by a few libraries |
581 | + # to hide internal frames. |
582 | + if tb.tb_frame.f_locals.get('__traceback_hide__'): |
583 | + tb = tb.tb_next |
584 | + continue |
585 | + filename = tb.tb_frame.f_code.co_filename |
586 | + function = tb.tb_frame.f_code.co_name |
587 | + lineno = tb.tb_lineno - 1 |
588 | + loader = tb.tb_frame.f_globals.get('__loader__') |
589 | + module_name = tb.tb_frame.f_globals.get('__name__') |
590 | + pre_context_lineno, pre_context, context_line, post_context = \ |
591 | + self._get_lines_from_file(filename, lineno, 7, loader, |
592 | + module_name) |
593 | + if pre_context_lineno is not None: |
594 | + frames.append({ |
595 | + 'tb': tb, |
596 | + 'filename': filename, |
597 | + 'function': function, |
598 | + 'lineno': lineno + 1, |
599 | + # The only diff in this method: call self.sanitize_vars() |
600 | + 'vars': self.sanitize_vars(tb.tb_frame.f_locals.items()), |
601 | + 'id': id(tb), |
602 | + 'pre_context': pre_context, |
603 | + 'context_line': context_line, |
604 | + 'post_context': post_context, |
605 | + 'pre_context_lineno': pre_context_lineno + 1, |
606 | + }) |
607 | + tb = tb.tb_next |
608 | + |
609 | + if not frames: |
610 | + frames = [{ |
611 | + 'filename': '<unknown>', |
612 | + 'function': '?', |
613 | + 'lineno': '?', |
614 | + 'context_line': '???', |
615 | + }] |
616 | + |
617 | + return frames |
618 | + |
619 | + # These two methods are new -- Sanitize the request's POST and GET dicts, |
620 | + # and local variables in frames, not only Django's settings. |
621 | + def sanitize_vars(self, items): |
622 | + sanitized = [] |
623 | + for item in items: |
624 | + if debug.HIDDEN_SETTINGS.search(item[0]): |
625 | + sanitized.append((item[0], '********')) |
626 | + else: |
627 | + sanitized.append(item) |
628 | + return sanitized |
629 | + |
630 | + def sanitize_request(self, request): |
631 | + """Remove sensitive from the request before it is displayed""" |
632 | + dup_post = request.POST.copy() |
633 | + for key in request.POST.iterkeys(): |
634 | + if debug.HIDDEN_SETTINGS.search(key): |
635 | + dup_post[key] = '********' |
636 | + request.POST = dup_post |
637 | + dup_get = request.GET.copy() |
638 | + for key in request.GET.iterkeys(): |
639 | + if debug.HIDDEN_SETTINGS.search(key): |
640 | + dup_get[key] = '********' |
641 | + request.GET = dup_get |
642 | + return request |
643 | + |
644 | + |
645 | +debug.ExceptionReporter = SanitizedExceptionReporter |
646 | + |
647 | + |
648 | +class LogExceptionMiddleware(object): |
649 | + def process_exception(self, request, exception): |
650 | + """Log the traceback, so that it can be kept in the oops file""" |
651 | + reporter = SanitizedExceptionReporter(request, *sys.exc_info()) |
652 | + template_debug = settings.TEMPLATE_DEBUG |
653 | + settings.TEMPLATE_DEBUG = True |
654 | + try: |
655 | + logging.warn(traceback.format_exc()) |
656 | + for query in connection.queries: |
657 | + logging.warn("time: %(time)s sql: %(sql)s" % query) |
658 | + finally: |
659 | + settings.TEMPLATE_DEBUG = template_debug |
660 | |
661 | === added file 'src/webcatalog/schema.py' |
662 | --- src/webcatalog/schema.py 1970-01-01 00:00:00 +0000 |
663 | +++ src/webcatalog/schema.py 2011-06-21 11:33:32 +0000 |
664 | @@ -0,0 +1,61 @@ |
665 | +import django |
666 | + |
667 | +from configglue.pyschema import ConfigSection |
668 | +from configglue.pyschema.options import (BoolConfigOption, StringConfigOption, |
669 | + LinesConfigOption, IntConfigOption, DictConfigOption, TupleConfigOption) |
670 | +from django_configglue.schema import ( |
671 | + Django112Schema, |
672 | + schemas, |
673 | + ) |
674 | + |
675 | +# Currently we've updated to latest configglue/django-configglue |
676 | +# but they remove a registered schema for django 1.1.1, which is |
677 | +# the currently installed django version on our servers, resulting in: |
678 | +# http://razorgirl.info/job/software-center-agent-deploy/23/console |
679 | +# So we register the 112 schema to match until we upgrade. Once we |
680 | +# upgraded this should still work without updating (as the version |
681 | +# will be 1.3). |
682 | +schemas.register(Django112Schema, '1.1.1') |
683 | +DjangoSchema = schemas.get(django.get_version()) |
684 | + |
685 | + |
686 | +class WebCatalogSchema(DjangoSchema): |
687 | + """Config options specific to the web catalog.""" |
688 | + # default section |
689 | + extra_pythonpath = LinesConfigOption(item=StringConfigOption()) |
690 | + pgconnect_timeout = IntConfigOption(default=10) |
691 | + should_serve_https = BoolConfigOption() |
692 | + |
693 | + oops = ConfigSection() |
694 | + oops.oops_dir = StringConfigOption(help='Absolute path to the directory' |
695 | + ' oops reports will be stored in') |
696 | + |
697 | + openid = ConfigSection() |
698 | + openid.openid_sso_server_url = StringConfigOption() |
699 | + openid.openid_create_users = BoolConfigOption() |
700 | + openid.openid_update_details_from_sreg = BoolConfigOption() |
701 | + openid.openid_launchpad_teams_mapping = DictConfigOption() |
702 | + openid.openid_sreg_extra_fields = LinesConfigOption( |
703 | + item=StringConfigOption()) |
704 | + |
705 | + webcatalog = ConfigSection() |
706 | + webcatalog.serve_site_media = BoolConfigOption(default=True) |
707 | + webcatalog.sca_api_url = StringConfigOption() |
708 | + webcatalog.disk_apt_cache_location = StringConfigOption() |
709 | + |
710 | + google = ConfigSection() |
711 | + google.google_analytics_id = StringConfigOption() |
712 | + |
713 | + logging = ConfigSection() |
714 | + logging.webapp_logging_config = StringConfigOption() |
715 | + |
716 | + # preflight |
717 | + preflight = ConfigSection() |
718 | + preflight.preflight_base_template = StringConfigOption( |
719 | + default="webcatalog/base.html") |
720 | + |
721 | + #adminaudit |
722 | + adminaudit_emails_recipients = LinesConfigOption( |
723 | + item=StringConfigOption()) |
724 | + adminaudit_summary_subject = StringConfigOption( |
725 | + default='Admin Audit Summary') |
726 | |
727 | === renamed directory 'django_project/templates/light' => 'src/webcatalog/templates/light' |
728 | === added file 'src/webcatalog/wsgi.py' |
729 | --- src/webcatalog/wsgi.py 1970-01-01 00:00:00 +0000 |
730 | +++ src/webcatalog/wsgi.py 2011-06-21 11:33:32 +0000 |
731 | @@ -0,0 +1,18 @@ |
732 | +import logging.config |
733 | +import platform |
734 | + |
735 | +from canonical.oops.serializer import OOPSRFC822Serializer |
736 | +from canonical.oops.wsgi import OopsWare |
737 | +from django.core.handlers.wsgi import WSGIHandler |
738 | +from django.conf import settings |
739 | + |
740 | +def make_app(): |
741 | + """Encapsulate our webcatalog handler in an OOPS app for error reporting.""" |
742 | + default_id = ''.join(x for x in platform.node() if x.isalpha()) |
743 | + appserver_id = getattr(settings, 'APPSERVER_ID', default_id) |
744 | + logging.config.fileConfig(settings.WEBAPP_LOGGING_CONFIG) |
745 | + oops_dir = getattr(settings, 'OOPS_DIR', '/tmp') |
746 | + oops_app = OopsWare(WSGIHandler(), oops_dir=oops_dir, |
747 | + key=appserver_id, hide_meta=True) |
748 | + oops_app.serial = OOPSRFC822Serializer(appserver_id, oops_dir, None) |
749 | + return oops_app |
There are still some RnR/SCA leftovers in the code, lines:
- 54 (mentions devportal),
- 676 (comment mentions sca-deploy)
Also, if you add user=postgres in [default_database], will enable to run against PostgreSQL without the need for one bit of config (and this setting is ignored by SQLite).