##// END OF EJS Templates
Added tag v1.7.0 for changeset 351ad34d5632
Added tag v1.7.0 for changeset 351ad34d5632

File last commit:

r3960:5293d4bb merge default
r3970:e0e244e9 default
Show More
base.py
348 lines | 13.3 KiB | text/x-python | PythonLexer
renamed project to rhodecode
r547 """The base Controller API
Provides the BaseController class for subclassing.
"""
Fixes issue #201...
r1373 import logging
Added Request time tracking
r1601 import time
implements #285: Implemented non changeable urls for clone url, and web views
r1813 import traceback
Wrapped calls for git and hg middleware in extra block that clears db Session....
r1761
from paste.auth.basic import AuthBasicAuthenticator
Alternative HTTP response codes when client failed to Authenticate correctly
r2132 from paste.httpexceptions import HTTPUnauthorized, HTTPForbidden
patched basic auth function to overcome git issues with proxy that doesn't send both username and password. ref #586
r2912 from paste.httpheaders import WWW_AUTHENTICATE, AUTHORIZATION
Wrapped calls for git and hg middleware in extra block that clears db Session....
r1761
Fixes issue #201...
r1373 from pylons import config, tmpl_context as c, request, session, url
renamed project to rhodecode
r547 from pylons.controllers import WSGIController
Fixes issue #201...
r1373 from pylons.controllers.util import redirect
renamed project to rhodecode
r547 from pylons.templating import render_mako as render
gui-improvments
r1304
reduce cookie size for better support of client side sessions
r1718 from rhodecode import __version__, BACKENDS
Implemented basic locking functionality....
r2726 from rhodecode.lib.utils2 import str2bool, safe_unicode, AttributeDict,\
added option to ini file to define lightweight dashboard items per page before pagination
r3087 safe_str, safe_int
Wrapped calls for git and hg middleware in extra block that clears db Session....
r1761 from rhodecode.lib.auth import AuthUser, get_container_username, authfunc,\
Full IP restrictions enabled...
r3146 HasPermissionAnyMiddleware, CookieStoreWrapper
removed duplicated logic of how we invalidate caches for repos
r3693 from rhodecode.lib.utils import get_repo_slug
renamed project to rhodecode
r547 from rhodecode.model import meta
reduce cookie size for better support of client side sessions
r1718
don't use config for visual settings. It totally doesn't work on multi instance mode
r2955 from rhodecode.model.db import Repository, RhodeCodeUi, User, RhodeCodeSetting
#302 - basic notification system, models+tests
r1702 from rhodecode.model.notification import NotificationModel
reduce cookie size for better support of client side sessions
r1718 from rhodecode.model.scm import ScmModel
Implemented basic locking functionality....
r2726 from rhodecode.model.meta import Session
Moved out reposcan into hg Model....
r665
Fixes issue #201...
r1373 log = logging.getLogger(__name__)
pep8ify
r1307
implements #285: Implemented non changeable urls for clone url, and web views
r1813
fixed multiple IP addresses in each of extracted IP....
r3669 def _filter_proxy(ip):
"""
HEADERS can have mutliple ips inside the left-most being the original
client, and each successive proxy that passed the request adding the IP
address where it received the request from.
:param ip:
"""
if ',' in ip:
_ips = ip.split(',')
_first_ip = _ips[0].strip()
log.debug('Got multiple IPs %s, using %s' % (','.join(_ips), _first_ip))
return _first_ip
return ip
Add ip reference into BaseController
r2374 def _get_ip_addr(environ):
proxy_key = 'HTTP_X_REAL_IP'
proxy_key2 = 'HTTP_X_FORWARDED_FOR'
def_key = 'REMOTE_ADDR'
fix multiple ips addresses in X_FORWARDER_FOR header
r3153 ip = environ.get(proxy_key)
add IP into base logging, and change a little IP extraction login, if some header is passed as empty
r2486 if ip:
fixed multiple IP addresses in each of extracted IP....
r3669 return _filter_proxy(ip)
add IP into base logging, and change a little IP extraction login, if some header is passed as empty
r2486
fix multiple ips addresses in X_FORWARDER_FOR header
r3153 ip = environ.get(proxy_key2)
add IP into base logging, and change a little IP extraction login, if some header is passed as empty
r2486 if ip:
fixed multiple IP addresses in each of extracted IP....
r3669 return _filter_proxy(ip)
add IP into base logging, and change a little IP extraction login, if some header is passed as empty
r2486
ip = environ.get(def_key, '0.0.0.0')
fixed multiple IP addresses in each of extracted IP....
r3669 return _filter_proxy(ip)
Add ip reference into BaseController
r2374
better path extraction method....
r2490 def _get_access_path(environ):
path = environ.get('PATH_INFO')
org_req = environ.get('pylons.original_request')
if org_req:
path = org_req.environ.get('PATH_INFO')
return path
Alternative HTTP response codes when client failed to Authenticate correctly
r2132 class BasicAuth(AuthBasicAuthenticator):
def __init__(self, realm, authfunc, auth_http_code=None):
self.realm = realm
self.authfunc = authfunc
self._rc_auth_http_code = auth_http_code
def build_authentication(self):
head = WWW_AUTHENTICATE.tuples('Basic realm="%s"' % self.realm)
if self._rc_auth_http_code and self._rc_auth_http_code == '403':
# return 403 if alternative http return code is specified in
# RhodeCode config
return HTTPForbidden(headers=head)
return HTTPUnauthorized(headers=head)
patched basic auth function to overcome git issues with proxy that doesn't send both username and password. ref #586
r2912 def authenticate(self, environ):
authorization = AUTHORIZATION(environ)
if not authorization:
return self.build_authentication()
(authmeth, auth) = authorization.split(' ', 1)
if 'basic' != authmeth.lower():
return self.build_authentication()
auth = auth.strip().decode('base64')
_parts = auth.split(':', 1)
if len(_parts) == 2:
username, password = _parts
if self.authfunc(environ, username, password):
return username
return self.build_authentication()
__call__ = authenticate
Alternative HTTP response codes when client failed to Authenticate correctly
r2132
Wrapped calls for git and hg middleware in extra block that clears db Session....
r1761 class BaseVCSController(object):
implements #285: Implemented non changeable urls for clone url, and web views
r1813
Wrapped calls for git and hg middleware in extra block that clears db Session....
r1761 def __init__(self, application, config):
self.application = application
self.config = config
# base path of repo locations
self.basepath = self.config['base_path']
#authenticate this mercurial request using authfunc
Alternative HTTP response codes when client failed to Authenticate correctly
r2132 self.authenticate = BasicAuth('', authfunc,
config.get('auth_ret_code'))
Added UserIpMap interface for allowed IP addresses and IP restriction access...
r3125 self.ip_addr = '0.0.0.0'
implements #285: Implemented non changeable urls for clone url, and web views
r1813
code garden, pep8
r1978 def _handle_request(self, environ, start_response):
raise NotImplementedError()
implements #285: Implemented non changeable urls for clone url, and web views
r1813 def _get_by_id(self, repo_name):
"""
Get's a special pattern _<ID> from clone url and tries to replace it
with a repository_name for support of _<ID> non changable urls
:param repo_name:
"""
try:
data = repo_name.split('/')
if len(data) >= 2:
by_id = data[1].split('_')
if len(by_id) == 2 and by_id[1].isdigit():
_repo_name = Repository.get(by_id[1]).repo_name
data[1] = _repo_name
Don't catch all exceptions
r3631 except Exception:
implements #285: Implemented non changeable urls for clone url, and web views
r1813 log.debug('Failed to extract repo_name from id %s' % (
traceback.format_exc()
)
)
return '/'.join(data)
Wrapped calls for git and hg middleware in extra block that clears db Session....
r1761 def _invalidate_cache(self, repo_name):
"""
Set's cache for this repository for invalidation on next access
implements #285: Implemented non changeable urls for clone url, and web views
r1813
Wrapped calls for git and hg middleware in extra block that clears db Session....
r1761 :param repo_name: full repo name, also a cache key
"""
removed duplicated logic of how we invalidate caches for repos
r3693 ScmModel().mark_for_invalidation(repo_name)
implements #285: Implemented non changeable urls for clone url, and web views
r1813
Added UserIpMap interface for allowed IP addresses and IP restriction access...
r3125 def _check_permission(self, action, user, repo_name, ip_addr=None):
Wrapped calls for git and hg middleware in extra block that clears db Session....
r1761 """
Checks permissions using action (push/pull) user and repository
name
:param action: push or pull action
:param user: user instance
:param repo_name: repository name
"""
Added UserIpMap interface for allowed IP addresses and IP restriction access...
r3125 #check IP
Full IP restrictions enabled...
r3146 authuser = AuthUser(user_id=user.user_id, ip_addr=ip_addr)
if not authuser.ip_allowed:
Added UserIpMap interface for allowed IP addresses and IP restriction access...
r3125 return False
else:
log.info('Access for IP:%s allowed' % (ip_addr))
Wrapped calls for git and hg middleware in extra block that clears db Session....
r1761 if action == 'push':
if not HasPermissionAnyMiddleware('repository.write',
'repository.admin')(user,
repo_name):
return False
else:
#any other action need at least read permission
if not HasPermissionAnyMiddleware('repository.read',
'repository.write',
'repository.admin')(user,
repo_name):
return False
implements #285: Implemented non changeable urls for clone url, and web views
r1813 return True
Added HTTP_X_FORWARDED_FOR as another method of extracting IP for pull/push logs....
r2184 def _get_ip_addr(self, environ):
Add ip reference into BaseController
r2374 return _get_ip_addr(environ)
Added HTTP_X_FORWARDED_FOR as another method of extracting IP for pull/push logs....
r2184
Implementes #509 require SSL flag now works for both git and mercurial....
r2668 def _check_ssl(self, environ, start_response):
"""
Checks the SSL check flag and returns False if SSL is not present
and required True otherwise
"""
org_proto = environ['wsgi._org_proto']
#check if we have SSL required ! if not it's a bad request !
Added form for controlling mercurial extensions...
r2708 require_ssl = str2bool(RhodeCodeUi.get_by_key('push_ssl').ui_value)
Implementes #509 require SSL flag now works for both git and mercurial....
r2668 if require_ssl and org_proto == 'http':
log.debug('proto is %s and SSL is required BAD REQUEST !'
% org_proto)
return False
merged + fixed pull request #62: Implemented metatags and visualisation options....
r2674 return True
Implementes #509 require SSL flag now works for both git and mercurial....
r2668
Implemented basic locking functionality....
r2726 def _check_locking_state(self, environ, action, repo, user_id):
"""
Checks locking on this repository, if locking is enabled and lock is
present returns a tuple of make_lock, locked, locked_by.
make_lock can have 3 states None (do nothing) True, make lock
False release lock, This value is later propagated to hooks, which
do the locking. Think about this as signals passed to hooks what to do.
"""
added new suite of tests for VCS operations...
r2752 locked = False # defines that locked error should be thrown to user
Implemented basic locking functionality....
r2726 make_lock = None
repo = Repository.get_by_repo_name(repo)
user = User.get(user_id)
# this is kind of hacky, but due to how mercurial handles client-server
# server see all operation on changeset; bookmarks, phases and
# obsolescence marker in different transaction, we don't want to check
# locking on those
obsolete_call = environ['QUERY_STRING'] in ['cmd=listkeys',]
locked_by = repo.locked
if repo and repo.enable_locking and not obsolete_call:
if action == 'push':
#check if it's already locked !, if it is compare users
user_id, _date = repo.locked
if user.user_id == user_id:
added new suite of tests for VCS operations...
r2752 log.debug('Got push from user %s, now unlocking' % (user))
Implemented basic locking functionality....
r2726 # unlock if we have push from user who locked
make_lock = False
else:
# we're not the same user who locked, ban with 423 !
locked = True
if action == 'pull':
if repo.locked[0] and repo.locked[1]:
locked = True
else:
log.debug('Setting lock on repo %s by %s' % (repo, user))
make_lock = True
else:
log.debug('Repository %s do not have locking enabled' % (repo))
added new suite of tests for VCS operations...
r2752 log.debug('FINAL locking values make_lock:%s,locked:%s,locked_by:%s'
% (make_lock, locked, locked_by))
Implemented basic locking functionality....
r2726 return make_lock, locked, locked_by
Wrapped calls for git and hg middleware in extra block that clears db Session....
r1761 def __call__(self, environ, start_response):
start = time.time()
try:
return self._handle_request(environ, start_response)
finally:
logger name update
r1763 log = logging.getLogger('rhodecode.' + self.__class__.__name__)
Wrapped calls for git and hg middleware in extra block that clears db Session....
r1761 log.debug('Request time: %.3fs' % (time.time() - start))
meta.Session.remove()
renamed project to rhodecode
r547 class BaseController(WSGIController):
extended repo creation by repo type. fixed fork creation to maintain repo type.
r659
renamed project to rhodecode
r547 def __before__(self):
Added UserIpMap interface for allowed IP addresses and IP restriction access...
r3125 """
__before__ is called before controller methods and after __call__
"""
renamed hg_app to rhodecode
r548 c.rhodecode_version = __version__
implements #212 moved default encoding variable into rhodecode-config. It's now possible to change...
r2016 c.rhodecode_instanceid = config.get('instance_id')
implemented #89 google analytics code
r890 c.rhodecode_name = config.get('rhodecode_title')
implements #293 gravatar link should be disabled when use_gravatar = false
r1629 c.use_gravatar = str2bool(config.get('use_gravatar'))
fixes for #89 ga code
r891 c.ga_code = config.get('rhodecode_ga_code')
merged + fixed pull request #62: Implemented metatags and visualisation options....
r2674 # Visual options
c.visual = AttributeDict({})
don't use config for visual settings. It totally doesn't work on multi instance mode
r2955 rc_config = RhodeCodeSetting.get_app_settings()
added dashboard items config in visual settings
r3904 ## DB stored
don't use config for visual settings. It totally doesn't work on multi instance mode
r2955 c.visual.show_public_icon = str2bool(rc_config.get('rhodecode_show_public_icon'))
c.visual.show_private_icon = str2bool(rc_config.get('rhodecode_show_private_icon'))
c.visual.stylify_metatags = str2bool(rc_config.get('rhodecode_stylify_metatags'))
added dashboard items config in visual settings
r3904 c.visual.dashboard_items = safe_int(rc_config.get('rhodecode_dashboard_items', 100))
repository extra fields implementation...
r3308 c.visual.repository_fields = str2bool(rc_config.get('rhodecode_repository_fields'))
Implements #842 RhodeCode version disclosure....
r3910 c.visual.show_version = str2bool(rc_config.get('rhodecode_show_version'))
added dashboard items config in visual settings
r3904 ## INI stored
self.cut_off_limit = int(config.get('cut_off_limit'))
Added flag to controll option for changing the repos path location...
r3920 c.visual.allow_repo_location_change = str2bool(config.get('allow_repo_location_change', True))
added dashboard items config in visual settings
r3904
show only open pull requests in the counter, and use repo context bar in pull requests view
r3580 c.repo_name = get_repo_slug(request) # can be empty
extended repo creation by repo type. fixed fork creation to maintain repo type.
r659 c.backends = BACKENDS.keys()
#302 - basic notification system, models+tests
r1702 c.unread_notifications = NotificationModel()\
.get_unread_cnt_for_user(c.rhodecode_user.user_id)
commit less models...
r1749 self.sa = meta.Session
another major codes rewrite:...
r1045 self.scm_model = ScmModel(self.sa)
fixes #200, rewrote the whole caching mechanism to get rid of such problems. Now cached instances are attached...
r1366
renamed project to rhodecode
r547 def __call__(self, environ, start_response):
"""Invoke the Controller"""
# WSGIController.__call__ dispatches to the Controller method
# the request is routed to. This routing information is
# available in environ['pylons.routes_dict']
try:
Add ip reference into BaseController
r2374 self.ip_addr = _get_ip_addr(environ)
Some code cleanups and fixes
r1628 # make sure that we update permissions each time we call controller
Major rewrite of auth objects. Moved parts of filling user data into user model....
r1117 api_key = request.GET.get('api_key')
Added session wrapper, for rc 1.2.X compatibility. Adds backwards compatability...
r2030 cookie_store = CookieStoreWrapper(session.get('rhodecode_user'))
reduce cookie size for better support of client side sessions
r1718 user_id = cookie_store.get('user_id', None)
Liad Shani
Improved container-based auth support for middleware
r1630 username = get_container_username(environ, config)
Added UserIpMap interface for allowed IP addresses and IP restriction access...
r3125 auth_user = AuthUser(user_id, api_key, username, self.ip_addr)
- fixes celery sqlalchemy session issues for async forking...
r1728 request.user = auth_user
Some code cleanups and fixes
r1628 self.rhodecode_user = c.rhodecode_user = auth_user
Liad Shani
Added automatic logout of deactivated/deleted users
r1618 if not self.rhodecode_user.is_authenticated and \
self.rhodecode_user.user_id is not None:
Added session wrapper, for rc 1.2.X compatibility. Adds backwards compatability...
r2030 self.rhodecode_user.set_authenticated(
cookie_store.get('is_authenticated')
)
add IP into base logging, and change a little IP extraction login, if some header is passed as empty
r2486 log.info('IP: %s User: %s accessed %s' % (
better path extraction method....
r2490 self.ip_addr, auth_user, safe_unicode(_get_access_path(environ)))
fixed logging issue on non-ascii repos
r2027 )
renamed project to rhodecode
r547 return WSGIController.__call__(self, environ, start_response)
finally:
meta.Session.remove()
another major codes rewrite:...
r1045
class BaseRepoController(BaseController):
"""
Some code cleanups and fixes
r1628 Base class for controllers responsible for loading all needed data for
repository loaded items are
source code cleanup: remove trailing white space, normalize file endings
r1203
Some code cleanups and fixes
r1628 c.rhodecode_repo: instance of scm repository
c.rhodecode_db_repo: instance of db
c.repository_followers: number of followers
c.repository_forks: number of forks
Leonardo
Adding the context bar too all pages related to a Repository....
r3527 c.repository_following: weather the current user is following the current repo
another major codes rewrite:...
r1045 """
def __before__(self):
super(BaseRepoController, self).__before__()
if c.repo_name:
- pull request generates overview based on it's params...
r2440 dbr = c.rhodecode_db_repo = Repository.get_by_repo_name(c.repo_name)
Fixes issue #201...
r1373 c.rhodecode_repo = c.rhodecode_db_repo.scm_instance
Update last_change from VCS data on request....
r2937 # update last change according to VCS data
Added full last changeset info to lightweight dashboard
r3147 dbr.update_changeset_cache(dbr.get_changeset())
Fixes issue #201...
r1373 if c.rhodecode_repo is None:
log.error('%s this repository is present in database but it '
'cannot be created as an scm instance', c.repo_name)
fixed condition evaluated for gitrepo that returned null, simplified scm functions
r1282
Fixes issue #201...
r1373 redirect(url('home'))
gui-improvments
r1304
- pull request generates overview based on it's params...
r2440 # some globals counter for menu
c.repository_followers = self.scm_model.get_followers(dbr)
c.repository_forks = self.scm_model.get_forks(dbr)
white space cleanup
r2478 c.repository_pull_requests = self.scm_model.get_pull_requests(dbr)
Leonardo
Adding the context bar too all pages related to a Repository....
r3527 c.repository_following = self.scm_model.is_following_repo(c.repo_name,
self.rhodecode_user.user_id)