Commit ab94e3df0bed4f5bd980bf8231a6990a6369beac

Authored by Sergio Oliveira
2 parents 2fedfd73 fd31cbb7

Merge branch 'settings_py'

@@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
3 *.pot 3 *.pot
4 *.pyc 4 *.pyc
5 *.pyo 5 *.pyo
6 -*.egg 6 +*.egg*
7 local_settings.py 7 local_settings.py
8 project_cfg.py 8 project_cfg.py
9 9
colab/plugins/context_processors.py
@@ -2,10 +2,10 @@ @@ -2,10 +2,10 @@
2 from django.conf import settings 2 from django.conf import settings
3 3
4 4
5 -def proxied_apps(request):  
6 - proxied_apps = {} 5 +def colab_apps(request):
  6 + colab_apps = {}
7 7
8 for app_name, app in settings.COLAB_APPS.items(): 8 for app_name, app in settings.COLAB_APPS.items():
9 - proxied_apps[app_name] = app 9 + colab_apps[app_name] = app
10 10
11 - return {'proxy': proxied_apps} 11 + return {'plugins': colab_apps}
colab/plugins/templates/plugins/menu_template.html
1 {% for title, links in menu_links.items %} 1 {% for title, links in menu_links.items %}
2 {% if links|length == 1 %} 2 {% if links|length == 1 %}
3 - {% for text, link in links %} 3 + {% for colab_url in links %}
4 <li> 4 <li>
5 - <a href="{{ link }}">{{ title }}</a> 5 + <a href="{{ colab_url.url }}">{{ title }}</a>
6 </li> 6 </li>
7 {% endfor %} 7 {% endfor %}
8 {% else %} 8 {% else %}
9 <li class="dropdown"> 9 <li class="dropdown">
10 <a href="#" class="dropdown-toggle" data-toggle="dropdown">{{ title }} <b class="caret"></b></a> 10 <a href="#" class="dropdown-toggle" data-toggle="dropdown">{{ title }} <b class="caret"></b></a>
11 <ul class="dropdown-menu"> 11 <ul class="dropdown-menu">
12 - {% for text, link in links %}  
13 - <li><a href="{{ link }}">{{ text }}</a></li> 12 + {% for colab_url in links %}
  13 + <li><a href="{{ colab_url.url }}">{{ colab_url.display }}</a></li>
14 {% endfor %} 14 {% endfor %}
15 </ul> 15 </ul>
16 </li> 16 </li>
colab/plugins/templatetags/plugins.py
@@ -3,45 +3,48 @@ from collections import OrderedDict @@ -3,45 +3,48 @@ from collections import OrderedDict
3 from django import template 3 from django import template
4 from django.core.cache import cache 4 from django.core.cache import cache
5 from django.template.loader import render_to_string 5 from django.template.loader import render_to_string
6 -from django.utils.translation import ugettext_lazy as _ 6 +from django.utils.translation import get_language
7 7
8 register = template.Library() 8 register = template.Library()
9 9
10 10
11 @register.simple_tag(takes_context=True) 11 @register.simple_tag(takes_context=True)
12 def plugins_menu(context): 12 def plugins_menu(context):
  13 +
13 if context['user'].is_authenticated(): 14 if context['user'].is_authenticated():
14 cache_key = 'colab-proxy-menu-authenticated' 15 cache_key = 'colab-proxy-menu-authenticated'
15 else: 16 else:
16 cache_key = 'colab-proxy-menu-anonymous' 17 cache_key = 'colab-proxy-menu-anonymous'
17 18
  19 + lang = get_language()
  20 + cache_key += '-{}'.format(lang)
  21 +
18 menu_from_cache = cache.get(cache_key) 22 menu_from_cache = cache.get(cache_key)
19 23
20 if menu_from_cache: 24 if menu_from_cache:
21 return menu_from_cache 25 return menu_from_cache
22 26
23 menu_links = OrderedDict() 27 menu_links = OrderedDict()
24 - proxied_apps = context.get('proxy', {}) 28 + colab_apps = context.get('plugins', {})
25 29
26 - for app_name, app in proxied_apps.items():  
27 - if not app.get('menu'): 30 + for app_name, app in colab_apps.items():
  31 + if not app.get('menu_urls'):
