aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcin Kuzminski <marcin@python-works.com>2012-02-28 20:21:35 +0200
committerMarcin Kuzminski <marcin@python-works.com>2012-02-28 20:21:35 +0200
commitd54925bd6f843dd6f0b772c4b640d3a0edce213b (patch)
treed5b453aba8140fdf9bfb4ca0649940807de3413e
parenta3e59db9d11eb013356cbdabcffcfaeabe9f39bd (diff)
parent9d10f3247c025873da64c32fcc0f940df0eac388 (diff)
merge with betav1.3.2
-rw-r--r--CONTRIBUTORS3
-rw-r--r--docs/changelog.rst19
-rw-r--r--docs/theme/nature/layout.html2
-rw-r--r--rhodecode/controllers/admin/repos_groups.py5
-rw-r--r--rhodecode/controllers/admin/users_groups.py3
-rw-r--r--rhodecode/lib/__init__.py2
-rw-r--r--rhodecode/lib/caching_query.py6
-rw-r--r--rhodecode/lib/middleware/https_fixup.py12
-rw-r--r--rhodecode/lib/middleware/simplegit.py31
-rw-r--r--rhodecode/lib/utils.py10
-rwxr-xr-xrhodecode/model/db.py29
-rw-r--r--rhodecode/model/forms.py47
-rw-r--r--rhodecode/model/repos_group.py6
-rw-r--r--rhodecode/tests/functional/test_admin_users_groups.py53
-rw-r--r--rhodecode/tests/test_models.py39
15 files changed, 204 insertions, 63 deletions
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index e7a0e8c9..b4c25cb3 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -15,4 +15,5 @@ List of contributors to RhodeCode project:
Les Peabody <lpeabody@gmail.com>
Jonas Oberschweiber <jonas.oberschweiber@d-velop.de>
Matt Zuba <matt.zuba@goodwillaz.org>
- Aras Pranckevicius <aras@unity3d.com> \ No newline at end of file
+ Aras Pranckevicius <aras@unity3d.com>
+ Tony Bussieres <t.bussieres@gmail.com>
diff --git a/docs/changelog.rst b/docs/changelog.rst
index 21d94e5d..181098e0 100644
--- a/docs/changelog.rst
+++ b/docs/changelog.rst
@@ -4,6 +4,25 @@ Changelog
=========
+1.3.2 (**2012-02-28**)
+----------------------
+
+news
+++++
+
+
+fixes
++++++
+
+- fixed git protocol issues with repos-groups
+- fixed git remote repos validator that prevented from cloning remote git repos
+- fixes #370 ending slashes fixes for repo and groups
+- fixes #368 improved git-protocol detection to handle other clients
+- fixes #366 When Setting Repository Group To Blank Repo Group Wont Be
+ Moved To Root
+- fixes #371 fixed issues with beaker/sqlalchemy and non-ascii cache keys
+- fixed #373 missing cascade drop on user_group_to_perm table
+
1.3.1 (**2012-02-27**)
----------------------
diff --git a/docs/theme/nature/layout.html b/docs/theme/nature/layout.html
index 8f722a4d..e7e86a83 100644
--- a/docs/theme/nature/layout.html
+++ b/docs/theme/nature/layout.html
@@ -13,6 +13,6 @@
<div style="padding:5px">
<a href="http://flattr.com/thing/167489/RhodeCode" target="_blank">
<img src="http://api.flattr.com/button/flattr-badge-large.png" alt="Flattr this" title="Flattr this" border="0" /></a>
- </div>
+ </div>
</div>
{% endblock %}}
diff --git a/rhodecode/controllers/admin/repos_groups.py b/rhodecode/controllers/admin/repos_groups.py
index abfcc330..a3588f82 100644
--- a/rhodecode/controllers/admin/repos_groups.py
+++ b/rhodecode/controllers/admin/repos_groups.py
@@ -263,6 +263,11 @@ class ReposGroupsController(BaseController):
raise HTTPInternalServerError()
def show_by_name(self, group_name):
+ """
+ This is a proxy that does a lookup group_name -> id, and shows
+ the group by id view instead
+ """
+ group_name = group_name.rstrip('/')
id_ = RepoGroup.get_by_group_name(group_name).group_id
return self.show(id_)
diff --git a/rhodecode/controllers/admin/users_groups.py b/rhodecode/controllers/admin/users_groups.py
index b4672157..04193bcb 100644
--- a/rhodecode/controllers/admin/users_groups.py
+++ b/rhodecode/controllers/admin/users_groups.py
@@ -160,11 +160,12 @@ class UsersGroupsController(BaseController):
try:
UsersGroupModel().delete(id)
- h.flash(_('successfully deleted users group'), category='success')
Session.commit()
+ h.flash(_('successfully deleted users group'), category='success')
except UsersGroupsAssignedException, e:
h.flash(e, category='error')
except Exception:
+ log.error(traceback.format_exc())
h.flash(_('An error occurred during deletion of users group'),
category='error')
return redirect(url('users_groups'))
diff --git a/rhodecode/lib/__init__.py b/rhodecode/lib/__init__.py
index b52294d8..d6c13d30 100644
--- a/rhodecode/lib/__init__.py
+++ b/rhodecode/lib/__init__.py
@@ -231,7 +231,7 @@ def safe_str(unicode_, to_encoding=None):
:rtype: str
:returns: str object
"""
-
+
# if it's not basestr cast to str
if not isinstance(unicode_, basestring):
return str(unicode_)
diff --git a/rhodecode/lib/caching_query.py b/rhodecode/lib/caching_query.py
index 781dc8f1..00d3169c 100644
--- a/rhodecode/lib/caching_query.py
+++ b/rhodecode/lib/caching_query.py
@@ -24,6 +24,7 @@ from beaker.exceptions import BeakerException
from sqlalchemy.orm.interfaces import MapperOption
from sqlalchemy.orm.query import Query
from sqlalchemy.sql import visitors
+from rhodecode.lib import safe_str
class CachingQuery(Query):
@@ -137,9 +138,10 @@ def _get_cache_parameters(query):
if cache_key is None:
# cache key - the value arguments from this query's parameters.
- args = [str(x) for x in _params_from_query(query)]
- args.extend(filter(lambda k:k not in ['None', None, u'None'],
+ args = [safe_str(x) for x in _params_from_query(query)]
+ args.extend(filter(lambda k: k not in ['None', None, u'None'],
[str(query._limit), str(query._offset)]))
+
cache_key = " ".join(args)
if cache_key is None:
diff --git a/rhodecode/lib/middleware/https_fixup.py b/rhodecode/lib/middleware/https_fixup.py
index 4cdb1ed2..4ecf95c1 100644
--- a/rhodecode/lib/middleware/https_fixup.py
+++ b/rhodecode/lib/middleware/https_fixup.py
@@ -42,13 +42,21 @@ class HttpsFixup(object):
middleware you should set this header inside your
proxy ie. nginx, apache etc.
"""
- proto = environ.get('HTTP_X_URL_SCHEME')
if str2bool(self.config.get('force_https')):
proto = 'https'
-
+ else:
+ if 'HTTP_X_URL_SCHEME' in environ:
+ proto = environ.get('HTTP_X_URL_SCHEME')
+ elif 'HTTP_X_FORWARDED_SCHEME' in environ:
+ proto = environ.get('HTTP_X_FORWARDED_SCHEME')
+ elif 'HTTP_X_FORWARDED_PROTO' in environ:
+ proto = environ.get('HTTP_X_FORWARDED_PROTO')
+ else:
+ proto = 'http'
if proto == 'https':
environ['wsgi.url_scheme'] = proto
else:
environ['wsgi.url_scheme'] = 'http'
+
return None
diff --git a/rhodecode/lib/middleware/simplegit.py b/rhodecode/lib/middleware/simplegit.py
index 47acf7cf..59c6f1ae 100644
--- a/rhodecode/lib/middleware/simplegit.py
+++ b/rhodecode/lib/middleware/simplegit.py
@@ -25,6 +25,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
+import re
import logging
import traceback
@@ -79,21 +80,20 @@ from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError
log = logging.getLogger(__name__)
-def is_git(environ):
- """Returns True if request's target is git server.
- ``HTTP_USER_AGENT`` would then have git client version given.
+GIT_PROTO_PAT = re.compile(r'^/(.+)/(info/refs|git-upload-pack|git-receive-pack)')
+
- :param environ:
- """
- http_user_agent = environ.get('HTTP_USER_AGENT')
- if http_user_agent and http_user_agent.startswith('git'):
- return True
- return False
+def is_git(environ):
+ path_info = environ['PATH_INFO']
+ isgit_path = GIT_PROTO_PAT.match(path_info)
+ log.debug('is a git path %s pathinfo : %s' % (isgit_path, path_info))
+ return isgit_path
class SimpleGit(BaseVCSController):
def _handle_request(self, environ, start_response):
+
if not is_git(environ):
return self.application(environ, start_response)
@@ -218,13 +218,11 @@ class SimpleGit(BaseVCSController):
"""
try:
environ['PATH_INFO'] = self._get_by_id(environ['PATH_INFO'])
- repo_name = '/'.join(environ['PATH_INFO'].split('/')[1:])
- if repo_name.endswith('/'):
- repo_name = repo_name.rstrip('/')
+ repo_name = GIT_PROTO_PAT.match(environ['PATH_INFO']).group(1)
except:
log.error(traceback.format_exc())
raise
- repo_name = repo_name.split('/')[0]
+
return repo_name
def __get_user(self, username):
@@ -238,9 +236,10 @@ class SimpleGit(BaseVCSController):
service = environ['QUERY_STRING'].split('=')
if len(service) > 1:
service_cmd = service[1]
- mapping = {'git-receive-pack': 'push',
- 'git-upload-pack': 'pull',
- }
+ mapping = {
+ 'git-receive-pack': 'push',
+ 'git-upload-pack': 'pull',
+ }
return mapping.get(service_cmd,
service_cmd if service_cmd else 'other')
diff --git a/rhodecode/lib/utils.py b/rhodecode/lib/utils.py
index 9b82080f..641aed62 100644
--- a/rhodecode/lib/utils.py
+++ b/rhodecode/lib/utils.py
@@ -92,11 +92,17 @@ def repo_name_slug(value):
def get_repo_slug(request):
- return request.environ['pylons.routes_dict'].get('repo_name')
+ _repo = request.environ['pylons.routes_dict'].get('repo_name')
+ if _repo:
+ _repo = _repo.rstrip('/')
+ return _repo
def get_repos_group_slug(request):
- return request.environ['pylons.routes_dict'].get('group_name')
+ _group = request.environ['pylons.routes_dict'].get('group_name')
+ if _group:
+ _group = _group.rstrip('/')
+ return _group
def action_logger(user, action, repo, ipaddr='', sa=None, commit=False):
diff --git a/rhodecode/model/db.py b/rhodecode/model/db.py
index 14997fbe..ab6b9765 100755
--- a/rhodecode/model/db.py
+++ b/rhodecode/model/db.py
@@ -44,6 +44,7 @@ from rhodecode.lib.compat import json
from rhodecode.lib.caching_query import FromCache
from rhodecode.model.meta import Base, Session
+import hashlib
log = logging.getLogger(__name__)
@@ -52,6 +53,8 @@ log = logging.getLogger(__name__)
# BASE CLASSES
#==============================================================================
+_hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest()
+
class ModelSerializer(json.JSONEncoder):
"""
@@ -337,8 +340,11 @@ class User(Base, BaseModel):
q = cls.query().filter(cls.username == username)
if cache:
- q = q.options(FromCache("sql_cache_short",
- "get_user_%s" % username))
+ q = q.options(FromCache(
+ "sql_cache_short",
+ "get_user_%s" % _hash_key(username)
+ )
+ )
return q.scalar()
@classmethod
@@ -394,7 +400,7 @@ class UserLog(Base, BaseModel):
return datetime.date(*self.action_date.timetuple()[:3])
user = relationship('User')
- repository = relationship('Repository',cascade='')
+ repository = relationship('Repository', cascade='')
class UsersGroup(Base, BaseModel):
@@ -406,6 +412,7 @@ class UsersGroup(Base, BaseModel):
users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
members = relationship('UsersGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
+ users_group_to_perm = relationship('UsersGroupToPerm', cascade='all')
def __repr__(self):
return '<userGroup(%s)>' % (self.users_group_name)
@@ -418,8 +425,11 @@ class UsersGroup(Base, BaseModel):
else:
q = cls.query().filter(cls.users_group_name == group_name)
if cache:
- q = q.options(FromCache("sql_cache_short",
- "get_user_%s" % group_name))
+ q = q.options(FromCache(
+ "sql_cache_short",
+ "get_user_%s" % _hash_key(group_name)
+ )
+ )
return q.scalar()
@classmethod
@@ -748,8 +758,11 @@ class RepoGroup(Base, BaseModel):
gr = cls.query()\
.filter(cls.group_name == group_name)
if cache:
- gr = gr.options(FromCache("sql_cache_short",
- "get_group_%s" % group_name))
+ gr = gr.options(FromCache(
+ "sql_cache_short",
+ "get_group_%s" % _hash_key(group_name)
+ )
+ )
return gr.scalar()
@property
@@ -1038,7 +1051,7 @@ class CacheInvalidation(Base, BaseModel):
prefix = ''
iid = rhodecode.CONFIG.get('instance_id')
if iid:
- prefix = iid
+ prefix = iid
return "%s%s" % (prefix, key)
@classmethod
diff --git a/rhodecode/model/forms.py b/rhodecode/model/forms.py
index 3fe679f2..7fc9103d 100644
--- a/rhodecode/model/forms.py
+++ b/rhodecode/model/forms.py
@@ -345,32 +345,46 @@ def SlugifyName():
def ValidCloneUri():
- from mercurial.httprepo import httprepository, httpsrepository
from rhodecode.lib.utils import make_ui
+ def url_handler(repo_type, url, proto, ui=None):
+ if repo_type == 'hg':
+ from mercurial.httprepo import httprepository, httpsrepository
+ if proto == 'https':
+ httpsrepository(make_ui('db'), url).capabilities
+ elif proto == 'http':
+ httprepository(make_ui('db'), url).capabilities
+ elif repo_type == 'git':
+ #TODO: write a git url validator
+ pass
+
class _ValidCloneUri(formencode.validators.FancyValidator):
def to_python(self, value, state):
- if not value:
+
+ repo_type = value.get('repo_type')
+ url = value.get('clone_uri')
+ e_dict = {'clone_uri': _('invalid clone url')}
+
+ if not url:
pass
- elif value.startswith('https'):
+ elif url.startswith('https'):
try:
- httpsrepository(make_ui('db'), value).capabilities
+ url_handler(repo_type, url, 'https', make_ui('db'))
except Exception:
log.error(traceback.format_exc())
- raise formencode.Invalid(_('invalid clone url'), value,
- state)
- elif value.startswith('http'):
+ raise formencode.Invalid('', value, state, error_dict=e_dict)
+ elif url.startswith('http'):
try:
- httprepository(make_ui('db'), value).capabilities
+ url_handler(repo_type, url, 'http', make_ui('db'))
except Exception:
log.error(traceback.format_exc())
- raise formencode.Invalid(_('invalid clone url'), value,
- state)
+ raise formencode.Invalid('', value, state, error_dict=e_dict)
else:
- raise formencode.Invalid(_('Invalid clone url, provide a '
- 'valid clone http\s url'), value,
- state)
+ e_dict = {'clone_uri': _('Invalid clone url, provide a '
+ 'valid clone http\s url')}
+ raise formencode.Invalid('', value, state, error_dict=e_dict)
+
return value
return _ValidCloneUri
@@ -645,8 +659,7 @@ def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
filter_extra_fields = False
repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
SlugifyName())
- clone_uri = All(UnicodeString(strip=True, min=1, not_empty=False),
- ValidCloneUri()())
+ clone_uri = All(UnicodeString(strip=True, min=1, not_empty=False))
repo_group = OneOf(repo_groups, hideList=True)
repo_type = OneOf(supported_backends)
description = UnicodeString(strip=True, min=1, not_empty=True)
@@ -658,7 +671,9 @@ def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
#this is repo owner
user = All(UnicodeString(not_empty=True), ValidRepoUser)
- chained_validators = [ValidRepoName(edit, old_data), ValidPerms()]
+ chained_validators = [ValidCloneUri()(),
+ ValidRepoName(edit, old_data),
+ ValidPerms()]
return _RepoForm
diff --git a/rhodecode/model/repos_group.py b/rhodecode/model/repos_group.py
index 94590ccb..5bc435e7 100644
--- a/rhodecode/model/repos_group.py
+++ b/rhodecode/model/repos_group.py
@@ -187,20 +187,20 @@ class ReposGroupModel(BaseModel):
# change properties
repos_group.group_description = form_data['group_description']
repos_group.parent_group = RepoGroup.get(form_data['group_parent_id'])
+ repos_group.group_parent_id = form_data['group_parent_id']
repos_group.group_name = repos_group.get_new_name(form_data['group_name'])
-
new_path = repos_group.full_path
self.sa.add(repos_group)
- self.__rename_group(old_path, new_path)
-
# we need to get all repositories from this new group and
# rename them accordingly to new group path
for r in repos_group.repositories:
r.repo_name = r.get_new_name(r.just_name)
self.sa.add(r)
+ self.__rename_group(old_path, new_path)
+
return repos_group
except:
log.error(traceback.format_exc())
diff --git a/rhodecode/tests/functional/test_admin_users_groups.py b/rhodecode/tests/functional/test_admin_users_groups.py
index 65ace078..5e43e9a1 100644
--- a/rhodecode/tests/functional/test_admin_users_groups.py
+++ b/rhodecode/tests/functional/test_admin_users_groups.py
@@ -1,8 +1,9 @@
from rhodecode.tests import *
-from rhodecode.model.db import UsersGroup
+from rhodecode.model.db import UsersGroup, UsersGroupToPerm, Permission
TEST_USERS_GROUP = 'admins_test'
+
class TestAdminUsersGroupsController(TestController):
def test_index(self):
@@ -16,7 +17,7 @@ class TestAdminUsersGroupsController(TestController):
self.log_user()
users_group_name = TEST_USERS_GROUP
response = self.app.post(url('users_groups'),
- {'users_group_name':users_group_name,
+ {'users_group_name': users_group_name,
'active':True})
response.follow()
@@ -47,7 +48,6 @@ class TestAdminUsersGroupsController(TestController):
self.checkSessionFlash(response,
'created users group %s' % users_group_name)
-
gr = self.Session.query(UsersGroup)\
.filter(UsersGroup.users_group_name ==
users_group_name).one()
@@ -60,6 +60,53 @@ class TestAdminUsersGroupsController(TestController):
self.assertEqual(gr, None)
+ def test_enable_repository_read_on_group(self):
+ self.log_user()
+ users_group_name = TEST_USERS_GROUP + 'another2'
+ response = self.app.post(url('users_groups'),
+ {'users_group_name': users_group_name,
+ 'active':True})
+ response.follow()
+
+ ug = UsersGroup.get_by_group_name(users_group_name)
+ self.checkSessionFlash(response,
+ 'created users group %s' % users_group_name)
+
+ response = self.app.put(url('users_group_perm', id=ug.users_group_id),
+ {'create_repo_perm': True})
+
+ response.follow()
+ ug = UsersGroup.get_by_group_name(users_group_name)
+ p = Permission.get_by_key('hg.create.repository')
+ # check if user has this perm
+ perms = UsersGroupToPerm.query()\
+ .filter(UsersGroupToPerm.users_group == ug).all()
+ perms = [[x.__dict__['users_group_id'],
+ x.__dict__['permission_id'],] for x in perms]
+ self.assertEqual(
+ perms,
+ [[ug.users_group_id, p.permission_id]]
+ )
+
+ # DELETE !
+ ug = UsersGroup.get_by_group_name(users_group_name)
+ ugid = ug.users_group_id
+ response = self.app.delete(url('users_group', id=ug.users_group_id))
+ response = response.follow()
+ gr = self.Session.query(UsersGroup)\
+ .filter(UsersGroup.users_group_name ==
+ users_group_name).scalar()
+
+ self.assertEqual(gr, None)
+ p = Permission.get_by_key('hg.create.repository')
+ perms = UsersGroupToPerm.query()\
+ .filter(UsersGroupToPerm.users_group_id == ugid).all()
+ perms = [[x.__dict__['users_group_id'],
+ x.__dict__['permission_id'],] for x in perms]
+ self.assertEqual(
+ perms,
+ []
+ )
def test_delete_browser_fakeout(self):
response = self.app.post(url('users_group', id=1),
diff --git a/rhodecode/tests/test_models.py b/rhodecode/tests/test_models.py
index b0fd6e48..4863d2eb 100644
--- a/rhodecode/tests/test_models.py
+++ b/rhodecode/tests/test_models.py
@@ -23,7 +23,6 @@ def _make_group(path, desc='desc', parent_id=None,
return gr
gr = ReposGroupModel().create(path, desc, parent_id)
- Session.commit()
return gr
@@ -31,13 +30,19 @@ class TestReposGroups(unittest.TestCase):
def setUp(self):
self.g1 = _make_group('test1', skip_if_exists=True)
+ Session.commit()
self.g2 = _make_group('test2', skip_if_exists=True)
+ Session.commit()
self.g3 = _make_group('test3', skip_if_exists=True)
+ Session.commit()
def tearDown(self):
print 'out'
def __check_path(self, *path):
+ """
+ Checks the path for existance !
+ """
path = [TESTS_TMP_PATH] + list(path)
path = os.path.join(*path)
return os.path.isdir(path)
@@ -49,12 +54,13 @@ class TestReposGroups(unittest.TestCase):
ReposGroupModel().delete(id_)
def __update_group(self, id_, path, desc='desc', parent_id=None):
- form_data = dict(group_name=path,
- group_description=desc,
- group_parent_id=parent_id,
- perms_updates=[],
- perms_new=[])
-
+ form_data = dict(
+ group_name=path,
+ group_description=desc,
+ group_parent_id=parent_id,
+ perms_updates=[],
+ perms_new=[]
+ )
gr = ReposGroupModel().update(id_, form_data)
return gr
@@ -150,6 +156,25 @@ class TestReposGroups(unittest.TestCase):
self.assertEqual(r.repo_name, os.path.join('g2', 'g1', r.just_name))
+ def test_move_to_root(self):
+ g1 = _make_group('t11')
+ Session.commit()
+ g2 = _make_group('t22',parent_id=g1.group_id)
+ Session.commit()
+
+ self.assertEqual(g2.full_path,'t11/t22')
+ self.assertTrue(self.__check_path('t11', 't22'))
+
+ g2 = self.__update_group(g2.group_id, 'g22', parent_id=None)
+ Session.commit()
+
+ self.assertEqual(g2.group_name,'g22')
+ # we moved out group from t1 to '' so it's full path should be 'g2'
+ self.assertEqual(g2.full_path,'g22')
+ self.assertFalse(self.__check_path('t11', 't22'))
+ self.assertTrue(self.__check_path('g22'))
+
+
class TestUser(unittest.TestCase):
def __init__(self, methodName='runTest'):
Session.remove()