comparison rhodecode/lib/base.py @ 4116:ffd45b185016 rhodecode-2.2.5-gpl

Imported some of the GPLv3'd changes from RhodeCode v2.2.5. This imports changes between changesets 21af6c4eab3d and 6177597791c2 in RhodeCode's original repository, including only changes to Python files and HTML. RhodeCode clearly licensed its changes to these files under GPLv3 in their /LICENSE file, which states the following: The Python code and integrated HTML are licensed under the GPLv3 license. (See: https://code.rhodecode.com/rhodecode/files/v2.2.5/LICENSE or http://web.archive.org/web/20140512193334/https://code.rhodecode.com/rhodecode/files/f3b123159901f15426d18e3dc395e8369f70ebe0/LICENSE for an online copy of that LICENSE file) Conservancy reviewed these changes and confirmed that they can be licensed as a whole to the Kallithea project under GPLv3-only. While some of the contents committed herein are clearly licensed GPLv3-or-later, on the whole we must assume the are GPLv3-only, since the statement above from RhodeCode indicates that they intend GPLv3-only as their license, per GPLv3ยง14 and other relevant sections of GPLv3.
author Bradley M. Kuhn <bkuhn@sfconservancy.org>
date Wed, 02 Jul 2014 19:03:13 -0400
parents a5888ca796b5
children 7e5f8c12a3fc
comparison
equal deleted inserted replaced
4115:8b7294a804a0 4116:ffd45b185016
1 """The base Controller API 1 # -*- coding: utf-8 -*-
2 2 # This program is free software: you can redistribute it and/or modify
3 Provides the BaseController class for subclassing. 3 # it under the terms of the GNU General Public License as published by
4 # the Free Software Foundation, either version 3 of the License, or
5 # (at your option) any later version.
6 #
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
11 #
12 # You should have received a copy of the GNU General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14
4 """ 15 """
16 rhodecode.lib.base
17 ~~~~~~~~~~~~~~~~~~
18
19 The base Controller API
20 Provides the BaseController class for subclassing. And usage in different
21 controllers
22
23 :created_on: Oct 06, 2010
24 :author: marcink
25 :copyright: (c) 2013 RhodeCode GmbH.
26 :license: GPLv3, see LICENSE for more details.
27 """
28
5 import logging 29 import logging
6 import time 30 import time
7 import traceback 31 import traceback
8 32
9 from paste.auth.basic import AuthBasicAuthenticator 33 from paste.auth.basic import AuthBasicAuthenticator
11 from paste.httpheaders import WWW_AUTHENTICATE, AUTHORIZATION 35 from paste.httpheaders import WWW_AUTHENTICATE, AUTHORIZATION
12 36
13 from pylons import config, tmpl_context as c, request, session, url 37 from pylons import config, tmpl_context as c, request, session, url
14 from pylons.controllers import WSGIController 38 from pylons.controllers import WSGIController
15 from pylons.controllers.util import redirect 39 from pylons.controllers.util import redirect
16 from pylons.templating import render_mako as render 40 from pylons.templating import render_mako as render # don't remove this import
17 41
18 from rhodecode import __version__, BACKENDS 42 from rhodecode import __version__, BACKENDS
19 43
20 from rhodecode.lib.utils2 import str2bool, safe_unicode, AttributeDict,\ 44 from rhodecode.lib.utils2 import str2bool, safe_unicode, AttributeDict,\
21 safe_str, safe_int 45 safe_str, safe_int
22 from rhodecode.lib.auth import AuthUser, get_container_username, authfunc,\ 46 from rhodecode.lib import auth_modules
23 HasPermissionAnyMiddleware, CookieStoreWrapper 47 from rhodecode.lib.auth import AuthUser, HasPermissionAnyMiddleware, CookieStoreWrapper
24 from rhodecode.lib.utils import get_repo_slug 48 from rhodecode.lib.utils import get_repo_slug
25 from rhodecode.lib.exceptions import UserCreationError 49 from rhodecode.lib.exceptions import UserCreationError
26 from rhodecode.model import meta 50 from rhodecode.model import meta
27 51
28 from rhodecode.model.db import Repository, RhodeCodeUi, User, RhodeCodeSetting 52 from rhodecode.model.db import Repository, RhodeCodeUi, User, RhodeCodeSetting
98 return self.build_authentication() 122 return self.build_authentication()
99 auth = auth.strip().decode('base64') 123 auth = auth.strip().decode('base64')
100 _parts = auth.split(':', 1) 124 _parts = auth.split(':', 1)
101 if len(_parts) == 2: 125 if len(_parts) == 2:
102 username, password = _parts 126 username, password = _parts
103 if self.authfunc(environ, username, password): 127 if self.authfunc(username, password, environ):
104 return username 128 return username
105 return self.build_authentication() 129 return self.build_authentication()
106 130
107 __call__ = authenticate 131 __call__ = authenticate
108 132
112 def __init__(self, application, config): 136 def __init__(self, application, config):
113 self.application = application 137 self.application = application
114 self.config = config 138 self.config = config
115 # base path of repo locations 139 # base path of repo locations
116 self.basepath = self.config['base_path'] 140 self.basepath = self.config['base_path']
117 #authenticate this mercurial request using authfunc 141 #authenticate this VCS request using authfunc
118 self.authenticate = BasicAuth('', authfunc, 142 self.authenticate = BasicAuth('', auth_modules.authenticate,
119 config.get('auth_ret_code')) 143 config.get('auth_ret_code'))
120 self.ip_addr = '0.0.0.0' 144 self.ip_addr = '0.0.0.0'
121 145
122 def _handle_request(self, environ, start_response): 146 def _handle_request(self, environ, start_response):
123 raise NotImplementedError() 147 raise NotImplementedError()
127 Gets a special pattern _<ID> from clone url and tries to replace it 151 Gets a special pattern _<ID> from clone url and tries to replace it
128 with a repository_name for support of _<ID> non changable urls 152 with a repository_name for support of _<ID> non changable urls
129 153
130 :param repo_name: 154 :param repo_name:
131 """ 155 """
132 try: 156
133 data = repo_name.split('/') 157 data = repo_name.split('/')
134 if len(data) >= 2: 158 if len(data) >= 2:
135 by_id = data[1].split('_') 159 from rhodecode.lib.utils import get_repo_by_id
136 if len(by_id) == 2 and by_id[1].isdigit(): 160 by_id_match = get_repo_by_id(repo_name)
137 _repo_name = Repository.get(by_id[1]).repo_name 161 if by_id_match:
138 data[1] = _repo_name 162 data[1] = by_id_match
139 except Exception:
140 log.debug('Failed to extract repo_name from id %s' % (
141 traceback.format_exc()
142 )
143 )
144 163
145 return '/'.join(data) 164 return '/'.join(data)
146 165
147 def _invalidate_cache(self, repo_name): 166 def _invalidate_cache(self, repo_name):
148 """ 167 """
159 178
160 :param action: push or pull action 179 :param action: push or pull action
161 :param user: user instance 180 :param user: user instance
162 :param repo_name: repository name 181 :param repo_name: repository name
163 """ 182 """
164 #check IP 183 # check IP
165 authuser = AuthUser(user_id=user.user_id, ip_addr=ip_addr) 184 inherit = user.inherit_default_permissions
166 if not authuser.ip_allowed: 185 ip_allowed = AuthUser.check_ip_allowed(user.user_id, ip_addr,
186 inherit_from_default=inherit)
187 if ip_allowed:
188 log.info('Access for IP:%s allowed' % (ip_addr,))
189 else:
167 return False 190 return False
168 else: 191
169 log.info('Access for IP:%s allowed' % (ip_addr))
170 if action == 'push': 192 if action == 'push':
171 if not HasPermissionAnyMiddleware('repository.write', 193 if not HasPermissionAnyMiddleware('repository.write',
172 'repository.admin')(user, 194 'repository.admin')(user,
173 repo_name): 195 repo_name):
174 return False 196 return False
259 def __before__(self): 281 def __before__(self):
260 """ 282 """
261 __before__ is called before controller methods and after __call__ 283 __before__ is called before controller methods and after __call__
262 """ 284 """
263 c.rhodecode_version = __version__ 285 c.rhodecode_version = __version__
264 c.rhodecode_instanceid = config.get('instance_id') 286 rc_config = RhodeCodeSetting.get_app_settings()
265 c.rhodecode_name = config.get('rhodecode_title') 287
266 c.rhodecode_bugtracker = config.get('bugtracker', 'http://bitbucket.org/marcinkuzminski/rhodecode/issues')
267 c.use_gravatar = str2bool(config.get('use_gravatar'))
268 c.ga_code = config.get('rhodecode_ga_code')
269 # Visual options 288 # Visual options
270 c.visual = AttributeDict({}) 289 c.visual = AttributeDict({})
271 rc_config = RhodeCodeSetting.get_app_settings() 290
272 ## DB stored 291 ## DB stored
273 c.visual.show_public_icon = str2bool(rc_config.get('rhodecode_show_public_icon')) 292 c.visual.show_public_icon = str2bool(rc_config.get('rhodecode_show_public_icon'))
274 c.visual.show_private_icon = str2bool(rc_config.get('rhodecode_show_private_icon')) 293 c.visual.show_private_icon = str2bool(rc_config.get('rhodecode_show_private_icon'))
275 c.visual.stylify_metatags = str2bool(rc_config.get('rhodecode_stylify_metatags')) 294 c.visual.stylify_metatags = str2bool(rc_config.get('rhodecode_stylify_metatags'))
276 c.visual.dashboard_items = safe_int(rc_config.get('rhodecode_dashboard_items', 100)) 295 c.visual.dashboard_items = safe_int(rc_config.get('rhodecode_dashboard_items', 100))
296 c.visual.admin_grid_items = safe_int(rc_config.get('rhodecode_admin_grid_items', 100))
277 c.visual.repository_fields = str2bool(rc_config.get('rhodecode_repository_fields')) 297 c.visual.repository_fields = str2bool(rc_config.get('rhodecode_repository_fields'))
278 c.visual.show_version = str2bool(rc_config.get('rhodecode_show_version')) 298 c.visual.show_version = str2bool(rc_config.get('rhodecode_show_version'))
299 c.visual.use_gravatar = str2bool(rc_config.get('rhodecode_use_gravatar'))
300 c.visual.gravatar_url = rc_config.get('rhodecode_gravatar_url')
301
302 c.ga_code = rc_config.get('rhodecode_ga_code')
303 c.rhodecode_name = rc_config.get('rhodecode_title')
304 c.clone_uri_tmpl = rc_config.get('rhodecode_clone_uri_tmpl')
279 305
280 ## INI stored 306 ## INI stored
281 self.cut_off_limit = int(config.get('cut_off_limit'))
282 c.visual.allow_repo_location_change = str2bool(config.get('allow_repo_location_change', True)) 307 c.visual.allow_repo_location_change = str2bool(config.get('allow_repo_location_change', True))
283 c.visual.allow_custom_hooks_settings = str2bool(config.get('allow_custom_hooks_settings', True)) 308 c.visual.allow_custom_hooks_settings = str2bool(config.get('allow_custom_hooks_settings', True))
309
310 c.rhodecode_instanceid = config.get('instance_id')
311 c.rhodecode_bugtracker = config.get('bugtracker', url('rc_issue_tracker'))
312 # END CONFIG VARS
284 313
285 c.repo_name = get_repo_slug(request) # can be empty 314 c.repo_name = get_repo_slug(request) # can be empty
286 c.backends = BACKENDS.keys() 315 c.backends = BACKENDS.keys()
287 c.unread_notifications = NotificationModel()\ 316 c.unread_notifications = NotificationModel()\
288 .get_unread_cnt_for_user(c.rhodecode_user.user_id) 317 .get_unread_cnt_for_user(c.rhodecode_user.user_id)
318
319 self.cut_off_limit = safe_int(config.get('cut_off_limit'))
289 self.sa = meta.Session 320 self.sa = meta.Session
290 self.scm_model = ScmModel(self.sa) 321 self.scm_model = ScmModel(self.sa)
291 322
292 def __call__(self, environ, start_response): 323 def __call__(self, environ, start_response):
293 """Invoke the Controller""" 324 """Invoke the Controller"""
296 # available in environ['pylons.routes_dict'] 327 # available in environ['pylons.routes_dict']
297 try: 328 try:
298 self.ip_addr = _get_ip_addr(environ) 329 self.ip_addr = _get_ip_addr(environ)
299 # make sure that we update permissions each time we call controller 330 # make sure that we update permissions each time we call controller
300 api_key = request.GET.get('api_key') 331 api_key = request.GET.get('api_key')
301 cookie_store = CookieStoreWrapper(session.get('rhodecode_user')) 332
302 user_id = cookie_store.get('user_id', None) 333 if api_key:
303 username = get_container_username(environ, config) 334 # when using API_KEY we are sure user exists.
304 try: 335 auth_user = AuthUser(api_key=api_key, ip_addr=self.ip_addr)
305 auth_user = AuthUser(user_id, api_key, username, self.ip_addr) 336 authenticated = False
306 except UserCreationError, e: 337 else:
307 from rhodecode.lib import helpers as h 338 cookie_store = CookieStoreWrapper(session.get('rhodecode_user'))
308 h.flash(e, 'error') 339 try:
309 # container auth or other auth functions that create users on 340 auth_user = AuthUser(user_id=cookie_store.get('user_id', None),
310 # the fly can throw this exception signaling that there's issue 341 ip_addr=self.ip_addr)
311 # with user creation, explanation should be provided in 342 except UserCreationError, e:
312 # Exception itself 343 from rhodecode.lib import helpers as h
313 auth_user = AuthUser(ip_addr=self.ip_addr) 344 h.flash(e, 'error')
314 345 # container auth or other auth functions that create users on
346 # the fly can throw this exception signaling that there's issue
347 # with user creation, explanation should be provided in
348 # Exception itself
349 auth_user = AuthUser(ip_addr=self.ip_addr)
350
351 authenticated = cookie_store.get('is_authenticated')
352
353 if not auth_user.is_authenticated and auth_user.user_id is not None:
354 # user is not authenticated and not empty
355 auth_user.set_authenticated(authenticated)
315 request.user = auth_user 356 request.user = auth_user
357 #set globals for auth user
316 self.rhodecode_user = c.rhodecode_user = auth_user 358 self.rhodecode_user = c.rhodecode_user = auth_user
317 if not self.rhodecode_user.is_authenticated and \
318 self.rhodecode_user.user_id is not None:
319 self.rhodecode_user.set_authenticated(
320 cookie_store.get('is_authenticated')
321 )
322 log.info('IP: %s User: %s accessed %s' % ( 359 log.info('IP: %s User: %s accessed %s' % (
323 self.ip_addr, auth_user, safe_unicode(_get_access_path(environ))) 360 self.ip_addr, auth_user, safe_unicode(_get_access_path(environ)))
324 ) 361 )
325 return WSGIController.__call__(self, environ, start_response) 362 return WSGIController.__call__(self, environ, start_response)
326 finally: 363 finally:
339 c.repository_following: weather the current user is following the current repo 376 c.repository_following: weather the current user is following the current repo
340 """ 377 """
341 378
342 def __before__(self): 379 def __before__(self):
343 super(BaseRepoController, self).__before__() 380 super(BaseRepoController, self).__before__()
344 if c.repo_name: 381 if c.repo_name: # extracted from routes
345 382 _dbr = Repository.get_by_repo_name(c.repo_name)
346 dbr = c.rhodecode_db_repo = Repository.get_by_repo_name(c.repo_name) 383 if not _dbr:
384 return
385
386 log.debug('Found repository in database %s with state `%s`'
387 % (safe_unicode(_dbr), safe_unicode(_dbr.repo_state)))
388 route = getattr(request.environ.get('routes.route'), 'name', '')
389
390 # allow to delete repos that are somehow damages in filesystem
391 if route in ['delete_repo']:
392 return
393
394 if _dbr.repo_state in [Repository.STATE_PENDING]:
395 if route in ['repo_creating_home']:
396 return
397 check_url = url('repo_creating_home', repo_name=c.repo_name)
398 return redirect(check_url)
399
400 dbr = c.rhodecode_db_repo = _dbr
347 c.rhodecode_repo = c.rhodecode_db_repo.scm_instance 401 c.rhodecode_repo = c.rhodecode_db_repo.scm_instance
348 # update last change according to VCS data
349 dbr.update_changeset_cache(dbr.get_changeset())
350 if c.rhodecode_repo is None: 402 if c.rhodecode_repo is None:
351 log.error('%s this repository is present in database but it ' 403 log.error('%s this repository is present in database but it '
352 'cannot be created as an scm instance', c.repo_name) 404 'cannot be created as an scm instance', c.repo_name)
353 405
354 redirect(url('home')) 406 redirect(url('home'))
407
408 # update last change according to VCS data
409 dbr.update_changeset_cache(dbr.get_changeset())
355 410
356 # some globals counter for menu 411 # some globals counter for menu
357 c.repository_followers = self.scm_model.get_followers(dbr) 412 c.repository_followers = self.scm_model.get_followers(dbr)
358 c.repository_forks = self.scm_model.get_forks(dbr) 413 c.repository_forks = self.scm_model.get_forks(dbr)
359 c.repository_pull_requests = self.scm_model.get_pull_requests(dbr) 414 c.repository_pull_requests = self.scm_model.get_pull_requests(dbr)
360 c.repository_following = self.scm_model.is_following_repo(c.repo_name, 415 c.repository_following = self.scm_model.is_following_repo(
361 self.rhodecode_user.user_id) 416 c.repo_name, self.rhodecode_user.user_id)