##// END OF EJS Templates
settings: re-use attached request global config for performance...
bart -
r4200:007322e6 stable
parent child Browse files
Show More
@@ -1,615 +1,615 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2019 RhodeCode GmbH
3 # Copyright (C) 2010-2019 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 The base Controller API
22 The base Controller API
23 Provides the BaseController class for subclassing. And usage in different
23 Provides the BaseController class for subclassing. And usage in different
24 controllers
24 controllers
25 """
25 """
26
26
27 import logging
27 import logging
28 import socket
28 import socket
29
29
30 import markupsafe
30 import markupsafe
31 import ipaddress
31 import ipaddress
32
32
33 from paste.auth.basic import AuthBasicAuthenticator
33 from paste.auth.basic import AuthBasicAuthenticator
34 from paste.httpexceptions import HTTPUnauthorized, HTTPForbidden, get_exception
34 from paste.httpexceptions import HTTPUnauthorized, HTTPForbidden, get_exception
35 from paste.httpheaders import WWW_AUTHENTICATE, AUTHORIZATION
35 from paste.httpheaders import WWW_AUTHENTICATE, AUTHORIZATION
36
36
37 import rhodecode
37 import rhodecode
38 from rhodecode.apps._base import TemplateArgs
38 from rhodecode.apps._base import TemplateArgs
39 from rhodecode.authentication.base import VCS_TYPE
39 from rhodecode.authentication.base import VCS_TYPE
40 from rhodecode.lib import auth, utils2
40 from rhodecode.lib import auth, utils2
41 from rhodecode.lib import helpers as h
41 from rhodecode.lib import helpers as h
42 from rhodecode.lib.auth import AuthUser, CookieStoreWrapper
42 from rhodecode.lib.auth import AuthUser, CookieStoreWrapper
43 from rhodecode.lib.exceptions import UserCreationError
43 from rhodecode.lib.exceptions import UserCreationError
44 from rhodecode.lib.utils import (password_changed, get_enabled_hook_classes)
44 from rhodecode.lib.utils import (password_changed, get_enabled_hook_classes)
45 from rhodecode.lib.utils2 import (
45 from rhodecode.lib.utils2 import (
46 str2bool, safe_unicode, AttributeDict, safe_int, sha1, aslist, safe_str)
46 str2bool, safe_unicode, AttributeDict, safe_int, sha1, aslist, safe_str)
47 from rhodecode.model.db import Repository, User, ChangesetComment, UserBookmark
47 from rhodecode.model.db import Repository, User, ChangesetComment, UserBookmark
48 from rhodecode.model.notification import NotificationModel
48 from rhodecode.model.notification import NotificationModel
49 from rhodecode.model.settings import VcsSettingsModel, SettingsModel
49 from rhodecode.model.settings import VcsSettingsModel, SettingsModel
50
50
51 log = logging.getLogger(__name__)
51 log = logging.getLogger(__name__)
52
52
53
53
54 def _filter_proxy(ip):
54 def _filter_proxy(ip):
55 """
55 """
56 Passed in IP addresses in HEADERS can be in a special format of multiple
56 Passed in IP addresses in HEADERS can be in a special format of multiple
57 ips. Those comma separated IPs are passed from various proxies in the
57 ips. Those comma separated IPs are passed from various proxies in the
58 chain of request processing. The left-most being the original client.
58 chain of request processing. The left-most being the original client.
59 We only care about the first IP which came from the org. client.
59 We only care about the first IP which came from the org. client.
60
60
61 :param ip: ip string from headers
61 :param ip: ip string from headers
62 """
62 """
63 if ',' in ip:
63 if ',' in ip:
64 _ips = ip.split(',')
64 _ips = ip.split(',')
65 _first_ip = _ips[0].strip()
65 _first_ip = _ips[0].strip()
66 log.debug('Got multiple IPs %s, using %s', ','.join(_ips), _first_ip)
66 log.debug('Got multiple IPs %s, using %s', ','.join(_ips), _first_ip)
67 return _first_ip
67 return _first_ip
68 return ip
68 return ip
69
69
70
70
71 def _filter_port(ip):
71 def _filter_port(ip):
72 """
72 """
73 Removes a port from ip, there are 4 main cases to handle here.
73 Removes a port from ip, there are 4 main cases to handle here.
74 - ipv4 eg. 127.0.0.1
74 - ipv4 eg. 127.0.0.1
75 - ipv6 eg. ::1
75 - ipv6 eg. ::1
76 - ipv4+port eg. 127.0.0.1:8080
76 - ipv4+port eg. 127.0.0.1:8080
77 - ipv6+port eg. [::1]:8080
77 - ipv6+port eg. [::1]:8080
78
78
79 :param ip:
79 :param ip:
80 """
80 """
81 def is_ipv6(ip_addr):
81 def is_ipv6(ip_addr):
82 if hasattr(socket, 'inet_pton'):
82 if hasattr(socket, 'inet_pton'):
83 try:
83 try:
84 socket.inet_pton(socket.AF_INET6, ip_addr)
84 socket.inet_pton(socket.AF_INET6, ip_addr)
85 except socket.error:
85 except socket.error:
86 return False
86 return False
87 else:
87 else:
88 # fallback to ipaddress
88 # fallback to ipaddress
89 try:
89 try:
90 ipaddress.IPv6Address(safe_unicode(ip_addr))
90 ipaddress.IPv6Address(safe_unicode(ip_addr))
91 except Exception:
91 except Exception:
92 return False
92 return False
93 return True
93 return True
94
94
95 if ':' not in ip: # must be ipv4 pure ip
95 if ':' not in ip: # must be ipv4 pure ip
96 return ip
96 return ip
97
97
98 if '[' in ip and ']' in ip: # ipv6 with port
98 if '[' in ip and ']' in ip: # ipv6 with port
99 return ip.split(']')[0][1:].lower()
99 return ip.split(']')[0][1:].lower()
100
100
101 # must be ipv6 or ipv4 with port
101 # must be ipv6 or ipv4 with port
102 if is_ipv6(ip):
102 if is_ipv6(ip):
103 return ip
103 return ip
104 else:
104 else:
105 ip, _port = ip.split(':')[:2] # means ipv4+port
105 ip, _port = ip.split(':')[:2] # means ipv4+port
106 return ip
106 return ip
107
107
108
108
109 def get_ip_addr(environ):
109 def get_ip_addr(environ):
110 proxy_key = 'HTTP_X_REAL_IP'
110 proxy_key = 'HTTP_X_REAL_IP'
111 proxy_key2 = 'HTTP_X_FORWARDED_FOR'
111 proxy_key2 = 'HTTP_X_FORWARDED_FOR'
112 def_key = 'REMOTE_ADDR'
112 def_key = 'REMOTE_ADDR'
113 _filters = lambda x: _filter_port(_filter_proxy(x))
113 _filters = lambda x: _filter_port(_filter_proxy(x))
114
114
115 ip = environ.get(proxy_key)
115 ip = environ.get(proxy_key)
116 if ip:
116 if ip:
117 return _filters(ip)
117 return _filters(ip)
118
118
119 ip = environ.get(proxy_key2)
119 ip = environ.get(proxy_key2)
120 if ip:
120 if ip:
121 return _filters(ip)
121 return _filters(ip)
122
122
123 ip = environ.get(def_key, '0.0.0.0')
123 ip = environ.get(def_key, '0.0.0.0')
124 return _filters(ip)
124 return _filters(ip)
125
125
126
126
127 def get_server_ip_addr(environ, log_errors=True):
127 def get_server_ip_addr(environ, log_errors=True):
128 hostname = environ.get('SERVER_NAME')
128 hostname = environ.get('SERVER_NAME')
129 try:
129 try:
130 return socket.gethostbyname(hostname)
130 return socket.gethostbyname(hostname)
131 except Exception as e:
131 except Exception as e:
132 if log_errors:
132 if log_errors:
133 # in some cases this lookup is not possible, and we don't want to
133 # in some cases this lookup is not possible, and we don't want to
134 # make it an exception in logs
134 # make it an exception in logs
135 log.exception('Could not retrieve server ip address: %s', e)
135 log.exception('Could not retrieve server ip address: %s', e)
136 return hostname
136 return hostname
137
137
138
138
139 def get_server_port(environ):
139 def get_server_port(environ):
140 return environ.get('SERVER_PORT')
140 return environ.get('SERVER_PORT')
141
141
142
142
143 def get_access_path(environ):
143 def get_access_path(environ):
144 path = environ.get('PATH_INFO')
144 path = environ.get('PATH_INFO')
145 org_req = environ.get('pylons.original_request')
145 org_req = environ.get('pylons.original_request')
146 if org_req:
146 if org_req:
147 path = org_req.environ.get('PATH_INFO')
147 path = org_req.environ.get('PATH_INFO')
148 return path
148 return path
149
149
150
150
151 def get_user_agent(environ):
151 def get_user_agent(environ):
152 return environ.get('HTTP_USER_AGENT')
152 return environ.get('HTTP_USER_AGENT')
153
153
154
154
155 def vcs_operation_context(
155 def vcs_operation_context(
156 environ, repo_name, username, action, scm, check_locking=True,
156 environ, repo_name, username, action, scm, check_locking=True,
157 is_shadow_repo=False, check_branch_perms=False, detect_force_push=False):
157 is_shadow_repo=False, check_branch_perms=False, detect_force_push=False):
158 """
158 """
159 Generate the context for a vcs operation, e.g. push or pull.
159 Generate the context for a vcs operation, e.g. push or pull.
160
160
161 This context is passed over the layers so that hooks triggered by the
161 This context is passed over the layers so that hooks triggered by the
162 vcs operation know details like the user, the user's IP address etc.
162 vcs operation know details like the user, the user's IP address etc.
163
163
164 :param check_locking: Allows to switch of the computation of the locking
164 :param check_locking: Allows to switch of the computation of the locking
165 data. This serves mainly the need of the simplevcs middleware to be
165 data. This serves mainly the need of the simplevcs middleware to be
166 able to disable this for certain operations.
166 able to disable this for certain operations.
167
167
168 """
168 """
169 # Tri-state value: False: unlock, None: nothing, True: lock
169 # Tri-state value: False: unlock, None: nothing, True: lock
170 make_lock = None
170 make_lock = None
171 locked_by = [None, None, None]
171 locked_by = [None, None, None]
172 is_anonymous = username == User.DEFAULT_USER
172 is_anonymous = username == User.DEFAULT_USER
173 user = User.get_by_username(username)
173 user = User.get_by_username(username)
174 if not is_anonymous and check_locking:
174 if not is_anonymous and check_locking:
175 log.debug('Checking locking on repository "%s"', repo_name)
175 log.debug('Checking locking on repository "%s"', repo_name)
176 repo = Repository.get_by_repo_name(repo_name)
176 repo = Repository.get_by_repo_name(repo_name)
177 make_lock, __, locked_by = repo.get_locking_state(
177 make_lock, __, locked_by = repo.get_locking_state(
178 action, user.user_id)
178 action, user.user_id)
179 user_id = user.user_id
179 user_id = user.user_id
180 settings_model = VcsSettingsModel(repo=repo_name)
180 settings_model = VcsSettingsModel(repo=repo_name)
181 ui_settings = settings_model.get_ui_settings()
181 ui_settings = settings_model.get_ui_settings()
182
182
183 # NOTE(marcink): This should be also in sync with
183 # NOTE(marcink): This should be also in sync with
184 # rhodecode/apps/ssh_support/lib/backends/base.py:update_environment scm_data
184 # rhodecode/apps/ssh_support/lib/backends/base.py:update_environment scm_data
185 store = [x for x in ui_settings if x.key == '/']
185 store = [x for x in ui_settings if x.key == '/']
186 repo_store = ''
186 repo_store = ''
187 if store:
187 if store:
188 repo_store = store[0].value
188 repo_store = store[0].value
189
189
190 scm_data = {
190 scm_data = {
191 'ip': get_ip_addr(environ),
191 'ip': get_ip_addr(environ),
192 'username': username,
192 'username': username,
193 'user_id': user_id,
193 'user_id': user_id,
194 'action': action,
194 'action': action,
195 'repository': repo_name,
195 'repository': repo_name,
196 'scm': scm,
196 'scm': scm,
197 'config': rhodecode.CONFIG['__file__'],
197 'config': rhodecode.CONFIG['__file__'],
198 'repo_store': repo_store,
198 'repo_store': repo_store,
199 'make_lock': make_lock,
199 'make_lock': make_lock,
200 'locked_by': locked_by,
200 'locked_by': locked_by,
201 'server_url': utils2.get_server_url(environ),
201 'server_url': utils2.get_server_url(environ),
202 'user_agent': get_user_agent(environ),
202 'user_agent': get_user_agent(environ),
203 'hooks': get_enabled_hook_classes(ui_settings),
203 'hooks': get_enabled_hook_classes(ui_settings),
204 'is_shadow_repo': is_shadow_repo,
204 'is_shadow_repo': is_shadow_repo,
205 'detect_force_push': detect_force_push,
205 'detect_force_push': detect_force_push,
206 'check_branch_perms': check_branch_perms,
206 'check_branch_perms': check_branch_perms,
207 }
207 }
208 return scm_data
208 return scm_data
209
209
210
210
211 class BasicAuth(AuthBasicAuthenticator):
211 class BasicAuth(AuthBasicAuthenticator):
212
212
213 def __init__(self, realm, authfunc, registry, auth_http_code=None,
213 def __init__(self, realm, authfunc, registry, auth_http_code=None,
214 initial_call_detection=False, acl_repo_name=None):
214 initial_call_detection=False, acl_repo_name=None):
215 self.realm = realm
215 self.realm = realm
216 self.initial_call = initial_call_detection
216 self.initial_call = initial_call_detection
217 self.authfunc = authfunc
217 self.authfunc = authfunc
218 self.registry = registry
218 self.registry = registry
219 self.acl_repo_name = acl_repo_name
219 self.acl_repo_name = acl_repo_name
220 self._rc_auth_http_code = auth_http_code
220 self._rc_auth_http_code = auth_http_code
221
221
222 def _get_response_from_code(self, http_code):
222 def _get_response_from_code(self, http_code):
223 try:
223 try:
224 return get_exception(safe_int(http_code))
224 return get_exception(safe_int(http_code))
225 except Exception:
225 except Exception:
226 log.exception('Failed to fetch response for code %s', http_code)
226 log.exception('Failed to fetch response for code %s', http_code)
227 return HTTPForbidden
227 return HTTPForbidden
228
228
229 def get_rc_realm(self):
229 def get_rc_realm(self):
230 return safe_str(self.registry.rhodecode_settings.get('rhodecode_realm'))
230 return safe_str(self.registry.rhodecode_settings.get('rhodecode_realm'))
231
231
232 def build_authentication(self):
232 def build_authentication(self):
233 head = WWW_AUTHENTICATE.tuples('Basic realm="%s"' % self.realm)
233 head = WWW_AUTHENTICATE.tuples('Basic realm="%s"' % self.realm)
234 if self._rc_auth_http_code and not self.initial_call:
234 if self._rc_auth_http_code and not self.initial_call:
235 # return alternative HTTP code if alternative http return code
235 # return alternative HTTP code if alternative http return code
236 # is specified in RhodeCode config, but ONLY if it's not the
236 # is specified in RhodeCode config, but ONLY if it's not the
237 # FIRST call
237 # FIRST call
238 custom_response_klass = self._get_response_from_code(
238 custom_response_klass = self._get_response_from_code(
239 self._rc_auth_http_code)
239 self._rc_auth_http_code)
240 return custom_response_klass(headers=head)
240 return custom_response_klass(headers=head)
241 return HTTPUnauthorized(headers=head)
241 return HTTPUnauthorized(headers=head)
242
242
243 def authenticate(self, environ):
243 def authenticate(self, environ):
244 authorization = AUTHORIZATION(environ)
244 authorization = AUTHORIZATION(environ)
245 if not authorization:
245 if not authorization:
246 return self.build_authentication()
246 return self.build_authentication()
247 (authmeth, auth) = authorization.split(' ', 1)
247 (authmeth, auth) = authorization.split(' ', 1)
248 if 'basic' != authmeth.lower():
248 if 'basic' != authmeth.lower():
249 return self.build_authentication()
249 return self.build_authentication()
250 auth = auth.strip().decode('base64')
250 auth = auth.strip().decode('base64')
251 _parts = auth.split(':', 1)
251 _parts = auth.split(':', 1)
252 if len(_parts) == 2:
252 if len(_parts) == 2:
253 username, password = _parts
253 username, password = _parts
254 auth_data = self.authfunc(
254 auth_data = self.authfunc(
255 username, password, environ, VCS_TYPE,
255 username, password, environ, VCS_TYPE,
256 registry=self.registry, acl_repo_name=self.acl_repo_name)
256 registry=self.registry, acl_repo_name=self.acl_repo_name)
257 if auth_data:
257 if auth_data:
258 return {'username': username, 'auth_data': auth_data}
258 return {'username': username, 'auth_data': auth_data}
259 if username and password:
259 if username and password:
260 # we mark that we actually executed authentication once, at
260 # we mark that we actually executed authentication once, at
261 # that point we can use the alternative auth code
261 # that point we can use the alternative auth code
262 self.initial_call = False
262 self.initial_call = False
263
263
264 return self.build_authentication()
264 return self.build_authentication()
265
265
266 __call__ = authenticate
266 __call__ = authenticate
267
267
268
268
269 def calculate_version_hash(config):
269 def calculate_version_hash(config):
270 return sha1(
270 return sha1(
271 config.get('beaker.session.secret', '') +
271 config.get('beaker.session.secret', '') +
272 rhodecode.__version__)[:8]
272 rhodecode.__version__)[:8]
273
273
274
274
275 def get_current_lang(request):
275 def get_current_lang(request):
276 # NOTE(marcink): remove after pyramid move
276 # NOTE(marcink): remove after pyramid move
277 try:
277 try:
278 return translation.get_lang()[0]
278 return translation.get_lang()[0]
279 except:
279 except:
280 pass
280 pass
281
281
282 return getattr(request, '_LOCALE_', request.locale_name)
282 return getattr(request, '_LOCALE_', request.locale_name)
283
283
284
284
285 def attach_context_attributes(context, request, user_id=None):
285 def attach_context_attributes(context, request, user_id=None):
286 """
286 """
287 Attach variables into template context called `c`.
287 Attach variables into template context called `c`.
288 """
288 """
289 config = request.registry.settings
289 config = request.registry.settings
290
290
291 rc_config = SettingsModel().get_all_settings(cache=True)
291 rc_config = SettingsModel().get_all_settings(cache=True, from_request=False)
292 context.rc_config = rc_config
292 context.rc_config = rc_config
293 context.rhodecode_version = rhodecode.__version__
293 context.rhodecode_version = rhodecode.__version__
294 context.rhodecode_edition = config.get('rhodecode.edition')
294 context.rhodecode_edition = config.get('rhodecode.edition')
295 # unique secret + version does not leak the version but keep consistency
295 # unique secret + version does not leak the version but keep consistency
296 context.rhodecode_version_hash = calculate_version_hash(config)
296 context.rhodecode_version_hash = calculate_version_hash(config)
297
297
298 # Default language set for the incoming request
298 # Default language set for the incoming request
299 context.language = get_current_lang(request)
299 context.language = get_current_lang(request)
300
300
301 # Visual options
301 # Visual options
302 context.visual = AttributeDict({})
302 context.visual = AttributeDict({})
303
303
304 # DB stored Visual Items
304 # DB stored Visual Items
305 context.visual.show_public_icon = str2bool(
305 context.visual.show_public_icon = str2bool(
306 rc_config.get('rhodecode_show_public_icon'))
306 rc_config.get('rhodecode_show_public_icon'))
307 context.visual.show_private_icon = str2bool(
307 context.visual.show_private_icon = str2bool(
308 rc_config.get('rhodecode_show_private_icon'))
308 rc_config.get('rhodecode_show_private_icon'))
309 context.visual.stylify_metatags = str2bool(
309 context.visual.stylify_metatags = str2bool(
310 rc_config.get('rhodecode_stylify_metatags'))
310 rc_config.get('rhodecode_stylify_metatags'))
311 context.visual.dashboard_items = safe_int(
311 context.visual.dashboard_items = safe_int(
312 rc_config.get('rhodecode_dashboard_items', 100))
312 rc_config.get('rhodecode_dashboard_items', 100))
313 context.visual.admin_grid_items = safe_int(
313 context.visual.admin_grid_items = safe_int(
314 rc_config.get('rhodecode_admin_grid_items', 100))
314 rc_config.get('rhodecode_admin_grid_items', 100))
315 context.visual.show_revision_number = str2bool(
315 context.visual.show_revision_number = str2bool(
316 rc_config.get('rhodecode_show_revision_number', True))
316 rc_config.get('rhodecode_show_revision_number', True))
317 context.visual.show_sha_length = safe_int(
317 context.visual.show_sha_length = safe_int(
318 rc_config.get('rhodecode_show_sha_length', 100))
318 rc_config.get('rhodecode_show_sha_length', 100))
319 context.visual.repository_fields = str2bool(
319 context.visual.repository_fields = str2bool(
320 rc_config.get('rhodecode_repository_fields'))
320 rc_config.get('rhodecode_repository_fields'))
321 context.visual.show_version = str2bool(
321 context.visual.show_version = str2bool(
322 rc_config.get('rhodecode_show_version'))
322 rc_config.get('rhodecode_show_version'))
323 context.visual.use_gravatar = str2bool(
323 context.visual.use_gravatar = str2bool(
324 rc_config.get('rhodecode_use_gravatar'))
324 rc_config.get('rhodecode_use_gravatar'))
325 context.visual.gravatar_url = rc_config.get('rhodecode_gravatar_url')
325 context.visual.gravatar_url = rc_config.get('rhodecode_gravatar_url')
326 context.visual.default_renderer = rc_config.get(
326 context.visual.default_renderer = rc_config.get(
327 'rhodecode_markup_renderer', 'rst')
327 'rhodecode_markup_renderer', 'rst')
328 context.visual.comment_types = ChangesetComment.COMMENT_TYPES
328 context.visual.comment_types = ChangesetComment.COMMENT_TYPES
329 context.visual.rhodecode_support_url = \
329 context.visual.rhodecode_support_url = \
330 rc_config.get('rhodecode_support_url') or h.route_url('rhodecode_support')
330 rc_config.get('rhodecode_support_url') or h.route_url('rhodecode_support')
331
331
332 context.visual.affected_files_cut_off = 60
332 context.visual.affected_files_cut_off = 60
333
333
334 context.pre_code = rc_config.get('rhodecode_pre_code')
334 context.pre_code = rc_config.get('rhodecode_pre_code')
335 context.post_code = rc_config.get('rhodecode_post_code')
335 context.post_code = rc_config.get('rhodecode_post_code')
336 context.rhodecode_name = rc_config.get('rhodecode_title')
336 context.rhodecode_name = rc_config.get('rhodecode_title')
337 context.default_encodings = aslist(config.get('default_encoding'), sep=',')
337 context.default_encodings = aslist(config.get('default_encoding'), sep=',')
338 # if we have specified default_encoding in the request, it has more
338 # if we have specified default_encoding in the request, it has more
339 # priority
339 # priority
340 if request.GET.get('default_encoding'):
340 if request.GET.get('default_encoding'):
341 context.default_encodings.insert(0, request.GET.get('default_encoding'))
341 context.default_encodings.insert(0, request.GET.get('default_encoding'))
342 context.clone_uri_tmpl = rc_config.get('rhodecode_clone_uri_tmpl')
342 context.clone_uri_tmpl = rc_config.get('rhodecode_clone_uri_tmpl')
343 context.clone_uri_ssh_tmpl = rc_config.get('rhodecode_clone_uri_ssh_tmpl')
343 context.clone_uri_ssh_tmpl = rc_config.get('rhodecode_clone_uri_ssh_tmpl')
344
344
345 # INI stored
345 # INI stored
346 context.labs_active = str2bool(
346 context.labs_active = str2bool(
347 config.get('labs_settings_active', 'false'))
347 config.get('labs_settings_active', 'false'))
348 context.ssh_enabled = str2bool(
348 context.ssh_enabled = str2bool(
349 config.get('ssh.generate_authorized_keyfile', 'false'))
349 config.get('ssh.generate_authorized_keyfile', 'false'))
350 context.ssh_key_generator_enabled = str2bool(
350 context.ssh_key_generator_enabled = str2bool(
351 config.get('ssh.enable_ui_key_generator', 'true'))
351 config.get('ssh.enable_ui_key_generator', 'true'))
352
352
353 context.visual.allow_repo_location_change = str2bool(
353 context.visual.allow_repo_location_change = str2bool(
354 config.get('allow_repo_location_change', True))
354 config.get('allow_repo_location_change', True))
355 context.visual.allow_custom_hooks_settings = str2bool(
355 context.visual.allow_custom_hooks_settings = str2bool(
356 config.get('allow_custom_hooks_settings', True))
356 config.get('allow_custom_hooks_settings', True))
357 context.debug_style = str2bool(config.get('debug_style', False))
357 context.debug_style = str2bool(config.get('debug_style', False))
358
358
359 context.rhodecode_instanceid = config.get('instance_id')
359 context.rhodecode_instanceid = config.get('instance_id')
360
360
361 context.visual.cut_off_limit_diff = safe_int(
361 context.visual.cut_off_limit_diff = safe_int(
362 config.get('cut_off_limit_diff'))
362 config.get('cut_off_limit_diff'))
363 context.visual.cut_off_limit_file = safe_int(
363 context.visual.cut_off_limit_file = safe_int(
364 config.get('cut_off_limit_file'))
364 config.get('cut_off_limit_file'))
365
365
366 context.license = AttributeDict({})
366 context.license = AttributeDict({})
367 context.license.hide_license_info = str2bool(
367 context.license.hide_license_info = str2bool(
368 config.get('license.hide_license_info', False))
368 config.get('license.hide_license_info', False))
369
369
370 # AppEnlight
370 # AppEnlight
371 context.appenlight_enabled = str2bool(config.get('appenlight', 'false'))
371 context.appenlight_enabled = str2bool(config.get('appenlight', 'false'))
372 context.appenlight_api_public_key = config.get(
372 context.appenlight_api_public_key = config.get(
373 'appenlight.api_public_key', '')
373 'appenlight.api_public_key', '')
374 context.appenlight_server_url = config.get('appenlight.server_url', '')
374 context.appenlight_server_url = config.get('appenlight.server_url', '')
375
375
376 diffmode = {
376 diffmode = {
377 "unified": "unified",
377 "unified": "unified",
378 "sideside": "sideside"
378 "sideside": "sideside"
379 }.get(request.GET.get('diffmode'))
379 }.get(request.GET.get('diffmode'))
380
380
381 is_api = hasattr(request, 'rpc_user')
381 is_api = hasattr(request, 'rpc_user')
382 session_attrs = {
382 session_attrs = {
383 # defaults
383 # defaults
384 "clone_url_format": "http",
384 "clone_url_format": "http",
385 "diffmode": "sideside"
385 "diffmode": "sideside"
386 }
386 }
387
387
388 if not is_api:
388 if not is_api:
389 # don't access pyramid session for API calls
389 # don't access pyramid session for API calls
390 if diffmode and diffmode != request.session.get('rc_user_session_attr.diffmode'):
390 if diffmode and diffmode != request.session.get('rc_user_session_attr.diffmode'):
391 request.session['rc_user_session_attr.diffmode'] = diffmode
391 request.session['rc_user_session_attr.diffmode'] = diffmode
392
392
393 # session settings per user
393 # session settings per user
394
394
395 for k, v in request.session.items():
395 for k, v in request.session.items():
396 pref = 'rc_user_session_attr.'
396 pref = 'rc_user_session_attr.'
397 if k and k.startswith(pref):
397 if k and k.startswith(pref):
398 k = k[len(pref):]
398 k = k[len(pref):]
399 session_attrs[k] = v
399 session_attrs[k] = v
400
400
401 context.user_session_attrs = session_attrs
401 context.user_session_attrs = session_attrs
402
402
403 # JS template context
403 # JS template context
404 context.template_context = {
404 context.template_context = {
405 'repo_name': None,
405 'repo_name': None,
406 'repo_type': None,
406 'repo_type': None,
407 'repo_landing_commit': None,
407 'repo_landing_commit': None,
408 'rhodecode_user': {
408 'rhodecode_user': {
409 'username': None,
409 'username': None,
410 'email': None,
410 'email': None,
411 'notification_status': False
411 'notification_status': False
412 },
412 },
413 'session_attrs': session_attrs,
413 'session_attrs': session_attrs,
414 'visual': {
414 'visual': {
415 'default_renderer': None
415 'default_renderer': None
416 },
416 },
417 'commit_data': {
417 'commit_data': {
418 'commit_id': None
418 'commit_id': None
419 },
419 },
420 'pull_request_data': {'pull_request_id': None},
420 'pull_request_data': {'pull_request_id': None},
421 'timeago': {
421 'timeago': {
422 'refresh_time': 120 * 1000,
422 'refresh_time': 120 * 1000,
423 'cutoff_limit': 1000 * 60 * 60 * 24 * 7
423 'cutoff_limit': 1000 * 60 * 60 * 24 * 7
424 },
424 },
425 'pyramid_dispatch': {
425 'pyramid_dispatch': {
426
426
427 },
427 },
428 'extra': {'plugins': {}}
428 'extra': {'plugins': {}}
429 }
429 }
430 # END CONFIG VARS
430 # END CONFIG VARS
431 if is_api:
431 if is_api:
432 csrf_token = None
432 csrf_token = None
433 else:
433 else:
434 csrf_token = auth.get_csrf_token(session=request.session)
434 csrf_token = auth.get_csrf_token(session=request.session)
435
435
436 context.csrf_token = csrf_token
436 context.csrf_token = csrf_token
437 context.backends = rhodecode.BACKENDS.keys()
437 context.backends = rhodecode.BACKENDS.keys()
438 context.backends.sort()
438 context.backends.sort()
439 unread_count = 0
439 unread_count = 0
440 user_bookmark_list = []
440 user_bookmark_list = []
441 if user_id:
441 if user_id:
442 unread_count = NotificationModel().get_unread_cnt_for_user(user_id)
442 unread_count = NotificationModel().get_unread_cnt_for_user(user_id)
443 user_bookmark_list = UserBookmark.get_bookmarks_for_user(user_id)
443 user_bookmark_list = UserBookmark.get_bookmarks_for_user(user_id)
444 context.unread_notifications = unread_count
444 context.unread_notifications = unread_count
445 context.bookmark_items = user_bookmark_list
445 context.bookmark_items = user_bookmark_list
446
446
447 # web case
447 # web case
448 if hasattr(request, 'user'):
448 if hasattr(request, 'user'):
449 context.auth_user = request.user
449 context.auth_user = request.user
450 context.rhodecode_user = request.user
450 context.rhodecode_user = request.user
451
451
452 # api case
452 # api case
453 if hasattr(request, 'rpc_user'):
453 if hasattr(request, 'rpc_user'):
454 context.auth_user = request.rpc_user
454 context.auth_user = request.rpc_user
455 context.rhodecode_user = request.rpc_user
455 context.rhodecode_user = request.rpc_user
456
456
457 # attach the whole call context to the request
457 # attach the whole call context to the request
458 request.call_context = context
458 request.call_context = context
459
459
460
460
461 def get_auth_user(request):
461 def get_auth_user(request):
462 environ = request.environ
462 environ = request.environ
463 session = request.session
463 session = request.session
464
464
465 ip_addr = get_ip_addr(environ)
465 ip_addr = get_ip_addr(environ)
466
466
467 # make sure that we update permissions each time we call controller
467 # make sure that we update permissions each time we call controller
468 _auth_token = (request.GET.get('auth_token', '') or request.GET.get('api_key', ''))
468 _auth_token = (request.GET.get('auth_token', '') or request.GET.get('api_key', ''))
469 if not _auth_token and request.matchdict:
469 if not _auth_token and request.matchdict:
470 url_auth_token = request.matchdict.get('_auth_token')
470 url_auth_token = request.matchdict.get('_auth_token')
471 _auth_token = url_auth_token
471 _auth_token = url_auth_token
472 if _auth_token:
472 if _auth_token:
473 log.debug('Using URL extracted auth token `...%s`', _auth_token[-4:])
473 log.debug('Using URL extracted auth token `...%s`', _auth_token[-4:])
474
474
475 if _auth_token:
475 if _auth_token:
476 # when using API_KEY we assume user exists, and
476 # when using API_KEY we assume user exists, and
477 # doesn't need auth based on cookies.
477 # doesn't need auth based on cookies.
478 auth_user = AuthUser(api_key=_auth_token, ip_addr=ip_addr)
478 auth_user = AuthUser(api_key=_auth_token, ip_addr=ip_addr)
479 authenticated = False
479 authenticated = False
480 else:
480 else:
481 cookie_store = CookieStoreWrapper(session.get('rhodecode_user'))
481 cookie_store = CookieStoreWrapper(session.get('rhodecode_user'))
482 try:
482 try:
483 auth_user = AuthUser(user_id=cookie_store.get('user_id', None),
483 auth_user = AuthUser(user_id=cookie_store.get('user_id', None),
484 ip_addr=ip_addr)
484 ip_addr=ip_addr)
485 except UserCreationError as e:
485 except UserCreationError as e:
486 h.flash(e, 'error')
486 h.flash(e, 'error')
487 # container auth or other auth functions that create users
487 # container auth or other auth functions that create users
488 # on the fly can throw this exception signaling that there's
488 # on the fly can throw this exception signaling that there's
489 # issue with user creation, explanation should be provided
489 # issue with user creation, explanation should be provided
490 # in Exception itself. We then create a simple blank
490 # in Exception itself. We then create a simple blank
491 # AuthUser
491 # AuthUser
492 auth_user = AuthUser(ip_addr=ip_addr)
492 auth_user = AuthUser(ip_addr=ip_addr)
493
493
494 # in case someone changes a password for user it triggers session
494 # in case someone changes a password for user it triggers session
495 # flush and forces a re-login
495 # flush and forces a re-login
496 if password_changed(auth_user, session):
496 if password_changed(auth_user, session):
497 session.invalidate()
497 session.invalidate()
498 cookie_store = CookieStoreWrapper(session.get('rhodecode_user'))
498 cookie_store = CookieStoreWrapper(session.get('rhodecode_user'))
499 auth_user = AuthUser(ip_addr=ip_addr)
499 auth_user = AuthUser(ip_addr=ip_addr)
500
500
501 authenticated = cookie_store.get('is_authenticated')
501 authenticated = cookie_store.get('is_authenticated')
502
502
503 if not auth_user.is_authenticated and auth_user.is_user_object:
503 if not auth_user.is_authenticated and auth_user.is_user_object:
504 # user is not authenticated and not empty
504 # user is not authenticated and not empty
505 auth_user.set_authenticated(authenticated)
505 auth_user.set_authenticated(authenticated)
506
506
507 return auth_user, _auth_token
507 return auth_user, _auth_token
508
508
509
509
510 def h_filter(s):
510 def h_filter(s):
511 """
511 """
512 Custom filter for Mako templates. Mako by standard uses `markupsafe.escape`
512 Custom filter for Mako templates. Mako by standard uses `markupsafe.escape`
513 we wrap this with additional functionality that converts None to empty
513 we wrap this with additional functionality that converts None to empty
514 strings
514 strings
515 """
515 """
516 if s is None:
516 if s is None:
517 return markupsafe.Markup()
517 return markupsafe.Markup()
518 return markupsafe.escape(s)
518 return markupsafe.escape(s)
519
519
520
520
521 def add_events_routes(config):
521 def add_events_routes(config):
522 """
522 """
523 Adds routing that can be used in events. Because some events are triggered
523 Adds routing that can be used in events. Because some events are triggered
524 outside of pyramid context, we need to bootstrap request with some
524 outside of pyramid context, we need to bootstrap request with some
525 routing registered
525 routing registered
526 """
526 """
527
527
528 from rhodecode.apps._base import ADMIN_PREFIX
528 from rhodecode.apps._base import ADMIN_PREFIX
529
529
530 config.add_route(name='home', pattern='/')
530 config.add_route(name='home', pattern='/')
531 config.add_route(name='main_page_repos_data', pattern='/_home_repos')
531 config.add_route(name='main_page_repos_data', pattern='/_home_repos')
532 config.add_route(name='main_page_repo_groups_data', pattern='/_home_repo_groups')
532 config.add_route(name='main_page_repo_groups_data', pattern='/_home_repo_groups')
533
533
534 config.add_route(name='login', pattern=ADMIN_PREFIX + '/login')
534 config.add_route(name='login', pattern=ADMIN_PREFIX + '/login')
535 config.add_route(name='logout', pattern=ADMIN_PREFIX + '/logout')
535 config.add_route(name='logout', pattern=ADMIN_PREFIX + '/logout')
536 config.add_route(name='repo_summary', pattern='/{repo_name}')
536 config.add_route(name='repo_summary', pattern='/{repo_name}')
537 config.add_route(name='repo_summary_explicit', pattern='/{repo_name}/summary')
537 config.add_route(name='repo_summary_explicit', pattern='/{repo_name}/summary')
538 config.add_route(name='repo_group_home', pattern='/{repo_group_name}')
538 config.add_route(name='repo_group_home', pattern='/{repo_group_name}')
539
539
540 config.add_route(name='pullrequest_show',
540 config.add_route(name='pullrequest_show',
541 pattern='/{repo_name}/pull-request/{pull_request_id}')
541 pattern='/{repo_name}/pull-request/{pull_request_id}')
542 config.add_route(name='pull_requests_global',
542 config.add_route(name='pull_requests_global',
543 pattern='/pull-request/{pull_request_id}')
543 pattern='/pull-request/{pull_request_id}')
544
544
545 config.add_route(name='repo_commit',
545 config.add_route(name='repo_commit',
546 pattern='/{repo_name}/changeset/{commit_id}')
546 pattern='/{repo_name}/changeset/{commit_id}')
547 config.add_route(name='repo_files',
547 config.add_route(name='repo_files',
548 pattern='/{repo_name}/files/{commit_id}/{f_path}')
548 pattern='/{repo_name}/files/{commit_id}/{f_path}')
549
549
550 config.add_route(name='hovercard_user',
550 config.add_route(name='hovercard_user',
551 pattern='/_hovercard/user/{user_id}')
551 pattern='/_hovercard/user/{user_id}')
552
552
553 config.add_route(name='hovercard_user_group',
553 config.add_route(name='hovercard_user_group',
554 pattern='/_hovercard/user_group/{user_group_id}')
554 pattern='/_hovercard/user_group/{user_group_id}')
555
555
556 config.add_route(name='hovercard_pull_request',
556 config.add_route(name='hovercard_pull_request',
557 pattern='/_hovercard/pull_request/{pull_request_id}')
557 pattern='/_hovercard/pull_request/{pull_request_id}')
558
558
559 config.add_route(name='hovercard_repo_commit',
559 config.add_route(name='hovercard_repo_commit',
560 pattern='/_hovercard/commit/{repo_name}/{commit_id}')
560 pattern='/_hovercard/commit/{repo_name}/{commit_id}')
561
561
562
562
563 def bootstrap_config(request):
563 def bootstrap_config(request):
564 import pyramid.testing
564 import pyramid.testing
565 registry = pyramid.testing.Registry('RcTestRegistry')
565 registry = pyramid.testing.Registry('RcTestRegistry')
566
566
567 config = pyramid.testing.setUp(registry=registry, request=request)
567 config = pyramid.testing.setUp(registry=registry, request=request)
568
568
569 # allow pyramid lookup in testing
569 # allow pyramid lookup in testing
570 config.include('pyramid_mako')
570 config.include('pyramid_mako')
571 config.include('rhodecode.lib.rc_beaker')
571 config.include('rhodecode.lib.rc_beaker')
572 config.include('rhodecode.lib.rc_cache')
572 config.include('rhodecode.lib.rc_cache')
573
573
574 add_events_routes(config)
574 add_events_routes(config)
575
575
576 return config
576 return config
577
577
578
578
579 def bootstrap_request(**kwargs):
579 def bootstrap_request(**kwargs):
580 import pyramid.testing
580 import pyramid.testing
581
581
582 class TestRequest(pyramid.testing.DummyRequest):
582 class TestRequest(pyramid.testing.DummyRequest):
583 application_url = kwargs.pop('application_url', 'http://example.com')
583 application_url = kwargs.pop('application_url', 'http://example.com')
584 host = kwargs.pop('host', 'example.com:80')
584 host = kwargs.pop('host', 'example.com:80')
585 domain = kwargs.pop('domain', 'example.com')
585 domain = kwargs.pop('domain', 'example.com')
586
586
587 def translate(self, msg):
587 def translate(self, msg):
588 return msg
588 return msg
589
589
590 def plularize(self, singular, plural, n):
590 def plularize(self, singular, plural, n):
591 return singular
591 return singular
592
592
593 def get_partial_renderer(self, tmpl_name):
593 def get_partial_renderer(self, tmpl_name):
594
594
595 from rhodecode.lib.partial_renderer import get_partial_renderer
595 from rhodecode.lib.partial_renderer import get_partial_renderer
596 return get_partial_renderer(request=self, tmpl_name=tmpl_name)
596 return get_partial_renderer(request=self, tmpl_name=tmpl_name)
597
597
598 _call_context = TemplateArgs()
598 _call_context = TemplateArgs()
599 _call_context.visual = TemplateArgs()
599 _call_context.visual = TemplateArgs()
600 _call_context.visual.show_sha_length = 12
600 _call_context.visual.show_sha_length = 12
601 _call_context.visual.show_revision_number = True
601 _call_context.visual.show_revision_number = True
602
602
603 @property
603 @property
604 def call_context(self):
604 def call_context(self):
605 return self._call_context
605 return self._call_context
606
606
607 class TestDummySession(pyramid.testing.DummySession):
607 class TestDummySession(pyramid.testing.DummySession):
608 def save(*arg, **kw):
608 def save(*arg, **kw):
609 pass
609 pass
610
610
611 request = TestRequest(**kwargs)
611 request = TestRequest(**kwargs)
612 request.session = TestDummySession()
612 request.session = TestDummySession()
613
613
614 return request
614 return request
615
615
@@ -1,894 +1,906 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2019 RhodeCode GmbH
3 # Copyright (C) 2010-2019 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 os
21 import os
22 import hashlib
22 import hashlib
23 import logging
23 import logging
24 from collections import namedtuple
24 from collections import namedtuple
25 from functools import wraps
25 from functools import wraps
26 import bleach
26 import bleach
27 from pyramid.threadlocal import get_current_request
27
28
28 from rhodecode.lib import rc_cache
29 from rhodecode.lib import rc_cache
29 from rhodecode.lib.utils2 import (
30 from rhodecode.lib.utils2 import (
30 Optional, AttributeDict, safe_str, remove_prefix, str2bool)
31 Optional, AttributeDict, safe_str, remove_prefix, str2bool)
31 from rhodecode.lib.vcs.backends import base
32 from rhodecode.lib.vcs.backends import base
32 from rhodecode.model import BaseModel
33 from rhodecode.model import BaseModel
33 from rhodecode.model.db import (
34 from rhodecode.model.db import (
34 RepoRhodeCodeUi, RepoRhodeCodeSetting, RhodeCodeUi, RhodeCodeSetting, CacheKey)
35 RepoRhodeCodeUi, RepoRhodeCodeSetting, RhodeCodeUi, RhodeCodeSetting, CacheKey)
35 from rhodecode.model.meta import Session
36 from rhodecode.model.meta import Session
36
37
37
38
38 log = logging.getLogger(__name__)
39 log = logging.getLogger(__name__)
39
40
40
41
41 UiSetting = namedtuple(
42 UiSetting = namedtuple(
42 'UiSetting', ['section', 'key', 'value', 'active'])
43 'UiSetting', ['section', 'key', 'value', 'active'])
43
44
44 SOCIAL_PLUGINS_LIST = ['github', 'bitbucket', 'twitter', 'google']
45 SOCIAL_PLUGINS_LIST = ['github', 'bitbucket', 'twitter', 'google']
45
46
46
47
47 class SettingNotFound(Exception):
48 class SettingNotFound(Exception):
48 def __init__(self, setting_id):
49 def __init__(self, setting_id):
49 msg = 'Setting `{}` is not found'.format(setting_id)
50 msg = 'Setting `{}` is not found'.format(setting_id)
50 super(SettingNotFound, self).__init__(msg)
51 super(SettingNotFound, self).__init__(msg)
51
52
52
53
53 class SettingsModel(BaseModel):
54 class SettingsModel(BaseModel):
54 BUILTIN_HOOKS = (
55 BUILTIN_HOOKS = (
55 RhodeCodeUi.HOOK_REPO_SIZE, RhodeCodeUi.HOOK_PUSH,
56 RhodeCodeUi.HOOK_REPO_SIZE, RhodeCodeUi.HOOK_PUSH,
56 RhodeCodeUi.HOOK_PRE_PUSH, RhodeCodeUi.HOOK_PRETX_PUSH,
57 RhodeCodeUi.HOOK_PRE_PUSH, RhodeCodeUi.HOOK_PRETX_PUSH,
57 RhodeCodeUi.HOOK_PULL, RhodeCodeUi.HOOK_PRE_PULL,
58 RhodeCodeUi.HOOK_PULL, RhodeCodeUi.HOOK_PRE_PULL,
58 RhodeCodeUi.HOOK_PUSH_KEY,)
59 RhodeCodeUi.HOOK_PUSH_KEY,)
59 HOOKS_SECTION = 'hooks'
60 HOOKS_SECTION = 'hooks'
60
61
61 def __init__(self, sa=None, repo=None):
62 def __init__(self, sa=None, repo=None):
62 self.repo = repo
63 self.repo = repo
63 self.UiDbModel = RepoRhodeCodeUi if repo else RhodeCodeUi
64 self.UiDbModel = RepoRhodeCodeUi if repo else RhodeCodeUi
64 self.SettingsDbModel = (
65 self.SettingsDbModel = (
65 RepoRhodeCodeSetting if repo else RhodeCodeSetting)
66 RepoRhodeCodeSetting if repo else RhodeCodeSetting)
66 super(SettingsModel, self).__init__(sa)
67 super(SettingsModel, self).__init__(sa)
67
68
68 def get_ui_by_key(self, key):
69 def get_ui_by_key(self, key):
69 q = self.UiDbModel.query()
70 q = self.UiDbModel.query()
70 q = q.filter(self.UiDbModel.ui_key == key)
71 q = q.filter(self.UiDbModel.ui_key == key)
71 q = self._filter_by_repo(RepoRhodeCodeUi, q)
72 q = self._filter_by_repo(RepoRhodeCodeUi, q)
72 return q.scalar()
73 return q.scalar()
73
74
74 def get_ui_by_section(self, section):
75 def get_ui_by_section(self, section):
75 q = self.UiDbModel.query()
76 q = self.UiDbModel.query()
76 q = q.filter(self.UiDbModel.ui_section == section)
77 q = q.filter(self.UiDbModel.ui_section == section)
77 q = self._filter_by_repo(RepoRhodeCodeUi, q)
78 q = self._filter_by_repo(RepoRhodeCodeUi, q)
78 return q.all()
79 return q.all()
79
80
80 def get_ui_by_section_and_key(self, section, key):
81 def get_ui_by_section_and_key(self, section, key):
81 q = self.UiDbModel.query()
82 q = self.UiDbModel.query()
82 q = q.filter(self.UiDbModel.ui_section == section)
83 q = q.filter(self.UiDbModel.ui_section == section)
83 q = q.filter(self.UiDbModel.ui_key == key)
84 q = q.filter(self.UiDbModel.ui_key == key)
84 q = self._filter_by_repo(RepoRhodeCodeUi, q)
85 q = self._filter_by_repo(RepoRhodeCodeUi, q)
85 return q.scalar()
86 return q.scalar()
86
87
87 def get_ui(self, section=None, key=None):
88 def get_ui(self, section=None, key=None):
88 q = self.UiDbModel.query()
89 q = self.UiDbModel.query()
89 q = self._filter_by_repo(RepoRhodeCodeUi, q)
90 q = self._filter_by_repo(RepoRhodeCodeUi, q)
90
91
91 if section:
92 if section:
92 q = q.filter(self.UiDbModel.ui_section == section)
93 q = q.filter(self.UiDbModel.ui_section == section)
93 if key:
94 if key:
94 q = q.filter(self.UiDbModel.ui_key == key)
95 q = q.filter(self.UiDbModel.ui_key == key)
95
96
96 # TODO: mikhail: add caching
97 # TODO: mikhail: add caching
97 result = [
98 result = [
98 UiSetting(
99 UiSetting(
99 section=safe_str(r.ui_section), key=safe_str(r.ui_key),
100 section=safe_str(r.ui_section), key=safe_str(r.ui_key),
100 value=safe_str(r.ui_value), active=r.ui_active
101 value=safe_str(r.ui_value), active=r.ui_active
101 )
102 )
102 for r in q.all()
103 for r in q.all()
103 ]
104 ]
104 return result
105 return result
105
106
106 def get_builtin_hooks(self):
107 def get_builtin_hooks(self):
107 q = self.UiDbModel.query()
108 q = self.UiDbModel.query()
108 q = q.filter(self.UiDbModel.ui_key.in_(self.BUILTIN_HOOKS))
109 q = q.filter(self.UiDbModel.ui_key.in_(self.BUILTIN_HOOKS))
109 return self._get_hooks(q)
110 return self._get_hooks(q)
110
111
111 def get_custom_hooks(self):
112 def get_custom_hooks(self):
112 q = self.UiDbModel.query()
113 q = self.UiDbModel.query()
113 q = q.filter(~self.UiDbModel.ui_key.in_(self.BUILTIN_HOOKS))
114 q = q.filter(~self.UiDbModel.ui_key.in_(self.BUILTIN_HOOKS))
114 return self._get_hooks(q)
115 return self._get_hooks(q)
115
116
116 def create_ui_section_value(self, section, val, key=None, active=True):
117 def create_ui_section_value(self, section, val, key=None, active=True):
117 new_ui = self.UiDbModel()
118 new_ui = self.UiDbModel()
118 new_ui.ui_section = section
119 new_ui.ui_section = section
119 new_ui.ui_value = val
120 new_ui.ui_value = val
120 new_ui.ui_active = active
121 new_ui.ui_active = active
121
122
122 repository_id = ''
123 repository_id = ''
123 if self.repo:
124 if self.repo:
124 repo = self._get_repo(self.repo)
125 repo = self._get_repo(self.repo)
125 repository_id = repo.repo_id
126 repository_id = repo.repo_id
126 new_ui.repository_id = repository_id
127 new_ui.repository_id = repository_id
127
128
128 if not key:
129 if not key:
129 # keys are unique so they need appended info
130 # keys are unique so they need appended info
130 if self.repo:
131 if self.repo:
131 key = hashlib.sha1(
132 key = hashlib.sha1(
132 '{}{}{}'.format(section, val, repository_id)).hexdigest()
133 '{}{}{}'.format(section, val, repository_id)).hexdigest()
133 else:
134 else:
134 key = hashlib.sha1('{}{}'.format(section, val)).hexdigest()
135 key = hashlib.sha1('{}{}'.format(section, val)).hexdigest()
135
136
136 new_ui.ui_key = key
137 new_ui.ui_key = key
137
138
138 Session().add(new_ui)
139 Session().add(new_ui)
139 return new_ui
140 return new_ui
140
141
141 def create_or_update_hook(self, key, value):
142 def create_or_update_hook(self, key, value):
142 ui = (
143 ui = (
143 self.get_ui_by_section_and_key(self.HOOKS_SECTION, key) or
144 self.get_ui_by_section_and_key(self.HOOKS_SECTION, key) or
144 self.UiDbModel())
145 self.UiDbModel())
145 ui.ui_section = self.HOOKS_SECTION
146 ui.ui_section = self.HOOKS_SECTION
146 ui.ui_active = True
147 ui.ui_active = True
147 ui.ui_key = key
148 ui.ui_key = key
148 ui.ui_value = value
149 ui.ui_value = value
149
150
150 if self.repo:
151 if self.repo:
151 repo = self._get_repo(self.repo)
152 repo = self._get_repo(self.repo)
152 repository_id = repo.repo_id
153 repository_id = repo.repo_id
153 ui.repository_id = repository_id
154 ui.repository_id = repository_id
154
155
155 Session().add(ui)
156 Session().add(ui)
156 return ui
157 return ui
157
158
158 def delete_ui(self, id_):
159 def delete_ui(self, id_):
159 ui = self.UiDbModel.get(id_)
160 ui = self.UiDbModel.get(id_)
160 if not ui:
161 if not ui:
161 raise SettingNotFound(id_)
162 raise SettingNotFound(id_)
162 Session().delete(ui)
163 Session().delete(ui)
163
164
164 def get_setting_by_name(self, name):
165 def get_setting_by_name(self, name):
165 q = self._get_settings_query()
166 q = self._get_settings_query()
166 q = q.filter(self.SettingsDbModel.app_settings_name == name)
167 q = q.filter(self.SettingsDbModel.app_settings_name == name)
167 return q.scalar()
168 return q.scalar()
168
169
169 def create_or_update_setting(
170 def create_or_update_setting(
170 self, name, val=Optional(''), type_=Optional('unicode')):
171 self, name, val=Optional(''), type_=Optional('unicode')):
171 """
172 """
172 Creates or updates RhodeCode setting. If updates is triggered it will
173 Creates or updates RhodeCode setting. If updates is triggered it will
173 only update parameters that are explicityl set Optional instance will
174 only update parameters that are explicityl set Optional instance will
174 be skipped
175 be skipped
175
176
176 :param name:
177 :param name:
177 :param val:
178 :param val:
178 :param type_:
179 :param type_:
179 :return:
180 :return:
180 """
181 """
181
182
182 res = self.get_setting_by_name(name)
183 res = self.get_setting_by_name(name)
183 repo = self._get_repo(self.repo) if self.repo else None
184 repo = self._get_repo(self.repo) if self.repo else None
184
185
185 if not res:
186 if not res:
186 val = Optional.extract(val)
187 val = Optional.extract(val)
187 type_ = Optional.extract(type_)
188 type_ = Optional.extract(type_)
188
189
189 args = (
190 args = (
190 (repo.repo_id, name, val, type_)
191 (repo.repo_id, name, val, type_)
191 if repo else (name, val, type_))
192 if repo else (name, val, type_))
192 res = self.SettingsDbModel(*args)
193 res = self.SettingsDbModel(*args)
193
194
194 else:
195 else:
195 if self.repo:
196 if self.repo:
196 res.repository_id = repo.repo_id
197 res.repository_id = repo.repo_id
197
198
198 res.app_settings_name = name
199 res.app_settings_name = name
199 if not isinstance(type_, Optional):
200 if not isinstance(type_, Optional):
200 # update if set
201 # update if set
201 res.app_settings_type = type_
202 res.app_settings_type = type_
202 if not isinstance(val, Optional):
203 if not isinstance(val, Optional):
203 # update if set
204 # update if set
204 res.app_settings_value = val
205 res.app_settings_value = val
205
206
206 Session().add(res)
207 Session().add(res)
207 return res
208 return res
208
209
209 def invalidate_settings_cache(self):
210 def invalidate_settings_cache(self):
210 invalidation_namespace = CacheKey.SETTINGS_INVALIDATION_NAMESPACE
211 invalidation_namespace = CacheKey.SETTINGS_INVALIDATION_NAMESPACE
211 CacheKey.set_invalidate(invalidation_namespace)
212 CacheKey.set_invalidate(invalidation_namespace)
212
213
213 def get_all_settings(self, cache=False):
214 def get_all_settings(self, cache=False, from_request=True):
215 # defines if we use GLOBAL, or PER_REPO
216 repo = self._get_repo(self.repo) if self.repo else None
217 key = "settings_repo.{}".format(repo.repo_id) if repo else "settings_app"
218
219 # initially try the requests context, this is the fastest
220 # we only fetch global config
221 if from_request:
222 request = get_current_request()
223
224 if request and not repo and hasattr(request, 'call_context') and hasattr(request.call_context, 'rc_config'):
225 rc_config = request.call_context.rc_config
226 if rc_config:
227 return rc_config
228
214 region = rc_cache.get_or_create_region('sql_cache_short')
229 region = rc_cache.get_or_create_region('sql_cache_short')
215 invalidation_namespace = CacheKey.SETTINGS_INVALIDATION_NAMESPACE
230 invalidation_namespace = CacheKey.SETTINGS_INVALIDATION_NAMESPACE
216
231
217 @region.conditional_cache_on_arguments(condition=cache)
232 @region.conditional_cache_on_arguments(condition=cache)
218 def _get_all_settings(name, key):
233 def _get_all_settings(name, key):
219 q = self._get_settings_query()
234 q = self._get_settings_query()
220 if not q:
235 if not q:
221 raise Exception('Could not get application settings !')
236 raise Exception('Could not get application settings !')
222
237
223 settings = {
238 settings = {
224 'rhodecode_' + result.app_settings_name: result.app_settings_value
239 'rhodecode_' + result.app_settings_name: result.app_settings_value
225 for result in q
240 for result in q
226 }
241 }
227 return settings
242 return settings
228
243
229 repo = self._get_repo(self.repo) if self.repo else None
230 key = "settings_repo.{}".format(repo.repo_id) if repo else "settings_app"
231
232 inv_context_manager = rc_cache.InvalidationContext(
244 inv_context_manager = rc_cache.InvalidationContext(
233 uid='cache_settings', invalidation_namespace=invalidation_namespace)
245 uid='cache_settings', invalidation_namespace=invalidation_namespace)
234 with inv_context_manager as invalidation_context:
246 with inv_context_manager as invalidation_context:
235 # check for stored invalidation signal, and maybe purge the cache
247 # check for stored invalidation signal, and maybe purge the cache
236 # before computing it again
248 # before computing it again
237 if invalidation_context.should_invalidate():
249 if invalidation_context.should_invalidate():
238 # NOTE:(marcink) we flush the whole sql_cache_short region, because it
250 # NOTE:(marcink) we flush the whole sql_cache_short region, because it
239 # reads different settings etc. It's little too much but those caches
251 # reads different settings etc. It's little too much but those caches
240 # are anyway very short lived and it's a safest way.
252 # are anyway very short lived and it's a safest way.
241 region = rc_cache.get_or_create_region('sql_cache_short')
253 region = rc_cache.get_or_create_region('sql_cache_short')
242 region.invalidate()
254 region.invalidate()
243
255
244 result = _get_all_settings('rhodecode_settings', key)
256 result = _get_all_settings('rhodecode_settings', key)
245 log.debug('Fetching app settings for key: %s took: %.4fs', key,
257 log.debug('Fetching app settings for key: %s took: %.4fs', key,
246 inv_context_manager.compute_time)
258 inv_context_manager.compute_time)
247
259
248 return result
260 return result
249
261
250 def get_auth_settings(self):
262 def get_auth_settings(self):
251 q = self._get_settings_query()
263 q = self._get_settings_query()
252 q = q.filter(
264 q = q.filter(
253 self.SettingsDbModel.app_settings_name.startswith('auth_'))
265 self.SettingsDbModel.app_settings_name.startswith('auth_'))
254 rows = q.all()
266 rows = q.all()
255 auth_settings = {
267 auth_settings = {
256 row.app_settings_name: row.app_settings_value for row in rows}
268 row.app_settings_name: row.app_settings_value for row in rows}
257 return auth_settings
269 return auth_settings
258
270
259 def get_auth_plugins(self):
271 def get_auth_plugins(self):
260 auth_plugins = self.get_setting_by_name("auth_plugins")
272 auth_plugins = self.get_setting_by_name("auth_plugins")
261 return auth_plugins.app_settings_value
273 return auth_plugins.app_settings_value
262
274
263 def get_default_repo_settings(self, strip_prefix=False):
275 def get_default_repo_settings(self, strip_prefix=False):
264 q = self._get_settings_query()
276 q = self._get_settings_query()
265 q = q.filter(
277 q = q.filter(
266 self.SettingsDbModel.app_settings_name.startswith('default_'))
278 self.SettingsDbModel.app_settings_name.startswith('default_'))
267 rows = q.all()
279 rows = q.all()
268
280
269 result = {}
281 result = {}
270 for row in rows:
282 for row in rows:
271 key = row.app_settings_name
283 key = row.app_settings_name
272 if strip_prefix:
284 if strip_prefix:
273 key = remove_prefix(key, prefix='default_')
285 key = remove_prefix(key, prefix='default_')
274 result.update({key: row.app_settings_value})
286 result.update({key: row.app_settings_value})
275 return result
287 return result
276
288
277 def get_repo(self):
289 def get_repo(self):
278 repo = self._get_repo(self.repo)
290 repo = self._get_repo(self.repo)
279 if not repo:
291 if not repo:
280 raise Exception(
292 raise Exception(
281 'Repository `{}` cannot be found inside the database'.format(
293 'Repository `{}` cannot be found inside the database'.format(
282 self.repo))
294 self.repo))
283 return repo
295 return repo
284
296
285 def _filter_by_repo(self, model, query):
297 def _filter_by_repo(self, model, query):
286 if self.repo:
298 if self.repo:
287 repo = self.get_repo()
299 repo = self.get_repo()
288 query = query.filter(model.repository_id == repo.repo_id)
300 query = query.filter(model.repository_id == repo.repo_id)
289 return query
301 return query
290
302
291 def _get_hooks(self, query):
303 def _get_hooks(self, query):
292 query = query.filter(self.UiDbModel.ui_section == self.HOOKS_SECTION)
304 query = query.filter(self.UiDbModel.ui_section == self.HOOKS_SECTION)
293 query = self._filter_by_repo(RepoRhodeCodeUi, query)
305 query = self._filter_by_repo(RepoRhodeCodeUi, query)
294 return query.all()
306 return query.all()
295
307
296 def _get_settings_query(self):
308 def _get_settings_query(self):
297 q = self.SettingsDbModel.query()
309 q = self.SettingsDbModel.query()
298 return self._filter_by_repo(RepoRhodeCodeSetting, q)
310 return self._filter_by_repo(RepoRhodeCodeSetting, q)
299
311
300 def list_enabled_social_plugins(self, settings):
312 def list_enabled_social_plugins(self, settings):
301 enabled = []
313 enabled = []
302 for plug in SOCIAL_PLUGINS_LIST:
314 for plug in SOCIAL_PLUGINS_LIST:
303 if str2bool(settings.get('rhodecode_auth_{}_enabled'.format(plug)
315 if str2bool(settings.get('rhodecode_auth_{}_enabled'.format(plug)
304 )):
316 )):
305 enabled.append(plug)
317 enabled.append(plug)
306 return enabled
318 return enabled
307
319
308
320
309 def assert_repo_settings(func):
321 def assert_repo_settings(func):
310 @wraps(func)
322 @wraps(func)
311 def _wrapper(self, *args, **kwargs):
323 def _wrapper(self, *args, **kwargs):
312 if not self.repo_settings:
324 if not self.repo_settings:
313 raise Exception('Repository is not specified')
325 raise Exception('Repository is not specified')
314 return func(self, *args, **kwargs)
326 return func(self, *args, **kwargs)
315 return _wrapper
327 return _wrapper
316
328
317
329
318 class IssueTrackerSettingsModel(object):
330 class IssueTrackerSettingsModel(object):
319 INHERIT_SETTINGS = 'inherit_issue_tracker_settings'
331 INHERIT_SETTINGS = 'inherit_issue_tracker_settings'
320 SETTINGS_PREFIX = 'issuetracker_'
332 SETTINGS_PREFIX = 'issuetracker_'
321
333
322 def __init__(self, sa=None, repo=None):
334 def __init__(self, sa=None, repo=None):
323 self.global_settings = SettingsModel(sa=sa)
335 self.global_settings = SettingsModel(sa=sa)
324 self.repo_settings = SettingsModel(sa=sa, repo=repo) if repo else None
336 self.repo_settings = SettingsModel(sa=sa, repo=repo) if repo else None
325
337
326 @property
338 @property
327 def inherit_global_settings(self):
339 def inherit_global_settings(self):
328 if not self.repo_settings:
340 if not self.repo_settings:
329 return True
341 return True
330 setting = self.repo_settings.get_setting_by_name(self.INHERIT_SETTINGS)
342 setting = self.repo_settings.get_setting_by_name(self.INHERIT_SETTINGS)
331 return setting.app_settings_value if setting else True
343 return setting.app_settings_value if setting else True
332
344
333 @inherit_global_settings.setter
345 @inherit_global_settings.setter
334 def inherit_global_settings(self, value):
346 def inherit_global_settings(self, value):
335 if self.repo_settings:
347 if self.repo_settings:
336 settings = self.repo_settings.create_or_update_setting(
348 settings = self.repo_settings.create_or_update_setting(
337 self.INHERIT_SETTINGS, value, type_='bool')
349 self.INHERIT_SETTINGS, value, type_='bool')
338 Session().add(settings)
350 Session().add(settings)
339
351
340 def _get_keyname(self, key, uid, prefix=''):
352 def _get_keyname(self, key, uid, prefix=''):
341 return '{0}{1}{2}_{3}'.format(
353 return '{0}{1}{2}_{3}'.format(
342 prefix, self.SETTINGS_PREFIX, key, uid)
354 prefix, self.SETTINGS_PREFIX, key, uid)
343
355
344 def _make_dict_for_settings(self, qs):
356 def _make_dict_for_settings(self, qs):
345 prefix_match = self._get_keyname('pat', '', 'rhodecode_')
357 prefix_match = self._get_keyname('pat', '', 'rhodecode_')
346
358
347 issuetracker_entries = {}
359 issuetracker_entries = {}
348 # create keys
360 # create keys
349 for k, v in qs.items():
361 for k, v in qs.items():
350 if k.startswith(prefix_match):
362 if k.startswith(prefix_match):
351 uid = k[len(prefix_match):]
363 uid = k[len(prefix_match):]
352 issuetracker_entries[uid] = None
364 issuetracker_entries[uid] = None
353
365
354 def url_cleaner(input_str):
366 def url_cleaner(input_str):
355 input_str = input_str.replace('"', '').replace("'", '')
367 input_str = input_str.replace('"', '').replace("'", '')
356 input_str = bleach.clean(input_str, strip=True)
368 input_str = bleach.clean(input_str, strip=True)
357 return input_str
369 return input_str
358
370
359 # populate
371 # populate
360 for uid in issuetracker_entries:
372 for uid in issuetracker_entries:
361 url_data = qs.get(self._get_keyname('url', uid, 'rhodecode_'))
373 url_data = qs.get(self._get_keyname('url', uid, 'rhodecode_'))
362
374
363 issuetracker_entries[uid] = AttributeDict({
375 issuetracker_entries[uid] = AttributeDict({
364 'pat': qs.get(
376 'pat': qs.get(
365 self._get_keyname('pat', uid, 'rhodecode_')),
377 self._get_keyname('pat', uid, 'rhodecode_')),
366 'url': url_cleaner(
378 'url': url_cleaner(
367 qs.get(self._get_keyname('url', uid, 'rhodecode_')) or ''),
379 qs.get(self._get_keyname('url', uid, 'rhodecode_')) or ''),
368 'pref': bleach.clean(
380 'pref': bleach.clean(
369 qs.get(self._get_keyname('pref', uid, 'rhodecode_')) or ''),
381 qs.get(self._get_keyname('pref', uid, 'rhodecode_')) or ''),
370 'desc': qs.get(
382 'desc': qs.get(
371 self._get_keyname('desc', uid, 'rhodecode_')),
383 self._get_keyname('desc', uid, 'rhodecode_')),
372 })
384 })
373
385
374 return issuetracker_entries
386 return issuetracker_entries
375
387
376 def get_global_settings(self, cache=False):
388 def get_global_settings(self, cache=False):
377 """
389 """
378 Returns list of global issue tracker settings
390 Returns list of global issue tracker settings
379 """
391 """
380 defaults = self.global_settings.get_all_settings(cache=cache)
392 defaults = self.global_settings.get_all_settings(cache=cache)
381 settings = self._make_dict_for_settings(defaults)
393 settings = self._make_dict_for_settings(defaults)
382 return settings
394 return settings
383
395
384 def get_repo_settings(self, cache=False):
396 def get_repo_settings(self, cache=False):
385 """
397 """
386 Returns list of issue tracker settings per repository
398 Returns list of issue tracker settings per repository
387 """
399 """
388 if not self.repo_settings:
400 if not self.repo_settings:
389 raise Exception('Repository is not specified')
401 raise Exception('Repository is not specified')
390 all_settings = self.repo_settings.get_all_settings(cache=cache)
402 all_settings = self.repo_settings.get_all_settings(cache=cache)
391 settings = self._make_dict_for_settings(all_settings)
403 settings = self._make_dict_for_settings(all_settings)
392 return settings
404 return settings
393
405
394 def get_settings(self, cache=False):
406 def get_settings(self, cache=False):
395 if self.inherit_global_settings:
407 if self.inherit_global_settings:
396 return self.get_global_settings(cache=cache)
408 return self.get_global_settings(cache=cache)
397 else:
409 else:
398 return self.get_repo_settings(cache=cache)
410 return self.get_repo_settings(cache=cache)
399
411
400 def delete_entries(self, uid):
412 def delete_entries(self, uid):
401 if self.repo_settings:
413 if self.repo_settings:
402 all_patterns = self.get_repo_settings()
414 all_patterns = self.get_repo_settings()
403 settings_model = self.repo_settings
415 settings_model = self.repo_settings
404 else:
416 else:
405 all_patterns = self.get_global_settings()
417 all_patterns = self.get_global_settings()
406 settings_model = self.global_settings
418 settings_model = self.global_settings
407 entries = all_patterns.get(uid, [])
419 entries = all_patterns.get(uid, [])
408
420
409 for del_key in entries:
421 for del_key in entries:
410 setting_name = self._get_keyname(del_key, uid)
422 setting_name = self._get_keyname(del_key, uid)
411 entry = settings_model.get_setting_by_name(setting_name)
423 entry = settings_model.get_setting_by_name(setting_name)
412 if entry:
424 if entry:
413 Session().delete(entry)
425 Session().delete(entry)
414
426
415 Session().commit()
427 Session().commit()
416
428
417 def create_or_update_setting(
429 def create_or_update_setting(
418 self, name, val=Optional(''), type_=Optional('unicode')):
430 self, name, val=Optional(''), type_=Optional('unicode')):
419 if self.repo_settings:
431 if self.repo_settings:
420 setting = self.repo_settings.create_or_update_setting(
432 setting = self.repo_settings.create_or_update_setting(
421 name, val, type_)
433 name, val, type_)
422 else:
434 else:
423 setting = self.global_settings.create_or_update_setting(
435 setting = self.global_settings.create_or_update_setting(
424 name, val, type_)
436 name, val, type_)
425 return setting
437 return setting
426
438
427
439
428 class VcsSettingsModel(object):
440 class VcsSettingsModel(object):
429
441
430 INHERIT_SETTINGS = 'inherit_vcs_settings'
442 INHERIT_SETTINGS = 'inherit_vcs_settings'
431 GENERAL_SETTINGS = (
443 GENERAL_SETTINGS = (
432 'use_outdated_comments',
444 'use_outdated_comments',
433 'pr_merge_enabled',
445 'pr_merge_enabled',
434 'hg_use_rebase_for_merging',
446 'hg_use_rebase_for_merging',
435 'hg_close_branch_before_merging',
447 'hg_close_branch_before_merging',
436 'git_use_rebase_for_merging',
448 'git_use_rebase_for_merging',
437 'git_close_branch_before_merging',
449 'git_close_branch_before_merging',
438 'diff_cache',
450 'diff_cache',
439 )
451 )
440
452
441 HOOKS_SETTINGS = (
453 HOOKS_SETTINGS = (
442 ('hooks', 'changegroup.repo_size'),
454 ('hooks', 'changegroup.repo_size'),
443 ('hooks', 'changegroup.push_logger'),
455 ('hooks', 'changegroup.push_logger'),
444 ('hooks', 'outgoing.pull_logger'),
456 ('hooks', 'outgoing.pull_logger'),
445 )
457 )
446 HG_SETTINGS = (
458 HG_SETTINGS = (
447 ('extensions', 'largefiles'),
459 ('extensions', 'largefiles'),
448 ('phases', 'publish'),
460 ('phases', 'publish'),
449 ('extensions', 'evolve'),
461 ('extensions', 'evolve'),
450 ('extensions', 'topic'),
462 ('extensions', 'topic'),
451 ('experimental', 'evolution'),
463 ('experimental', 'evolution'),
452 ('experimental', 'evolution.exchange'),
464 ('experimental', 'evolution.exchange'),
453 )
465 )
454 GIT_SETTINGS = (
466 GIT_SETTINGS = (
455 ('vcs_git_lfs', 'enabled'),
467 ('vcs_git_lfs', 'enabled'),
456 )
468 )
457 GLOBAL_HG_SETTINGS = (
469 GLOBAL_HG_SETTINGS = (
458 ('extensions', 'largefiles'),
470 ('extensions', 'largefiles'),
459 ('largefiles', 'usercache'),
471 ('largefiles', 'usercache'),
460 ('phases', 'publish'),
472 ('phases', 'publish'),
461 ('extensions', 'hgsubversion'),
473 ('extensions', 'hgsubversion'),
462 ('extensions', 'evolve'),
474 ('extensions', 'evolve'),
463 ('extensions', 'topic'),
475 ('extensions', 'topic'),
464 ('experimental', 'evolution'),
476 ('experimental', 'evolution'),
465 ('experimental', 'evolution.exchange'),
477 ('experimental', 'evolution.exchange'),
466 )
478 )
467
479
468 GLOBAL_GIT_SETTINGS = (
480 GLOBAL_GIT_SETTINGS = (
469 ('vcs_git_lfs', 'enabled'),
481 ('vcs_git_lfs', 'enabled'),
470 ('vcs_git_lfs', 'store_location')
482 ('vcs_git_lfs', 'store_location')
471 )
483 )
472
484
473 GLOBAL_SVN_SETTINGS = (
485 GLOBAL_SVN_SETTINGS = (
474 ('vcs_svn_proxy', 'http_requests_enabled'),
486 ('vcs_svn_proxy', 'http_requests_enabled'),
475 ('vcs_svn_proxy', 'http_server_url')
487 ('vcs_svn_proxy', 'http_server_url')
476 )
488 )
477
489
478 SVN_BRANCH_SECTION = 'vcs_svn_branch'
490 SVN_BRANCH_SECTION = 'vcs_svn_branch'
479 SVN_TAG_SECTION = 'vcs_svn_tag'
491 SVN_TAG_SECTION = 'vcs_svn_tag'
480 SSL_SETTING = ('web', 'push_ssl')
492 SSL_SETTING = ('web', 'push_ssl')
481 PATH_SETTING = ('paths', '/')
493 PATH_SETTING = ('paths', '/')
482
494
483 def __init__(self, sa=None, repo=None):
495 def __init__(self, sa=None, repo=None):
484 self.global_settings = SettingsModel(sa=sa)
496 self.global_settings = SettingsModel(sa=sa)
485 self.repo_settings = SettingsModel(sa=sa, repo=repo) if repo else None
497 self.repo_settings = SettingsModel(sa=sa, repo=repo) if repo else None
486 self._ui_settings = (
498 self._ui_settings = (
487 self.HG_SETTINGS + self.GIT_SETTINGS + self.HOOKS_SETTINGS)
499 self.HG_SETTINGS + self.GIT_SETTINGS + self.HOOKS_SETTINGS)
488 self._svn_sections = (self.SVN_BRANCH_SECTION, self.SVN_TAG_SECTION)
500 self._svn_sections = (self.SVN_BRANCH_SECTION, self.SVN_TAG_SECTION)
489
501
490 @property
502 @property
491 @assert_repo_settings
503 @assert_repo_settings
492 def inherit_global_settings(self):
504 def inherit_global_settings(self):
493 setting = self.repo_settings.get_setting_by_name(self.INHERIT_SETTINGS)
505 setting = self.repo_settings.get_setting_by_name(self.INHERIT_SETTINGS)
494 return setting.app_settings_value if setting else True
506 return setting.app_settings_value if setting else True
495
507
496 @inherit_global_settings.setter
508 @inherit_global_settings.setter
497 @assert_repo_settings
509 @assert_repo_settings
498 def inherit_global_settings(self, value):
510 def inherit_global_settings(self, value):
499 self.repo_settings.create_or_update_setting(
511 self.repo_settings.create_or_update_setting(
500 self.INHERIT_SETTINGS, value, type_='bool')
512 self.INHERIT_SETTINGS, value, type_='bool')
501
513
502 def get_global_svn_branch_patterns(self):
514 def get_global_svn_branch_patterns(self):
503 return self.global_settings.get_ui_by_section(self.SVN_BRANCH_SECTION)
515 return self.global_settings.get_ui_by_section(self.SVN_BRANCH_SECTION)
504
516
505 @assert_repo_settings
517 @assert_repo_settings
506 def get_repo_svn_branch_patterns(self):
518 def get_repo_svn_branch_patterns(self):
507 return self.repo_settings.get_ui_by_section(self.SVN_BRANCH_SECTION)
519 return self.repo_settings.get_ui_by_section(self.SVN_BRANCH_SECTION)
508
520
509 def get_global_svn_tag_patterns(self):
521 def get_global_svn_tag_patterns(self):
510 return self.global_settings.get_ui_by_section(self.SVN_TAG_SECTION)
522 return self.global_settings.get_ui_by_section(self.SVN_TAG_SECTION)
511
523
512 @assert_repo_settings
524 @assert_repo_settings
513 def get_repo_svn_tag_patterns(self):
525 def get_repo_svn_tag_patterns(self):
514 return self.repo_settings.get_ui_by_section(self.SVN_TAG_SECTION)
526 return self.repo_settings.get_ui_by_section(self.SVN_TAG_SECTION)
515
527
516 def get_global_settings(self):
528 def get_global_settings(self):
517 return self._collect_all_settings(global_=True)
529 return self._collect_all_settings(global_=True)
518
530
519 @assert_repo_settings
531 @assert_repo_settings
520 def get_repo_settings(self):
532 def get_repo_settings(self):
521 return self._collect_all_settings(global_=False)
533 return self._collect_all_settings(global_=False)
522
534
523 @assert_repo_settings
535 @assert_repo_settings
524 def get_repo_settings_inherited(self):
536 def get_repo_settings_inherited(self):
525 global_settings = self.get_global_settings()
537 global_settings = self.get_global_settings()
526 global_settings.update(self.get_repo_settings())
538 global_settings.update(self.get_repo_settings())
527 return global_settings
539 return global_settings
528
540
529 @assert_repo_settings
541 @assert_repo_settings
530 def create_or_update_repo_settings(
542 def create_or_update_repo_settings(
531 self, data, inherit_global_settings=False):
543 self, data, inherit_global_settings=False):
532 from rhodecode.model.scm import ScmModel
544 from rhodecode.model.scm import ScmModel
533
545
534 self.inherit_global_settings = inherit_global_settings
546 self.inherit_global_settings = inherit_global_settings
535
547
536 repo = self.repo_settings.get_repo()
548 repo = self.repo_settings.get_repo()
537 if not inherit_global_settings:
549 if not inherit_global_settings:
538 if repo.repo_type == 'svn':
550 if repo.repo_type == 'svn':
539 self.create_repo_svn_settings(data)
551 self.create_repo_svn_settings(data)
540 else:
552 else:
541 self.create_or_update_repo_hook_settings(data)
553 self.create_or_update_repo_hook_settings(data)
542 self.create_or_update_repo_pr_settings(data)
554 self.create_or_update_repo_pr_settings(data)
543
555
544 if repo.repo_type == 'hg':
556 if repo.repo_type == 'hg':
545 self.create_or_update_repo_hg_settings(data)
557 self.create_or_update_repo_hg_settings(data)
546
558
547 if repo.repo_type == 'git':
559 if repo.repo_type == 'git':
548 self.create_or_update_repo_git_settings(data)
560 self.create_or_update_repo_git_settings(data)
549
561
550 ScmModel().mark_for_invalidation(repo.repo_name, delete=True)
562 ScmModel().mark_for_invalidation(repo.repo_name, delete=True)
551
563
552 @assert_repo_settings
564 @assert_repo_settings
553 def create_or_update_repo_hook_settings(self, data):
565 def create_or_update_repo_hook_settings(self, data):
554 for section, key in self.HOOKS_SETTINGS:
566 for section, key in self.HOOKS_SETTINGS:
555 data_key = self._get_form_ui_key(section, key)
567 data_key = self._get_form_ui_key(section, key)
556 if data_key not in data:
568 if data_key not in data:
557 raise ValueError(
569 raise ValueError(
558 'The given data does not contain {} key'.format(data_key))
570 'The given data does not contain {} key'.format(data_key))
559
571
560 active = data.get(data_key)
572 active = data.get(data_key)
561 repo_setting = self.repo_settings.get_ui_by_section_and_key(
573 repo_setting = self.repo_settings.get_ui_by_section_and_key(
562 section, key)
574 section, key)
563 if not repo_setting:
575 if not repo_setting:
564 global_setting = self.global_settings.\
576 global_setting = self.global_settings.\
565 get_ui_by_section_and_key(section, key)
577 get_ui_by_section_and_key(section, key)
566 self.repo_settings.create_ui_section_value(
578 self.repo_settings.create_ui_section_value(
567 section, global_setting.ui_value, key=key, active=active)
579 section, global_setting.ui_value, key=key, active=active)
568 else:
580 else:
569 repo_setting.ui_active = active
581 repo_setting.ui_active = active
570 Session().add(repo_setting)
582 Session().add(repo_setting)
571
583
572 def update_global_hook_settings(self, data):
584 def update_global_hook_settings(self, data):
573 for section, key in self.HOOKS_SETTINGS:
585 for section, key in self.HOOKS_SETTINGS:
574 data_key = self._get_form_ui_key(section, key)
586 data_key = self._get_form_ui_key(section, key)
575 if data_key not in data:
587 if data_key not in data:
576 raise ValueError(
588 raise ValueError(
577 'The given data does not contain {} key'.format(data_key))
589 'The given data does not contain {} key'.format(data_key))
578 active = data.get(data_key)
590 active = data.get(data_key)
579 repo_setting = self.global_settings.get_ui_by_section_and_key(
591 repo_setting = self.global_settings.get_ui_by_section_and_key(
580 section, key)
592 section, key)
581 repo_setting.ui_active = active
593 repo_setting.ui_active = active
582 Session().add(repo_setting)
594 Session().add(repo_setting)
583
595
584 @assert_repo_settings
596 @assert_repo_settings
585 def create_or_update_repo_pr_settings(self, data):
597 def create_or_update_repo_pr_settings(self, data):
586 return self._create_or_update_general_settings(
598 return self._create_or_update_general_settings(
587 self.repo_settings, data)
599 self.repo_settings, data)
588
600
589 def create_or_update_global_pr_settings(self, data):
601 def create_or_update_global_pr_settings(self, data):
590 return self._create_or_update_general_settings(
602 return self._create_or_update_general_settings(
591 self.global_settings, data)
603 self.global_settings, data)
592
604
593 @assert_repo_settings
605 @assert_repo_settings
594 def create_repo_svn_settings(self, data):
606 def create_repo_svn_settings(self, data):
595 return self._create_svn_settings(self.repo_settings, data)
607 return self._create_svn_settings(self.repo_settings, data)
596
608
597 def _set_evolution(self, settings, is_enabled):
609 def _set_evolution(self, settings, is_enabled):
598 if is_enabled:
610 if is_enabled:
599 # if evolve is active set evolution=all
611 # if evolve is active set evolution=all
600
612
601 self._create_or_update_ui(
613 self._create_or_update_ui(
602 settings, *('experimental', 'evolution'), value='all',
614 settings, *('experimental', 'evolution'), value='all',
603 active=True)
615 active=True)
604 self._create_or_update_ui(
616 self._create_or_update_ui(
605 settings, *('experimental', 'evolution.exchange'), value='yes',
617 settings, *('experimental', 'evolution.exchange'), value='yes',
606 active=True)
618 active=True)
607 # if evolve is active set topics server support
619 # if evolve is active set topics server support
608 self._create_or_update_ui(
620 self._create_or_update_ui(
609 settings, *('extensions', 'topic'), value='',
621 settings, *('extensions', 'topic'), value='',
610 active=True)
622 active=True)
611
623
612 else:
624 else:
613 self._create_or_update_ui(
625 self._create_or_update_ui(
614 settings, *('experimental', 'evolution'), value='',
626 settings, *('experimental', 'evolution'), value='',
615 active=False)
627 active=False)
616 self._create_or_update_ui(
628 self._create_or_update_ui(
617 settings, *('experimental', 'evolution.exchange'), value='no',
629 settings, *('experimental', 'evolution.exchange'), value='no',
618 active=False)
630 active=False)
619 self._create_or_update_ui(
631 self._create_or_update_ui(
620 settings, *('extensions', 'topic'), value='',
632 settings, *('extensions', 'topic'), value='',
621 active=False)
633 active=False)
622
634
623 @assert_repo_settings
635 @assert_repo_settings
624 def create_or_update_repo_hg_settings(self, data):
636 def create_or_update_repo_hg_settings(self, data):
625 largefiles, phases, evolve = \
637 largefiles, phases, evolve = \
626 self.HG_SETTINGS[:3]
638 self.HG_SETTINGS[:3]
627 largefiles_key, phases_key, evolve_key = \
639 largefiles_key, phases_key, evolve_key = \
628 self._get_settings_keys(self.HG_SETTINGS[:3], data)
640 self._get_settings_keys(self.HG_SETTINGS[:3], data)
629
641
630 self._create_or_update_ui(
642 self._create_or_update_ui(
631 self.repo_settings, *largefiles, value='',
643 self.repo_settings, *largefiles, value='',
632 active=data[largefiles_key])
644 active=data[largefiles_key])
633 self._create_or_update_ui(
645 self._create_or_update_ui(
634 self.repo_settings, *evolve, value='',
646 self.repo_settings, *evolve, value='',
635 active=data[evolve_key])
647 active=data[evolve_key])
636 self._set_evolution(self.repo_settings, is_enabled=data[evolve_key])
648 self._set_evolution(self.repo_settings, is_enabled=data[evolve_key])
637
649
638 self._create_or_update_ui(
650 self._create_or_update_ui(
639 self.repo_settings, *phases, value=safe_str(data[phases_key]))
651 self.repo_settings, *phases, value=safe_str(data[phases_key]))
640
652
641 def create_or_update_global_hg_settings(self, data):
653 def create_or_update_global_hg_settings(self, data):
642 largefiles, largefiles_store, phases, hgsubversion, evolve \
654 largefiles, largefiles_store, phases, hgsubversion, evolve \
643 = self.GLOBAL_HG_SETTINGS[:5]
655 = self.GLOBAL_HG_SETTINGS[:5]
644 largefiles_key, largefiles_store_key, phases_key, subversion_key, evolve_key \
656 largefiles_key, largefiles_store_key, phases_key, subversion_key, evolve_key \
645 = self._get_settings_keys(self.GLOBAL_HG_SETTINGS[:5], data)
657 = self._get_settings_keys(self.GLOBAL_HG_SETTINGS[:5], data)
646
658
647 self._create_or_update_ui(
659 self._create_or_update_ui(
648 self.global_settings, *largefiles, value='',
660 self.global_settings, *largefiles, value='',
649 active=data[largefiles_key])
661 active=data[largefiles_key])
650 self._create_or_update_ui(
662 self._create_or_update_ui(
651 self.global_settings, *largefiles_store, value=data[largefiles_store_key])
663 self.global_settings, *largefiles_store, value=data[largefiles_store_key])
652 self._create_or_update_ui(
664 self._create_or_update_ui(
653 self.global_settings, *phases, value=safe_str(data[phases_key]))
665 self.global_settings, *phases, value=safe_str(data[phases_key]))
654 self._create_or_update_ui(
666 self._create_or_update_ui(
655 self.global_settings, *hgsubversion, active=data[subversion_key])
667 self.global_settings, *hgsubversion, active=data[subversion_key])
656 self._create_or_update_ui(
668 self._create_or_update_ui(
657 self.global_settings, *evolve, value='',
669 self.global_settings, *evolve, value='',
658 active=data[evolve_key])
670 active=data[evolve_key])
659 self._set_evolution(self.global_settings, is_enabled=data[evolve_key])
671 self._set_evolution(self.global_settings, is_enabled=data[evolve_key])
660
672
661 def create_or_update_repo_git_settings(self, data):
673 def create_or_update_repo_git_settings(self, data):
662 # NOTE(marcink): # comma makes unpack work properly
674 # NOTE(marcink): # comma makes unpack work properly
663 lfs_enabled, \
675 lfs_enabled, \
664 = self.GIT_SETTINGS
676 = self.GIT_SETTINGS
665
677
666 lfs_enabled_key, \
678 lfs_enabled_key, \
667 = self._get_settings_keys(self.GIT_SETTINGS, data)
679 = self._get_settings_keys(self.GIT_SETTINGS, data)
668
680
669 self._create_or_update_ui(
681 self._create_or_update_ui(
670 self.repo_settings, *lfs_enabled, value=data[lfs_enabled_key],
682 self.repo_settings, *lfs_enabled, value=data[lfs_enabled_key],
671 active=data[lfs_enabled_key])
683 active=data[lfs_enabled_key])
672
684
673 def create_or_update_global_git_settings(self, data):
685 def create_or_update_global_git_settings(self, data):
674 lfs_enabled, lfs_store_location \
686 lfs_enabled, lfs_store_location \
675 = self.GLOBAL_GIT_SETTINGS
687 = self.GLOBAL_GIT_SETTINGS
676 lfs_enabled_key, lfs_store_location_key \
688 lfs_enabled_key, lfs_store_location_key \
677 = self._get_settings_keys(self.GLOBAL_GIT_SETTINGS, data)
689 = self._get_settings_keys(self.GLOBAL_GIT_SETTINGS, data)
678
690
679 self._create_or_update_ui(
691 self._create_or_update_ui(
680 self.global_settings, *lfs_enabled, value=data[lfs_enabled_key],
692 self.global_settings, *lfs_enabled, value=data[lfs_enabled_key],
681 active=data[lfs_enabled_key])
693 active=data[lfs_enabled_key])
682 self._create_or_update_ui(
694 self._create_or_update_ui(
683 self.global_settings, *lfs_store_location,
695 self.global_settings, *lfs_store_location,
684 value=data[lfs_store_location_key])
696 value=data[lfs_store_location_key])
685
697
686 def create_or_update_global_svn_settings(self, data):
698 def create_or_update_global_svn_settings(self, data):
687 # branch/tags patterns
699 # branch/tags patterns
688 self._create_svn_settings(self.global_settings, data)
700 self._create_svn_settings(self.global_settings, data)
689
701
690 http_requests_enabled, http_server_url = self.GLOBAL_SVN_SETTINGS
702 http_requests_enabled, http_server_url = self.GLOBAL_SVN_SETTINGS
691 http_requests_enabled_key, http_server_url_key = self._get_settings_keys(
703 http_requests_enabled_key, http_server_url_key = self._get_settings_keys(
692 self.GLOBAL_SVN_SETTINGS, data)
704 self.GLOBAL_SVN_SETTINGS, data)
693
705
694 self._create_or_update_ui(
706 self._create_or_update_ui(
695 self.global_settings, *http_requests_enabled,
707 self.global_settings, *http_requests_enabled,
696 value=safe_str(data[http_requests_enabled_key]))
708 value=safe_str(data[http_requests_enabled_key]))
697 self._create_or_update_ui(
709 self._create_or_update_ui(
698 self.global_settings, *http_server_url,
710 self.global_settings, *http_server_url,
699 value=data[http_server_url_key])
711 value=data[http_server_url_key])
700
712
701 def update_global_ssl_setting(self, value):
713 def update_global_ssl_setting(self, value):
702 self._create_or_update_ui(
714 self._create_or_update_ui(
703 self.global_settings, *self.SSL_SETTING, value=value)
715 self.global_settings, *self.SSL_SETTING, value=value)
704
716
705 def update_global_path_setting(self, value):
717 def update_global_path_setting(self, value):
706 self._create_or_update_ui(
718 self._create_or_update_ui(
707 self.global_settings, *self.PATH_SETTING, value=value)
719 self.global_settings, *self.PATH_SETTING, value=value)
708
720
709 @assert_repo_settings
721 @assert_repo_settings
710 def delete_repo_svn_pattern(self, id_):
722 def delete_repo_svn_pattern(self, id_):
711 ui = self.repo_settings.UiDbModel.get(id_)
723 ui = self.repo_settings.UiDbModel.get(id_)
712 if ui and ui.repository.repo_name == self.repo_settings.repo:
724 if ui and ui.repository.repo_name == self.repo_settings.repo:
713 # only delete if it's the same repo as initialized settings
725 # only delete if it's the same repo as initialized settings
714 self.repo_settings.delete_ui(id_)
726 self.repo_settings.delete_ui(id_)
715 else:
727 else:
716 # raise error as if we wouldn't find this option
728 # raise error as if we wouldn't find this option
717 self.repo_settings.delete_ui(-1)
729 self.repo_settings.delete_ui(-1)
718
730
719 def delete_global_svn_pattern(self, id_):
731 def delete_global_svn_pattern(self, id_):
720 self.global_settings.delete_ui(id_)
732 self.global_settings.delete_ui(id_)
721
733
722 @assert_repo_settings
734 @assert_repo_settings
723 def get_repo_ui_settings(self, section=None, key=None):
735 def get_repo_ui_settings(self, section=None, key=None):
724 global_uis = self.global_settings.get_ui(section, key)
736 global_uis = self.global_settings.get_ui(section, key)
725 repo_uis = self.repo_settings.get_ui(section, key)
737 repo_uis = self.repo_settings.get_ui(section, key)
726
738
727 filtered_repo_uis = self._filter_ui_settings(repo_uis)
739 filtered_repo_uis = self._filter_ui_settings(repo_uis)
728 filtered_repo_uis_keys = [
740 filtered_repo_uis_keys = [
729 (s.section, s.key) for s in filtered_repo_uis]
741 (s.section, s.key) for s in filtered_repo_uis]
730
742
731 def _is_global_ui_filtered(ui):
743 def _is_global_ui_filtered(ui):
732 return (
744 return (
733 (ui.section, ui.key) in filtered_repo_uis_keys
745 (ui.section, ui.key) in filtered_repo_uis_keys
734 or ui.section in self._svn_sections)
746 or ui.section in self._svn_sections)
735
747
736 filtered_global_uis = [
748 filtered_global_uis = [
737 ui for ui in global_uis if not _is_global_ui_filtered(ui)]
749 ui for ui in global_uis if not _is_global_ui_filtered(ui)]
738
750
739 return filtered_global_uis + filtered_repo_uis
751 return filtered_global_uis + filtered_repo_uis
740
752
741 def get_global_ui_settings(self, section=None, key=None):
753 def get_global_ui_settings(self, section=None, key=None):
742 return self.global_settings.get_ui(section, key)
754 return self.global_settings.get_ui(section, key)
743
755
744 def get_ui_settings_as_config_obj(self, section=None, key=None):
756 def get_ui_settings_as_config_obj(self, section=None, key=None):
745 config = base.Config()
757 config = base.Config()
746
758
747 ui_settings = self.get_ui_settings(section=section, key=key)
759 ui_settings = self.get_ui_settings(section=section, key=key)
748
760
749 for entry in ui_settings:
761 for entry in ui_settings:
750 config.set(entry.section, entry.key, entry.value)
762 config.set(entry.section, entry.key, entry.value)
751
763
752 return config
764 return config
753
765
754 def get_ui_settings(self, section=None, key=None):
766 def get_ui_settings(self, section=None, key=None):
755 if not self.repo_settings or self.inherit_global_settings:
767 if not self.repo_settings or self.inherit_global_settings:
756 return self.get_global_ui_settings(section, key)
768 return self.get_global_ui_settings(section, key)
757 else:
769 else:
758 return self.get_repo_ui_settings(section, key)
770 return self.get_repo_ui_settings(section, key)
759
771
760 def get_svn_patterns(self, section=None):
772 def get_svn_patterns(self, section=None):
761 if not self.repo_settings:
773 if not self.repo_settings:
762 return self.get_global_ui_settings(section)
774 return self.get_global_ui_settings(section)
763 else:
775 else:
764 return self.get_repo_ui_settings(section)
776 return self.get_repo_ui_settings(section)
765
777
766 @assert_repo_settings
778 @assert_repo_settings
767 def get_repo_general_settings(self):
779 def get_repo_general_settings(self):
768 global_settings = self.global_settings.get_all_settings()
780 global_settings = self.global_settings.get_all_settings()
769 repo_settings = self.repo_settings.get_all_settings()
781 repo_settings = self.repo_settings.get_all_settings()
770 filtered_repo_settings = self._filter_general_settings(repo_settings)
782 filtered_repo_settings = self._filter_general_settings(repo_settings)
771 global_settings.update(filtered_repo_settings)
783 global_settings.update(filtered_repo_settings)
772 return global_settings
784 return global_settings
773
785
774 def get_global_general_settings(self):
786 def get_global_general_settings(self):
775 return self.global_settings.get_all_settings()
787 return self.global_settings.get_all_settings()
776
788
777 def get_general_settings(self):
789 def get_general_settings(self):
778 if not self.repo_settings or self.inherit_global_settings:
790 if not self.repo_settings or self.inherit_global_settings:
779 return self.get_global_general_settings()
791 return self.get_global_general_settings()
780 else:
792 else:
781 return self.get_repo_general_settings()
793 return self.get_repo_general_settings()
782
794
783 def get_repos_location(self):
795 def get_repos_location(self):
784 return self.global_settings.get_ui_by_key('/').ui_value
796 return self.global_settings.get_ui_by_key('/').ui_value
785
797
786 def _filter_ui_settings(self, settings):
798 def _filter_ui_settings(self, settings):
787 filtered_settings = [
799 filtered_settings = [
788 s for s in settings if self._should_keep_setting(s)]
800 s for s in settings if self._should_keep_setting(s)]
789 return filtered_settings
801 return filtered_settings
790
802
791 def _should_keep_setting(self, setting):
803 def _should_keep_setting(self, setting):
792 keep = (
804 keep = (
793 (setting.section, setting.key) in self._ui_settings or
805 (setting.section, setting.key) in self._ui_settings or
794 setting.section in self._svn_sections)
806 setting.section in self._svn_sections)
795 return keep
807 return keep
796
808
797 def _filter_general_settings(self, settings):
809 def _filter_general_settings(self, settings):
798 keys = ['rhodecode_{}'.format(key) for key in self.GENERAL_SETTINGS]
810 keys = ['rhodecode_{}'.format(key) for key in self.GENERAL_SETTINGS]
799 return {
811 return {
800 k: settings[k]
812 k: settings[k]
801 for k in settings if k in keys}
813 for k in settings if k in keys}
802
814
803 def _collect_all_settings(self, global_=False):
815 def _collect_all_settings(self, global_=False):
804 settings = self.global_settings if global_ else self.repo_settings
816 settings = self.global_settings if global_ else self.repo_settings
805 result = {}
817 result = {}
806
818
807 for section, key in self._ui_settings:
819 for section, key in self._ui_settings:
808 ui = settings.get_ui_by_section_and_key(section, key)
820 ui = settings.get_ui_by_section_and_key(section, key)
809 result_key = self._get_form_ui_key(section, key)
821 result_key = self._get_form_ui_key(section, key)
810
822
811 if ui:
823 if ui:
812 if section in ('hooks', 'extensions'):
824 if section in ('hooks', 'extensions'):
813 result[result_key] = ui.ui_active
825 result[result_key] = ui.ui_active
814 elif result_key in ['vcs_git_lfs_enabled']:
826 elif result_key in ['vcs_git_lfs_enabled']:
815 result[result_key] = ui.ui_active
827 result[result_key] = ui.ui_active
816 else:
828 else:
817 result[result_key] = ui.ui_value
829 result[result_key] = ui.ui_value
818
830
819 for name in self.GENERAL_SETTINGS:
831 for name in self.GENERAL_SETTINGS:
820 setting = settings.get_setting_by_name(name)
832 setting = settings.get_setting_by_name(name)
821 if setting:
833 if setting:
822 result_key = 'rhodecode_{}'.format(name)
834 result_key = 'rhodecode_{}'.format(name)
823 result[result_key] = setting.app_settings_value
835 result[result_key] = setting.app_settings_value
824
836
825 return result
837 return result
826
838
827 def _get_form_ui_key(self, section, key):
839 def _get_form_ui_key(self, section, key):
828 return '{section}_{key}'.format(
840 return '{section}_{key}'.format(
829 section=section, key=key.replace('.', '_'))
841 section=section, key=key.replace('.', '_'))
830
842
831 def _create_or_update_ui(
843 def _create_or_update_ui(
832 self, settings, section, key, value=None, active=None):
844 self, settings, section, key, value=None, active=None):
833 ui = settings.get_ui_by_section_and_key(section, key)
845 ui = settings.get_ui_by_section_and_key(section, key)
834 if not ui:
846 if not ui:
835 active = True if active is None else active
847 active = True if active is None else active
836 settings.create_ui_section_value(
848 settings.create_ui_section_value(
837 section, value, key=key, active=active)
849 section, value, key=key, active=active)
838 else:
850 else:
839 if active is not None:
851 if active is not None:
840 ui.ui_active = active
852 ui.ui_active = active
841 if value is not None:
853 if value is not None:
842 ui.ui_value = value
854 ui.ui_value = value
843 Session().add(ui)
855 Session().add(ui)
844
856
845 def _create_svn_settings(self, settings, data):
857 def _create_svn_settings(self, settings, data):
846 svn_settings = {
858 svn_settings = {
847 'new_svn_branch': self.SVN_BRANCH_SECTION,
859 'new_svn_branch': self.SVN_BRANCH_SECTION,
848 'new_svn_tag': self.SVN_TAG_SECTION
860 'new_svn_tag': self.SVN_TAG_SECTION
849 }
861 }
850 for key in svn_settings:
862 for key in svn_settings:
851 if data.get(key):
863 if data.get(key):
852 settings.create_ui_section_value(svn_settings[key], data[key])
864 settings.create_ui_section_value(svn_settings[key], data[key])
853
865
854 def _create_or_update_general_settings(self, settings, data):
866 def _create_or_update_general_settings(self, settings, data):
855 for name in self.GENERAL_SETTINGS:
867 for name in self.GENERAL_SETTINGS:
856 data_key = 'rhodecode_{}'.format(name)
868 data_key = 'rhodecode_{}'.format(name)
857 if data_key not in data:
869 if data_key not in data:
858 raise ValueError(
870 raise ValueError(
859 'The given data does not contain {} key'.format(data_key))
871 'The given data does not contain {} key'.format(data_key))
860 setting = settings.create_or_update_setting(
872 setting = settings.create_or_update_setting(
861 name, data[data_key], 'bool')
873 name, data[data_key], 'bool')
862 Session().add(setting)
874 Session().add(setting)
863
875
864 def _get_settings_keys(self, settings, data):
876 def _get_settings_keys(self, settings, data):
865 data_keys = [self._get_form_ui_key(*s) for s in settings]
877 data_keys = [self._get_form_ui_key(*s) for s in settings]
866 for data_key in data_keys:
878 for data_key in data_keys:
867 if data_key not in data:
879 if data_key not in data:
868 raise ValueError(
880 raise ValueError(
869 'The given data does not contain {} key'.format(data_key))
881 'The given data does not contain {} key'.format(data_key))
870 return data_keys
882 return data_keys
871
883
872 def create_largeobjects_dirs_if_needed(self, repo_store_path):
884 def create_largeobjects_dirs_if_needed(self, repo_store_path):
873 """
885 """
874 This is subscribed to the `pyramid.events.ApplicationCreated` event. It
886 This is subscribed to the `pyramid.events.ApplicationCreated` event. It
875 does a repository scan if enabled in the settings.
887 does a repository scan if enabled in the settings.
876 """
888 """
877
889
878 from rhodecode.lib.vcs.backends.hg import largefiles_store
890 from rhodecode.lib.vcs.backends.hg import largefiles_store
879 from rhodecode.lib.vcs.backends.git import lfs_store
891 from rhodecode.lib.vcs.backends.git import lfs_store
880
892
881 paths = [
893 paths = [
882 largefiles_store(repo_store_path),
894 largefiles_store(repo_store_path),
883 lfs_store(repo_store_path)]
895 lfs_store(repo_store_path)]
884
896
885 for path in paths:
897 for path in paths:
886 if os.path.isdir(path):
898 if os.path.isdir(path):
887 continue
899 continue
888 if os.path.isfile(path):
900 if os.path.isfile(path):
889 continue
901 continue
890 # not a file nor dir, we try to create it
902 # not a file nor dir, we try to create it
891 try:
903 try:
892 os.makedirs(path)
904 os.makedirs(path)
893 except Exception:
905 except Exception:
894 log.warning('Failed to create largefiles dir:%s', path)
906 log.warning('Failed to create largefiles dir:%s', path)
General Comments 0
You need to be logged in to leave comments. Login now