##// END OF EJS Templates
ssh: added support for auto generating authorized_keys from stored ssh keys.
marcink -
r1994:801a60b3 default
parent child Browse files
Show More
@@ -0,0 +1,54 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
21 import logging
22
23 from . import config_keys
24 from .events import SshKeyFileChangeEvent
25 from .subscribers import generate_ssh_authorized_keys_file_subscriber
26
27 from rhodecode.config.middleware import _bool_setting, _string_setting
28
29 log = logging.getLogger(__name__)
30
31
32 def _sanitize_settings_and_apply_defaults(settings):
33 """
34 Set defaults, convert to python types and validate settings.
35 """
36 _bool_setting(settings, config_keys.generate_authorized_keyfile, 'false')
37 _bool_setting(settings, config_keys.wrapper_allow_shell, 'false')
38
39 _string_setting(settings, config_keys.authorized_keys_file_path, '',
40 lower=False)
41 _string_setting(settings, config_keys.wrapper_cmd, '',
42 lower=False)
43 _string_setting(settings, config_keys.authorized_keys_line_ssh_opts, '',
44 lower=False)
45
46
47 def includeme(config):
48 settings = config.registry.settings
49 _sanitize_settings_and_apply_defaults(settings)
50
51 # if we have enable generation of file, subscribe to event
52 if settings[config_keys.generate_authorized_keyfile]:
53 config.add_subscriber(
54 generate_ssh_authorized_keys_file_subscriber, SshKeyFileChangeEvent)
@@ -0,0 +1,28 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
21
22 # Definition of setting keys used to configure this module. Defined here to
23 # avoid repetition of keys throughout the module.
24 generate_authorized_keyfile = 'ssh.generate_authorized_keyfile'
25 authorized_keys_file_path = 'ssh.authorized_keys_file_path'
26 authorized_keys_line_ssh_opts = 'ssh.authorized_keys_ssh_opts'
27 wrapper_cmd = 'ssh.wrapper_cmd'
28 wrapper_allow_shell = 'ssh.wrapper_cmd_allow_shell'
@@ -0,0 +1,29 b''
1 # Copyright (C) 2016-2017 RhodeCode GmbH
2 #
3 # This program is free software: you can redistribute it and/or modify
4 # it under the terms of the GNU Affero General Public License, version 3
5 # (only), as published by the Free Software Foundation.
6 #
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
11 #
12 # You should have received a copy of the GNU Affero General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 #
15 # This program is dual-licensed. If you wish to learn more about the
16 # RhodeCode Enterprise Edition, including its added features, Support services,
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
18
19
20 from rhodecode.events.base import RhodecodeEvent
21 from rhodecode.translation import _
22
23
24 class SshKeyFileChangeEvent(RhodecodeEvent):
25 """
26 This event will be triggered on every modification of the stored SSH keys
27 """
28 name = 'rhodecode-ssh-key-file-change'
29 display_name = _('RhodeCode SSH Key files changed.')
@@ -0,0 +1,36 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
21 import logging
22
23
24 from .utils import generate_ssh_authorized_keys_file
25
26
27 log = logging.getLogger(__name__)
28
29
30 def generate_ssh_authorized_keys_file_subscriber(event):
31 """
32 Subscriber to the `SshKeyFileChangeEvent`. This triggers the
33 automatic generation of authorized_keys file on any change in
34 ssh keys management
35 """
36 generate_ssh_authorized_keys_file(event.request.registry)
@@ -0,0 +1,19 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
@@ -0,0 +1,68 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
21
22
23 import os
24 import pytest
25 import mock
26
27 from rhodecode.apps.ssh_support import utils
28 from rhodecode.lib.utils2 import AttributeDict
29
30
31 class TestSshKeyFileGeneration(object):
32 @pytest.mark.parametrize('ssh_wrapper_cmd', ['/tmp/sshwrapper.py'])
33 @pytest.mark.parametrize('allow_shell', [True, False])
34 @pytest.mark.parametrize('ssh_opts', [None, 'mycustom,option'])
35 def test_write_keyfile(self, tmpdir, ssh_wrapper_cmd, allow_shell, ssh_opts):
36
37 authorized_keys_file_path = os.path.join(str(tmpdir), 'authorized_keys')
38
39 def keys():
40 return [
41 AttributeDict({'user': AttributeDict(username='admin'),
42 'ssh_key_data': 'ssh-rsa ADMIN_KEY'}),
43 AttributeDict({'user': AttributeDict(username='user'),
44 'ssh_key_data': 'ssh-rsa USER_KEY'}),
45 ]
46
47 with mock.patch('rhodecode.apps.ssh_support.utils.get_all_active_keys',
48 return_value=keys()):
49 utils._generate_ssh_authorized_keys_file(
50 authorized_keys_file_path, ssh_wrapper_cmd,
51 allow_shell, ssh_opts
52 )
53
54 assert os.path.isfile(authorized_keys_file_path)
55 with open(authorized_keys_file_path) as f:
56 content = f.read()
57
58 assert 'command="/tmp/sshwrapper.py' in content
59 assert 'This file is managed by RhodeCode, ' \
60 'please do not edit it manually.' in content
61
62 if allow_shell:
63 assert '--shell --user' in content
64 else:
65 assert '--user' in content
66
67 if ssh_opts:
68 assert ssh_opts in content
@@ -0,0 +1,107 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
21 import os
22 import stat
23 import logging
24 import tempfile
25 import datetime
26
27 from . import config_keys
28 from rhodecode.model.db import true, joinedload, User, UserSshKeys
29
30
31 log = logging.getLogger(__name__)
32
33 HEADER = \
34 "# This file is managed by RhodeCode, please do not edit it manually. # \n" \
35 "# Current entries: {}, create date: UTC:{}.\n"
36
37 # Default SSH options for authorized_keys file, can be override via .ini
38 SSH_OPTS = 'no-pty,no-port-forwarding,no-X11-forwarding,no-agent-forwarding'
39
40
41 def get_all_active_keys():
42 result = UserSshKeys.query() \
43 .options(joinedload(UserSshKeys.user)) \
44 .filter(UserSshKeys.user != User.get_default_user()) \
45 .filter(User.active == true()) \
46 .all()
47 return result
48
49
50 def _generate_ssh_authorized_keys_file(
51 authorized_keys_file_path, ssh_wrapper_cmd, allow_shell, ssh_opts):
52 all_active_keys = get_all_active_keys()
53
54 if allow_shell:
55 ssh_wrapper_cmd = ssh_wrapper_cmd + ' --shell'
56
57 if not os.path.isfile(authorized_keys_file_path):
58 with open(authorized_keys_file_path, 'w'):
59 pass
60
61 if not os.access(authorized_keys_file_path, os.R_OK):
62 raise OSError('Access to file {} is without read access'.format(
63 authorized_keys_file_path))
64
65 line_tmpl = '{ssh_opts},command="{wrapper_command} --user {user}" {key}\n'
66
67 fd, tmp_authorized_keys = tempfile.mkstemp(
68 '.authorized_keys_write',
69 dir=os.path.dirname(authorized_keys_file_path))
70
71 now = datetime.datetime.utcnow().isoformat()
72 keys_file = os.fdopen(fd, 'wb')
73 keys_file.write(HEADER.format(len(all_active_keys), now))
74
75 for user_key in all_active_keys:
76 username = user_key.user.username
77 keys_file.write(
78 line_tmpl.format(
79 ssh_opts=ssh_opts or SSH_OPTS,
80 wrapper_command=ssh_wrapper_cmd,
81 user=username, key=user_key.ssh_key_data))
82 log.debug('addkey: Key added for user: `%s`', username)
83 keys_file.close()
84
85 # Explicitly setting read-only permissions to authorized_keys
86 os.chmod(tmp_authorized_keys, stat.S_IRUSR | stat.S_IWUSR)
87 # Rename is atomic operation
88 os.rename(tmp_authorized_keys, authorized_keys_file_path)
89
90
91 def generate_ssh_authorized_keys_file(registry):
92 log.info('Generating new authorized key file')
93
94 authorized_keys_file_path = registry.settings.get(
95 config_keys.authorized_keys_file_path)
96
97 ssh_wrapper_cmd = registry.settings.get(
98 config_keys.wrapper_cmd)
99 allow_shell = registry.settings.get(
100 config_keys.wrapper_allow_shell)
101 ssh_opts = registry.settings.get(
102 config_keys.authorized_keys_line_ssh_opts)
103
104 _generate_ssh_authorized_keys_file(
105 authorized_keys_file_path, ssh_wrapper_cmd, allow_shell, ssh_opts)
106
107 return 0
@@ -1,678 +1,699 b''
1
1
2
2
3 ################################################################################
3 ################################################################################
4 ## RHODECODE COMMUNITY EDITION CONFIGURATION ##
4 ## RHODECODE COMMUNITY EDITION CONFIGURATION ##
5 # The %(here)s variable will be replaced with the parent directory of this file#
5 # The %(here)s variable will be replaced with the parent directory of this file#
6 ################################################################################
6 ################################################################################
7
7
8 [DEFAULT]
8 [DEFAULT]
9 debug = true
9 debug = true
10
10
11 ################################################################################
11 ################################################################################
12 ## EMAIL CONFIGURATION ##
12 ## EMAIL CONFIGURATION ##
13 ## Uncomment and replace with the email address which should receive ##
13 ## Uncomment and replace with the email address which should receive ##
14 ## any error reports after an application crash ##
14 ## any error reports after an application crash ##
15 ## Additionally these settings will be used by the RhodeCode mailing system ##
15 ## Additionally these settings will be used by the RhodeCode mailing system ##
16 ################################################################################
16 ################################################################################
17
17
18 ## prefix all emails subjects with given prefix, helps filtering out emails
18 ## prefix all emails subjects with given prefix, helps filtering out emails
19 #email_prefix = [RhodeCode]
19 #email_prefix = [RhodeCode]
20
20
21 ## email FROM address all mails will be sent
21 ## email FROM address all mails will be sent
22 #app_email_from = rhodecode-noreply@localhost
22 #app_email_from = rhodecode-noreply@localhost
23
23
24 ## Uncomment and replace with the address which should receive any error report
24 ## Uncomment and replace with the address which should receive any error report
25 ## note: using appenlight for error handling doesn't need this to be uncommented
25 ## note: using appenlight for error handling doesn't need this to be uncommented
26 #email_to = admin@localhost
26 #email_to = admin@localhost
27
27
28 ## in case of Application errors, sent an error email form
28 ## in case of Application errors, sent an error email form
29 #error_email_from = rhodecode_error@localhost
29 #error_email_from = rhodecode_error@localhost
30
30
31 ## additional error message to be send in case of server crash
31 ## additional error message to be send in case of server crash
32 #error_message =
32 #error_message =
33
33
34
34
35 #smtp_server = mail.server.com
35 #smtp_server = mail.server.com
36 #smtp_username =
36 #smtp_username =
37 #smtp_password =
37 #smtp_password =
38 #smtp_port =
38 #smtp_port =
39 #smtp_use_tls = false
39 #smtp_use_tls = false
40 #smtp_use_ssl = true
40 #smtp_use_ssl = true
41 ## Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
41 ## Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
42 #smtp_auth =
42 #smtp_auth =
43
43
44 [server:main]
44 [server:main]
45 ## COMMON ##
45 ## COMMON ##
46 host = 127.0.0.1
46 host = 127.0.0.1
47 port = 5000
47 port = 5000
48
48
49 ##################################
49 ##################################
50 ## WAITRESS WSGI SERVER ##
50 ## WAITRESS WSGI SERVER ##
51 ## Recommended for Development ##
51 ## Recommended for Development ##
52 ##################################
52 ##################################
53
53
54 use = egg:waitress#main
54 use = egg:waitress#main
55 ## number of worker threads
55 ## number of worker threads
56 threads = 5
56 threads = 5
57 ## MAX BODY SIZE 100GB
57 ## MAX BODY SIZE 100GB
58 max_request_body_size = 107374182400
58 max_request_body_size = 107374182400
59 ## Use poll instead of select, fixes file descriptors limits problems.
59 ## Use poll instead of select, fixes file descriptors limits problems.
60 ## May not work on old windows systems.
60 ## May not work on old windows systems.
61 asyncore_use_poll = true
61 asyncore_use_poll = true
62
62
63
63
64 ##########################
64 ##########################
65 ## GUNICORN WSGI SERVER ##
65 ## GUNICORN WSGI SERVER ##
66 ##########################
66 ##########################
67 ## run with gunicorn --log-config rhodecode.ini --paste rhodecode.ini
67 ## run with gunicorn --log-config rhodecode.ini --paste rhodecode.ini
68
68
69 #use = egg:gunicorn#main
69 #use = egg:gunicorn#main
70 ## Sets the number of process workers. You must set `instance_id = *`
70 ## Sets the number of process workers. You must set `instance_id = *`
71 ## when this option is set to more than one worker, recommended
71 ## when this option is set to more than one worker, recommended
72 ## value is (2 * NUMBER_OF_CPUS + 1), eg 2CPU = 5 workers
72 ## value is (2 * NUMBER_OF_CPUS + 1), eg 2CPU = 5 workers
73 ## The `instance_id = *` must be set in the [app:main] section below
73 ## The `instance_id = *` must be set in the [app:main] section below
74 #workers = 2
74 #workers = 2
75 ## number of threads for each of the worker, must be set to 1 for gevent
75 ## number of threads for each of the worker, must be set to 1 for gevent
76 ## generally recommened to be at 1
76 ## generally recommened to be at 1
77 #threads = 1
77 #threads = 1
78 ## process name
78 ## process name
79 #proc_name = rhodecode
79 #proc_name = rhodecode
80 ## type of worker class, one of sync, gevent
80 ## type of worker class, one of sync, gevent
81 ## recommended for bigger setup is using of of other than sync one
81 ## recommended for bigger setup is using of of other than sync one
82 #worker_class = sync
82 #worker_class = sync
83 ## The maximum number of simultaneous clients. Valid only for Gevent
83 ## The maximum number of simultaneous clients. Valid only for Gevent
84 #worker_connections = 10
84 #worker_connections = 10
85 ## max number of requests that worker will handle before being gracefully
85 ## max number of requests that worker will handle before being gracefully
86 ## restarted, could prevent memory leaks
86 ## restarted, could prevent memory leaks
87 #max_requests = 1000
87 #max_requests = 1000
88 #max_requests_jitter = 30
88 #max_requests_jitter = 30
89 ## amount of time a worker can spend with handling a request before it
89 ## amount of time a worker can spend with handling a request before it
90 ## gets killed and restarted. Set to 6hrs
90 ## gets killed and restarted. Set to 6hrs
91 #timeout = 21600
91 #timeout = 21600
92
92
93
93
94 ## prefix middleware for RhodeCode.
94 ## prefix middleware for RhodeCode.
95 ## recommended when using proxy setup.
95 ## recommended when using proxy setup.
96 ## allows to set RhodeCode under a prefix in server.
96 ## allows to set RhodeCode under a prefix in server.
97 ## eg https://server.com/custom_prefix. Enable `filter-with =` option below as well.
97 ## eg https://server.com/custom_prefix. Enable `filter-with =` option below as well.
98 ## And set your prefix like: `prefix = /custom_prefix`
98 ## And set your prefix like: `prefix = /custom_prefix`
99 ## be sure to also set beaker.session.cookie_path = /custom_prefix if you need
99 ## be sure to also set beaker.session.cookie_path = /custom_prefix if you need
100 ## to make your cookies only work on prefix url
100 ## to make your cookies only work on prefix url
101 [filter:proxy-prefix]
101 [filter:proxy-prefix]
102 use = egg:PasteDeploy#prefix
102 use = egg:PasteDeploy#prefix
103 prefix = /
103 prefix = /
104
104
105 [app:main]
105 [app:main]
106 use = egg:rhodecode-enterprise-ce
106 use = egg:rhodecode-enterprise-ce
107
107
108 ## enable proxy prefix middleware, defined above
108 ## enable proxy prefix middleware, defined above
109 #filter-with = proxy-prefix
109 #filter-with = proxy-prefix
110
110
111 # During development the we want to have the debug toolbar enabled
111 # During development the we want to have the debug toolbar enabled
112 pyramid.includes =
112 pyramid.includes =
113 pyramid_debugtoolbar
113 pyramid_debugtoolbar
114 rhodecode.utils.debugtoolbar
114 rhodecode.utils.debugtoolbar
115 rhodecode.lib.middleware.request_wrapper
115 rhodecode.lib.middleware.request_wrapper
116
116
117 pyramid.reload_templates = true
117 pyramid.reload_templates = true
118
118
119 debugtoolbar.hosts = 0.0.0.0/0
119 debugtoolbar.hosts = 0.0.0.0/0
120 debugtoolbar.exclude_prefixes =
120 debugtoolbar.exclude_prefixes =
121 /css
121 /css
122 /fonts
122 /fonts
123 /images
123 /images
124 /js
124 /js
125
125
126 ## RHODECODE PLUGINS ##
126 ## RHODECODE PLUGINS ##
127 rhodecode.includes =
127 rhodecode.includes =
128 rhodecode.api
128 rhodecode.api
129
129
130
130
131 # api prefix url
131 # api prefix url
132 rhodecode.api.url = /_admin/api
132 rhodecode.api.url = /_admin/api
133
133
134
134
135 ## END RHODECODE PLUGINS ##
135 ## END RHODECODE PLUGINS ##
136
136
137 ## encryption key used to encrypt social plugin tokens,
137 ## encryption key used to encrypt social plugin tokens,
138 ## remote_urls with credentials etc, if not set it defaults to
138 ## remote_urls with credentials etc, if not set it defaults to
139 ## `beaker.session.secret`
139 ## `beaker.session.secret`
140 #rhodecode.encrypted_values.secret =
140 #rhodecode.encrypted_values.secret =
141
141
142 ## decryption strict mode (enabled by default). It controls if decryption raises
142 ## decryption strict mode (enabled by default). It controls if decryption raises
143 ## `SignatureVerificationError` in case of wrong key, or damaged encryption data.
143 ## `SignatureVerificationError` in case of wrong key, or damaged encryption data.
144 #rhodecode.encrypted_values.strict = false
144 #rhodecode.encrypted_values.strict = false
145
145
146 ## return gzipped responses from Rhodecode (static files/application)
146 ## return gzipped responses from Rhodecode (static files/application)
147 gzip_responses = false
147 gzip_responses = false
148
148
149 ## autogenerate javascript routes file on startup
149 ## autogenerate javascript routes file on startup
150 generate_js_files = false
150 generate_js_files = false
151
151
152 ## Optional Languages
152 ## Optional Languages
153 ## en(default), be, de, es, fr, it, ja, pl, pt, ru, zh
153 ## en(default), be, de, es, fr, it, ja, pl, pt, ru, zh
154 lang = en
154 lang = en
155
155
156 ## perform a full repository scan on each server start, this should be
156 ## perform a full repository scan on each server start, this should be
157 ## set to false after first startup, to allow faster server restarts.
157 ## set to false after first startup, to allow faster server restarts.
158 startup.import_repos = false
158 startup.import_repos = false
159
159
160 ## Uncomment and set this path to use archive download cache.
160 ## Uncomment and set this path to use archive download cache.
161 ## Once enabled, generated archives will be cached at this location
161 ## Once enabled, generated archives will be cached at this location
162 ## and served from the cache during subsequent requests for the same archive of
162 ## and served from the cache during subsequent requests for the same archive of
163 ## the repository.
163 ## the repository.
164 #archive_cache_dir = /tmp/tarballcache
164 #archive_cache_dir = /tmp/tarballcache
165
165
166 ## change this to unique ID for security
166 ## change this to unique ID for security
167 app_instance_uuid = rc-production
167 app_instance_uuid = rc-production
168
168
169 ## cut off limit for large diffs (size in bytes)
169 ## cut off limit for large diffs (size in bytes)
170 cut_off_limit_diff = 1024000
170 cut_off_limit_diff = 1024000
171 cut_off_limit_file = 256000
171 cut_off_limit_file = 256000
172
172
173 ## use cache version of scm repo everywhere
173 ## use cache version of scm repo everywhere
174 vcs_full_cache = true
174 vcs_full_cache = true
175
175
176 ## force https in RhodeCode, fixes https redirects, assumes it's always https
176 ## force https in RhodeCode, fixes https redirects, assumes it's always https
177 ## Normally this is controlled by proper http flags sent from http server
177 ## Normally this is controlled by proper http flags sent from http server
178 force_https = false
178 force_https = false
179
179
180 ## use Strict-Transport-Security headers
180 ## use Strict-Transport-Security headers
181 use_htsts = false
181 use_htsts = false
182
182
183 ## number of commits stats will parse on each iteration
183 ## number of commits stats will parse on each iteration
184 commit_parse_limit = 25
184 commit_parse_limit = 25
185
185
186 ## git rev filter option, --all is the default filter, if you need to
186 ## git rev filter option, --all is the default filter, if you need to
187 ## hide all refs in changelog switch this to --branches --tags
187 ## hide all refs in changelog switch this to --branches --tags
188 git_rev_filter = --branches --tags
188 git_rev_filter = --branches --tags
189
189
190 # Set to true if your repos are exposed using the dumb protocol
190 # Set to true if your repos are exposed using the dumb protocol
191 git_update_server_info = false
191 git_update_server_info = false
192
192
193 ## RSS/ATOM feed options
193 ## RSS/ATOM feed options
194 rss_cut_off_limit = 256000
194 rss_cut_off_limit = 256000
195 rss_items_per_page = 10
195 rss_items_per_page = 10
196 rss_include_diff = false
196 rss_include_diff = false
197
197
198 ## gist URL alias, used to create nicer urls for gist. This should be an
198 ## gist URL alias, used to create nicer urls for gist. This should be an
199 ## url that does rewrites to _admin/gists/{gistid}.
199 ## url that does rewrites to _admin/gists/{gistid}.
200 ## example: http://gist.rhodecode.org/{gistid}. Empty means use the internal
200 ## example: http://gist.rhodecode.org/{gistid}. Empty means use the internal
201 ## RhodeCode url, ie. http[s]://rhodecode.server/_admin/gists/{gistid}
201 ## RhodeCode url, ie. http[s]://rhodecode.server/_admin/gists/{gistid}
202 gist_alias_url =
202 gist_alias_url =
203
203
204 ## List of views (using glob pattern syntax) that AUTH TOKENS could be
204 ## List of views (using glob pattern syntax) that AUTH TOKENS could be
205 ## used for access.
205 ## used for access.
206 ## Adding ?auth_token=TOKEN_HASH to the url authenticates this request as if it
206 ## Adding ?auth_token=TOKEN_HASH to the url authenticates this request as if it
207 ## came from the the logged in user who own this authentication token.
207 ## came from the the logged in user who own this authentication token.
208 ##
208 ##
209 ## list of all views can be found under `_admin/permissions/auth_token_access`
209 ## list of all views can be found under `_admin/permissions/auth_token_access`
210 ## The list should be "," separated and on a single line.
210 ## The list should be "," separated and on a single line.
211 ##
211 ##
212 ## Most common views to enable:
212 ## Most common views to enable:
213 # RepoCommitsView:repo_commit_download
213 # RepoCommitsView:repo_commit_download
214 # RepoCommitsView:repo_commit_patch
214 # RepoCommitsView:repo_commit_patch
215 # RepoCommitsView:repo_commit_raw
215 # RepoCommitsView:repo_commit_raw
216 # RepoFilesView:repo_files_diff
216 # RepoFilesView:repo_files_diff
217 # RepoFilesView:repo_archivefile
217 # RepoFilesView:repo_archivefile
218 # RepoFilesView:repo_file_raw
218 # RepoFilesView:repo_file_raw
219 # GistView:*
219 # GistView:*
220 api_access_controllers_whitelist =
220 api_access_controllers_whitelist =
221
221
222 ## default encoding used to convert from and to unicode
222 ## default encoding used to convert from and to unicode
223 ## can be also a comma separated list of encoding in case of mixed encodings
223 ## can be also a comma separated list of encoding in case of mixed encodings
224 default_encoding = UTF-8
224 default_encoding = UTF-8
225
225
226 ## instance-id prefix
226 ## instance-id prefix
227 ## a prefix key for this instance used for cache invalidation when running
227 ## a prefix key for this instance used for cache invalidation when running
228 ## multiple instances of rhodecode, make sure it's globally unique for
228 ## multiple instances of rhodecode, make sure it's globally unique for
229 ## all running rhodecode instances. Leave empty if you don't use it
229 ## all running rhodecode instances. Leave empty if you don't use it
230 instance_id =
230 instance_id =
231
231
232 ## Fallback authentication plugin. Set this to a plugin ID to force the usage
232 ## Fallback authentication plugin. Set this to a plugin ID to force the usage
233 ## of an authentication plugin also if it is disabled by it's settings.
233 ## of an authentication plugin also if it is disabled by it's settings.
234 ## This could be useful if you are unable to log in to the system due to broken
234 ## This could be useful if you are unable to log in to the system due to broken
235 ## authentication settings. Then you can enable e.g. the internal rhodecode auth
235 ## authentication settings. Then you can enable e.g. the internal rhodecode auth
236 ## module to log in again and fix the settings.
236 ## module to log in again and fix the settings.
237 ##
237 ##
238 ## Available builtin plugin IDs (hash is part of the ID):
238 ## Available builtin plugin IDs (hash is part of the ID):
239 ## egg:rhodecode-enterprise-ce#rhodecode
239 ## egg:rhodecode-enterprise-ce#rhodecode
240 ## egg:rhodecode-enterprise-ce#pam
240 ## egg:rhodecode-enterprise-ce#pam
241 ## egg:rhodecode-enterprise-ce#ldap
241 ## egg:rhodecode-enterprise-ce#ldap
242 ## egg:rhodecode-enterprise-ce#jasig_cas
242 ## egg:rhodecode-enterprise-ce#jasig_cas
243 ## egg:rhodecode-enterprise-ce#headers
243 ## egg:rhodecode-enterprise-ce#headers
244 ## egg:rhodecode-enterprise-ce#crowd
244 ## egg:rhodecode-enterprise-ce#crowd
245 #rhodecode.auth_plugin_fallback = egg:rhodecode-enterprise-ce#rhodecode
245 #rhodecode.auth_plugin_fallback = egg:rhodecode-enterprise-ce#rhodecode
246
246
247 ## alternative return HTTP header for failed authentication. Default HTTP
247 ## alternative return HTTP header for failed authentication. Default HTTP
248 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
248 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
249 ## handling that causing a series of failed authentication calls.
249 ## handling that causing a series of failed authentication calls.
250 ## Set this variable to 403 to return HTTPForbidden, or any other HTTP code
250 ## Set this variable to 403 to return HTTPForbidden, or any other HTTP code
251 ## This will be served instead of default 401 on bad authnetication
251 ## This will be served instead of default 401 on bad authnetication
252 auth_ret_code =
252 auth_ret_code =
253
253
254 ## use special detection method when serving auth_ret_code, instead of serving
254 ## use special detection method when serving auth_ret_code, instead of serving
255 ## ret_code directly, use 401 initially (Which triggers credentials prompt)
255 ## ret_code directly, use 401 initially (Which triggers credentials prompt)
256 ## and then serve auth_ret_code to clients
256 ## and then serve auth_ret_code to clients
257 auth_ret_code_detection = false
257 auth_ret_code_detection = false
258
258
259 ## locking return code. When repository is locked return this HTTP code. 2XX
259 ## locking return code. When repository is locked return this HTTP code. 2XX
260 ## codes don't break the transactions while 4XX codes do
260 ## codes don't break the transactions while 4XX codes do
261 lock_ret_code = 423
261 lock_ret_code = 423
262
262
263 ## allows to change the repository location in settings page
263 ## allows to change the repository location in settings page
264 allow_repo_location_change = true
264 allow_repo_location_change = true
265
265
266 ## allows to setup custom hooks in settings page
266 ## allows to setup custom hooks in settings page
267 allow_custom_hooks_settings = true
267 allow_custom_hooks_settings = true
268
268
269 ## generated license token, goto license page in RhodeCode settings to obtain
269 ## generated license token, goto license page in RhodeCode settings to obtain
270 ## new token
270 ## new token
271 license_token =
271 license_token =
272
272
273 ## supervisor connection uri, for managing supervisor and logs.
273 ## supervisor connection uri, for managing supervisor and logs.
274 supervisor.uri =
274 supervisor.uri =
275 ## supervisord group name/id we only want this RC instance to handle
275 ## supervisord group name/id we only want this RC instance to handle
276 supervisor.group_id = dev
276 supervisor.group_id = dev
277
277
278 ## Display extended labs settings
278 ## Display extended labs settings
279 labs_settings_active = true
279 labs_settings_active = true
280
280
281 ####################################
281 ####################################
282 ### CELERY CONFIG ####
282 ### CELERY CONFIG ####
283 ####################################
283 ####################################
284 use_celery = false
284 use_celery = false
285 broker.host = localhost
285 broker.host = localhost
286 broker.vhost = rabbitmqhost
286 broker.vhost = rabbitmqhost
287 broker.port = 5672
287 broker.port = 5672
288 broker.user = rabbitmq
288 broker.user = rabbitmq
289 broker.password = qweqwe
289 broker.password = qweqwe
290
290
291 celery.imports = rhodecode.lib.celerylib.tasks
291 celery.imports = rhodecode.lib.celerylib.tasks
292
292
293 celery.result.backend = amqp
293 celery.result.backend = amqp
294 celery.result.dburi = amqp://
294 celery.result.dburi = amqp://
295 celery.result.serialier = json
295 celery.result.serialier = json
296
296
297 #celery.send.task.error.emails = true
297 #celery.send.task.error.emails = true
298 #celery.amqp.task.result.expires = 18000
298 #celery.amqp.task.result.expires = 18000
299
299
300 celeryd.concurrency = 2
300 celeryd.concurrency = 2
301 #celeryd.log.file = celeryd.log
301 #celeryd.log.file = celeryd.log
302 celeryd.log.level = debug
302 celeryd.log.level = debug
303 celeryd.max.tasks.per.child = 1
303 celeryd.max.tasks.per.child = 1
304
304
305 ## tasks will never be sent to the queue, but executed locally instead.
305 ## tasks will never be sent to the queue, but executed locally instead.
306 celery.always.eager = false
306 celery.always.eager = false
307
307
308 ####################################
308 ####################################
309 ### BEAKER CACHE ####
309 ### BEAKER CACHE ####
310 ####################################
310 ####################################
311 # default cache dir for templates. Putting this into a ramdisk
311 # default cache dir for templates. Putting this into a ramdisk
312 ## can boost performance, eg. %(here)s/data_ramdisk
312 ## can boost performance, eg. %(here)s/data_ramdisk
313 cache_dir = %(here)s/data
313 cache_dir = %(here)s/data
314
314
315 ## locking and default file storage for Beaker. Putting this into a ramdisk
315 ## locking and default file storage for Beaker. Putting this into a ramdisk
316 ## can boost performance, eg. %(here)s/data_ramdisk/cache/beaker_data
316 ## can boost performance, eg. %(here)s/data_ramdisk/cache/beaker_data
317 beaker.cache.data_dir = %(here)s/data/cache/beaker_data
317 beaker.cache.data_dir = %(here)s/data/cache/beaker_data
318 beaker.cache.lock_dir = %(here)s/data/cache/beaker_lock
318 beaker.cache.lock_dir = %(here)s/data/cache/beaker_lock
319
319
320 beaker.cache.regions = super_short_term, short_term, long_term, sql_cache_short, auth_plugins, repo_cache_long
320 beaker.cache.regions = super_short_term, short_term, long_term, sql_cache_short, auth_plugins, repo_cache_long
321
321
322 beaker.cache.super_short_term.type = memory
322 beaker.cache.super_short_term.type = memory
323 beaker.cache.super_short_term.expire = 10
323 beaker.cache.super_short_term.expire = 10
324 beaker.cache.super_short_term.key_length = 256
324 beaker.cache.super_short_term.key_length = 256
325
325
326 beaker.cache.short_term.type = memory
326 beaker.cache.short_term.type = memory
327 beaker.cache.short_term.expire = 60
327 beaker.cache.short_term.expire = 60
328 beaker.cache.short_term.key_length = 256
328 beaker.cache.short_term.key_length = 256
329
329
330 beaker.cache.long_term.type = memory
330 beaker.cache.long_term.type = memory
331 beaker.cache.long_term.expire = 36000
331 beaker.cache.long_term.expire = 36000
332 beaker.cache.long_term.key_length = 256
332 beaker.cache.long_term.key_length = 256
333
333
334 beaker.cache.sql_cache_short.type = memory
334 beaker.cache.sql_cache_short.type = memory
335 beaker.cache.sql_cache_short.expire = 10
335 beaker.cache.sql_cache_short.expire = 10
336 beaker.cache.sql_cache_short.key_length = 256
336 beaker.cache.sql_cache_short.key_length = 256
337
337
338 ## default is memory cache, configure only if required
338 ## default is memory cache, configure only if required
339 ## using multi-node or multi-worker setup
339 ## using multi-node or multi-worker setup
340 #beaker.cache.auth_plugins.type = ext:database
340 #beaker.cache.auth_plugins.type = ext:database
341 #beaker.cache.auth_plugins.lock_dir = %(here)s/data/cache/auth_plugin_lock
341 #beaker.cache.auth_plugins.lock_dir = %(here)s/data/cache/auth_plugin_lock
342 #beaker.cache.auth_plugins.url = postgresql://postgres:secret@localhost/rhodecode
342 #beaker.cache.auth_plugins.url = postgresql://postgres:secret@localhost/rhodecode
343 #beaker.cache.auth_plugins.url = mysql://root:secret@127.0.0.1/rhodecode
343 #beaker.cache.auth_plugins.url = mysql://root:secret@127.0.0.1/rhodecode
344 #beaker.cache.auth_plugins.sa.pool_recycle = 3600
344 #beaker.cache.auth_plugins.sa.pool_recycle = 3600
345 #beaker.cache.auth_plugins.sa.pool_size = 10
345 #beaker.cache.auth_plugins.sa.pool_size = 10
346 #beaker.cache.auth_plugins.sa.max_overflow = 0
346 #beaker.cache.auth_plugins.sa.max_overflow = 0
347
347
348 beaker.cache.repo_cache_long.type = memorylru_base
348 beaker.cache.repo_cache_long.type = memorylru_base
349 beaker.cache.repo_cache_long.max_items = 4096
349 beaker.cache.repo_cache_long.max_items = 4096
350 beaker.cache.repo_cache_long.expire = 2592000
350 beaker.cache.repo_cache_long.expire = 2592000
351
351
352 ## default is memorylru_base cache, configure only if required
352 ## default is memorylru_base cache, configure only if required
353 ## using multi-node or multi-worker setup
353 ## using multi-node or multi-worker setup
354 #beaker.cache.repo_cache_long.type = ext:memcached
354 #beaker.cache.repo_cache_long.type = ext:memcached
355 #beaker.cache.repo_cache_long.url = localhost:11211
355 #beaker.cache.repo_cache_long.url = localhost:11211
356 #beaker.cache.repo_cache_long.expire = 1209600
356 #beaker.cache.repo_cache_long.expire = 1209600
357 #beaker.cache.repo_cache_long.key_length = 256
357 #beaker.cache.repo_cache_long.key_length = 256
358
358
359 ####################################
359 ####################################
360 ### BEAKER SESSION ####
360 ### BEAKER SESSION ####
361 ####################################
361 ####################################
362
362
363 ## .session.type is type of storage options for the session, current allowed
363 ## .session.type is type of storage options for the session, current allowed
364 ## types are file, ext:memcached, ext:database, and memory (default).
364 ## types are file, ext:memcached, ext:database, and memory (default).
365 beaker.session.type = file
365 beaker.session.type = file
366 beaker.session.data_dir = %(here)s/data/sessions/data
366 beaker.session.data_dir = %(here)s/data/sessions/data
367
367
368 ## db based session, fast, and allows easy management over logged in users
368 ## db based session, fast, and allows easy management over logged in users
369 #beaker.session.type = ext:database
369 #beaker.session.type = ext:database
370 #beaker.session.table_name = db_session
370 #beaker.session.table_name = db_session
371 #beaker.session.sa.url = postgresql://postgres:secret@localhost/rhodecode
371 #beaker.session.sa.url = postgresql://postgres:secret@localhost/rhodecode
372 #beaker.session.sa.url = mysql://root:secret@127.0.0.1/rhodecode
372 #beaker.session.sa.url = mysql://root:secret@127.0.0.1/rhodecode
373 #beaker.session.sa.pool_recycle = 3600
373 #beaker.session.sa.pool_recycle = 3600
374 #beaker.session.sa.echo = false
374 #beaker.session.sa.echo = false
375
375
376 beaker.session.key = rhodecode
376 beaker.session.key = rhodecode
377 beaker.session.secret = develop-rc-uytcxaz
377 beaker.session.secret = develop-rc-uytcxaz
378 beaker.session.lock_dir = %(here)s/data/sessions/lock
378 beaker.session.lock_dir = %(here)s/data/sessions/lock
379
379
380 ## Secure encrypted cookie. Requires AES and AES python libraries
380 ## Secure encrypted cookie. Requires AES and AES python libraries
381 ## you must disable beaker.session.secret to use this
381 ## you must disable beaker.session.secret to use this
382 #beaker.session.encrypt_key = key_for_encryption
382 #beaker.session.encrypt_key = key_for_encryption
383 #beaker.session.validate_key = validation_key
383 #beaker.session.validate_key = validation_key
384
384
385 ## sets session as invalid(also logging out user) if it haven not been
385 ## sets session as invalid(also logging out user) if it haven not been
386 ## accessed for given amount of time in seconds
386 ## accessed for given amount of time in seconds
387 beaker.session.timeout = 2592000
387 beaker.session.timeout = 2592000
388 beaker.session.httponly = true
388 beaker.session.httponly = true
389 ## Path to use for the cookie. Set to prefix if you use prefix middleware
389 ## Path to use for the cookie. Set to prefix if you use prefix middleware
390 #beaker.session.cookie_path = /custom_prefix
390 #beaker.session.cookie_path = /custom_prefix
391
391
392 ## uncomment for https secure cookie
392 ## uncomment for https secure cookie
393 beaker.session.secure = false
393 beaker.session.secure = false
394
394
395 ## auto save the session to not to use .save()
395 ## auto save the session to not to use .save()
396 beaker.session.auto = false
396 beaker.session.auto = false
397
397
398 ## default cookie expiration time in seconds, set to `true` to set expire
398 ## default cookie expiration time in seconds, set to `true` to set expire
399 ## at browser close
399 ## at browser close
400 #beaker.session.cookie_expires = 3600
400 #beaker.session.cookie_expires = 3600
401
401
402 ###################################
402 ###################################
403 ## SEARCH INDEXING CONFIGURATION ##
403 ## SEARCH INDEXING CONFIGURATION ##
404 ###################################
404 ###################################
405 ## Full text search indexer is available in rhodecode-tools under
405 ## Full text search indexer is available in rhodecode-tools under
406 ## `rhodecode-tools index` command
406 ## `rhodecode-tools index` command
407
407
408 ## WHOOSH Backend, doesn't require additional services to run
408 ## WHOOSH Backend, doesn't require additional services to run
409 ## it works good with few dozen repos
409 ## it works good with few dozen repos
410 search.module = rhodecode.lib.index.whoosh
410 search.module = rhodecode.lib.index.whoosh
411 search.location = %(here)s/data/index
411 search.location = %(here)s/data/index
412
412
413 ########################################
413 ########################################
414 ### CHANNELSTREAM CONFIG ####
414 ### CHANNELSTREAM CONFIG ####
415 ########################################
415 ########################################
416 ## channelstream enables persistent connections and live notification
416 ## channelstream enables persistent connections and live notification
417 ## in the system. It's also used by the chat system
417 ## in the system. It's also used by the chat system
418 channelstream.enabled = false
418 channelstream.enabled = false
419
419
420 ## server address for channelstream server on the backend
420 ## server address for channelstream server on the backend
421 channelstream.server = 127.0.0.1:9800
421 channelstream.server = 127.0.0.1:9800
422
422
423 ## location of the channelstream server from outside world
423 ## location of the channelstream server from outside world
424 ## use ws:// for http or wss:// for https. This address needs to be handled
424 ## use ws:// for http or wss:// for https. This address needs to be handled
425 ## by external HTTP server such as Nginx or Apache
425 ## by external HTTP server such as Nginx or Apache
426 ## see nginx/apache configuration examples in our docs
426 ## see nginx/apache configuration examples in our docs
427 channelstream.ws_url = ws://rhodecode.yourserver.com/_channelstream
427 channelstream.ws_url = ws://rhodecode.yourserver.com/_channelstream
428 channelstream.secret = secret
428 channelstream.secret = secret
429 channelstream.history.location = %(here)s/channelstream_history
429 channelstream.history.location = %(here)s/channelstream_history
430
430
431 ## Internal application path that Javascript uses to connect into.
431 ## Internal application path that Javascript uses to connect into.
432 ## If you use proxy-prefix the prefix should be added before /_channelstream
432 ## If you use proxy-prefix the prefix should be added before /_channelstream
433 channelstream.proxy_path = /_channelstream
433 channelstream.proxy_path = /_channelstream
434
434
435
435
436 ###################################
436 ###################################
437 ## APPENLIGHT CONFIG ##
437 ## APPENLIGHT CONFIG ##
438 ###################################
438 ###################################
439
439
440 ## Appenlight is tailored to work with RhodeCode, see
440 ## Appenlight is tailored to work with RhodeCode, see
441 ## http://appenlight.com for details how to obtain an account
441 ## http://appenlight.com for details how to obtain an account
442
442
443 ## appenlight integration enabled
443 ## appenlight integration enabled
444 appenlight = false
444 appenlight = false
445
445
446 appenlight.server_url = https://api.appenlight.com
446 appenlight.server_url = https://api.appenlight.com
447 appenlight.api_key = YOUR_API_KEY
447 appenlight.api_key = YOUR_API_KEY
448 #appenlight.transport_config = https://api.appenlight.com?threaded=1&timeout=5
448 #appenlight.transport_config = https://api.appenlight.com?threaded=1&timeout=5
449
449
450 # used for JS client
450 # used for JS client
451 appenlight.api_public_key = YOUR_API_PUBLIC_KEY
451 appenlight.api_public_key = YOUR_API_PUBLIC_KEY
452
452
453 ## TWEAK AMOUNT OF INFO SENT HERE
453 ## TWEAK AMOUNT OF INFO SENT HERE
454
454
455 ## enables 404 error logging (default False)
455 ## enables 404 error logging (default False)
456 appenlight.report_404 = false
456 appenlight.report_404 = false
457
457
458 ## time in seconds after request is considered being slow (default 1)
458 ## time in seconds after request is considered being slow (default 1)
459 appenlight.slow_request_time = 1
459 appenlight.slow_request_time = 1
460
460
461 ## record slow requests in application
461 ## record slow requests in application
462 ## (needs to be enabled for slow datastore recording and time tracking)
462 ## (needs to be enabled for slow datastore recording and time tracking)
463 appenlight.slow_requests = true
463 appenlight.slow_requests = true
464
464
465 ## enable hooking to application loggers
465 ## enable hooking to application loggers
466 appenlight.logging = true
466 appenlight.logging = true
467
467
468 ## minimum log level for log capture
468 ## minimum log level for log capture
469 appenlight.logging.level = WARNING
469 appenlight.logging.level = WARNING
470
470
471 ## send logs only from erroneous/slow requests
471 ## send logs only from erroneous/slow requests
472 ## (saves API quota for intensive logging)
472 ## (saves API quota for intensive logging)
473 appenlight.logging_on_error = false
473 appenlight.logging_on_error = false
474
474
475 ## list of additonal keywords that should be grabbed from environ object
475 ## list of additonal keywords that should be grabbed from environ object
476 ## can be string with comma separated list of words in lowercase
476 ## can be string with comma separated list of words in lowercase
477 ## (by default client will always send following info:
477 ## (by default client will always send following info:
478 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
478 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
479 ## start with HTTP* this list be extended with additional keywords here
479 ## start with HTTP* this list be extended with additional keywords here
480 appenlight.environ_keys_whitelist =
480 appenlight.environ_keys_whitelist =
481
481
482 ## list of keywords that should be blanked from request object
482 ## list of keywords that should be blanked from request object
483 ## can be string with comma separated list of words in lowercase
483 ## can be string with comma separated list of words in lowercase
484 ## (by default client will always blank keys that contain following words
484 ## (by default client will always blank keys that contain following words
485 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
485 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
486 ## this list be extended with additional keywords set here
486 ## this list be extended with additional keywords set here
487 appenlight.request_keys_blacklist =
487 appenlight.request_keys_blacklist =
488
488
489 ## list of namespaces that should be ignores when gathering log entries
489 ## list of namespaces that should be ignores when gathering log entries
490 ## can be string with comma separated list of namespaces
490 ## can be string with comma separated list of namespaces
491 ## (by default the client ignores own entries: appenlight_client.client)
491 ## (by default the client ignores own entries: appenlight_client.client)
492 appenlight.log_namespace_blacklist =
492 appenlight.log_namespace_blacklist =
493
493
494
494
495 ################################################################################
495 ################################################################################
496 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
496 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
497 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
497 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
498 ## execute malicious code after an exception is raised. ##
498 ## execute malicious code after an exception is raised. ##
499 ################################################################################
499 ################################################################################
500 #set debug = false
500 #set debug = false
501
501
502
502
503 ##############
503 ##############
504 ## STYLING ##
504 ## STYLING ##
505 ##############
505 ##############
506 debug_style = true
506 debug_style = true
507
507
508 ###########################################
508 ###########################################
509 ### MAIN RHODECODE DATABASE CONFIG ###
509 ### MAIN RHODECODE DATABASE CONFIG ###
510 ###########################################
510 ###########################################
511 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db?timeout=30
511 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db?timeout=30
512 #sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode
512 #sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode
513 #sqlalchemy.db1.url = mysql://root:qweqwe@localhost/rhodecode
513 #sqlalchemy.db1.url = mysql://root:qweqwe@localhost/rhodecode
514 sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db?timeout=30
514 sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db?timeout=30
515
515
516 # see sqlalchemy docs for other advanced settings
516 # see sqlalchemy docs for other advanced settings
517
517
518 ## print the sql statements to output
518 ## print the sql statements to output
519 sqlalchemy.db1.echo = false
519 sqlalchemy.db1.echo = false
520 ## recycle the connections after this amount of seconds
520 ## recycle the connections after this amount of seconds
521 sqlalchemy.db1.pool_recycle = 3600
521 sqlalchemy.db1.pool_recycle = 3600
522 sqlalchemy.db1.convert_unicode = true
522 sqlalchemy.db1.convert_unicode = true
523
523
524 ## the number of connections to keep open inside the connection pool.
524 ## the number of connections to keep open inside the connection pool.
525 ## 0 indicates no limit
525 ## 0 indicates no limit
526 #sqlalchemy.db1.pool_size = 5
526 #sqlalchemy.db1.pool_size = 5
527
527
528 ## the number of connections to allow in connection pool "overflow", that is
528 ## the number of connections to allow in connection pool "overflow", that is
529 ## connections that can be opened above and beyond the pool_size setting,
529 ## connections that can be opened above and beyond the pool_size setting,
530 ## which defaults to five.
530 ## which defaults to five.
531 #sqlalchemy.db1.max_overflow = 10
531 #sqlalchemy.db1.max_overflow = 10
532
532
533
533
534 ##################
534 ##################
535 ### VCS CONFIG ###
535 ### VCS CONFIG ###
536 ##################
536 ##################
537 vcs.server.enable = true
537 vcs.server.enable = true
538 vcs.server = localhost:9900
538 vcs.server = localhost:9900
539
539
540 ## Web server connectivity protocol, responsible for web based VCS operatations
540 ## Web server connectivity protocol, responsible for web based VCS operatations
541 ## Available protocols are:
541 ## Available protocols are:
542 ## `http` - use http-rpc backend (default)
542 ## `http` - use http-rpc backend (default)
543 vcs.server.protocol = http
543 vcs.server.protocol = http
544
544
545 ## Push/Pull operations protocol, available options are:
545 ## Push/Pull operations protocol, available options are:
546 ## `http` - use http-rpc backend (default)
546 ## `http` - use http-rpc backend (default)
547 ##
547 ##
548 vcs.scm_app_implementation = http
548 vcs.scm_app_implementation = http
549
549
550 ## Push/Pull operations hooks protocol, available options are:
550 ## Push/Pull operations hooks protocol, available options are:
551 ## `http` - use http-rpc backend (default)
551 ## `http` - use http-rpc backend (default)
552 vcs.hooks.protocol = http
552 vcs.hooks.protocol = http
553
553
554 vcs.server.log_level = debug
554 vcs.server.log_level = debug
555 ## Start VCSServer with this instance as a subprocess, usefull for development
555 ## Start VCSServer with this instance as a subprocess, usefull for development
556 vcs.start_server = true
556 vcs.start_server = true
557
557
558 ## List of enabled VCS backends, available options are:
558 ## List of enabled VCS backends, available options are:
559 ## `hg` - mercurial
559 ## `hg` - mercurial
560 ## `git` - git
560 ## `git` - git
561 ## `svn` - subversion
561 ## `svn` - subversion
562 vcs.backends = hg, git, svn
562 vcs.backends = hg, git, svn
563
563
564 vcs.connection_timeout = 3600
564 vcs.connection_timeout = 3600
565 ## Compatibility version when creating SVN repositories. Defaults to newest version when commented out.
565 ## Compatibility version when creating SVN repositories. Defaults to newest version when commented out.
566 ## Available options are: pre-1.4-compatible, pre-1.5-compatible, pre-1.6-compatible, pre-1.8-compatible
566 ## Available options are: pre-1.4-compatible, pre-1.5-compatible, pre-1.6-compatible, pre-1.8-compatible
567 #vcs.svn.compatible_version = pre-1.8-compatible
567 #vcs.svn.compatible_version = pre-1.8-compatible
568
568
569
569
570 ############################################################
570 ############################################################
571 ### Subversion proxy support (mod_dav_svn) ###
571 ### Subversion proxy support (mod_dav_svn) ###
572 ### Maps RhodeCode repo groups into SVN paths for Apache ###
572 ### Maps RhodeCode repo groups into SVN paths for Apache ###
573 ############################################################
573 ############################################################
574 ## Enable or disable the config file generation.
574 ## Enable or disable the config file generation.
575 svn.proxy.generate_config = false
575 svn.proxy.generate_config = false
576 ## Generate config file with `SVNListParentPath` set to `On`.
576 ## Generate config file with `SVNListParentPath` set to `On`.
577 svn.proxy.list_parent_path = true
577 svn.proxy.list_parent_path = true
578 ## Set location and file name of generated config file.
578 ## Set location and file name of generated config file.
579 svn.proxy.config_file_path = %(here)s/mod_dav_svn.conf
579 svn.proxy.config_file_path = %(here)s/mod_dav_svn.conf
580 ## Used as a prefix to the `Location` block in the generated config file.
580 ## Used as a prefix to the `Location` block in the generated config file.
581 ## In most cases it should be set to `/`.
581 ## In most cases it should be set to `/`.
582 svn.proxy.location_root = /
582 svn.proxy.location_root = /
583 ## Command to reload the mod dav svn configuration on change.
583 ## Command to reload the mod dav svn configuration on change.
584 ## Example: `/etc/init.d/apache2 reload`
584 ## Example: `/etc/init.d/apache2 reload`
585 #svn.proxy.reload_cmd = /etc/init.d/apache2 reload
585 #svn.proxy.reload_cmd = /etc/init.d/apache2 reload
586 ## If the timeout expires before the reload command finishes, the command will
586 ## If the timeout expires before the reload command finishes, the command will
587 ## be killed. Setting it to zero means no timeout. Defaults to 10 seconds.
587 ## be killed. Setting it to zero means no timeout. Defaults to 10 seconds.
588 #svn.proxy.reload_timeout = 10
588 #svn.proxy.reload_timeout = 10
589
589
590 ############################################################
591 ### SSH Support Settings ###
592 ############################################################
593
594 ## Defines if the authorized_keys file should be written on any change of
595 ## user ssh keys
596 ssh.generate_authorized_keyfile = false
597
598 ## Options for ssh, default is `no-pty,no-port-forwarding,no-X11-forwarding,no-agent-forwarding`
599 # ssh.authorized_keys_ssh_opts =
600
601 ## File to generate the authorized keys together with options
602 ssh.authorized_keys_file_path = /home/USER/.ssh/authorized_keys
603
604 ## Command to execute as an SSH wrapper, available from
605 ## https://code.rhodecode.com/rhodecode-ssh
606 ssh.wrapper_cmd = /home/USER/rhodecode-ssh/sshwrapper.py
607
608 ## Allow shell when executing the command
609 ssh.wrapper_cmd_allow_shell = false
610
590 ## Dummy marker to add new entries after.
611 ## Dummy marker to add new entries after.
591 ## Add any custom entries below. Please don't remove.
612 ## Add any custom entries below. Please don't remove.
592 custom.conf = 1
613 custom.conf = 1
593
614
594
615
595 ################################
616 ################################
596 ### LOGGING CONFIGURATION ####
617 ### LOGGING CONFIGURATION ####
597 ################################
618 ################################
598 [loggers]
619 [loggers]
599 keys = root, routes, rhodecode, sqlalchemy, beaker, templates
620 keys = root, routes, rhodecode, sqlalchemy, beaker, templates
600
621
601 [handlers]
622 [handlers]
602 keys = console, console_sql
623 keys = console, console_sql
603
624
604 [formatters]
625 [formatters]
605 keys = generic, color_formatter, color_formatter_sql
626 keys = generic, color_formatter, color_formatter_sql
606
627
607 #############
628 #############
608 ## LOGGERS ##
629 ## LOGGERS ##
609 #############
630 #############
610 [logger_root]
631 [logger_root]
611 level = NOTSET
632 level = NOTSET
612 handlers = console
633 handlers = console
613
634
614 [logger_routes]
635 [logger_routes]
615 level = DEBUG
636 level = DEBUG
616 handlers =
637 handlers =
617 qualname = routes.middleware
638 qualname = routes.middleware
618 ## "level = DEBUG" logs the route matched and routing variables.
639 ## "level = DEBUG" logs the route matched and routing variables.
619 propagate = 1
640 propagate = 1
620
641
621 [logger_beaker]
642 [logger_beaker]
622 level = DEBUG
643 level = DEBUG
623 handlers =
644 handlers =
624 qualname = beaker.container
645 qualname = beaker.container
625 propagate = 1
646 propagate = 1
626
647
627 [logger_templates]
648 [logger_templates]
628 level = INFO
649 level = INFO
629 handlers =
650 handlers =
630 qualname = pylons.templating
651 qualname = pylons.templating
631 propagate = 1
652 propagate = 1
632
653
633 [logger_rhodecode]
654 [logger_rhodecode]
634 level = DEBUG
655 level = DEBUG
635 handlers =
656 handlers =
636 qualname = rhodecode
657 qualname = rhodecode
637 propagate = 1
658 propagate = 1
638
659
639 [logger_sqlalchemy]
660 [logger_sqlalchemy]
640 level = INFO
661 level = INFO
641 handlers = console_sql
662 handlers = console_sql
642 qualname = sqlalchemy.engine
663 qualname = sqlalchemy.engine
643 propagate = 0
664 propagate = 0
644
665
645 ##############
666 ##############
646 ## HANDLERS ##
667 ## HANDLERS ##
647 ##############
668 ##############
648
669
649 [handler_console]
670 [handler_console]
650 class = StreamHandler
671 class = StreamHandler
651 args = (sys.stderr, )
672 args = (sys.stderr, )
652 level = DEBUG
673 level = DEBUG
653 formatter = color_formatter
674 formatter = color_formatter
654
675
655 [handler_console_sql]
676 [handler_console_sql]
656 class = StreamHandler
677 class = StreamHandler
657 args = (sys.stderr, )
678 args = (sys.stderr, )
658 level = DEBUG
679 level = DEBUG
659 formatter = color_formatter_sql
680 formatter = color_formatter_sql
660
681
661 ################
682 ################
662 ## FORMATTERS ##
683 ## FORMATTERS ##
663 ################
684 ################
664
685
665 [formatter_generic]
686 [formatter_generic]
666 class = rhodecode.lib.logging_formatter.ExceptionAwareFormatter
687 class = rhodecode.lib.logging_formatter.ExceptionAwareFormatter
667 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
688 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
668 datefmt = %Y-%m-%d %H:%M:%S
689 datefmt = %Y-%m-%d %H:%M:%S
669
690
670 [formatter_color_formatter]
691 [formatter_color_formatter]
671 class = rhodecode.lib.logging_formatter.ColorFormatter
692 class = rhodecode.lib.logging_formatter.ColorFormatter
672 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
693 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
673 datefmt = %Y-%m-%d %H:%M:%S
694 datefmt = %Y-%m-%d %H:%M:%S
674
695
675 [formatter_color_formatter_sql]
696 [formatter_color_formatter_sql]
676 class = rhodecode.lib.logging_formatter.ColorFormatterSql
697 class = rhodecode.lib.logging_formatter.ColorFormatterSql
677 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
698 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
678 datefmt = %Y-%m-%d %H:%M:%S
699 datefmt = %Y-%m-%d %H:%M:%S
@@ -1,647 +1,668 b''
1
1
2
2
3 ################################################################################
3 ################################################################################
4 ## RHODECODE COMMUNITY EDITION CONFIGURATION ##
4 ## RHODECODE COMMUNITY EDITION CONFIGURATION ##
5 # The %(here)s variable will be replaced with the parent directory of this file#
5 # The %(here)s variable will be replaced with the parent directory of this file#
6 ################################################################################
6 ################################################################################
7
7
8 [DEFAULT]
8 [DEFAULT]
9 debug = true
9 debug = true
10
10
11 ################################################################################
11 ################################################################################
12 ## EMAIL CONFIGURATION ##
12 ## EMAIL CONFIGURATION ##
13 ## Uncomment and replace with the email address which should receive ##
13 ## Uncomment and replace with the email address which should receive ##
14 ## any error reports after an application crash ##
14 ## any error reports after an application crash ##
15 ## Additionally these settings will be used by the RhodeCode mailing system ##
15 ## Additionally these settings will be used by the RhodeCode mailing system ##
16 ################################################################################
16 ################################################################################
17
17
18 ## prefix all emails subjects with given prefix, helps filtering out emails
18 ## prefix all emails subjects with given prefix, helps filtering out emails
19 #email_prefix = [RhodeCode]
19 #email_prefix = [RhodeCode]
20
20
21 ## email FROM address all mails will be sent
21 ## email FROM address all mails will be sent
22 #app_email_from = rhodecode-noreply@localhost
22 #app_email_from = rhodecode-noreply@localhost
23
23
24 ## Uncomment and replace with the address which should receive any error report
24 ## Uncomment and replace with the address which should receive any error report
25 ## note: using appenlight for error handling doesn't need this to be uncommented
25 ## note: using appenlight for error handling doesn't need this to be uncommented
26 #email_to = admin@localhost
26 #email_to = admin@localhost
27
27
28 ## in case of Application errors, sent an error email form
28 ## in case of Application errors, sent an error email form
29 #error_email_from = rhodecode_error@localhost
29 #error_email_from = rhodecode_error@localhost
30
30
31 ## additional error message to be send in case of server crash
31 ## additional error message to be send in case of server crash
32 #error_message =
32 #error_message =
33
33
34
34
35 #smtp_server = mail.server.com
35 #smtp_server = mail.server.com
36 #smtp_username =
36 #smtp_username =
37 #smtp_password =
37 #smtp_password =
38 #smtp_port =
38 #smtp_port =
39 #smtp_use_tls = false
39 #smtp_use_tls = false
40 #smtp_use_ssl = true
40 #smtp_use_ssl = true
41 ## Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
41 ## Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
42 #smtp_auth =
42 #smtp_auth =
43
43
44 [server:main]
44 [server:main]
45 ## COMMON ##
45 ## COMMON ##
46 host = 127.0.0.1
46 host = 127.0.0.1
47 port = 5000
47 port = 5000
48
48
49 ##################################
49 ##################################
50 ## WAITRESS WSGI SERVER ##
50 ## WAITRESS WSGI SERVER ##
51 ## Recommended for Development ##
51 ## Recommended for Development ##
52 ##################################
52 ##################################
53
53
54 #use = egg:waitress#main
54 #use = egg:waitress#main
55 ## number of worker threads
55 ## number of worker threads
56 #threads = 5
56 #threads = 5
57 ## MAX BODY SIZE 100GB
57 ## MAX BODY SIZE 100GB
58 #max_request_body_size = 107374182400
58 #max_request_body_size = 107374182400
59 ## Use poll instead of select, fixes file descriptors limits problems.
59 ## Use poll instead of select, fixes file descriptors limits problems.
60 ## May not work on old windows systems.
60 ## May not work on old windows systems.
61 #asyncore_use_poll = true
61 #asyncore_use_poll = true
62
62
63
63
64 ##########################
64 ##########################
65 ## GUNICORN WSGI SERVER ##
65 ## GUNICORN WSGI SERVER ##
66 ##########################
66 ##########################
67 ## run with gunicorn --log-config rhodecode.ini --paste rhodecode.ini
67 ## run with gunicorn --log-config rhodecode.ini --paste rhodecode.ini
68
68
69 use = egg:gunicorn#main
69 use = egg:gunicorn#main
70 ## Sets the number of process workers. You must set `instance_id = *`
70 ## Sets the number of process workers. You must set `instance_id = *`
71 ## when this option is set to more than one worker, recommended
71 ## when this option is set to more than one worker, recommended
72 ## value is (2 * NUMBER_OF_CPUS + 1), eg 2CPU = 5 workers
72 ## value is (2 * NUMBER_OF_CPUS + 1), eg 2CPU = 5 workers
73 ## The `instance_id = *` must be set in the [app:main] section below
73 ## The `instance_id = *` must be set in the [app:main] section below
74 workers = 2
74 workers = 2
75 ## number of threads for each of the worker, must be set to 1 for gevent
75 ## number of threads for each of the worker, must be set to 1 for gevent
76 ## generally recommened to be at 1
76 ## generally recommened to be at 1
77 #threads = 1
77 #threads = 1
78 ## process name
78 ## process name
79 proc_name = rhodecode
79 proc_name = rhodecode
80 ## type of worker class, one of sync, gevent
80 ## type of worker class, one of sync, gevent
81 ## recommended for bigger setup is using of of other than sync one
81 ## recommended for bigger setup is using of of other than sync one
82 worker_class = sync
82 worker_class = sync
83 ## The maximum number of simultaneous clients. Valid only for Gevent
83 ## The maximum number of simultaneous clients. Valid only for Gevent
84 #worker_connections = 10
84 #worker_connections = 10
85 ## max number of requests that worker will handle before being gracefully
85 ## max number of requests that worker will handle before being gracefully
86 ## restarted, could prevent memory leaks
86 ## restarted, could prevent memory leaks
87 max_requests = 1000
87 max_requests = 1000
88 max_requests_jitter = 30
88 max_requests_jitter = 30
89 ## amount of time a worker can spend with handling a request before it
89 ## amount of time a worker can spend with handling a request before it
90 ## gets killed and restarted. Set to 6hrs
90 ## gets killed and restarted. Set to 6hrs
91 timeout = 21600
91 timeout = 21600
92
92
93
93
94 ## prefix middleware for RhodeCode.
94 ## prefix middleware for RhodeCode.
95 ## recommended when using proxy setup.
95 ## recommended when using proxy setup.
96 ## allows to set RhodeCode under a prefix in server.
96 ## allows to set RhodeCode under a prefix in server.
97 ## eg https://server.com/custom_prefix. Enable `filter-with =` option below as well.
97 ## eg https://server.com/custom_prefix. Enable `filter-with =` option below as well.
98 ## And set your prefix like: `prefix = /custom_prefix`
98 ## And set your prefix like: `prefix = /custom_prefix`
99 ## be sure to also set beaker.session.cookie_path = /custom_prefix if you need
99 ## be sure to also set beaker.session.cookie_path = /custom_prefix if you need
100 ## to make your cookies only work on prefix url
100 ## to make your cookies only work on prefix url
101 [filter:proxy-prefix]
101 [filter:proxy-prefix]
102 use = egg:PasteDeploy#prefix
102 use = egg:PasteDeploy#prefix
103 prefix = /
103 prefix = /
104
104
105 [app:main]
105 [app:main]
106 use = egg:rhodecode-enterprise-ce
106 use = egg:rhodecode-enterprise-ce
107
107
108 ## enable proxy prefix middleware, defined above
108 ## enable proxy prefix middleware, defined above
109 #filter-with = proxy-prefix
109 #filter-with = proxy-prefix
110
110
111 ## encryption key used to encrypt social plugin tokens,
111 ## encryption key used to encrypt social plugin tokens,
112 ## remote_urls with credentials etc, if not set it defaults to
112 ## remote_urls with credentials etc, if not set it defaults to
113 ## `beaker.session.secret`
113 ## `beaker.session.secret`
114 #rhodecode.encrypted_values.secret =
114 #rhodecode.encrypted_values.secret =
115
115
116 ## decryption strict mode (enabled by default). It controls if decryption raises
116 ## decryption strict mode (enabled by default). It controls if decryption raises
117 ## `SignatureVerificationError` in case of wrong key, or damaged encryption data.
117 ## `SignatureVerificationError` in case of wrong key, or damaged encryption data.
118 #rhodecode.encrypted_values.strict = false
118 #rhodecode.encrypted_values.strict = false
119
119
120 ## return gzipped responses from Rhodecode (static files/application)
120 ## return gzipped responses from Rhodecode (static files/application)
121 gzip_responses = false
121 gzip_responses = false
122
122
123 ## autogenerate javascript routes file on startup
123 ## autogenerate javascript routes file on startup
124 generate_js_files = false
124 generate_js_files = false
125
125
126 ## Optional Languages
126 ## Optional Languages
127 ## en(default), be, de, es, fr, it, ja, pl, pt, ru, zh
127 ## en(default), be, de, es, fr, it, ja, pl, pt, ru, zh
128 lang = en
128 lang = en
129
129
130 ## perform a full repository scan on each server start, this should be
130 ## perform a full repository scan on each server start, this should be
131 ## set to false after first startup, to allow faster server restarts.
131 ## set to false after first startup, to allow faster server restarts.
132 startup.import_repos = false
132 startup.import_repos = false
133
133
134 ## Uncomment and set this path to use archive download cache.
134 ## Uncomment and set this path to use archive download cache.
135 ## Once enabled, generated archives will be cached at this location
135 ## Once enabled, generated archives will be cached at this location
136 ## and served from the cache during subsequent requests for the same archive of
136 ## and served from the cache during subsequent requests for the same archive of
137 ## the repository.
137 ## the repository.
138 #archive_cache_dir = /tmp/tarballcache
138 #archive_cache_dir = /tmp/tarballcache
139
139
140 ## change this to unique ID for security
140 ## change this to unique ID for security
141 app_instance_uuid = rc-production
141 app_instance_uuid = rc-production
142
142
143 ## cut off limit for large diffs (size in bytes)
143 ## cut off limit for large diffs (size in bytes)
144 cut_off_limit_diff = 1024000
144 cut_off_limit_diff = 1024000
145 cut_off_limit_file = 256000
145 cut_off_limit_file = 256000
146
146
147 ## use cache version of scm repo everywhere
147 ## use cache version of scm repo everywhere
148 vcs_full_cache = true
148 vcs_full_cache = true
149
149
150 ## force https in RhodeCode, fixes https redirects, assumes it's always https
150 ## force https in RhodeCode, fixes https redirects, assumes it's always https
151 ## Normally this is controlled by proper http flags sent from http server
151 ## Normally this is controlled by proper http flags sent from http server
152 force_https = false
152 force_https = false
153
153
154 ## use Strict-Transport-Security headers
154 ## use Strict-Transport-Security headers
155 use_htsts = false
155 use_htsts = false
156
156
157 ## number of commits stats will parse on each iteration
157 ## number of commits stats will parse on each iteration
158 commit_parse_limit = 25
158 commit_parse_limit = 25
159
159
160 ## git rev filter option, --all is the default filter, if you need to
160 ## git rev filter option, --all is the default filter, if you need to
161 ## hide all refs in changelog switch this to --branches --tags
161 ## hide all refs in changelog switch this to --branches --tags
162 git_rev_filter = --branches --tags
162 git_rev_filter = --branches --tags
163
163
164 # Set to true if your repos are exposed using the dumb protocol
164 # Set to true if your repos are exposed using the dumb protocol
165 git_update_server_info = false
165 git_update_server_info = false
166
166
167 ## RSS/ATOM feed options
167 ## RSS/ATOM feed options
168 rss_cut_off_limit = 256000
168 rss_cut_off_limit = 256000
169 rss_items_per_page = 10
169 rss_items_per_page = 10
170 rss_include_diff = false
170 rss_include_diff = false
171
171
172 ## gist URL alias, used to create nicer urls for gist. This should be an
172 ## gist URL alias, used to create nicer urls for gist. This should be an
173 ## url that does rewrites to _admin/gists/{gistid}.
173 ## url that does rewrites to _admin/gists/{gistid}.
174 ## example: http://gist.rhodecode.org/{gistid}. Empty means use the internal
174 ## example: http://gist.rhodecode.org/{gistid}. Empty means use the internal
175 ## RhodeCode url, ie. http[s]://rhodecode.server/_admin/gists/{gistid}
175 ## RhodeCode url, ie. http[s]://rhodecode.server/_admin/gists/{gistid}
176 gist_alias_url =
176 gist_alias_url =
177
177
178 ## List of views (using glob pattern syntax) that AUTH TOKENS could be
178 ## List of views (using glob pattern syntax) that AUTH TOKENS could be
179 ## used for access.
179 ## used for access.
180 ## Adding ?auth_token=TOKEN_HASH to the url authenticates this request as if it
180 ## Adding ?auth_token=TOKEN_HASH to the url authenticates this request as if it
181 ## came from the the logged in user who own this authentication token.
181 ## came from the the logged in user who own this authentication token.
182 ##
182 ##
183 ## list of all views can be found under `_admin/permissions/auth_token_access`
183 ## list of all views can be found under `_admin/permissions/auth_token_access`
184 ## The list should be "," separated and on a single line.
184 ## The list should be "," separated and on a single line.
185 ##
185 ##
186 ## Most common views to enable:
186 ## Most common views to enable:
187 # RepoCommitsView:repo_commit_download
187 # RepoCommitsView:repo_commit_download
188 # RepoCommitsView:repo_commit_patch
188 # RepoCommitsView:repo_commit_patch
189 # RepoCommitsView:repo_commit_raw
189 # RepoCommitsView:repo_commit_raw
190 # RepoFilesView:repo_files_diff
190 # RepoFilesView:repo_files_diff
191 # RepoFilesView:repo_archivefile
191 # RepoFilesView:repo_archivefile
192 # RepoFilesView:repo_file_raw
192 # RepoFilesView:repo_file_raw
193 # GistView:*
193 # GistView:*
194 api_access_controllers_whitelist =
194 api_access_controllers_whitelist =
195
195
196 ## default encoding used to convert from and to unicode
196 ## default encoding used to convert from and to unicode
197 ## can be also a comma separated list of encoding in case of mixed encodings
197 ## can be also a comma separated list of encoding in case of mixed encodings
198 default_encoding = UTF-8
198 default_encoding = UTF-8
199
199
200 ## instance-id prefix
200 ## instance-id prefix
201 ## a prefix key for this instance used for cache invalidation when running
201 ## a prefix key for this instance used for cache invalidation when running
202 ## multiple instances of rhodecode, make sure it's globally unique for
202 ## multiple instances of rhodecode, make sure it's globally unique for
203 ## all running rhodecode instances. Leave empty if you don't use it
203 ## all running rhodecode instances. Leave empty if you don't use it
204 instance_id =
204 instance_id =
205
205
206 ## Fallback authentication plugin. Set this to a plugin ID to force the usage
206 ## Fallback authentication plugin. Set this to a plugin ID to force the usage
207 ## of an authentication plugin also if it is disabled by it's settings.
207 ## of an authentication plugin also if it is disabled by it's settings.
208 ## This could be useful if you are unable to log in to the system due to broken
208 ## This could be useful if you are unable to log in to the system due to broken
209 ## authentication settings. Then you can enable e.g. the internal rhodecode auth
209 ## authentication settings. Then you can enable e.g. the internal rhodecode auth
210 ## module to log in again and fix the settings.
210 ## module to log in again and fix the settings.
211 ##
211 ##
212 ## Available builtin plugin IDs (hash is part of the ID):
212 ## Available builtin plugin IDs (hash is part of the ID):
213 ## egg:rhodecode-enterprise-ce#rhodecode
213 ## egg:rhodecode-enterprise-ce#rhodecode
214 ## egg:rhodecode-enterprise-ce#pam
214 ## egg:rhodecode-enterprise-ce#pam
215 ## egg:rhodecode-enterprise-ce#ldap
215 ## egg:rhodecode-enterprise-ce#ldap
216 ## egg:rhodecode-enterprise-ce#jasig_cas
216 ## egg:rhodecode-enterprise-ce#jasig_cas
217 ## egg:rhodecode-enterprise-ce#headers
217 ## egg:rhodecode-enterprise-ce#headers
218 ## egg:rhodecode-enterprise-ce#crowd
218 ## egg:rhodecode-enterprise-ce#crowd
219 #rhodecode.auth_plugin_fallback = egg:rhodecode-enterprise-ce#rhodecode
219 #rhodecode.auth_plugin_fallback = egg:rhodecode-enterprise-ce#rhodecode
220
220
221 ## alternative return HTTP header for failed authentication. Default HTTP
221 ## alternative return HTTP header for failed authentication. Default HTTP
222 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
222 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
223 ## handling that causing a series of failed authentication calls.
223 ## handling that causing a series of failed authentication calls.
224 ## Set this variable to 403 to return HTTPForbidden, or any other HTTP code
224 ## Set this variable to 403 to return HTTPForbidden, or any other HTTP code
225 ## This will be served instead of default 401 on bad authnetication
225 ## This will be served instead of default 401 on bad authnetication
226 auth_ret_code =
226 auth_ret_code =
227
227
228 ## use special detection method when serving auth_ret_code, instead of serving
228 ## use special detection method when serving auth_ret_code, instead of serving
229 ## ret_code directly, use 401 initially (Which triggers credentials prompt)
229 ## ret_code directly, use 401 initially (Which triggers credentials prompt)
230 ## and then serve auth_ret_code to clients
230 ## and then serve auth_ret_code to clients
231 auth_ret_code_detection = false
231 auth_ret_code_detection = false
232
232
233 ## locking return code. When repository is locked return this HTTP code. 2XX
233 ## locking return code. When repository is locked return this HTTP code. 2XX
234 ## codes don't break the transactions while 4XX codes do
234 ## codes don't break the transactions while 4XX codes do
235 lock_ret_code = 423
235 lock_ret_code = 423
236
236
237 ## allows to change the repository location in settings page
237 ## allows to change the repository location in settings page
238 allow_repo_location_change = true
238 allow_repo_location_change = true
239
239
240 ## allows to setup custom hooks in settings page
240 ## allows to setup custom hooks in settings page
241 allow_custom_hooks_settings = true
241 allow_custom_hooks_settings = true
242
242
243 ## generated license token, goto license page in RhodeCode settings to obtain
243 ## generated license token, goto license page in RhodeCode settings to obtain
244 ## new token
244 ## new token
245 license_token =
245 license_token =
246
246
247 ## supervisor connection uri, for managing supervisor and logs.
247 ## supervisor connection uri, for managing supervisor and logs.
248 supervisor.uri =
248 supervisor.uri =
249 ## supervisord group name/id we only want this RC instance to handle
249 ## supervisord group name/id we only want this RC instance to handle
250 supervisor.group_id = prod
250 supervisor.group_id = prod
251
251
252 ## Display extended labs settings
252 ## Display extended labs settings
253 labs_settings_active = true
253 labs_settings_active = true
254
254
255 ####################################
255 ####################################
256 ### CELERY CONFIG ####
256 ### CELERY CONFIG ####
257 ####################################
257 ####################################
258 use_celery = false
258 use_celery = false
259 broker.host = localhost
259 broker.host = localhost
260 broker.vhost = rabbitmqhost
260 broker.vhost = rabbitmqhost
261 broker.port = 5672
261 broker.port = 5672
262 broker.user = rabbitmq
262 broker.user = rabbitmq
263 broker.password = qweqwe
263 broker.password = qweqwe
264
264
265 celery.imports = rhodecode.lib.celerylib.tasks
265 celery.imports = rhodecode.lib.celerylib.tasks
266
266
267 celery.result.backend = amqp
267 celery.result.backend = amqp
268 celery.result.dburi = amqp://
268 celery.result.dburi = amqp://
269 celery.result.serialier = json
269 celery.result.serialier = json
270
270
271 #celery.send.task.error.emails = true
271 #celery.send.task.error.emails = true
272 #celery.amqp.task.result.expires = 18000
272 #celery.amqp.task.result.expires = 18000
273
273
274 celeryd.concurrency = 2
274 celeryd.concurrency = 2
275 #celeryd.log.file = celeryd.log
275 #celeryd.log.file = celeryd.log
276 celeryd.log.level = debug
276 celeryd.log.level = debug
277 celeryd.max.tasks.per.child = 1
277 celeryd.max.tasks.per.child = 1
278
278
279 ## tasks will never be sent to the queue, but executed locally instead.
279 ## tasks will never be sent to the queue, but executed locally instead.
280 celery.always.eager = false
280 celery.always.eager = false
281
281
282 ####################################
282 ####################################
283 ### BEAKER CACHE ####
283 ### BEAKER CACHE ####
284 ####################################
284 ####################################
285 # default cache dir for templates. Putting this into a ramdisk
285 # default cache dir for templates. Putting this into a ramdisk
286 ## can boost performance, eg. %(here)s/data_ramdisk
286 ## can boost performance, eg. %(here)s/data_ramdisk
287 cache_dir = %(here)s/data
287 cache_dir = %(here)s/data
288
288
289 ## locking and default file storage for Beaker. Putting this into a ramdisk
289 ## locking and default file storage for Beaker. Putting this into a ramdisk
290 ## can boost performance, eg. %(here)s/data_ramdisk/cache/beaker_data
290 ## can boost performance, eg. %(here)s/data_ramdisk/cache/beaker_data
291 beaker.cache.data_dir = %(here)s/data/cache/beaker_data
291 beaker.cache.data_dir = %(here)s/data/cache/beaker_data
292 beaker.cache.lock_dir = %(here)s/data/cache/beaker_lock
292 beaker.cache.lock_dir = %(here)s/data/cache/beaker_lock
293
293
294 beaker.cache.regions = super_short_term, short_term, long_term, sql_cache_short, auth_plugins, repo_cache_long
294 beaker.cache.regions = super_short_term, short_term, long_term, sql_cache_short, auth_plugins, repo_cache_long
295
295
296 beaker.cache.super_short_term.type = memory
296 beaker.cache.super_short_term.type = memory
297 beaker.cache.super_short_term.expire = 10
297 beaker.cache.super_short_term.expire = 10
298 beaker.cache.super_short_term.key_length = 256
298 beaker.cache.super_short_term.key_length = 256
299
299
300 beaker.cache.short_term.type = memory
300 beaker.cache.short_term.type = memory
301 beaker.cache.short_term.expire = 60
301 beaker.cache.short_term.expire = 60
302 beaker.cache.short_term.key_length = 256
302 beaker.cache.short_term.key_length = 256
303
303
304 beaker.cache.long_term.type = memory
304 beaker.cache.long_term.type = memory
305 beaker.cache.long_term.expire = 36000
305 beaker.cache.long_term.expire = 36000
306 beaker.cache.long_term.key_length = 256
306 beaker.cache.long_term.key_length = 256
307
307
308 beaker.cache.sql_cache_short.type = memory
308 beaker.cache.sql_cache_short.type = memory
309 beaker.cache.sql_cache_short.expire = 10
309 beaker.cache.sql_cache_short.expire = 10
310 beaker.cache.sql_cache_short.key_length = 256
310 beaker.cache.sql_cache_short.key_length = 256
311
311
312 ## default is memory cache, configure only if required
312 ## default is memory cache, configure only if required
313 ## using multi-node or multi-worker setup
313 ## using multi-node or multi-worker setup
314 #beaker.cache.auth_plugins.type = ext:database
314 #beaker.cache.auth_plugins.type = ext:database
315 #beaker.cache.auth_plugins.lock_dir = %(here)s/data/cache/auth_plugin_lock
315 #beaker.cache.auth_plugins.lock_dir = %(here)s/data/cache/auth_plugin_lock
316 #beaker.cache.auth_plugins.url = postgresql://postgres:secret@localhost/rhodecode
316 #beaker.cache.auth_plugins.url = postgresql://postgres:secret@localhost/rhodecode
317 #beaker.cache.auth_plugins.url = mysql://root:secret@127.0.0.1/rhodecode
317 #beaker.cache.auth_plugins.url = mysql://root:secret@127.0.0.1/rhodecode
318 #beaker.cache.auth_plugins.sa.pool_recycle = 3600
318 #beaker.cache.auth_plugins.sa.pool_recycle = 3600
319 #beaker.cache.auth_plugins.sa.pool_size = 10
319 #beaker.cache.auth_plugins.sa.pool_size = 10
320 #beaker.cache.auth_plugins.sa.max_overflow = 0
320 #beaker.cache.auth_plugins.sa.max_overflow = 0
321
321
322 beaker.cache.repo_cache_long.type = memorylru_base
322 beaker.cache.repo_cache_long.type = memorylru_base
323 beaker.cache.repo_cache_long.max_items = 4096
323 beaker.cache.repo_cache_long.max_items = 4096
324 beaker.cache.repo_cache_long.expire = 2592000
324 beaker.cache.repo_cache_long.expire = 2592000
325
325
326 ## default is memorylru_base cache, configure only if required
326 ## default is memorylru_base cache, configure only if required
327 ## using multi-node or multi-worker setup
327 ## using multi-node or multi-worker setup
328 #beaker.cache.repo_cache_long.type = ext:memcached
328 #beaker.cache.repo_cache_long.type = ext:memcached
329 #beaker.cache.repo_cache_long.url = localhost:11211
329 #beaker.cache.repo_cache_long.url = localhost:11211
330 #beaker.cache.repo_cache_long.expire = 1209600
330 #beaker.cache.repo_cache_long.expire = 1209600
331 #beaker.cache.repo_cache_long.key_length = 256
331 #beaker.cache.repo_cache_long.key_length = 256
332
332
333 ####################################
333 ####################################
334 ### BEAKER SESSION ####
334 ### BEAKER SESSION ####
335 ####################################
335 ####################################
336
336
337 ## .session.type is type of storage options for the session, current allowed
337 ## .session.type is type of storage options for the session, current allowed
338 ## types are file, ext:memcached, ext:database, and memory (default).
338 ## types are file, ext:memcached, ext:database, and memory (default).
339 beaker.session.type = file
339 beaker.session.type = file
340 beaker.session.data_dir = %(here)s/data/sessions/data
340 beaker.session.data_dir = %(here)s/data/sessions/data
341
341
342 ## db based session, fast, and allows easy management over logged in users
342 ## db based session, fast, and allows easy management over logged in users
343 #beaker.session.type = ext:database
343 #beaker.session.type = ext:database
344 #beaker.session.table_name = db_session
344 #beaker.session.table_name = db_session
345 #beaker.session.sa.url = postgresql://postgres:secret@localhost/rhodecode
345 #beaker.session.sa.url = postgresql://postgres:secret@localhost/rhodecode
346 #beaker.session.sa.url = mysql://root:secret@127.0.0.1/rhodecode
346 #beaker.session.sa.url = mysql://root:secret@127.0.0.1/rhodecode
347 #beaker.session.sa.pool_recycle = 3600
347 #beaker.session.sa.pool_recycle = 3600
348 #beaker.session.sa.echo = false
348 #beaker.session.sa.echo = false
349
349
350 beaker.session.key = rhodecode
350 beaker.session.key = rhodecode
351 beaker.session.secret = production-rc-uytcxaz
351 beaker.session.secret = production-rc-uytcxaz
352 beaker.session.lock_dir = %(here)s/data/sessions/lock
352 beaker.session.lock_dir = %(here)s/data/sessions/lock
353
353
354 ## Secure encrypted cookie. Requires AES and AES python libraries
354 ## Secure encrypted cookie. Requires AES and AES python libraries
355 ## you must disable beaker.session.secret to use this
355 ## you must disable beaker.session.secret to use this
356 #beaker.session.encrypt_key = key_for_encryption
356 #beaker.session.encrypt_key = key_for_encryption
357 #beaker.session.validate_key = validation_key
357 #beaker.session.validate_key = validation_key
358
358
359 ## sets session as invalid(also logging out user) if it haven not been
359 ## sets session as invalid(also logging out user) if it haven not been
360 ## accessed for given amount of time in seconds
360 ## accessed for given amount of time in seconds
361 beaker.session.timeout = 2592000
361 beaker.session.timeout = 2592000
362 beaker.session.httponly = true
362 beaker.session.httponly = true
363 ## Path to use for the cookie. Set to prefix if you use prefix middleware
363 ## Path to use for the cookie. Set to prefix if you use prefix middleware
364 #beaker.session.cookie_path = /custom_prefix
364 #beaker.session.cookie_path = /custom_prefix
365
365
366 ## uncomment for https secure cookie
366 ## uncomment for https secure cookie
367 beaker.session.secure = false
367 beaker.session.secure = false
368
368
369 ## auto save the session to not to use .save()
369 ## auto save the session to not to use .save()
370 beaker.session.auto = false
370 beaker.session.auto = false
371
371
372 ## default cookie expiration time in seconds, set to `true` to set expire
372 ## default cookie expiration time in seconds, set to `true` to set expire
373 ## at browser close
373 ## at browser close
374 #beaker.session.cookie_expires = 3600
374 #beaker.session.cookie_expires = 3600
375
375
376 ###################################
376 ###################################
377 ## SEARCH INDEXING CONFIGURATION ##
377 ## SEARCH INDEXING CONFIGURATION ##
378 ###################################
378 ###################################
379 ## Full text search indexer is available in rhodecode-tools under
379 ## Full text search indexer is available in rhodecode-tools under
380 ## `rhodecode-tools index` command
380 ## `rhodecode-tools index` command
381
381
382 ## WHOOSH Backend, doesn't require additional services to run
382 ## WHOOSH Backend, doesn't require additional services to run
383 ## it works good with few dozen repos
383 ## it works good with few dozen repos
384 search.module = rhodecode.lib.index.whoosh
384 search.module = rhodecode.lib.index.whoosh
385 search.location = %(here)s/data/index
385 search.location = %(here)s/data/index
386
386
387 ########################################
387 ########################################
388 ### CHANNELSTREAM CONFIG ####
388 ### CHANNELSTREAM CONFIG ####
389 ########################################
389 ########################################
390 ## channelstream enables persistent connections and live notification
390 ## channelstream enables persistent connections and live notification
391 ## in the system. It's also used by the chat system
391 ## in the system. It's also used by the chat system
392 channelstream.enabled = false
392 channelstream.enabled = false
393
393
394 ## server address for channelstream server on the backend
394 ## server address for channelstream server on the backend
395 channelstream.server = 127.0.0.1:9800
395 channelstream.server = 127.0.0.1:9800
396
396
397 ## location of the channelstream server from outside world
397 ## location of the channelstream server from outside world
398 ## use ws:// for http or wss:// for https. This address needs to be handled
398 ## use ws:// for http or wss:// for https. This address needs to be handled
399 ## by external HTTP server such as Nginx or Apache
399 ## by external HTTP server such as Nginx or Apache
400 ## see nginx/apache configuration examples in our docs
400 ## see nginx/apache configuration examples in our docs
401 channelstream.ws_url = ws://rhodecode.yourserver.com/_channelstream
401 channelstream.ws_url = ws://rhodecode.yourserver.com/_channelstream
402 channelstream.secret = secret
402 channelstream.secret = secret
403 channelstream.history.location = %(here)s/channelstream_history
403 channelstream.history.location = %(here)s/channelstream_history
404
404
405 ## Internal application path that Javascript uses to connect into.
405 ## Internal application path that Javascript uses to connect into.
406 ## If you use proxy-prefix the prefix should be added before /_channelstream
406 ## If you use proxy-prefix the prefix should be added before /_channelstream
407 channelstream.proxy_path = /_channelstream
407 channelstream.proxy_path = /_channelstream
408
408
409
409
410 ###################################
410 ###################################
411 ## APPENLIGHT CONFIG ##
411 ## APPENLIGHT CONFIG ##
412 ###################################
412 ###################################
413
413
414 ## Appenlight is tailored to work with RhodeCode, see
414 ## Appenlight is tailored to work with RhodeCode, see
415 ## http://appenlight.com for details how to obtain an account
415 ## http://appenlight.com for details how to obtain an account
416
416
417 ## appenlight integration enabled
417 ## appenlight integration enabled
418 appenlight = false
418 appenlight = false
419
419
420 appenlight.server_url = https://api.appenlight.com
420 appenlight.server_url = https://api.appenlight.com
421 appenlight.api_key = YOUR_API_KEY
421 appenlight.api_key = YOUR_API_KEY
422 #appenlight.transport_config = https://api.appenlight.com?threaded=1&timeout=5
422 #appenlight.transport_config = https://api.appenlight.com?threaded=1&timeout=5
423
423
424 # used for JS client
424 # used for JS client
425 appenlight.api_public_key = YOUR_API_PUBLIC_KEY
425 appenlight.api_public_key = YOUR_API_PUBLIC_KEY
426
426
427 ## TWEAK AMOUNT OF INFO SENT HERE
427 ## TWEAK AMOUNT OF INFO SENT HERE
428
428
429 ## enables 404 error logging (default False)
429 ## enables 404 error logging (default False)
430 appenlight.report_404 = false
430 appenlight.report_404 = false
431
431
432 ## time in seconds after request is considered being slow (default 1)
432 ## time in seconds after request is considered being slow (default 1)
433 appenlight.slow_request_time = 1
433 appenlight.slow_request_time = 1
434
434
435 ## record slow requests in application
435 ## record slow requests in application
436 ## (needs to be enabled for slow datastore recording and time tracking)
436 ## (needs to be enabled for slow datastore recording and time tracking)
437 appenlight.slow_requests = true
437 appenlight.slow_requests = true
438
438
439 ## enable hooking to application loggers
439 ## enable hooking to application loggers
440 appenlight.logging = true
440 appenlight.logging = true
441
441
442 ## minimum log level for log capture
442 ## minimum log level for log capture
443 appenlight.logging.level = WARNING
443 appenlight.logging.level = WARNING
444
444
445 ## send logs only from erroneous/slow requests
445 ## send logs only from erroneous/slow requests
446 ## (saves API quota for intensive logging)
446 ## (saves API quota for intensive logging)
447 appenlight.logging_on_error = false
447 appenlight.logging_on_error = false
448
448
449 ## list of additonal keywords that should be grabbed from environ object
449 ## list of additonal keywords that should be grabbed from environ object
450 ## can be string with comma separated list of words in lowercase
450 ## can be string with comma separated list of words in lowercase
451 ## (by default client will always send following info:
451 ## (by default client will always send following info:
452 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
452 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
453 ## start with HTTP* this list be extended with additional keywords here
453 ## start with HTTP* this list be extended with additional keywords here
454 appenlight.environ_keys_whitelist =
454 appenlight.environ_keys_whitelist =
455
455
456 ## list of keywords that should be blanked from request object
456 ## list of keywords that should be blanked from request object
457 ## can be string with comma separated list of words in lowercase
457 ## can be string with comma separated list of words in lowercase
458 ## (by default client will always blank keys that contain following words
458 ## (by default client will always blank keys that contain following words
459 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
459 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
460 ## this list be extended with additional keywords set here
460 ## this list be extended with additional keywords set here
461 appenlight.request_keys_blacklist =
461 appenlight.request_keys_blacklist =
462
462
463 ## list of namespaces that should be ignores when gathering log entries
463 ## list of namespaces that should be ignores when gathering log entries
464 ## can be string with comma separated list of namespaces
464 ## can be string with comma separated list of namespaces
465 ## (by default the client ignores own entries: appenlight_client.client)
465 ## (by default the client ignores own entries: appenlight_client.client)
466 appenlight.log_namespace_blacklist =
466 appenlight.log_namespace_blacklist =
467
467
468
468
469 ################################################################################
469 ################################################################################
470 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
470 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
471 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
471 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
472 ## execute malicious code after an exception is raised. ##
472 ## execute malicious code after an exception is raised. ##
473 ################################################################################
473 ################################################################################
474 set debug = false
474 set debug = false
475
475
476
476
477 ###########################################
477 ###########################################
478 ### MAIN RHODECODE DATABASE CONFIG ###
478 ### MAIN RHODECODE DATABASE CONFIG ###
479 ###########################################
479 ###########################################
480 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db?timeout=30
480 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db?timeout=30
481 #sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode
481 #sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode
482 #sqlalchemy.db1.url = mysql://root:qweqwe@localhost/rhodecode
482 #sqlalchemy.db1.url = mysql://root:qweqwe@localhost/rhodecode
483 sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode
483 sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode
484
484
485 # see sqlalchemy docs for other advanced settings
485 # see sqlalchemy docs for other advanced settings
486
486
487 ## print the sql statements to output
487 ## print the sql statements to output
488 sqlalchemy.db1.echo = false
488 sqlalchemy.db1.echo = false
489 ## recycle the connections after this amount of seconds
489 ## recycle the connections after this amount of seconds
490 sqlalchemy.db1.pool_recycle = 3600
490 sqlalchemy.db1.pool_recycle = 3600
491 sqlalchemy.db1.convert_unicode = true
491 sqlalchemy.db1.convert_unicode = true
492
492
493 ## the number of connections to keep open inside the connection pool.
493 ## the number of connections to keep open inside the connection pool.
494 ## 0 indicates no limit
494 ## 0 indicates no limit
495 #sqlalchemy.db1.pool_size = 5
495 #sqlalchemy.db1.pool_size = 5
496
496
497 ## the number of connections to allow in connection pool "overflow", that is
497 ## the number of connections to allow in connection pool "overflow", that is
498 ## connections that can be opened above and beyond the pool_size setting,
498 ## connections that can be opened above and beyond the pool_size setting,
499 ## which defaults to five.
499 ## which defaults to five.
500 #sqlalchemy.db1.max_overflow = 10
500 #sqlalchemy.db1.max_overflow = 10
501
501
502
502
503 ##################
503 ##################
504 ### VCS CONFIG ###
504 ### VCS CONFIG ###
505 ##################
505 ##################
506 vcs.server.enable = true
506 vcs.server.enable = true
507 vcs.server = localhost:9900
507 vcs.server = localhost:9900
508
508
509 ## Web server connectivity protocol, responsible for web based VCS operatations
509 ## Web server connectivity protocol, responsible for web based VCS operatations
510 ## Available protocols are:
510 ## Available protocols are:
511 ## `http` - use http-rpc backend (default)
511 ## `http` - use http-rpc backend (default)
512 vcs.server.protocol = http
512 vcs.server.protocol = http
513
513
514 ## Push/Pull operations protocol, available options are:
514 ## Push/Pull operations protocol, available options are:
515 ## `http` - use http-rpc backend (default)
515 ## `http` - use http-rpc backend (default)
516 ##
516 ##
517 vcs.scm_app_implementation = http
517 vcs.scm_app_implementation = http
518
518
519 ## Push/Pull operations hooks protocol, available options are:
519 ## Push/Pull operations hooks protocol, available options are:
520 ## `http` - use http-rpc backend (default)
520 ## `http` - use http-rpc backend (default)
521 vcs.hooks.protocol = http
521 vcs.hooks.protocol = http
522
522
523 vcs.server.log_level = info
523 vcs.server.log_level = info
524 ## Start VCSServer with this instance as a subprocess, usefull for development
524 ## Start VCSServer with this instance as a subprocess, usefull for development
525 vcs.start_server = false
525 vcs.start_server = false
526
526
527 ## List of enabled VCS backends, available options are:
527 ## List of enabled VCS backends, available options are:
528 ## `hg` - mercurial
528 ## `hg` - mercurial
529 ## `git` - git
529 ## `git` - git
530 ## `svn` - subversion
530 ## `svn` - subversion
531 vcs.backends = hg, git, svn
531 vcs.backends = hg, git, svn
532
532
533 vcs.connection_timeout = 3600
533 vcs.connection_timeout = 3600
534 ## Compatibility version when creating SVN repositories. Defaults to newest version when commented out.
534 ## Compatibility version when creating SVN repositories. Defaults to newest version when commented out.
535 ## Available options are: pre-1.4-compatible, pre-1.5-compatible, pre-1.6-compatible, pre-1.8-compatible
535 ## Available options are: pre-1.4-compatible, pre-1.5-compatible, pre-1.6-compatible, pre-1.8-compatible
536 #vcs.svn.compatible_version = pre-1.8-compatible
536 #vcs.svn.compatible_version = pre-1.8-compatible
537
537
538
538
539 ############################################################
539 ############################################################
540 ### Subversion proxy support (mod_dav_svn) ###
540 ### Subversion proxy support (mod_dav_svn) ###
541 ### Maps RhodeCode repo groups into SVN paths for Apache ###
541 ### Maps RhodeCode repo groups into SVN paths for Apache ###
542 ############################################################
542 ############################################################
543 ## Enable or disable the config file generation.
543 ## Enable or disable the config file generation.
544 svn.proxy.generate_config = false
544 svn.proxy.generate_config = false
545 ## Generate config file with `SVNListParentPath` set to `On`.
545 ## Generate config file with `SVNListParentPath` set to `On`.
546 svn.proxy.list_parent_path = true
546 svn.proxy.list_parent_path = true
547 ## Set location and file name of generated config file.
547 ## Set location and file name of generated config file.
548 svn.proxy.config_file_path = %(here)s/mod_dav_svn.conf
548 svn.proxy.config_file_path = %(here)s/mod_dav_svn.conf
549 ## Used as a prefix to the `Location` block in the generated config file.
549 ## Used as a prefix to the `Location` block in the generated config file.
550 ## In most cases it should be set to `/`.
550 ## In most cases it should be set to `/`.
551 svn.proxy.location_root = /
551 svn.proxy.location_root = /
552 ## Command to reload the mod dav svn configuration on change.
552 ## Command to reload the mod dav svn configuration on change.
553 ## Example: `/etc/init.d/apache2 reload`
553 ## Example: `/etc/init.d/apache2 reload`
554 #svn.proxy.reload_cmd = /etc/init.d/apache2 reload
554 #svn.proxy.reload_cmd = /etc/init.d/apache2 reload
555 ## If the timeout expires before the reload command finishes, the command will
555 ## If the timeout expires before the reload command finishes, the command will
556 ## be killed. Setting it to zero means no timeout. Defaults to 10 seconds.
556 ## be killed. Setting it to zero means no timeout. Defaults to 10 seconds.
557 #svn.proxy.reload_timeout = 10
557 #svn.proxy.reload_timeout = 10
558
558
559 ############################################################
560 ### SSH Support Settings ###
561 ############################################################
562
563 ## Defines if the authorized_keys file should be written on any change of
564 ## user ssh keys
565 ssh.generate_authorized_keyfile = false
566
567 ## Options for ssh, default is `no-pty,no-port-forwarding,no-X11-forwarding,no-agent-forwarding`
568 # ssh.authorized_keys_ssh_opts =
569
570 ## File to generate the authorized keys together with options
571 ssh.authorized_keys_file_path = /home/USER/.ssh/authorized_keys
572
573 ## Command to execute as an SSH wrapper, available from
574 ## https://code.rhodecode.com/rhodecode-ssh
575 ssh.wrapper_cmd = /home/USER/rhodecode-ssh/sshwrapper.py
576
577 ## Allow shell when executing the command
578 ssh.wrapper_cmd_allow_shell = false
579
559 ## Dummy marker to add new entries after.
580 ## Dummy marker to add new entries after.
560 ## Add any custom entries below. Please don't remove.
581 ## Add any custom entries below. Please don't remove.
561 custom.conf = 1
582 custom.conf = 1
562
583
563
584
564 ################################
585 ################################
565 ### LOGGING CONFIGURATION ####
586 ### LOGGING CONFIGURATION ####
566 ################################
587 ################################
567 [loggers]
588 [loggers]
568 keys = root, routes, rhodecode, sqlalchemy, beaker, templates
589 keys = root, routes, rhodecode, sqlalchemy, beaker, templates
569
590
570 [handlers]
591 [handlers]
571 keys = console, console_sql
592 keys = console, console_sql
572
593
573 [formatters]
594 [formatters]
574 keys = generic, color_formatter, color_formatter_sql
595 keys = generic, color_formatter, color_formatter_sql
575
596
576 #############
597 #############
577 ## LOGGERS ##
598 ## LOGGERS ##
578 #############
599 #############
579 [logger_root]
600 [logger_root]
580 level = NOTSET
601 level = NOTSET
581 handlers = console
602 handlers = console
582
603
583 [logger_routes]
604 [logger_routes]
584 level = DEBUG
605 level = DEBUG
585 handlers =
606 handlers =
586 qualname = routes.middleware
607 qualname = routes.middleware
587 ## "level = DEBUG" logs the route matched and routing variables.
608 ## "level = DEBUG" logs the route matched and routing variables.
588 propagate = 1
609 propagate = 1
589
610
590 [logger_beaker]
611 [logger_beaker]
591 level = DEBUG
612 level = DEBUG
592 handlers =
613 handlers =
593 qualname = beaker.container
614 qualname = beaker.container
594 propagate = 1
615 propagate = 1
595
616
596 [logger_templates]
617 [logger_templates]
597 level = INFO
618 level = INFO
598 handlers =
619 handlers =
599 qualname = pylons.templating
620 qualname = pylons.templating
600 propagate = 1
621 propagate = 1
601
622
602 [logger_rhodecode]
623 [logger_rhodecode]
603 level = DEBUG
624 level = DEBUG
604 handlers =
625 handlers =
605 qualname = rhodecode
626 qualname = rhodecode
606 propagate = 1
627 propagate = 1
607
628
608 [logger_sqlalchemy]
629 [logger_sqlalchemy]
609 level = INFO
630 level = INFO
610 handlers = console_sql
631 handlers = console_sql
611 qualname = sqlalchemy.engine
632 qualname = sqlalchemy.engine
612 propagate = 0
633 propagate = 0
613
634
614 ##############
635 ##############
615 ## HANDLERS ##
636 ## HANDLERS ##
616 ##############
637 ##############
617
638
618 [handler_console]
639 [handler_console]
619 class = StreamHandler
640 class = StreamHandler
620 args = (sys.stderr, )
641 args = (sys.stderr, )
621 level = INFO
642 level = INFO
622 formatter = generic
643 formatter = generic
623
644
624 [handler_console_sql]
645 [handler_console_sql]
625 class = StreamHandler
646 class = StreamHandler
626 args = (sys.stderr, )
647 args = (sys.stderr, )
627 level = WARN
648 level = WARN
628 formatter = generic
649 formatter = generic
629
650
630 ################
651 ################
631 ## FORMATTERS ##
652 ## FORMATTERS ##
632 ################
653 ################
633
654
634 [formatter_generic]
655 [formatter_generic]
635 class = rhodecode.lib.logging_formatter.ExceptionAwareFormatter
656 class = rhodecode.lib.logging_formatter.ExceptionAwareFormatter
636 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
657 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
637 datefmt = %Y-%m-%d %H:%M:%S
658 datefmt = %Y-%m-%d %H:%M:%S
638
659
639 [formatter_color_formatter]
660 [formatter_color_formatter]
640 class = rhodecode.lib.logging_formatter.ColorFormatter
661 class = rhodecode.lib.logging_formatter.ColorFormatter
641 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
662 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
642 datefmt = %Y-%m-%d %H:%M:%S
663 datefmt = %Y-%m-%d %H:%M:%S
643
664
644 [formatter_color_formatter_sql]
665 [formatter_color_formatter_sql]
645 class = rhodecode.lib.logging_formatter.ColorFormatterSql
666 class = rhodecode.lib.logging_formatter.ColorFormatterSql
646 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
667 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
647 datefmt = %Y-%m-%d %H:%M:%S
668 datefmt = %Y-%m-%d %H:%M:%S
@@ -1,630 +1,637 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import logging
21 import logging
22 import datetime
22 import datetime
23 import formencode
23 import formencode
24
24
25 from pyramid.httpexceptions import HTTPFound
25 from pyramid.httpexceptions import HTTPFound
26 from pyramid.view import view_config
26 from pyramid.view import view_config
27 from sqlalchemy.sql.functions import coalesce
27 from sqlalchemy.sql.functions import coalesce
28 from sqlalchemy.exc import IntegrityError
28 from sqlalchemy.exc import IntegrityError
29
29
30 from rhodecode.apps._base import BaseAppView, DataGridAppView
30 from rhodecode.apps._base import BaseAppView, DataGridAppView
31 from rhodecode.apps.ssh_support import SshKeyFileChangeEvent
32 from rhodecode.events import trigger
31
33
32 from rhodecode.lib import audit_logger
34 from rhodecode.lib import audit_logger
33 from rhodecode.lib.ext_json import json
35 from rhodecode.lib.ext_json import json
34 from rhodecode.lib.auth import (
36 from rhodecode.lib.auth import (
35 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
37 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
36 from rhodecode.lib import helpers as h
38 from rhodecode.lib import helpers as h
37 from rhodecode.lib.utils2 import safe_int, safe_unicode
39 from rhodecode.lib.utils2 import safe_int, safe_unicode
38 from rhodecode.model.auth_token import AuthTokenModel
40 from rhodecode.model.auth_token import AuthTokenModel
39 from rhodecode.model.ssh_key import SshKeyModel
41 from rhodecode.model.ssh_key import SshKeyModel
40 from rhodecode.model.user import UserModel
42 from rhodecode.model.user import UserModel
41 from rhodecode.model.user_group import UserGroupModel
43 from rhodecode.model.user_group import UserGroupModel
42 from rhodecode.model.db import (
44 from rhodecode.model.db import (
43 or_, User, UserIpMap, UserEmailMap, UserApiKeys, UserSshKeys)
45 or_, User, UserIpMap, UserEmailMap, UserApiKeys, UserSshKeys)
44 from rhodecode.model.meta import Session
46 from rhodecode.model.meta import Session
45
47
46 log = logging.getLogger(__name__)
48 log = logging.getLogger(__name__)
47
49
48
50
49 class AdminUsersView(BaseAppView, DataGridAppView):
51 class AdminUsersView(BaseAppView, DataGridAppView):
50 ALLOW_SCOPED_TOKENS = False
52 ALLOW_SCOPED_TOKENS = False
51 """
53 """
52 This view has alternative version inside EE, if modified please take a look
54 This view has alternative version inside EE, if modified please take a look
53 in there as well.
55 in there as well.
54 """
56 """
55
57
56 def load_default_context(self):
58 def load_default_context(self):
57 c = self._get_local_tmpl_context()
59 c = self._get_local_tmpl_context()
58 c.allow_scoped_tokens = self.ALLOW_SCOPED_TOKENS
60 c.allow_scoped_tokens = self.ALLOW_SCOPED_TOKENS
59 self._register_global_c(c)
61 self._register_global_c(c)
60 return c
62 return c
61
63
62 def _redirect_for_default_user(self, username):
64 def _redirect_for_default_user(self, username):
63 _ = self.request.translate
65 _ = self.request.translate
64 if username == User.DEFAULT_USER:
66 if username == User.DEFAULT_USER:
65 h.flash(_("You can't edit this user"), category='warning')
67 h.flash(_("You can't edit this user"), category='warning')
66 # TODO(marcink): redirect to 'users' admin panel once this
68 # TODO(marcink): redirect to 'users' admin panel once this
67 # is a pyramid view
69 # is a pyramid view
68 raise HTTPFound('/')
70 raise HTTPFound('/')
69
71
70 @HasPermissionAllDecorator('hg.admin')
72 @HasPermissionAllDecorator('hg.admin')
71 @view_config(
73 @view_config(
72 route_name='users', request_method='GET',
74 route_name='users', request_method='GET',
73 renderer='rhodecode:templates/admin/users/users.mako')
75 renderer='rhodecode:templates/admin/users/users.mako')
74 def users_list(self):
76 def users_list(self):
75 c = self.load_default_context()
77 c = self.load_default_context()
76 return self._get_template_context(c)
78 return self._get_template_context(c)
77
79
78 @HasPermissionAllDecorator('hg.admin')
80 @HasPermissionAllDecorator('hg.admin')
79 @view_config(
81 @view_config(
80 # renderer defined below
82 # renderer defined below
81 route_name='users_data', request_method='GET',
83 route_name='users_data', request_method='GET',
82 renderer='json_ext', xhr=True)
84 renderer='json_ext', xhr=True)
83 def users_list_data(self):
85 def users_list_data(self):
84 column_map = {
86 column_map = {
85 'first_name': 'name',
87 'first_name': 'name',
86 'last_name': 'lastname',
88 'last_name': 'lastname',
87 }
89 }
88 draw, start, limit = self._extract_chunk(self.request)
90 draw, start, limit = self._extract_chunk(self.request)
89 search_q, order_by, order_dir = self._extract_ordering(
91 search_q, order_by, order_dir = self._extract_ordering(
90 self.request, column_map=column_map)
92 self.request, column_map=column_map)
91
93
92 _render = self.request.get_partial_renderer(
94 _render = self.request.get_partial_renderer(
93 'data_table/_dt_elements.mako')
95 'data_table/_dt_elements.mako')
94
96
95 def user_actions(user_id, username):
97 def user_actions(user_id, username):
96 return _render("user_actions", user_id, username)
98 return _render("user_actions", user_id, username)
97
99
98 users_data_total_count = User.query()\
100 users_data_total_count = User.query()\
99 .filter(User.username != User.DEFAULT_USER) \
101 .filter(User.username != User.DEFAULT_USER) \
100 .count()
102 .count()
101
103
102 # json generate
104 # json generate
103 base_q = User.query().filter(User.username != User.DEFAULT_USER)
105 base_q = User.query().filter(User.username != User.DEFAULT_USER)
104
106
105 if search_q:
107 if search_q:
106 like_expression = u'%{}%'.format(safe_unicode(search_q))
108 like_expression = u'%{}%'.format(safe_unicode(search_q))
107 base_q = base_q.filter(or_(
109 base_q = base_q.filter(or_(
108 User.username.ilike(like_expression),
110 User.username.ilike(like_expression),
109 User._email.ilike(like_expression),
111 User._email.ilike(like_expression),
110 User.name.ilike(like_expression),
112 User.name.ilike(like_expression),
111 User.lastname.ilike(like_expression),
113 User.lastname.ilike(like_expression),
112 ))
114 ))
113
115
114 users_data_total_filtered_count = base_q.count()
116 users_data_total_filtered_count = base_q.count()
115
117
116 sort_col = getattr(User, order_by, None)
118 sort_col = getattr(User, order_by, None)
117 if sort_col:
119 if sort_col:
118 if order_dir == 'asc':
120 if order_dir == 'asc':
119 # handle null values properly to order by NULL last
121 # handle null values properly to order by NULL last
120 if order_by in ['last_activity']:
122 if order_by in ['last_activity']:
121 sort_col = coalesce(sort_col, datetime.date.max)
123 sort_col = coalesce(sort_col, datetime.date.max)
122 sort_col = sort_col.asc()
124 sort_col = sort_col.asc()
123 else:
125 else:
124 # handle null values properly to order by NULL last
126 # handle null values properly to order by NULL last
125 if order_by in ['last_activity']:
127 if order_by in ['last_activity']:
126 sort_col = coalesce(sort_col, datetime.date.min)
128 sort_col = coalesce(sort_col, datetime.date.min)
127 sort_col = sort_col.desc()
129 sort_col = sort_col.desc()
128
130
129 base_q = base_q.order_by(sort_col)
131 base_q = base_q.order_by(sort_col)
130 base_q = base_q.offset(start).limit(limit)
132 base_q = base_q.offset(start).limit(limit)
131
133
132 users_list = base_q.all()
134 users_list = base_q.all()
133
135
134 users_data = []
136 users_data = []
135 for user in users_list:
137 for user in users_list:
136 users_data.append({
138 users_data.append({
137 "username": h.gravatar_with_user(self.request, user.username),
139 "username": h.gravatar_with_user(self.request, user.username),
138 "email": user.email,
140 "email": user.email,
139 "first_name": user.first_name,
141 "first_name": user.first_name,
140 "last_name": user.last_name,
142 "last_name": user.last_name,
141 "last_login": h.format_date(user.last_login),
143 "last_login": h.format_date(user.last_login),
142 "last_activity": h.format_date(user.last_activity),
144 "last_activity": h.format_date(user.last_activity),
143 "active": h.bool2icon(user.active),
145 "active": h.bool2icon(user.active),
144 "active_raw": user.active,
146 "active_raw": user.active,
145 "admin": h.bool2icon(user.admin),
147 "admin": h.bool2icon(user.admin),
146 "extern_type": user.extern_type,
148 "extern_type": user.extern_type,
147 "extern_name": user.extern_name,
149 "extern_name": user.extern_name,
148 "action": user_actions(user.user_id, user.username),
150 "action": user_actions(user.user_id, user.username),
149 })
151 })
150
152
151 data = ({
153 data = ({
152 'draw': draw,
154 'draw': draw,
153 'data': users_data,
155 'data': users_data,
154 'recordsTotal': users_data_total_count,
156 'recordsTotal': users_data_total_count,
155 'recordsFiltered': users_data_total_filtered_count,
157 'recordsFiltered': users_data_total_filtered_count,
156 })
158 })
157
159
158 return data
160 return data
159
161
160 @LoginRequired()
162 @LoginRequired()
161 @HasPermissionAllDecorator('hg.admin')
163 @HasPermissionAllDecorator('hg.admin')
162 @view_config(
164 @view_config(
163 route_name='edit_user_auth_tokens', request_method='GET',
165 route_name='edit_user_auth_tokens', request_method='GET',
164 renderer='rhodecode:templates/admin/users/user_edit.mako')
166 renderer='rhodecode:templates/admin/users/user_edit.mako')
165 def auth_tokens(self):
167 def auth_tokens(self):
166 _ = self.request.translate
168 _ = self.request.translate
167 c = self.load_default_context()
169 c = self.load_default_context()
168
170
169 user_id = self.request.matchdict.get('user_id')
171 user_id = self.request.matchdict.get('user_id')
170 c.user = User.get_or_404(user_id)
172 c.user = User.get_or_404(user_id)
171 self._redirect_for_default_user(c.user.username)
173 self._redirect_for_default_user(c.user.username)
172
174
173 c.active = 'auth_tokens'
175 c.active = 'auth_tokens'
174
176
175 c.lifetime_values = [
177 c.lifetime_values = [
176 (str(-1), _('forever')),
178 (str(-1), _('forever')),
177 (str(5), _('5 minutes')),
179 (str(5), _('5 minutes')),
178 (str(60), _('1 hour')),
180 (str(60), _('1 hour')),
179 (str(60 * 24), _('1 day')),
181 (str(60 * 24), _('1 day')),
180 (str(60 * 24 * 30), _('1 month')),
182 (str(60 * 24 * 30), _('1 month')),
181 ]
183 ]
182 c.lifetime_options = [(c.lifetime_values, _("Lifetime"))]
184 c.lifetime_options = [(c.lifetime_values, _("Lifetime"))]
183 c.role_values = [
185 c.role_values = [
184 (x, AuthTokenModel.cls._get_role_name(x))
186 (x, AuthTokenModel.cls._get_role_name(x))
185 for x in AuthTokenModel.cls.ROLES]
187 for x in AuthTokenModel.cls.ROLES]
186 c.role_options = [(c.role_values, _("Role"))]
188 c.role_options = [(c.role_values, _("Role"))]
187 c.user_auth_tokens = AuthTokenModel().get_auth_tokens(
189 c.user_auth_tokens = AuthTokenModel().get_auth_tokens(
188 c.user.user_id, show_expired=True)
190 c.user.user_id, show_expired=True)
189 return self._get_template_context(c)
191 return self._get_template_context(c)
190
192
191 def maybe_attach_token_scope(self, token):
193 def maybe_attach_token_scope(self, token):
192 # implemented in EE edition
194 # implemented in EE edition
193 pass
195 pass
194
196
195 @LoginRequired()
197 @LoginRequired()
196 @HasPermissionAllDecorator('hg.admin')
198 @HasPermissionAllDecorator('hg.admin')
197 @CSRFRequired()
199 @CSRFRequired()
198 @view_config(
200 @view_config(
199 route_name='edit_user_auth_tokens_add', request_method='POST')
201 route_name='edit_user_auth_tokens_add', request_method='POST')
200 def auth_tokens_add(self):
202 def auth_tokens_add(self):
201 _ = self.request.translate
203 _ = self.request.translate
202 c = self.load_default_context()
204 c = self.load_default_context()
203
205
204 user_id = self.request.matchdict.get('user_id')
206 user_id = self.request.matchdict.get('user_id')
205 c.user = User.get_or_404(user_id)
207 c.user = User.get_or_404(user_id)
206
208
207 self._redirect_for_default_user(c.user.username)
209 self._redirect_for_default_user(c.user.username)
208
210
209 user_data = c.user.get_api_data()
211 user_data = c.user.get_api_data()
210 lifetime = safe_int(self.request.POST.get('lifetime'), -1)
212 lifetime = safe_int(self.request.POST.get('lifetime'), -1)
211 description = self.request.POST.get('description')
213 description = self.request.POST.get('description')
212 role = self.request.POST.get('role')
214 role = self.request.POST.get('role')
213
215
214 token = AuthTokenModel().create(
216 token = AuthTokenModel().create(
215 c.user.user_id, description, lifetime, role)
217 c.user.user_id, description, lifetime, role)
216 token_data = token.get_api_data()
218 token_data = token.get_api_data()
217
219
218 self.maybe_attach_token_scope(token)
220 self.maybe_attach_token_scope(token)
219 audit_logger.store_web(
221 audit_logger.store_web(
220 'user.edit.token.add', action_data={
222 'user.edit.token.add', action_data={
221 'data': {'token': token_data, 'user': user_data}},
223 'data': {'token': token_data, 'user': user_data}},
222 user=self._rhodecode_user, )
224 user=self._rhodecode_user, )
223 Session().commit()
225 Session().commit()
224
226
225 h.flash(_("Auth token successfully created"), category='success')
227 h.flash(_("Auth token successfully created"), category='success')
226 return HTTPFound(h.route_path('edit_user_auth_tokens', user_id=user_id))
228 return HTTPFound(h.route_path('edit_user_auth_tokens', user_id=user_id))
227
229
228 @LoginRequired()
230 @LoginRequired()
229 @HasPermissionAllDecorator('hg.admin')
231 @HasPermissionAllDecorator('hg.admin')
230 @CSRFRequired()
232 @CSRFRequired()
231 @view_config(
233 @view_config(
232 route_name='edit_user_auth_tokens_delete', request_method='POST')
234 route_name='edit_user_auth_tokens_delete', request_method='POST')
233 def auth_tokens_delete(self):
235 def auth_tokens_delete(self):
234 _ = self.request.translate
236 _ = self.request.translate
235 c = self.load_default_context()
237 c = self.load_default_context()
236
238
237 user_id = self.request.matchdict.get('user_id')
239 user_id = self.request.matchdict.get('user_id')
238 c.user = User.get_or_404(user_id)
240 c.user = User.get_or_404(user_id)
239 self._redirect_for_default_user(c.user.username)
241 self._redirect_for_default_user(c.user.username)
240 user_data = c.user.get_api_data()
242 user_data = c.user.get_api_data()
241
243
242 del_auth_token = self.request.POST.get('del_auth_token')
244 del_auth_token = self.request.POST.get('del_auth_token')
243
245
244 if del_auth_token:
246 if del_auth_token:
245 token = UserApiKeys.get_or_404(del_auth_token)
247 token = UserApiKeys.get_or_404(del_auth_token)
246 token_data = token.get_api_data()
248 token_data = token.get_api_data()
247
249
248 AuthTokenModel().delete(del_auth_token, c.user.user_id)
250 AuthTokenModel().delete(del_auth_token, c.user.user_id)
249 audit_logger.store_web(
251 audit_logger.store_web(
250 'user.edit.token.delete', action_data={
252 'user.edit.token.delete', action_data={
251 'data': {'token': token_data, 'user': user_data}},
253 'data': {'token': token_data, 'user': user_data}},
252 user=self._rhodecode_user,)
254 user=self._rhodecode_user,)
253 Session().commit()
255 Session().commit()
254 h.flash(_("Auth token successfully deleted"), category='success')
256 h.flash(_("Auth token successfully deleted"), category='success')
255
257
256 return HTTPFound(h.route_path('edit_user_auth_tokens', user_id=user_id))
258 return HTTPFound(h.route_path('edit_user_auth_tokens', user_id=user_id))
257
259
258 @LoginRequired()
260 @LoginRequired()
259 @HasPermissionAllDecorator('hg.admin')
261 @HasPermissionAllDecorator('hg.admin')
260 @view_config(
262 @view_config(
261 route_name='edit_user_ssh_keys', request_method='GET',
263 route_name='edit_user_ssh_keys', request_method='GET',
262 renderer='rhodecode:templates/admin/users/user_edit.mako')
264 renderer='rhodecode:templates/admin/users/user_edit.mako')
263 def ssh_keys(self):
265 def ssh_keys(self):
264 _ = self.request.translate
266 _ = self.request.translate
265 c = self.load_default_context()
267 c = self.load_default_context()
266
268
267 user_id = self.request.matchdict.get('user_id')
269 user_id = self.request.matchdict.get('user_id')
268 c.user = User.get_or_404(user_id)
270 c.user = User.get_or_404(user_id)
269 self._redirect_for_default_user(c.user.username)
271 self._redirect_for_default_user(c.user.username)
270
272
271 c.active = 'ssh_keys'
273 c.active = 'ssh_keys'
272 c.default_key = self.request.GET.get('default_key')
274 c.default_key = self.request.GET.get('default_key')
273 c.user_ssh_keys = SshKeyModel().get_ssh_keys(c.user.user_id)
275 c.user_ssh_keys = SshKeyModel().get_ssh_keys(c.user.user_id)
274 return self._get_template_context(c)
276 return self._get_template_context(c)
275
277
276 @LoginRequired()
278 @LoginRequired()
277 @HasPermissionAllDecorator('hg.admin')
279 @HasPermissionAllDecorator('hg.admin')
278 @view_config(
280 @view_config(
279 route_name='edit_user_ssh_keys_generate_keypair', request_method='GET',
281 route_name='edit_user_ssh_keys_generate_keypair', request_method='GET',
280 renderer='rhodecode:templates/admin/users/user_edit.mako')
282 renderer='rhodecode:templates/admin/users/user_edit.mako')
281 def ssh_keys_generate_keypair(self):
283 def ssh_keys_generate_keypair(self):
282 _ = self.request.translate
284 _ = self.request.translate
283 c = self.load_default_context()
285 c = self.load_default_context()
284
286
285 user_id = self.request.matchdict.get('user_id')
287 user_id = self.request.matchdict.get('user_id')
286 c.user = User.get_or_404(user_id)
288 c.user = User.get_or_404(user_id)
287 self._redirect_for_default_user(c.user.username)
289 self._redirect_for_default_user(c.user.username)
288
290
289 c.active = 'ssh_keys_generate'
291 c.active = 'ssh_keys_generate'
290 comment = 'RhodeCode-SSH {}'.format(c.user.email or '')
292 comment = 'RhodeCode-SSH {}'.format(c.user.email or '')
291 c.private, c.public = SshKeyModel().generate_keypair(comment=comment)
293 c.private, c.public = SshKeyModel().generate_keypair(comment=comment)
292
294
293 return self._get_template_context(c)
295 return self._get_template_context(c)
294
296
295 @LoginRequired()
297 @LoginRequired()
296 @HasPermissionAllDecorator('hg.admin')
298 @HasPermissionAllDecorator('hg.admin')
297 @CSRFRequired()
299 @CSRFRequired()
298 @view_config(
300 @view_config(
299 route_name='edit_user_ssh_keys_add', request_method='POST')
301 route_name='edit_user_ssh_keys_add', request_method='POST')
300 def ssh_keys_add(self):
302 def ssh_keys_add(self):
301 _ = self.request.translate
303 _ = self.request.translate
302 c = self.load_default_context()
304 c = self.load_default_context()
303
305
304 user_id = self.request.matchdict.get('user_id')
306 user_id = self.request.matchdict.get('user_id')
305 c.user = User.get_or_404(user_id)
307 c.user = User.get_or_404(user_id)
306
308
307 self._redirect_for_default_user(c.user.username)
309 self._redirect_for_default_user(c.user.username)
308
310
309 user_data = c.user.get_api_data()
311 user_data = c.user.get_api_data()
310 key_data = self.request.POST.get('key_data')
312 key_data = self.request.POST.get('key_data')
311 description = self.request.POST.get('description')
313 description = self.request.POST.get('description')
312
314
313 try:
315 try:
314 if not key_data:
316 if not key_data:
315 raise ValueError('Please add a valid public key')
317 raise ValueError('Please add a valid public key')
316
318
317 key = SshKeyModel().parse_key(key_data.strip())
319 key = SshKeyModel().parse_key(key_data.strip())
318 fingerprint = key.hash_md5()
320 fingerprint = key.hash_md5()
319
321
320 ssh_key = SshKeyModel().create(
322 ssh_key = SshKeyModel().create(
321 c.user.user_id, fingerprint, key_data, description)
323 c.user.user_id, fingerprint, key_data, description)
322 ssh_key_data = ssh_key.get_api_data()
324 ssh_key_data = ssh_key.get_api_data()
323
325
324 audit_logger.store_web(
326 audit_logger.store_web(
325 'user.edit.ssh_key.add', action_data={
327 'user.edit.ssh_key.add', action_data={
326 'data': {'ssh_key': ssh_key_data, 'user': user_data}},
328 'data': {'ssh_key': ssh_key_data, 'user': user_data}},
327 user=self._rhodecode_user, )
329 user=self._rhodecode_user, )
328 Session().commit()
330 Session().commit()
329
331
332 # Trigger an event on change of keys.
333 trigger(SshKeyFileChangeEvent(), self.request.registry)
334
330 h.flash(_("Ssh Key successfully created"), category='success')
335 h.flash(_("Ssh Key successfully created"), category='success')
331
336
332 except IntegrityError:
337 except IntegrityError:
333 log.exception("Exception during ssh key saving")
338 log.exception("Exception during ssh key saving")
334 h.flash(_('An error occurred during ssh key saving: {}').format(
339 h.flash(_('An error occurred during ssh key saving: {}').format(
335 'Such key already exists, please use a different one'),
340 'Such key already exists, please use a different one'),
336 category='error')
341 category='error')
337 except Exception as e:
342 except Exception as e:
338 log.exception("Exception during ssh key saving")
343 log.exception("Exception during ssh key saving")
339 h.flash(_('An error occurred during ssh key saving: {}').format(e),
344 h.flash(_('An error occurred during ssh key saving: {}').format(e),
340 category='error')
345 category='error')
341
346
342 return HTTPFound(
347 return HTTPFound(
343 h.route_path('edit_user_ssh_keys', user_id=user_id))
348 h.route_path('edit_user_ssh_keys', user_id=user_id))
344
349
345 @LoginRequired()
350 @LoginRequired()
346 @HasPermissionAllDecorator('hg.admin')
351 @HasPermissionAllDecorator('hg.admin')
347 @CSRFRequired()
352 @CSRFRequired()
348 @view_config(
353 @view_config(
349 route_name='edit_user_ssh_keys_delete', request_method='POST')
354 route_name='edit_user_ssh_keys_delete', request_method='POST')
350 def ssh_keys_delete(self):
355 def ssh_keys_delete(self):
351 _ = self.request.translate
356 _ = self.request.translate
352 c = self.load_default_context()
357 c = self.load_default_context()
353
358
354 user_id = self.request.matchdict.get('user_id')
359 user_id = self.request.matchdict.get('user_id')
355 c.user = User.get_or_404(user_id)
360 c.user = User.get_or_404(user_id)
356 self._redirect_for_default_user(c.user.username)
361 self._redirect_for_default_user(c.user.username)
357 user_data = c.user.get_api_data()
362 user_data = c.user.get_api_data()
358
363
359 del_ssh_key = self.request.POST.get('del_ssh_key')
364 del_ssh_key = self.request.POST.get('del_ssh_key')
360
365
361 if del_ssh_key:
366 if del_ssh_key:
362 ssh_key = UserSshKeys.get_or_404(del_ssh_key)
367 ssh_key = UserSshKeys.get_or_404(del_ssh_key)
363 ssh_key_data = ssh_key.get_api_data()
368 ssh_key_data = ssh_key.get_api_data()
364
369
365 SshKeyModel().delete(del_ssh_key, c.user.user_id)
370 SshKeyModel().delete(del_ssh_key, c.user.user_id)
366 audit_logger.store_web(
371 audit_logger.store_web(
367 'user.edit.ssh_key.delete', action_data={
372 'user.edit.ssh_key.delete', action_data={
368 'data': {'ssh_key': ssh_key_data, 'user': user_data}},
373 'data': {'ssh_key': ssh_key_data, 'user': user_data}},
369 user=self._rhodecode_user,)
374 user=self._rhodecode_user,)
370 Session().commit()
375 Session().commit()
376 # Trigger an event on change of keys.
377 trigger(SshKeyFileChangeEvent(), self.request.registry)
371 h.flash(_("Ssh key successfully deleted"), category='success')
378 h.flash(_("Ssh key successfully deleted"), category='success')
372
379
373 return HTTPFound(h.route_path('edit_user_ssh_keys', user_id=user_id))
380 return HTTPFound(h.route_path('edit_user_ssh_keys', user_id=user_id))
374
381
375 @LoginRequired()
382 @LoginRequired()
376 @HasPermissionAllDecorator('hg.admin')
383 @HasPermissionAllDecorator('hg.admin')
377 @view_config(
384 @view_config(
378 route_name='edit_user_emails', request_method='GET',
385 route_name='edit_user_emails', request_method='GET',
379 renderer='rhodecode:templates/admin/users/user_edit.mako')
386 renderer='rhodecode:templates/admin/users/user_edit.mako')
380 def emails(self):
387 def emails(self):
381 _ = self.request.translate
388 _ = self.request.translate
382 c = self.load_default_context()
389 c = self.load_default_context()
383
390
384 user_id = self.request.matchdict.get('user_id')
391 user_id = self.request.matchdict.get('user_id')
385 c.user = User.get_or_404(user_id)
392 c.user = User.get_or_404(user_id)
386 self._redirect_for_default_user(c.user.username)
393 self._redirect_for_default_user(c.user.username)
387
394
388 c.active = 'emails'
395 c.active = 'emails'
389 c.user_email_map = UserEmailMap.query() \
396 c.user_email_map = UserEmailMap.query() \
390 .filter(UserEmailMap.user == c.user).all()
397 .filter(UserEmailMap.user == c.user).all()
391
398
392 return self._get_template_context(c)
399 return self._get_template_context(c)
393
400
394 @LoginRequired()
401 @LoginRequired()
395 @HasPermissionAllDecorator('hg.admin')
402 @HasPermissionAllDecorator('hg.admin')
396 @CSRFRequired()
403 @CSRFRequired()
397 @view_config(
404 @view_config(
398 route_name='edit_user_emails_add', request_method='POST')
405 route_name='edit_user_emails_add', request_method='POST')
399 def emails_add(self):
406 def emails_add(self):
400 _ = self.request.translate
407 _ = self.request.translate
401 c = self.load_default_context()
408 c = self.load_default_context()
402
409
403 user_id = self.request.matchdict.get('user_id')
410 user_id = self.request.matchdict.get('user_id')
404 c.user = User.get_or_404(user_id)
411 c.user = User.get_or_404(user_id)
405 self._redirect_for_default_user(c.user.username)
412 self._redirect_for_default_user(c.user.username)
406
413
407 email = self.request.POST.get('new_email')
414 email = self.request.POST.get('new_email')
408 user_data = c.user.get_api_data()
415 user_data = c.user.get_api_data()
409 try:
416 try:
410 UserModel().add_extra_email(c.user.user_id, email)
417 UserModel().add_extra_email(c.user.user_id, email)
411 audit_logger.store_web(
418 audit_logger.store_web(
412 'user.edit.email.add', action_data={'email': email, 'user': user_data},
419 'user.edit.email.add', action_data={'email': email, 'user': user_data},
413 user=self._rhodecode_user)
420 user=self._rhodecode_user)
414 Session().commit()
421 Session().commit()
415 h.flash(_("Added new email address `%s` for user account") % email,
422 h.flash(_("Added new email address `%s` for user account") % email,
416 category='success')
423 category='success')
417 except formencode.Invalid as error:
424 except formencode.Invalid as error:
418 h.flash(h.escape(error.error_dict['email']), category='error')
425 h.flash(h.escape(error.error_dict['email']), category='error')
419 except Exception:
426 except Exception:
420 log.exception("Exception during email saving")
427 log.exception("Exception during email saving")
421 h.flash(_('An error occurred during email saving'),
428 h.flash(_('An error occurred during email saving'),
422 category='error')
429 category='error')
423 raise HTTPFound(h.route_path('edit_user_emails', user_id=user_id))
430 raise HTTPFound(h.route_path('edit_user_emails', user_id=user_id))
424
431
425 @LoginRequired()
432 @LoginRequired()
426 @HasPermissionAllDecorator('hg.admin')
433 @HasPermissionAllDecorator('hg.admin')
427 @CSRFRequired()
434 @CSRFRequired()
428 @view_config(
435 @view_config(
429 route_name='edit_user_emails_delete', request_method='POST')
436 route_name='edit_user_emails_delete', request_method='POST')
430 def emails_delete(self):
437 def emails_delete(self):
431 _ = self.request.translate
438 _ = self.request.translate
432 c = self.load_default_context()
439 c = self.load_default_context()
433
440
434 user_id = self.request.matchdict.get('user_id')
441 user_id = self.request.matchdict.get('user_id')
435 c.user = User.get_or_404(user_id)
442 c.user = User.get_or_404(user_id)
436 self._redirect_for_default_user(c.user.username)
443 self._redirect_for_default_user(c.user.username)
437
444
438 email_id = self.request.POST.get('del_email_id')
445 email_id = self.request.POST.get('del_email_id')
439 user_model = UserModel()
446 user_model = UserModel()
440
447
441 email = UserEmailMap.query().get(email_id).email
448 email = UserEmailMap.query().get(email_id).email
442 user_data = c.user.get_api_data()
449 user_data = c.user.get_api_data()
443 user_model.delete_extra_email(c.user.user_id, email_id)
450 user_model.delete_extra_email(c.user.user_id, email_id)
444 audit_logger.store_web(
451 audit_logger.store_web(
445 'user.edit.email.delete', action_data={'email': email, 'user': user_data},
452 'user.edit.email.delete', action_data={'email': email, 'user': user_data},
446 user=self._rhodecode_user)
453 user=self._rhodecode_user)
447 Session().commit()
454 Session().commit()
448 h.flash(_("Removed email address from user account"),
455 h.flash(_("Removed email address from user account"),
449 category='success')
456 category='success')
450 raise HTTPFound(h.route_path('edit_user_emails', user_id=user_id))
457 raise HTTPFound(h.route_path('edit_user_emails', user_id=user_id))
451
458
452 @LoginRequired()
459 @LoginRequired()
453 @HasPermissionAllDecorator('hg.admin')
460 @HasPermissionAllDecorator('hg.admin')
454 @view_config(
461 @view_config(
455 route_name='edit_user_ips', request_method='GET',
462 route_name='edit_user_ips', request_method='GET',
456 renderer='rhodecode:templates/admin/users/user_edit.mako')
463 renderer='rhodecode:templates/admin/users/user_edit.mako')
457 def ips(self):
464 def ips(self):
458 _ = self.request.translate
465 _ = self.request.translate
459 c = self.load_default_context()
466 c = self.load_default_context()
460
467
461 user_id = self.request.matchdict.get('user_id')
468 user_id = self.request.matchdict.get('user_id')
462 c.user = User.get_or_404(user_id)
469 c.user = User.get_or_404(user_id)
463 self._redirect_for_default_user(c.user.username)
470 self._redirect_for_default_user(c.user.username)
464
471
465 c.active = 'ips'
472 c.active = 'ips'
466 c.user_ip_map = UserIpMap.query() \
473 c.user_ip_map = UserIpMap.query() \
467 .filter(UserIpMap.user == c.user).all()
474 .filter(UserIpMap.user == c.user).all()
468
475
469 c.inherit_default_ips = c.user.inherit_default_permissions
476 c.inherit_default_ips = c.user.inherit_default_permissions
470 c.default_user_ip_map = UserIpMap.query() \
477 c.default_user_ip_map = UserIpMap.query() \
471 .filter(UserIpMap.user == User.get_default_user()).all()
478 .filter(UserIpMap.user == User.get_default_user()).all()
472
479
473 return self._get_template_context(c)
480 return self._get_template_context(c)
474
481
475 @LoginRequired()
482 @LoginRequired()
476 @HasPermissionAllDecorator('hg.admin')
483 @HasPermissionAllDecorator('hg.admin')
477 @CSRFRequired()
484 @CSRFRequired()
478 @view_config(
485 @view_config(
479 route_name='edit_user_ips_add', request_method='POST')
486 route_name='edit_user_ips_add', request_method='POST')
480 def ips_add(self):
487 def ips_add(self):
481 _ = self.request.translate
488 _ = self.request.translate
482 c = self.load_default_context()
489 c = self.load_default_context()
483
490
484 user_id = self.request.matchdict.get('user_id')
491 user_id = self.request.matchdict.get('user_id')
485 c.user = User.get_or_404(user_id)
492 c.user = User.get_or_404(user_id)
486 # NOTE(marcink): this view is allowed for default users, as we can
493 # NOTE(marcink): this view is allowed for default users, as we can
487 # edit their IP white list
494 # edit their IP white list
488
495
489 user_model = UserModel()
496 user_model = UserModel()
490 desc = self.request.POST.get('description')
497 desc = self.request.POST.get('description')
491 try:
498 try:
492 ip_list = user_model.parse_ip_range(
499 ip_list = user_model.parse_ip_range(
493 self.request.POST.get('new_ip'))
500 self.request.POST.get('new_ip'))
494 except Exception as e:
501 except Exception as e:
495 ip_list = []
502 ip_list = []
496 log.exception("Exception during ip saving")
503 log.exception("Exception during ip saving")
497 h.flash(_('An error occurred during ip saving:%s' % (e,)),
504 h.flash(_('An error occurred during ip saving:%s' % (e,)),
498 category='error')
505 category='error')
499 added = []
506 added = []
500 user_data = c.user.get_api_data()
507 user_data = c.user.get_api_data()
501 for ip in ip_list:
508 for ip in ip_list:
502 try:
509 try:
503 user_model.add_extra_ip(c.user.user_id, ip, desc)
510 user_model.add_extra_ip(c.user.user_id, ip, desc)
504 audit_logger.store_web(
511 audit_logger.store_web(
505 'user.edit.ip.add', action_data={'ip': ip, 'user': user_data},
512 'user.edit.ip.add', action_data={'ip': ip, 'user': user_data},
506 user=self._rhodecode_user)
513 user=self._rhodecode_user)
507 Session().commit()
514 Session().commit()
508 added.append(ip)
515 added.append(ip)
509 except formencode.Invalid as error:
516 except formencode.Invalid as error:
510 msg = error.error_dict['ip']
517 msg = error.error_dict['ip']
511 h.flash(msg, category='error')
518 h.flash(msg, category='error')
512 except Exception:
519 except Exception:
513 log.exception("Exception during ip saving")
520 log.exception("Exception during ip saving")
514 h.flash(_('An error occurred during ip saving'),
521 h.flash(_('An error occurred during ip saving'),
515 category='error')
522 category='error')
516 if added:
523 if added:
517 h.flash(
524 h.flash(
518 _("Added ips %s to user whitelist") % (', '.join(ip_list), ),
525 _("Added ips %s to user whitelist") % (', '.join(ip_list), ),
519 category='success')
526 category='success')
520 if 'default_user' in self.request.POST:
527 if 'default_user' in self.request.POST:
521 # case for editing global IP list we do it for 'DEFAULT' user
528 # case for editing global IP list we do it for 'DEFAULT' user
522 raise HTTPFound(h.route_path('admin_permissions_ips'))
529 raise HTTPFound(h.route_path('admin_permissions_ips'))
523 raise HTTPFound(h.route_path('edit_user_ips', user_id=user_id))
530 raise HTTPFound(h.route_path('edit_user_ips', user_id=user_id))
524
531
525 @LoginRequired()
532 @LoginRequired()
526 @HasPermissionAllDecorator('hg.admin')
533 @HasPermissionAllDecorator('hg.admin')
527 @CSRFRequired()
534 @CSRFRequired()
528 @view_config(
535 @view_config(
529 route_name='edit_user_ips_delete', request_method='POST')
536 route_name='edit_user_ips_delete', request_method='POST')
530 def ips_delete(self):
537 def ips_delete(self):
531 _ = self.request.translate
538 _ = self.request.translate
532 c = self.load_default_context()
539 c = self.load_default_context()
533
540
534 user_id = self.request.matchdict.get('user_id')
541 user_id = self.request.matchdict.get('user_id')
535 c.user = User.get_or_404(user_id)
542 c.user = User.get_or_404(user_id)
536 # NOTE(marcink): this view is allowed for default users, as we can
543 # NOTE(marcink): this view is allowed for default users, as we can
537 # edit their IP white list
544 # edit their IP white list
538
545
539 ip_id = self.request.POST.get('del_ip_id')
546 ip_id = self.request.POST.get('del_ip_id')
540 user_model = UserModel()
547 user_model = UserModel()
541 user_data = c.user.get_api_data()
548 user_data = c.user.get_api_data()
542 ip = UserIpMap.query().get(ip_id).ip_addr
549 ip = UserIpMap.query().get(ip_id).ip_addr
543 user_model.delete_extra_ip(c.user.user_id, ip_id)
550 user_model.delete_extra_ip(c.user.user_id, ip_id)
544 audit_logger.store_web(
551 audit_logger.store_web(
545 'user.edit.ip.delete', action_data={'ip': ip, 'user': user_data},
552 'user.edit.ip.delete', action_data={'ip': ip, 'user': user_data},
546 user=self._rhodecode_user)
553 user=self._rhodecode_user)
547 Session().commit()
554 Session().commit()
548 h.flash(_("Removed ip address from user whitelist"), category='success')
555 h.flash(_("Removed ip address from user whitelist"), category='success')
549
556
550 if 'default_user' in self.request.POST:
557 if 'default_user' in self.request.POST:
551 # case for editing global IP list we do it for 'DEFAULT' user
558 # case for editing global IP list we do it for 'DEFAULT' user
552 raise HTTPFound(h.route_path('admin_permissions_ips'))
559 raise HTTPFound(h.route_path('admin_permissions_ips'))
553 raise HTTPFound(h.route_path('edit_user_ips', user_id=user_id))
560 raise HTTPFound(h.route_path('edit_user_ips', user_id=user_id))
554
561
555 @LoginRequired()
562 @LoginRequired()
556 @HasPermissionAllDecorator('hg.admin')
563 @HasPermissionAllDecorator('hg.admin')
557 @view_config(
564 @view_config(
558 route_name='edit_user_groups_management', request_method='GET',
565 route_name='edit_user_groups_management', request_method='GET',
559 renderer='rhodecode:templates/admin/users/user_edit.mako')
566 renderer='rhodecode:templates/admin/users/user_edit.mako')
560 def groups_management(self):
567 def groups_management(self):
561 c = self.load_default_context()
568 c = self.load_default_context()
562
569
563 user_id = self.request.matchdict.get('user_id')
570 user_id = self.request.matchdict.get('user_id')
564 c.user = User.get_or_404(user_id)
571 c.user = User.get_or_404(user_id)
565 c.data = c.user.group_member
572 c.data = c.user.group_member
566 self._redirect_for_default_user(c.user.username)
573 self._redirect_for_default_user(c.user.username)
567 groups = [UserGroupModel.get_user_groups_as_dict(group.users_group)
574 groups = [UserGroupModel.get_user_groups_as_dict(group.users_group)
568 for group in c.user.group_member]
575 for group in c.user.group_member]
569 c.groups = json.dumps(groups)
576 c.groups = json.dumps(groups)
570 c.active = 'groups'
577 c.active = 'groups'
571
578
572 return self._get_template_context(c)
579 return self._get_template_context(c)
573
580
574 @LoginRequired()
581 @LoginRequired()
575 @HasPermissionAllDecorator('hg.admin')
582 @HasPermissionAllDecorator('hg.admin')
576 @CSRFRequired()
583 @CSRFRequired()
577 @view_config(
584 @view_config(
578 route_name='edit_user_groups_management_updates', request_method='POST')
585 route_name='edit_user_groups_management_updates', request_method='POST')
579 def groups_management_updates(self):
586 def groups_management_updates(self):
580 _ = self.request.translate
587 _ = self.request.translate
581 c = self.load_default_context()
588 c = self.load_default_context()
582
589
583 user_id = self.request.matchdict.get('user_id')
590 user_id = self.request.matchdict.get('user_id')
584 c.user = User.get_or_404(user_id)
591 c.user = User.get_or_404(user_id)
585 self._redirect_for_default_user(c.user.username)
592 self._redirect_for_default_user(c.user.username)
586
593
587 users_groups = set(self.request.POST.getall('users_group_id'))
594 users_groups = set(self.request.POST.getall('users_group_id'))
588 users_groups_model = []
595 users_groups_model = []
589
596
590 for ugid in users_groups:
597 for ugid in users_groups:
591 users_groups_model.append(UserGroupModel().get_group(safe_int(ugid)))
598 users_groups_model.append(UserGroupModel().get_group(safe_int(ugid)))
592 user_group_model = UserGroupModel()
599 user_group_model = UserGroupModel()
593 user_group_model.change_groups(c.user, users_groups_model)
600 user_group_model.change_groups(c.user, users_groups_model)
594
601
595 Session().commit()
602 Session().commit()
596 c.active = 'user_groups_management'
603 c.active = 'user_groups_management'
597 h.flash(_("Groups successfully changed"), category='success')
604 h.flash(_("Groups successfully changed"), category='success')
598
605
599 return HTTPFound(h.route_path(
606 return HTTPFound(h.route_path(
600 'edit_user_groups_management', user_id=user_id))
607 'edit_user_groups_management', user_id=user_id))
601
608
602 @LoginRequired()
609 @LoginRequired()
603 @HasPermissionAllDecorator('hg.admin')
610 @HasPermissionAllDecorator('hg.admin')
604 @view_config(
611 @view_config(
605 route_name='edit_user_audit_logs', request_method='GET',
612 route_name='edit_user_audit_logs', request_method='GET',
606 renderer='rhodecode:templates/admin/users/user_edit.mako')
613 renderer='rhodecode:templates/admin/users/user_edit.mako')
607 def user_audit_logs(self):
614 def user_audit_logs(self):
608 _ = self.request.translate
615 _ = self.request.translate
609 c = self.load_default_context()
616 c = self.load_default_context()
610
617
611 user_id = self.request.matchdict.get('user_id')
618 user_id = self.request.matchdict.get('user_id')
612 c.user = User.get_or_404(user_id)
619 c.user = User.get_or_404(user_id)
613 self._redirect_for_default_user(c.user.username)
620 self._redirect_for_default_user(c.user.username)
614 c.active = 'audit'
621 c.active = 'audit'
615
622
616 p = safe_int(self.request.GET.get('page', 1), 1)
623 p = safe_int(self.request.GET.get('page', 1), 1)
617
624
618 filter_term = self.request.GET.get('filter')
625 filter_term = self.request.GET.get('filter')
619 user_log = UserModel().get_user_log(c.user, filter_term)
626 user_log = UserModel().get_user_log(c.user, filter_term)
620
627
621 def url_generator(**kw):
628 def url_generator(**kw):
622 if filter_term:
629 if filter_term:
623 kw['filter'] = filter_term
630 kw['filter'] = filter_term
624 return self.request.current_route_path(_query=kw)
631 return self.request.current_route_path(_query=kw)
625
632
626 c.audit_logs = h.Page(
633 c.audit_logs = h.Page(
627 user_log, page=p, items_per_page=10, url=url_generator)
634 user_log, page=p, items_per_page=10, url=url_generator)
628 c.filter_term = filter_term
635 c.filter_term = filter_term
629 return self._get_template_context(c)
636 return self._get_template_context(c)
630
637
@@ -1,534 +1,535 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 """
21 """
22 Pylons middleware initialization
22 Pylons middleware initialization
23 """
23 """
24 import logging
24 import logging
25 import traceback
25 import traceback
26 from collections import OrderedDict
26 from collections import OrderedDict
27
27
28 from paste.registry import RegistryManager
28 from paste.registry import RegistryManager
29 from paste.gzipper import make_gzip_middleware
29 from paste.gzipper import make_gzip_middleware
30 from pylons.wsgiapp import PylonsApp
30 from pylons.wsgiapp import PylonsApp
31 from pyramid.authorization import ACLAuthorizationPolicy
31 from pyramid.authorization import ACLAuthorizationPolicy
32 from pyramid.config import Configurator
32 from pyramid.config import Configurator
33 from pyramid.settings import asbool, aslist
33 from pyramid.settings import asbool, aslist
34 from pyramid.wsgi import wsgiapp
34 from pyramid.wsgi import wsgiapp
35 from pyramid.httpexceptions import (
35 from pyramid.httpexceptions import (
36 HTTPException, HTTPError, HTTPInternalServerError, HTTPFound)
36 HTTPException, HTTPError, HTTPInternalServerError, HTTPFound)
37 from pyramid.events import ApplicationCreated
37 from pyramid.events import ApplicationCreated
38 from pyramid.renderers import render_to_response
38 from pyramid.renderers import render_to_response
39 from routes.middleware import RoutesMiddleware
39 from routes.middleware import RoutesMiddleware
40 import rhodecode
40 import rhodecode
41
41
42 from rhodecode.model import meta
42 from rhodecode.model import meta
43 from rhodecode.config import patches
43 from rhodecode.config import patches
44 from rhodecode.config.routing import STATIC_FILE_PREFIX
44 from rhodecode.config.routing import STATIC_FILE_PREFIX
45 from rhodecode.config.environment import (
45 from rhodecode.config.environment import (
46 load_environment, load_pyramid_environment)
46 load_environment, load_pyramid_environment)
47
47
48 from rhodecode.lib.vcs import VCSCommunicationError
48 from rhodecode.lib.vcs import VCSCommunicationError
49 from rhodecode.lib.exceptions import VCSServerUnavailable
49 from rhodecode.lib.exceptions import VCSServerUnavailable
50 from rhodecode.lib.middleware.appenlight import wrap_in_appenlight_if_enabled
50 from rhodecode.lib.middleware.appenlight import wrap_in_appenlight_if_enabled
51 from rhodecode.lib.middleware.error_handling import (
51 from rhodecode.lib.middleware.error_handling import (
52 PylonsErrorHandlingMiddleware)
52 PylonsErrorHandlingMiddleware)
53 from rhodecode.lib.middleware.https_fixup import HttpsFixup
53 from rhodecode.lib.middleware.https_fixup import HttpsFixup
54 from rhodecode.lib.middleware.vcs import VCSMiddleware
54 from rhodecode.lib.middleware.vcs import VCSMiddleware
55 from rhodecode.lib.plugins.utils import register_rhodecode_plugin
55 from rhodecode.lib.plugins.utils import register_rhodecode_plugin
56 from rhodecode.lib.utils2 import aslist as rhodecode_aslist, AttributeDict
56 from rhodecode.lib.utils2 import aslist as rhodecode_aslist, AttributeDict
57 from rhodecode.subscribers import (
57 from rhodecode.subscribers import (
58 scan_repositories_if_enabled, write_js_routes_if_enabled,
58 scan_repositories_if_enabled, write_js_routes_if_enabled,
59 write_metadata_if_needed)
59 write_metadata_if_needed)
60
60
61
61
62 log = logging.getLogger(__name__)
62 log = logging.getLogger(__name__)
63
63
64
64
65 # this is used to avoid avoid the route lookup overhead in routesmiddleware
65 # this is used to avoid avoid the route lookup overhead in routesmiddleware
66 # for certain routes which won't go to pylons to - eg. static files, debugger
66 # for certain routes which won't go to pylons to - eg. static files, debugger
67 # it is only needed for the pylons migration and can be removed once complete
67 # it is only needed for the pylons migration and can be removed once complete
68 class SkippableRoutesMiddleware(RoutesMiddleware):
68 class SkippableRoutesMiddleware(RoutesMiddleware):
69 """ Routes middleware that allows you to skip prefixes """
69 """ Routes middleware that allows you to skip prefixes """
70
70
71 def __init__(self, *args, **kw):
71 def __init__(self, *args, **kw):
72 self.skip_prefixes = kw.pop('skip_prefixes', [])
72 self.skip_prefixes = kw.pop('skip_prefixes', [])
73 super(SkippableRoutesMiddleware, self).__init__(*args, **kw)
73 super(SkippableRoutesMiddleware, self).__init__(*args, **kw)
74
74
75 def __call__(self, environ, start_response):
75 def __call__(self, environ, start_response):
76 for prefix in self.skip_prefixes:
76 for prefix in self.skip_prefixes:
77 if environ['PATH_INFO'].startswith(prefix):
77 if environ['PATH_INFO'].startswith(prefix):
78 # added to avoid the case when a missing /_static route falls
78 # added to avoid the case when a missing /_static route falls
79 # through to pylons and causes an exception as pylons is
79 # through to pylons and causes an exception as pylons is
80 # expecting wsgiorg.routingargs to be set in the environ
80 # expecting wsgiorg.routingargs to be set in the environ
81 # by RoutesMiddleware.
81 # by RoutesMiddleware.
82 if 'wsgiorg.routing_args' not in environ:
82 if 'wsgiorg.routing_args' not in environ:
83 environ['wsgiorg.routing_args'] = (None, {})
83 environ['wsgiorg.routing_args'] = (None, {})
84 return self.app(environ, start_response)
84 return self.app(environ, start_response)
85
85
86 return super(SkippableRoutesMiddleware, self).__call__(
86 return super(SkippableRoutesMiddleware, self).__call__(
87 environ, start_response)
87 environ, start_response)
88
88
89
89
90 def make_app(global_conf, static_files=True, **app_conf):
90 def make_app(global_conf, static_files=True, **app_conf):
91 """Create a Pylons WSGI application and return it
91 """Create a Pylons WSGI application and return it
92
92
93 ``global_conf``
93 ``global_conf``
94 The inherited configuration for this application. Normally from
94 The inherited configuration for this application. Normally from
95 the [DEFAULT] section of the Paste ini file.
95 the [DEFAULT] section of the Paste ini file.
96
96
97 ``app_conf``
97 ``app_conf``
98 The application's local configuration. Normally specified in
98 The application's local configuration. Normally specified in
99 the [app:<name>] section of the Paste ini file (where <name>
99 the [app:<name>] section of the Paste ini file (where <name>
100 defaults to main).
100 defaults to main).
101
101
102 """
102 """
103 # Apply compatibility patches
103 # Apply compatibility patches
104 patches.kombu_1_5_1_python_2_7_11()
104 patches.kombu_1_5_1_python_2_7_11()
105 patches.inspect_getargspec()
105 patches.inspect_getargspec()
106
106
107 # Configure the Pylons environment
107 # Configure the Pylons environment
108 config = load_environment(global_conf, app_conf)
108 config = load_environment(global_conf, app_conf)
109
109
110 # The Pylons WSGI app
110 # The Pylons WSGI app
111 app = PylonsApp(config=config)
111 app = PylonsApp(config=config)
112
112
113 # Establish the Registry for this application
113 # Establish the Registry for this application
114 app = RegistryManager(app)
114 app = RegistryManager(app)
115
115
116 app.config = config
116 app.config = config
117
117
118 return app
118 return app
119
119
120
120
121 def make_pyramid_app(global_config, **settings):
121 def make_pyramid_app(global_config, **settings):
122 """
122 """
123 Constructs the WSGI application based on Pyramid and wraps the Pylons based
123 Constructs the WSGI application based on Pyramid and wraps the Pylons based
124 application.
124 application.
125
125
126 Specials:
126 Specials:
127
127
128 * We migrate from Pylons to Pyramid. While doing this, we keep both
128 * We migrate from Pylons to Pyramid. While doing this, we keep both
129 frameworks functional. This involves moving some WSGI middlewares around
129 frameworks functional. This involves moving some WSGI middlewares around
130 and providing access to some data internals, so that the old code is
130 and providing access to some data internals, so that the old code is
131 still functional.
131 still functional.
132
132
133 * The application can also be integrated like a plugin via the call to
133 * The application can also be integrated like a plugin via the call to
134 `includeme`. This is accompanied with the other utility functions which
134 `includeme`. This is accompanied with the other utility functions which
135 are called. Changing this should be done with great care to not break
135 are called. Changing this should be done with great care to not break
136 cases when these fragments are assembled from another place.
136 cases when these fragments are assembled from another place.
137
137
138 """
138 """
139 # The edition string should be available in pylons too, so we add it here
139 # The edition string should be available in pylons too, so we add it here
140 # before copying the settings.
140 # before copying the settings.
141 settings.setdefault('rhodecode.edition', 'Community Edition')
141 settings.setdefault('rhodecode.edition', 'Community Edition')
142
142
143 # As long as our Pylons application does expect "unprepared" settings, make
143 # As long as our Pylons application does expect "unprepared" settings, make
144 # sure that we keep an unmodified copy. This avoids unintentional change of
144 # sure that we keep an unmodified copy. This avoids unintentional change of
145 # behavior in the old application.
145 # behavior in the old application.
146 settings_pylons = settings.copy()
146 settings_pylons = settings.copy()
147
147
148 sanitize_settings_and_apply_defaults(settings)
148 sanitize_settings_and_apply_defaults(settings)
149 config = Configurator(settings=settings)
149 config = Configurator(settings=settings)
150 add_pylons_compat_data(config.registry, global_config, settings_pylons)
150 add_pylons_compat_data(config.registry, global_config, settings_pylons)
151
151
152 load_pyramid_environment(global_config, settings)
152 load_pyramid_environment(global_config, settings)
153
153
154 includeme_first(config)
154 includeme_first(config)
155 includeme(config)
155 includeme(config)
156
156
157 pyramid_app = config.make_wsgi_app()
157 pyramid_app = config.make_wsgi_app()
158 pyramid_app = wrap_app_in_wsgi_middlewares(pyramid_app, config)
158 pyramid_app = wrap_app_in_wsgi_middlewares(pyramid_app, config)
159 pyramid_app.config = config
159 pyramid_app.config = config
160
160
161 # creating the app uses a connection - return it after we are done
161 # creating the app uses a connection - return it after we are done
162 meta.Session.remove()
162 meta.Session.remove()
163
163
164 return pyramid_app
164 return pyramid_app
165
165
166
166
167 def make_not_found_view(config):
167 def make_not_found_view(config):
168 """
168 """
169 This creates the view which should be registered as not-found-view to
169 This creates the view which should be registered as not-found-view to
170 pyramid. Basically it contains of the old pylons app, converted to a view.
170 pyramid. Basically it contains of the old pylons app, converted to a view.
171 Additionally it is wrapped by some other middlewares.
171 Additionally it is wrapped by some other middlewares.
172 """
172 """
173 settings = config.registry.settings
173 settings = config.registry.settings
174 vcs_server_enabled = settings['vcs.server.enable']
174 vcs_server_enabled = settings['vcs.server.enable']
175
175
176 # Make pylons app from unprepared settings.
176 # Make pylons app from unprepared settings.
177 pylons_app = make_app(
177 pylons_app = make_app(
178 config.registry._pylons_compat_global_config,
178 config.registry._pylons_compat_global_config,
179 **config.registry._pylons_compat_settings)
179 **config.registry._pylons_compat_settings)
180 config.registry._pylons_compat_config = pylons_app.config
180 config.registry._pylons_compat_config = pylons_app.config
181
181
182 # Appenlight monitoring.
182 # Appenlight monitoring.
183 pylons_app, appenlight_client = wrap_in_appenlight_if_enabled(
183 pylons_app, appenlight_client = wrap_in_appenlight_if_enabled(
184 pylons_app, settings)
184 pylons_app, settings)
185
185
186 # The pylons app is executed inside of the pyramid 404 exception handler.
186 # The pylons app is executed inside of the pyramid 404 exception handler.
187 # Exceptions which are raised inside of it are not handled by pyramid
187 # Exceptions which are raised inside of it are not handled by pyramid
188 # again. Therefore we add a middleware that invokes the error handler in
188 # again. Therefore we add a middleware that invokes the error handler in
189 # case of an exception or error response. This way we return proper error
189 # case of an exception or error response. This way we return proper error
190 # HTML pages in case of an error.
190 # HTML pages in case of an error.
191 reraise = (settings.get('debugtoolbar.enabled', False) or
191 reraise = (settings.get('debugtoolbar.enabled', False) or
192 rhodecode.disable_error_handler)
192 rhodecode.disable_error_handler)
193 pylons_app = PylonsErrorHandlingMiddleware(
193 pylons_app = PylonsErrorHandlingMiddleware(
194 pylons_app, error_handler, reraise)
194 pylons_app, error_handler, reraise)
195
195
196 # The VCSMiddleware shall operate like a fallback if pyramid doesn't find a
196 # The VCSMiddleware shall operate like a fallback if pyramid doesn't find a
197 # view to handle the request. Therefore it is wrapped around the pylons
197 # view to handle the request. Therefore it is wrapped around the pylons
198 # app. It has to be outside of the error handling otherwise error responses
198 # app. It has to be outside of the error handling otherwise error responses
199 # from the vcsserver are converted to HTML error pages. This confuses the
199 # from the vcsserver are converted to HTML error pages. This confuses the
200 # command line tools and the user won't get a meaningful error message.
200 # command line tools and the user won't get a meaningful error message.
201 if vcs_server_enabled:
201 if vcs_server_enabled:
202 pylons_app = VCSMiddleware(
202 pylons_app = VCSMiddleware(
203 pylons_app, settings, appenlight_client, registry=config.registry)
203 pylons_app, settings, appenlight_client, registry=config.registry)
204
204
205 # Convert WSGI app to pyramid view and return it.
205 # Convert WSGI app to pyramid view and return it.
206 return wsgiapp(pylons_app)
206 return wsgiapp(pylons_app)
207
207
208
208
209 def add_pylons_compat_data(registry, global_config, settings):
209 def add_pylons_compat_data(registry, global_config, settings):
210 """
210 """
211 Attach data to the registry to support the Pylons integration.
211 Attach data to the registry to support the Pylons integration.
212 """
212 """
213 registry._pylons_compat_global_config = global_config
213 registry._pylons_compat_global_config = global_config
214 registry._pylons_compat_settings = settings
214 registry._pylons_compat_settings = settings
215
215
216
216
217 def error_handler(exception, request):
217 def error_handler(exception, request):
218 import rhodecode
218 import rhodecode
219 from rhodecode.lib import helpers
219 from rhodecode.lib import helpers
220
220
221 rhodecode_title = rhodecode.CONFIG.get('rhodecode_title') or 'RhodeCode'
221 rhodecode_title = rhodecode.CONFIG.get('rhodecode_title') or 'RhodeCode'
222
222
223 base_response = HTTPInternalServerError()
223 base_response = HTTPInternalServerError()
224 # prefer original exception for the response since it may have headers set
224 # prefer original exception for the response since it may have headers set
225 if isinstance(exception, HTTPException):
225 if isinstance(exception, HTTPException):
226 base_response = exception
226 base_response = exception
227 elif isinstance(exception, VCSCommunicationError):
227 elif isinstance(exception, VCSCommunicationError):
228 base_response = VCSServerUnavailable()
228 base_response = VCSServerUnavailable()
229
229
230 def is_http_error(response):
230 def is_http_error(response):
231 # error which should have traceback
231 # error which should have traceback
232 return response.status_code > 499
232 return response.status_code > 499
233
233
234 if is_http_error(base_response):
234 if is_http_error(base_response):
235 log.exception(
235 log.exception(
236 'error occurred handling this request for path: %s', request.path)
236 'error occurred handling this request for path: %s', request.path)
237
237
238 c = AttributeDict()
238 c = AttributeDict()
239 c.error_message = base_response.status
239 c.error_message = base_response.status
240 c.error_explanation = base_response.explanation or str(base_response)
240 c.error_explanation = base_response.explanation or str(base_response)
241 c.visual = AttributeDict()
241 c.visual = AttributeDict()
242
242
243 c.visual.rhodecode_support_url = (
243 c.visual.rhodecode_support_url = (
244 request.registry.settings.get('rhodecode_support_url') or
244 request.registry.settings.get('rhodecode_support_url') or
245 request.route_url('rhodecode_support')
245 request.route_url('rhodecode_support')
246 )
246 )
247 c.redirect_time = 0
247 c.redirect_time = 0
248 c.rhodecode_name = rhodecode_title
248 c.rhodecode_name = rhodecode_title
249 if not c.rhodecode_name:
249 if not c.rhodecode_name:
250 c.rhodecode_name = 'Rhodecode'
250 c.rhodecode_name = 'Rhodecode'
251
251
252 c.causes = []
252 c.causes = []
253 if hasattr(base_response, 'causes'):
253 if hasattr(base_response, 'causes'):
254 c.causes = base_response.causes
254 c.causes = base_response.causes
255 c.messages = helpers.flash.pop_messages(request=request)
255 c.messages = helpers.flash.pop_messages(request=request)
256 c.traceback = traceback.format_exc()
256 c.traceback = traceback.format_exc()
257 response = render_to_response(
257 response = render_to_response(
258 '/errors/error_document.mako', {'c': c, 'h': helpers}, request=request,
258 '/errors/error_document.mako', {'c': c, 'h': helpers}, request=request,
259 response=base_response)
259 response=base_response)
260
260
261 return response
261 return response
262
262
263
263
264 def includeme(config):
264 def includeme(config):
265 settings = config.registry.settings
265 settings = config.registry.settings
266
266
267 # plugin information
267 # plugin information
268 config.registry.rhodecode_plugins = OrderedDict()
268 config.registry.rhodecode_plugins = OrderedDict()
269
269
270 config.add_directive(
270 config.add_directive(
271 'register_rhodecode_plugin', register_rhodecode_plugin)
271 'register_rhodecode_plugin', register_rhodecode_plugin)
272
272
273 if asbool(settings.get('appenlight', 'false')):
273 if asbool(settings.get('appenlight', 'false')):
274 config.include('appenlight_client.ext.pyramid_tween')
274 config.include('appenlight_client.ext.pyramid_tween')
275
275
276 if 'mako.default_filters' not in settings:
276 if 'mako.default_filters' not in settings:
277 # set custom default filters if we don't have it defined
277 # set custom default filters if we don't have it defined
278 settings['mako.imports'] = 'from rhodecode.lib.base import h_filter'
278 settings['mako.imports'] = 'from rhodecode.lib.base import h_filter'
279 settings['mako.default_filters'] = 'h_filter'
279 settings['mako.default_filters'] = 'h_filter'
280
280
281 # Includes which are required. The application would fail without them.
281 # Includes which are required. The application would fail without them.
282 config.include('pyramid_mako')
282 config.include('pyramid_mako')
283 config.include('pyramid_beaker')
283 config.include('pyramid_beaker')
284
284
285 config.include('rhodecode.authentication')
285 config.include('rhodecode.authentication')
286 config.include('rhodecode.integrations')
286 config.include('rhodecode.integrations')
287
287
288 # apps
288 # apps
289 config.include('rhodecode.apps._base')
289 config.include('rhodecode.apps._base')
290 config.include('rhodecode.apps.ops')
290 config.include('rhodecode.apps.ops')
291
291
292 config.include('rhodecode.apps.admin')
292 config.include('rhodecode.apps.admin')
293 config.include('rhodecode.apps.channelstream')
293 config.include('rhodecode.apps.channelstream')
294 config.include('rhodecode.apps.login')
294 config.include('rhodecode.apps.login')
295 config.include('rhodecode.apps.home')
295 config.include('rhodecode.apps.home')
296 config.include('rhodecode.apps.journal')
296 config.include('rhodecode.apps.journal')
297 config.include('rhodecode.apps.repository')
297 config.include('rhodecode.apps.repository')
298 config.include('rhodecode.apps.repo_group')
298 config.include('rhodecode.apps.repo_group')
299 config.include('rhodecode.apps.search')
299 config.include('rhodecode.apps.search')
300 config.include('rhodecode.apps.user_profile')
300 config.include('rhodecode.apps.user_profile')
301 config.include('rhodecode.apps.my_account')
301 config.include('rhodecode.apps.my_account')
302 config.include('rhodecode.apps.svn_support')
302 config.include('rhodecode.apps.svn_support')
303 config.include('rhodecode.apps.ssh_support')
303 config.include('rhodecode.apps.gist')
304 config.include('rhodecode.apps.gist')
304
305
305 config.include('rhodecode.apps.debug_style')
306 config.include('rhodecode.apps.debug_style')
306 config.include('rhodecode.tweens')
307 config.include('rhodecode.tweens')
307 config.include('rhodecode.api')
308 config.include('rhodecode.api')
308
309
309 config.add_route(
310 config.add_route(
310 'rhodecode_support', 'https://rhodecode.com/help/', static=True)
311 'rhodecode_support', 'https://rhodecode.com/help/', static=True)
311
312
312 config.add_translation_dirs('rhodecode:i18n/')
313 config.add_translation_dirs('rhodecode:i18n/')
313 settings['default_locale_name'] = settings.get('lang', 'en')
314 settings['default_locale_name'] = settings.get('lang', 'en')
314
315
315 # Add subscribers.
316 # Add subscribers.
316 config.add_subscriber(scan_repositories_if_enabled, ApplicationCreated)
317 config.add_subscriber(scan_repositories_if_enabled, ApplicationCreated)
317 config.add_subscriber(write_metadata_if_needed, ApplicationCreated)
318 config.add_subscriber(write_metadata_if_needed, ApplicationCreated)
318 config.add_subscriber(write_js_routes_if_enabled, ApplicationCreated)
319 config.add_subscriber(write_js_routes_if_enabled, ApplicationCreated)
319
320
320 config.add_request_method(
321 config.add_request_method(
321 'rhodecode.lib.partial_renderer.get_partial_renderer',
322 'rhodecode.lib.partial_renderer.get_partial_renderer',
322 'get_partial_renderer')
323 'get_partial_renderer')
323
324
324 # events
325 # events
325 # TODO(marcink): this should be done when pyramid migration is finished
326 # TODO(marcink): this should be done when pyramid migration is finished
326 # config.add_subscriber(
327 # config.add_subscriber(
327 # 'rhodecode.integrations.integrations_event_handler',
328 # 'rhodecode.integrations.integrations_event_handler',
328 # 'rhodecode.events.RhodecodeEvent')
329 # 'rhodecode.events.RhodecodeEvent')
329
330
330 # Set the authorization policy.
331 # Set the authorization policy.
331 authz_policy = ACLAuthorizationPolicy()
332 authz_policy = ACLAuthorizationPolicy()
332 config.set_authorization_policy(authz_policy)
333 config.set_authorization_policy(authz_policy)
333
334
334 # Set the default renderer for HTML templates to mako.
335 # Set the default renderer for HTML templates to mako.
335 config.add_mako_renderer('.html')
336 config.add_mako_renderer('.html')
336
337
337 config.add_renderer(
338 config.add_renderer(
338 name='json_ext',
339 name='json_ext',
339 factory='rhodecode.lib.ext_json_renderer.pyramid_ext_json')
340 factory='rhodecode.lib.ext_json_renderer.pyramid_ext_json')
340
341
341 # include RhodeCode plugins
342 # include RhodeCode plugins
342 includes = aslist(settings.get('rhodecode.includes', []))
343 includes = aslist(settings.get('rhodecode.includes', []))
343 for inc in includes:
344 for inc in includes:
344 config.include(inc)
345 config.include(inc)
345
346
346 # This is the glue which allows us to migrate in chunks. By registering the
347 # This is the glue which allows us to migrate in chunks. By registering the
347 # pylons based application as the "Not Found" view in Pyramid, we will
348 # pylons based application as the "Not Found" view in Pyramid, we will
348 # fallback to the old application each time the new one does not yet know
349 # fallback to the old application each time the new one does not yet know
349 # how to handle a request.
350 # how to handle a request.
350 config.add_notfound_view(make_not_found_view(config))
351 config.add_notfound_view(make_not_found_view(config))
351
352
352 if not settings.get('debugtoolbar.enabled', False):
353 if not settings.get('debugtoolbar.enabled', False):
353 # disabled debugtoolbar handle all exceptions via the error_handlers
354 # disabled debugtoolbar handle all exceptions via the error_handlers
354 config.add_view(error_handler, context=Exception)
355 config.add_view(error_handler, context=Exception)
355
356
356 config.add_view(error_handler, context=HTTPError)
357 config.add_view(error_handler, context=HTTPError)
357
358
358
359
359 def includeme_first(config):
360 def includeme_first(config):
360 # redirect automatic browser favicon.ico requests to correct place
361 # redirect automatic browser favicon.ico requests to correct place
361 def favicon_redirect(context, request):
362 def favicon_redirect(context, request):
362 return HTTPFound(
363 return HTTPFound(
363 request.static_path('rhodecode:public/images/favicon.ico'))
364 request.static_path('rhodecode:public/images/favicon.ico'))
364
365
365 config.add_view(favicon_redirect, route_name='favicon')
366 config.add_view(favicon_redirect, route_name='favicon')
366 config.add_route('favicon', '/favicon.ico')
367 config.add_route('favicon', '/favicon.ico')
367
368
368 def robots_redirect(context, request):
369 def robots_redirect(context, request):
369 return HTTPFound(
370 return HTTPFound(
370 request.static_path('rhodecode:public/robots.txt'))
371 request.static_path('rhodecode:public/robots.txt'))
371
372
372 config.add_view(robots_redirect, route_name='robots')
373 config.add_view(robots_redirect, route_name='robots')
373 config.add_route('robots', '/robots.txt')
374 config.add_route('robots', '/robots.txt')
374
375
375 config.add_static_view(
376 config.add_static_view(
376 '_static/deform', 'deform:static')
377 '_static/deform', 'deform:static')
377 config.add_static_view(
378 config.add_static_view(
378 '_static/rhodecode', path='rhodecode:public', cache_max_age=3600 * 24)
379 '_static/rhodecode', path='rhodecode:public', cache_max_age=3600 * 24)
379
380
380
381
381 def wrap_app_in_wsgi_middlewares(pyramid_app, config):
382 def wrap_app_in_wsgi_middlewares(pyramid_app, config):
382 """
383 """
383 Apply outer WSGI middlewares around the application.
384 Apply outer WSGI middlewares around the application.
384
385
385 Part of this has been moved up from the Pylons layer, so that the
386 Part of this has been moved up from the Pylons layer, so that the
386 data is also available if old Pylons code is hit through an already ported
387 data is also available if old Pylons code is hit through an already ported
387 view.
388 view.
388 """
389 """
389 settings = config.registry.settings
390 settings = config.registry.settings
390
391
391 # enable https redirects based on HTTP_X_URL_SCHEME set by proxy
392 # enable https redirects based on HTTP_X_URL_SCHEME set by proxy
392 pyramid_app = HttpsFixup(pyramid_app, settings)
393 pyramid_app = HttpsFixup(pyramid_app, settings)
393
394
394 # Add RoutesMiddleware to support the pylons compatibility tween during
395 # Add RoutesMiddleware to support the pylons compatibility tween during
395 # migration to pyramid.
396 # migration to pyramid.
396
397
397 # TODO(marcink): remove after migration to pyramid
398 # TODO(marcink): remove after migration to pyramid
398 if hasattr(config.registry, '_pylons_compat_config'):
399 if hasattr(config.registry, '_pylons_compat_config'):
399 routes_map = config.registry._pylons_compat_config['routes.map']
400 routes_map = config.registry._pylons_compat_config['routes.map']
400 pyramid_app = SkippableRoutesMiddleware(
401 pyramid_app = SkippableRoutesMiddleware(
401 pyramid_app, routes_map,
402 pyramid_app, routes_map,
402 skip_prefixes=(STATIC_FILE_PREFIX, '/_debug_toolbar'))
403 skip_prefixes=(STATIC_FILE_PREFIX, '/_debug_toolbar'))
403
404
404 pyramid_app, _ = wrap_in_appenlight_if_enabled(pyramid_app, settings)
405 pyramid_app, _ = wrap_in_appenlight_if_enabled(pyramid_app, settings)
405
406
406 if settings['gzip_responses']:
407 if settings['gzip_responses']:
407 pyramid_app = make_gzip_middleware(
408 pyramid_app = make_gzip_middleware(
408 pyramid_app, settings, compress_level=1)
409 pyramid_app, settings, compress_level=1)
409
410
410 # this should be the outer most middleware in the wsgi stack since
411 # this should be the outer most middleware in the wsgi stack since
411 # middleware like Routes make database calls
412 # middleware like Routes make database calls
412 def pyramid_app_with_cleanup(environ, start_response):
413 def pyramid_app_with_cleanup(environ, start_response):
413 try:
414 try:
414 return pyramid_app(environ, start_response)
415 return pyramid_app(environ, start_response)
415 finally:
416 finally:
416 # Dispose current database session and rollback uncommitted
417 # Dispose current database session and rollback uncommitted
417 # transactions.
418 # transactions.
418 meta.Session.remove()
419 meta.Session.remove()
419
420
420 # In a single threaded mode server, on non sqlite db we should have
421 # In a single threaded mode server, on non sqlite db we should have
421 # '0 Current Checked out connections' at the end of a request,
422 # '0 Current Checked out connections' at the end of a request,
422 # if not, then something, somewhere is leaving a connection open
423 # if not, then something, somewhere is leaving a connection open
423 pool = meta.Base.metadata.bind.engine.pool
424 pool = meta.Base.metadata.bind.engine.pool
424 log.debug('sa pool status: %s', pool.status())
425 log.debug('sa pool status: %s', pool.status())
425
426
426 return pyramid_app_with_cleanup
427 return pyramid_app_with_cleanup
427
428
428
429
429 def sanitize_settings_and_apply_defaults(settings):
430 def sanitize_settings_and_apply_defaults(settings):
430 """
431 """
431 Applies settings defaults and does all type conversion.
432 Applies settings defaults and does all type conversion.
432
433
433 We would move all settings parsing and preparation into this place, so that
434 We would move all settings parsing and preparation into this place, so that
434 we have only one place left which deals with this part. The remaining parts
435 we have only one place left which deals with this part. The remaining parts
435 of the application would start to rely fully on well prepared settings.
436 of the application would start to rely fully on well prepared settings.
436
437
437 This piece would later be split up per topic to avoid a big fat monster
438 This piece would later be split up per topic to avoid a big fat monster
438 function.
439 function.
439 """
440 """
440
441
441 # Pyramid's mako renderer has to search in the templates folder so that the
442 # Pyramid's mako renderer has to search in the templates folder so that the
442 # old templates still work. Ported and new templates are expected to use
443 # old templates still work. Ported and new templates are expected to use
443 # real asset specifications for the includes.
444 # real asset specifications for the includes.
444 mako_directories = settings.setdefault('mako.directories', [
445 mako_directories = settings.setdefault('mako.directories', [
445 # Base templates of the original Pylons application
446 # Base templates of the original Pylons application
446 'rhodecode:templates',
447 'rhodecode:templates',
447 ])
448 ])
448 log.debug(
449 log.debug(
449 "Using the following Mako template directories: %s",
450 "Using the following Mako template directories: %s",
450 mako_directories)
451 mako_directories)
451
452
452 # Default includes, possible to change as a user
453 # Default includes, possible to change as a user
453 pyramid_includes = settings.setdefault('pyramid.includes', [
454 pyramid_includes = settings.setdefault('pyramid.includes', [
454 'rhodecode.lib.middleware.request_wrapper',
455 'rhodecode.lib.middleware.request_wrapper',
455 ])
456 ])
456 log.debug(
457 log.debug(
457 "Using the following pyramid.includes: %s",
458 "Using the following pyramid.includes: %s",
458 pyramid_includes)
459 pyramid_includes)
459
460
460 # TODO: johbo: Re-think this, usually the call to config.include
461 # TODO: johbo: Re-think this, usually the call to config.include
461 # should allow to pass in a prefix.
462 # should allow to pass in a prefix.
462 settings.setdefault('rhodecode.api.url', '/_admin/api')
463 settings.setdefault('rhodecode.api.url', '/_admin/api')
463
464
464 # Sanitize generic settings.
465 # Sanitize generic settings.
465 _list_setting(settings, 'default_encoding', 'UTF-8')
466 _list_setting(settings, 'default_encoding', 'UTF-8')
466 _bool_setting(settings, 'is_test', 'false')
467 _bool_setting(settings, 'is_test', 'false')
467 _bool_setting(settings, 'gzip_responses', 'false')
468 _bool_setting(settings, 'gzip_responses', 'false')
468
469
469 # Call split out functions that sanitize settings for each topic.
470 # Call split out functions that sanitize settings for each topic.
470 _sanitize_appenlight_settings(settings)
471 _sanitize_appenlight_settings(settings)
471 _sanitize_vcs_settings(settings)
472 _sanitize_vcs_settings(settings)
472
473
473 return settings
474 return settings
474
475
475
476
476 def _sanitize_appenlight_settings(settings):
477 def _sanitize_appenlight_settings(settings):
477 _bool_setting(settings, 'appenlight', 'false')
478 _bool_setting(settings, 'appenlight', 'false')
478
479
479
480
480 def _sanitize_vcs_settings(settings):
481 def _sanitize_vcs_settings(settings):
481 """
482 """
482 Applies settings defaults and does type conversion for all VCS related
483 Applies settings defaults and does type conversion for all VCS related
483 settings.
484 settings.
484 """
485 """
485 _string_setting(settings, 'vcs.svn.compatible_version', '')
486 _string_setting(settings, 'vcs.svn.compatible_version', '')
486 _string_setting(settings, 'git_rev_filter', '--all')
487 _string_setting(settings, 'git_rev_filter', '--all')
487 _string_setting(settings, 'vcs.hooks.protocol', 'http')
488 _string_setting(settings, 'vcs.hooks.protocol', 'http')
488 _string_setting(settings, 'vcs.scm_app_implementation', 'http')
489 _string_setting(settings, 'vcs.scm_app_implementation', 'http')
489 _string_setting(settings, 'vcs.server', '')
490 _string_setting(settings, 'vcs.server', '')
490 _string_setting(settings, 'vcs.server.log_level', 'debug')
491 _string_setting(settings, 'vcs.server.log_level', 'debug')
491 _string_setting(settings, 'vcs.server.protocol', 'http')
492 _string_setting(settings, 'vcs.server.protocol', 'http')
492 _bool_setting(settings, 'startup.import_repos', 'false')
493 _bool_setting(settings, 'startup.import_repos', 'false')
493 _bool_setting(settings, 'vcs.hooks.direct_calls', 'false')
494 _bool_setting(settings, 'vcs.hooks.direct_calls', 'false')
494 _bool_setting(settings, 'vcs.server.enable', 'true')
495 _bool_setting(settings, 'vcs.server.enable', 'true')
495 _bool_setting(settings, 'vcs.start_server', 'false')
496 _bool_setting(settings, 'vcs.start_server', 'false')
496 _list_setting(settings, 'vcs.backends', 'hg, git, svn')
497 _list_setting(settings, 'vcs.backends', 'hg, git, svn')
497 _int_setting(settings, 'vcs.connection_timeout', 3600)
498 _int_setting(settings, 'vcs.connection_timeout', 3600)
498
499
499 # Support legacy values of vcs.scm_app_implementation. Legacy
500 # Support legacy values of vcs.scm_app_implementation. Legacy
500 # configurations may use 'rhodecode.lib.middleware.utils.scm_app_http'
501 # configurations may use 'rhodecode.lib.middleware.utils.scm_app_http'
501 # which is now mapped to 'http'.
502 # which is now mapped to 'http'.
502 scm_app_impl = settings['vcs.scm_app_implementation']
503 scm_app_impl = settings['vcs.scm_app_implementation']
503 if scm_app_impl == 'rhodecode.lib.middleware.utils.scm_app_http':
504 if scm_app_impl == 'rhodecode.lib.middleware.utils.scm_app_http':
504 settings['vcs.scm_app_implementation'] = 'http'
505 settings['vcs.scm_app_implementation'] = 'http'
505
506
506
507
507 def _int_setting(settings, name, default):
508 def _int_setting(settings, name, default):
508 settings[name] = int(settings.get(name, default))
509 settings[name] = int(settings.get(name, default))
509
510
510
511
511 def _bool_setting(settings, name, default):
512 def _bool_setting(settings, name, default):
512 input = settings.get(name, default)
513 input = settings.get(name, default)
513 if isinstance(input, unicode):
514 if isinstance(input, unicode):
514 input = input.encode('utf8')
515 input = input.encode('utf8')
515 settings[name] = asbool(input)
516 settings[name] = asbool(input)
516
517
517
518
518 def _list_setting(settings, name, default):
519 def _list_setting(settings, name, default):
519 raw_value = settings.get(name, default)
520 raw_value = settings.get(name, default)
520
521
521 old_separator = ','
522 old_separator = ','
522 if old_separator in raw_value:
523 if old_separator in raw_value:
523 # If we get a comma separated list, pass it to our own function.
524 # If we get a comma separated list, pass it to our own function.
524 settings[name] = rhodecode_aslist(raw_value, sep=old_separator)
525 settings[name] = rhodecode_aslist(raw_value, sep=old_separator)
525 else:
526 else:
526 # Otherwise we assume it uses pyramids space/newline separation.
527 # Otherwise we assume it uses pyramids space/newline separation.
527 settings[name] = aslist(raw_value)
528 settings[name] = aslist(raw_value)
528
529
529
530
530 def _string_setting(settings, name, default, lower=True):
531 def _string_setting(settings, name, default, lower=True):
531 value = settings.get(name, default)
532 value = settings.get(name, default)
532 if lower:
533 if lower:
533 value = value.lower()
534 value = value.lower()
534 settings[name] = value
535 settings[name] = value
General Comments 0
You need to be logged in to leave comments. Login now