28 continue 32 continue
29 33
30 - menu = app.get('menu')  
31 - title = menu.get('title', app_name)  
32 - links = menu.get('links', tuple()).items()  
33 - if context['user'].is_active:  
34 - links += menu.get('auth_links', tuple()).items()  
35 -  
36 - if not links:  
37 - continue 34 + menu = app.get('menu_urls')
  35 + title = app.get('menu_title', app_name)
38 36
39 if title not in menu_links: 37 if title not in menu_links:
40 - menu_links[_(title)] = [] 38 + menu_links[title] = []
  39 +
  40 + for colab_url in menu:
  41 + if not context['user'].is_active and colab_url.auth:
  42 + continue
  43 +
  44 + menu_links[title].append(colab_url)
41 45
42 - for text, link in links:  
43 - url = link  
44 - menu_links[_(title)].append((_(text), url)) 46 + if not menu_links[title]:
  47 + del menu_links[title]
45 48
46 menu = render_to_string('plugins/menu_template.html', 49 menu = render_to_string('plugins/menu_template.html',
47 {'menu_links': menu_links}) 50 {'menu_links': menu_links})
colab/plugins/urls.py
@@ -14,8 +14,8 @@ for app_name, app in settings.COLAB_APPS.items(): @@ -14,8 +14,8 @@ for app_name, app in settings.COLAB_APPS.items():
14 urls = app.get('urls') 14 urls = app.get('urls')
15 if not urls.get('include'): 15 if not urls.get('include'):
16 raise ImproperlyConfigured(undef_url_include_msg) 16 raise ImproperlyConfigured(undef_url_include_msg)
17 - print urls['include']  
18 urlpatterns += patterns('', 17 urlpatterns += patterns('',
19 url(urls.get('prefix', r''), include(urls['include'], 18 url(urls.get('prefix', r''), include(urls['include'],
20 namespace=urls.get('namespace'))), 19 namespace=urls.get('namespace'))),
21 - )  
22 \ No newline at end of file 20 \ No newline at end of file
  21 + )
  22 +
colab/plugins/utils/menu.py 0 → 100644
@@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
  1 +from django.core.urlresolvers import reverse_lazy
  2 +
  3 +
  4 +class ColabUrl(object):
  5 + def __init__(self, display, url, auth):
  6 + self.display = display
  7 + self.url = url
  8 + self.auth = auth
  9 +
  10 +
  11 +def colab_url_factory(namespace):
  12 +
  13 + def url(display, viewname, namespace=namespace, args=tuple(),
  14 + kwargs={}, auth=False):
  15 +
  16 + if namespace:
  17 + rev_viewname = ':'.join((namespace, viewname))
  18 + else:
  19 + rev_viewname = viewname
  20 +
  21 + url = reverse_lazy(rev_viewname, args=args, kwargs=kwargs)
  22 +
  23 + return ColabUrl(display, url, auth)
  24 +
  25 + return url
colab/settings.py
@@ -194,7 +194,7 @@ TEMPLATE_CONTEXT_PROCESSORS = ( @@ -194,7 +194,7 @@ TEMPLATE_CONTEXT_PROCESSORS = (
194 'django.core.context_processors.request', 194 'django.core.context_processors.request',
195 'django_mobile.context_processors.is_mobile', 195 'django_mobile.context_processors.is_mobile',
196 'colab.super_archives.context_processors.mailarchive', 196 'colab.super_archives.context_processors.mailarchive',
197 - 'colab.plugins.context_processors.proxied_apps', 197 + 'colab.plugins.context_processors.colab_apps',
198 'colab.home.context_processors.robots', 198 'colab.home.context_processors.robots',
199 'colab.home.context_processors.ribbon', 199 'colab.home.context_processors.ribbon',
200 'colab.home.context_processors.google_analytics', 200 'colab.home.context_processors.google_analytics',
@@ -280,8 +280,13 @@ CONVERSEJS_SHOW_ONLY_ONLINE_USERS = True @@ -280,8 +280,13 @@ CONVERSEJS_SHOW_ONLY_ONLINE_USERS = True
280 TASTYPIE_DEFAULT_FORMATS = ['json', ] 280 TASTYPIE_DEFAULT_FORMATS = ['json', ]
281 281
282 from .utils.conf import load_yaml_settings 282 from .utils.conf import load_yaml_settings
  283 +from .utils.conf import load_py_settings
  284 +from .utils.conf import load_colab_apps
  285 +
283 locals().update(load_yaml_settings()) 286 locals().update(load_yaml_settings())
284 287
  288 +locals().update(load_py_settings())
  289 +
285 if locals().get('RAVEN_DSN', False): 290 if locals().get('RAVEN_DSN', False):
286 RAVEN_CONFIG = { 291 RAVEN_CONFIG = {
287 'dsn': RAVEN_DSN + '?timeout=30', # noqa 292 'dsn': RAVEN_DSN + '?timeout=30', # noqa
@@ -291,6 +296,8 @@ if locals().get(&#39;RAVEN_DSN&#39;, False): @@ -291,6 +296,8 @@ if locals().get(&#39;RAVEN_DSN&#39;, False):
291 BROWSERID_ENABLED = locals().get('BROWSERID_ENABLED') or False 296 BROWSERID_ENABLED = locals().get('BROWSERID_ENABLED') or False
292 SOCIAL_NETWORK_ENABLED = locals().get('SOCIAL_NETWORK_ENABLED') or False 297 SOCIAL_NETWORK_ENABLED = locals().get('SOCIAL_NETWORK_ENABLED') or False
293 298
  299 +locals().update(load_colab_apps())
  300 +
294 COLAB_APPS = locals().get('COLAB_APPS') or {} 301 COLAB_APPS = locals().get('COLAB_APPS') or {}
295 PROXIED_APPS = {} 302 PROXIED_APPS = {}
296 303
colab/utils/conf.py
1 1
2 import os 2 import os
  3 +import sys
  4 +
  5 +import warnings
  6 +
3 import yaml 7 import yaml
4 8
5 import yamlordereddictloader 9 import yamlordereddictloader
6 10
7 from django.core.exceptions import ImproperlyConfigured 11 from django.core.exceptions import ImproperlyConfigured
8 12
  13 +import importlib
  14 +
  15 +
  16 +USING_YAML_SETTINGS = False
  17 +
9 18
10 class InaccessibleYAMLSettings(ImproperlyConfigured): 19 class InaccessibleYAMLSettings(ImproperlyConfigured):
11 """Settings YAML is Inaccessible. 20 """Settings YAML is Inaccessible.
@@ -29,22 +38,144 @@ def _load_yaml_file(yaml_path): @@ -29,22 +38,144 @@ def _load_yaml_file(yaml_path):
29 38
30 def load_yaml_settings(): 39 def load_yaml_settings():
31 settings_dir = '/etc/colab/settings.d' 40 settings_dir = '/etc/colab/settings.d'
32 - yaml_path = os.getenv('COLAB_SETTINGS', '/etc/colab/settings.yaml') 41 + yaml_path = os.getenv('COLAB_YAML_SETTINGS', '/etc/colab/settings.yaml')
33 42
34 - if not os.path.exists(yaml_path):  
35 - msg = "The yaml file {} does not exist".format(yaml_path)  
36 - raise InaccessibleYAMLSettings(msg) 43 + if os.path.exists(yaml_path):
  44 + global USING_YAML_SETTINGS
  45 + USING_YAML_SETTINGS = True
  46 + warnings.warn("YAML Settings file is deprecated. Use Py file instead.")
  47 + else:
  48 + return {}
37 49
38 yaml_settings = _load_yaml_file(yaml_path) 50 yaml_settings = _load_yaml_file(yaml_path)
39 51
  52 + parse_yml_menus(yaml_settings)
  53 +
40 # Try to read settings from settings.d 54 # Try to read settings from settings.d
41 if os.path.exists(settings_dir): 55 if os.path.exists(settings_dir):
42 for file_name in os.listdir(settings_dir): 56 for file_name in os.listdir(settings_dir):
43 if file_name.endswith('.yaml') or file_name.endswith('yml'): 57 if file_name.endswith('.yaml') or file_name.endswith('yml'):
44 file_path = os.path.join(settings_dir, file_name) 58 file_path = os.path.join(settings_dir, file_name)
45 yaml_settings_d = _load_yaml_file(file_path) 59 yaml_settings_d = _load_yaml_file(file_path)
  60 +
  61 + parse_yml_menus(yaml_settings_d)
  62 +
46 yaml_settings.update(yaml_settings_d) 63 yaml_settings.update(yaml_settings_d)
47 64
48 return yaml_settings or {} 65 return yaml_settings or {}
49 66
50 -yaml_settings = load_yaml_settings() 67 +
  68 +class InaccessiblePySettings(ImproperlyConfigured):
  69 + """Settings.py is Inaccessible.
  70 +
  71 + Check if the file exists and if you have read permissions."""
  72 +
  73 +
  74 +def _load_py_file(py_path, path):
  75 + original_path = sys.path
  76 +
  77 + sys.path = [path]
  78 + try:
  79 + py_settings = importlib.import_module(py_path)
  80 +
  81 + except IOError:
  82 + msg = ('Could not open settings file {}. Please '
  83 + 'check if the file exists and if user '
  84 + 'has read rights.').format(py_path)
  85 + raise InaccessiblePySettings(msg)
  86 +
  87 + except SyntaxError as excpt:
  88 + msg = ('Syntax Error: {}'.format(excpt))
  89 + raise InaccessiblePySettings(msg)
  90 +
  91 + finally:
  92 + sys.path = original_path
  93 +
  94 + py_setting = {var: getattr(py_settings, var) for var in dir(py_settings)
  95 + if not var.startswith('__')}
  96 +
  97 + return py_setting
  98 +
  99 +
  100 +def load_py_settings():
  101 + settings_dir = '/etc/colab/settings.d'
  102 + settings_file = os.getenv('COLAB_SETTINGS', '/etc/colab/settings.py')
  103 + settings_module = settings_file.split('.')[-2].split('/')[-1]
  104 + py_path = "/".join(settings_file.split('/')[:-1])
  105 +
  106 + global USING_YAML_SETTINGS
  107 + if not os.path.exists(py_path) and not USING_YAML_SETTINGS:
  108 + msg = "The py file {} does not exist".format(py_path)
  109 + raise InaccessiblePySettings(msg)
  110 + elif USING_YAML_SETTINGS:
  111 + return {}
  112 +
  113 + py_settings = _load_py_file(settings_module, py_path)
  114 +
  115 + # Try to read settings from settings.d
  116 +
  117 + if os.path.exists(settings_dir):
  118 + return py_settings
  119 + for file_name in os.listdir(settings_dir):
  120 + if file_name.endswith('.py'):
  121 + file_module = file_name.split('.')[0]
  122 + py_settings_d = _load_py_file(file_module, settings_dir)
  123 + py_settings.update(py_settings_d)
  124 +
  125 + return py_settings
  126 +
  127 +
  128 +def load_colab_apps():
  129 + plugins_dir = os.getenv('COLAB_PLUGINS', '/etc/colab/plugins.d/')
  130 +
  131 + global USING_YAML_SETTINGS
  132 + if USING_YAML_SETTINGS:
  133 + return {}
  134 +
  135 + COLAB_APPS = {}
  136 +
  137 + # Try to read settings from plugins.d
  138 + if os.path.exists(plugins_dir):
  139 + for file_name in os.listdir(plugins_dir):
  140 + if file_name.endswith('.py'):
  141 + file_module = file_name.split('.')[0]
  142 + py_settings_d = _load_py_file(file_module, plugins_dir)
  143 + fields = ['verbose_name', 'upstream', 'urls',
  144 + 'menu_urls', 'middlewares', 'dependencies',
  145 + 'context_processors']
  146 +
  147 + app_name = py_settings_d.get('name')
  148 + if not app_name:
  149 + warnings.warn("Plugin missing name variable")
  150 + continue
  151 +
  152 + COLAB_APPS[app_name] = {}
  153 + COLAB_APPS[app_name]['menu_title'] = \
  154 + py_settings_d.get('menu_title')
  155 +
  156 + for key in fields:
  157 + value = py_settings_d.get(key)
  158 + if value:
  159 + COLAB_APPS[app_name][key] = value
  160 +
  161 + return {'COLAB_APPS': COLAB_APPS}
  162 +
  163 +
  164 +def parse_yml_menus(yaml_settings):
  165 + if 'COLAB_APPS' in yaml_settings:
  166 + for key, plugin in yaml_settings['COLAB_APPS'].items():
  167 + if 'menu' in plugin:
  168 + parse_yml_tuples(yaml_settings['COLAB_APPS'][key]['menu'])
  169 +
  170 +
  171 +def parse_yml_tuples(menu):
  172 + dict_links = menu['links']
  173 + dict_auth_links = menu['auth_links']
  174 + menu['links'] = tuple()
  175 + menu['auth_links'] = tuple()
  176 +
  177 + for key, value in dict_links.items():
  178 + menu['links'] += ((key, value),)
  179 +
  180 + for key, value in dict_auth_links.items():
  181 + menu['auth_links'] += ((key, value),)
docs/source/user.rst
@@ -14,41 +14,33 @@ Install @@ -14,41 +14,33 @@ Install
14 14
15 Plugins 15 Plugins
16 ------- 16 -------
17 -.. attribute:: COLAB_APPS 17 +.. attribute:: name
18 18
19 - :default: None 19 +Declares the absolute name of the plugin app as a python import path. Example:
  20 +directory.something.someplugin
  21 +
  22 +.. attribute:: verbose_name
20 23
21 - Describes the activated plugins and its configurations. It's necessary to describe  
22 - for each app its name as the variable. The apps described here can be devided into  
23 - two categories, that beeing, colab proxy apps and third-party apps.  
24 - The upstream variable is only needed to colab proxy apps. 24 +Delclare the description name of the plugin.
25 25
26 .. attribute:: upstream 26 .. attribute:: upstream
27 27
28 -Declares the upstream server url of the proxy. Only declare if the plugin is a proxy. 28 +Declares the upstream server url of the proxy. Only declare if the plugin is a
  29 +proxy.
29 30
30 -dependecies  
31 -+++++++++++ 31 +.. attribute:: middlewares
32 32
33 - A list of the plugin dependecies that will be added to INSTALLED_APPS.  
34 - This doesn't automatically install the python dependecies, only add to django apps. 33 +Declares the middlewares of the plugin in a list format.
35 34
  35 +.. attribute:: context_processors
36 36
37 -menu  
38 -++++ 37 +Declares the context processors of the plugin in a list format too.
39 38
40 -.. attribute:: title 39 +.. attribute:: dependency
41 40
42 - Declares the menu title.  
43 -.. attribute:: links  
44 -  
45 - Declares the menu items and its links.  
46 -.. attribute:: auth_links  
47 -  
48 - Declares the menu items and its links when the user authenticated.  
49 -.. attribute:: dependecies  
50 -  
51 -Declares a list of the plugin dependecies. 41 +Declares the additional installed apps that this plugin depends on.
  42 +This doesn't automatically install the python dependecies, only add to django
  43 +apps.
52 44
53 urls 45 urls
54 ++++ 46 ++++
@@ -63,16 +55,35 @@ urls @@ -63,16 +55,35 @@ urls
63 55
64 Declares the namespace for the url. 56 Declares the namespace for the url.
65 57
66 -context_processors  
67 -++++++++++++++++++ 58 +menu
  59 +++++
68 60
69 - Declares the plugin context processors. 61 +These variables defines the menu title and links of the plugin.
70 62
71 -middlewares  
72 -+++++++++++ 63 +.. attribute:: menu_title
  64 +
  65 + Declares the menu title.
  66 +.. attribute:: menu_links
  67 +
  68 + Declares the menu items and its links.
  69 + This should be a tuple object with several colab_url elements.
  70 + The colab_url_factory creates a factory for your links along with your
  71 + namespace.
  72 + The auth parameter indicates wether the link should only be displayed when
  73 + the user is logged in.
  74 +
  75 +Example:
  76 +
  77 +.. code-block:: python
73 78
74 - Declares the plugin middlewares. 79 + from colab.plugins.utils.menu import colab_url_factory
75 80
  81 + url = colab_url_factory('plugin_app_name')
  82 +
  83 + menu_urls = (
  84 + url(display=_('Profile'), viewname='profile', kwargs={'path': '/profile/'}, auth=True),
  85 + url(display=_('Profile Two'), viewname='profile2', kwargs={'path': '/profile/2'}, auth=True),
  86 + )
76 87
77 Extra Template Folders 88 Extra Template Folders
78 ++++++++++++++++++++++ 89 ++++++++++++++++++++++
@@ -113,12 +124,12 @@ SVN @@ -113,12 +124,12 @@ SVN
113 .. TODO 124 .. TODO
114 125
115 Social Networks 126 Social Networks
116 -++++ 127 ++++++++++++++++
117 .. attribute:: SOCIAL_NETWORK_ENABLED 128 .. attribute:: SOCIAL_NETWORK_ENABLED
118 129
119 :default: False 130 :default: False
120 131
121 - When this variable is True, the social networks fields, like Facebook and 132 + When this variable is True, the social networks fields, like Facebook and
122 Twitter, are added in user profile. By default, this fields are disabled. 133 Twitter, are added in user profile. By default, this fields are disabled.
123 134
124 Auth 135 Auth
tests/config_settings.py 0 → 100644
@@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
  1 +SECRET_KEY = 'ddddddddddddddddddddddddddddddddddddddddddddddddddddddaddddddddd'
  2 +
  3 +DATABASES = {
  4 + 'default': {
  5 + 'ENGINE': 'django.db.backends.postgresql_psycopg2',
  6 + 'HOST': 'localhost',
  7 + 'NAME': 'colab',
  8 + 'USER': 'colab',
  9 + 'PASSWORD': 'colab',
  10 + }
  11 +}
tests/plugins.d/gitlab.py 0 → 100644
@@ -0,0 +1,39 @@ @@ -0,0 +1,39 @@
  1 +from django.utils.translation import ugettext_lazy as _
  2 +
  3 +name = 'colab.plugins.gitlab'
  4 +verbose_name = 'Gitlab Proxy'
  5 +
  6 +upstream = 'localhost'
  7 +#middlewares = []
  8 +
  9 +menu = {
  10 +'title': _('Code'),
  11 +'links': (
  12 + (_('Public Projects'), 'public/projects'),
  13 +),
  14 +'auth_links': (
  15 + (_('Profile'), 'profile'),
  16 + (_('New Project'), 'projects/new'),
  17 + (_('Projects'), 'dashboard/projects'),
  18 + (_('Groups'), 'profile/groups'),
  19 + (_('Issues'), 'dashboard/issues'),
  20 + (_('Merge Requests'), 'dashboard/merge_requests'),
  21 +
  22 +),
  23 +}
  24 +
  25 +
  26 +# dpaste:
  27 +# dependencies:
  28 +# - 'mptt'
  29 +# urls:
  30 +# include: 'dpaste.urls.dpaste'
  31 +# prefix: '^paste/'
  32 +# namespace: 'dpaste'
  33 +# menu:
  34 +# title: 'Dpaste'
  35 +# links:
  36 +# Public Projects: '/paste'
  37 +# auth_links:
  38 +# Profile: '/projects'
  39 +# New Project: '/projects/new'
@@ -4,7 +4,9 @@ import os @@ -4,7 +4,9 @@ import os
4 import sys 4 import sys
5 5
6 os.environ['DJANGO_SETTINGS_MODULE'] = 'tests.settings' 6 os.environ['DJANGO_SETTINGS_MODULE'] = 'tests.settings'
7 -os.environ['COLAB_SETTINGS'] = 'tests/settings.yaml' 7 +os.environ['COLAB_SETTINGS'] = 'tests/config_settings.py'
  8 +os.environ['COLAB_YAML_SETTINGS'] = 'tests/settings.yaml'
  9 +os.environ['COLAB_PLUGINS'] = 'tests/plugins.d'
8 os.environ['COVERAGE_PROCESS_START'] = '.coveragerc' 10 os.environ['COVERAGE_PROCESS_START'] = '.coveragerc'
9 os.environ['REUSE_DB'] = '0' 11 os.environ['REUSE_DB'] = '0'
10 12
tests/settings.yaml
@@ -1,73 +0,0 @@ @@ -1,73 +0,0 @@
1 -  
2 -  
3 -## Set to false in production  
4 -DEBUG: true  
5 -TEMPLATE_DEBUG: true  
6 -  
7 -## System admins  
8 -ADMINS: &admin  
9 - -  
10 - - John Foo  
11 - - john@example.com  
12 - -  
13 - - Mary Bar  
14 - - mary@example.com  
15 -  
16 -MANAGERS: *admin  
17 -  
18 -COLAB_FROM_ADDRESS: '"Colab" <noreply@example.com>'  
19 -SERVER_EMAIL: '"Colab" <noreply@example.com>'  
20 -  
21 -EMAIL_HOST: localhost  
22 -EMAIL_PORT: 25  
23 -EMAIL_SUBJECT_PREFIX: '[colab]'  
24 -  
25 -SECRET_KEY: 'hu8-)szdcjjsz%f02gt$5djbluxc$v0a%01l)di6oi)np7%8lu'  
26 -  
27 -# Must use it without trailing slash  
28 -SITE_URL: 'http://localhost:8000'  
29 -BROWSERID_AUDIENCES:  
30 - - http://localhost:8000  
31 -# - http://example.com  
32 -# - https://example.org  
33 -# - http://example.net  
34 -  
35 -ALLOWED_HOSTS:  
36 - - localhost  
37 -# - example.com  
38 -# - example.org  
39 -# - example.net  
40 -  
41 -### Uncomment to enable Broswer ID protocol for authentication  
42 -# BROWSERID_ENABLED: True  
43 -  
44 -### Uncomment to enable Converse.js  
45 -# CONVERSEJS_ENABLED: True  
46 -  
47 -### Uncomment to enable auto-registration  
48 -# CONVERSEJS_AUTO_REGISTER: 'xmpp.example.com'  
49 -  
50 -## Database settings  
51 -DATABASES:  
52 - default:  
53 - ENGINE: django.db.backends.postgresql_psycopg2  
54 - HOST: localhost  
55 - NAME: colab  
56 - USER: colab  
57 - PASSWORD: colab  
58 -  
59 -## Disable indexing  
60 -ROBOTS_NOINDEX: false  
61 -  
62 -### Log errors to Sentry instance  
63 -# RAVEN_DSN: 'http://public:secret@example.com/1'  
64 -  
65 -### Colab proxied apps  
66 -COLAB_APPS:  
67 - colab.plugins.gitlab:  
68 - upstream: 'http://localhost:8090/gitlab/'  
69 - private_token: ''  
70 -# colab.plugins.trac:  
71 -# upstream: 'http://localhost:5000/trac/'  
72 -  
73 -