Show More
@@ -15,4 +15,5 b' List of contributors to RhodeCode projec' | |||||
15 | Les Peabody <lpeabody@gmail.com> |
|
15 | Les Peabody <lpeabody@gmail.com> | |
16 | Jonas Oberschweiber <jonas.oberschweiber@d-velop.de> |
|
16 | Jonas Oberschweiber <jonas.oberschweiber@d-velop.de> | |
17 | Matt Zuba <matt.zuba@goodwillaz.org> |
|
17 | Matt Zuba <matt.zuba@goodwillaz.org> | |
18 | Aras Pranckevicius <aras@unity3d.com> No newline at end of file |
|
18 | Aras Pranckevicius <aras@unity3d.com> | |
|
19 | Tony Bussieres <t.bussieres@gmail.com> |
@@ -4,6 +4,25 b' Changelog' | |||||
4 | ========= |
|
4 | ========= | |
5 |
|
5 | |||
6 |
|
6 | |||
|
7 | 1.3.2 (**2012-02-28**) | |||
|
8 | ---------------------- | |||
|
9 | ||||
|
10 | news | |||
|
11 | ++++ | |||
|
12 | ||||
|
13 | ||||
|
14 | fixes | |||
|
15 | +++++ | |||
|
16 | ||||
|
17 | - fixed git protocol issues with repos-groups | |||
|
18 | - fixed git remote repos validator that prevented from cloning remote git repos | |||
|
19 | - fixes #370 ending slashes fixes for repo and groups | |||
|
20 | - fixes #368 improved git-protocol detection to handle other clients | |||
|
21 | - fixes #366 When Setting Repository Group To Blank Repo Group Wont Be | |||
|
22 | Moved To Root | |||
|
23 | - fixes #371 fixed issues with beaker/sqlalchemy and non-ascii cache keys | |||
|
24 | - fixed #373 missing cascade drop on user_group_to_perm table | |||
|
25 | ||||
7 | 1.3.1 (**2012-02-27**) |
|
26 | 1.3.1 (**2012-02-27**) | |
8 | ---------------------- |
|
27 | ---------------------- | |
9 |
|
28 |
@@ -13,6 +13,6 b'' | |||||
13 | <div style="padding:5px"> |
|
13 | <div style="padding:5px"> | |
14 | <a href="http://flattr.com/thing/167489/RhodeCode" target="_blank"> |
|
14 | <a href="http://flattr.com/thing/167489/RhodeCode" target="_blank"> | |
15 | <img src="http://api.flattr.com/button/flattr-badge-large.png" alt="Flattr this" title="Flattr this" border="0" /></a> |
|
15 | <img src="http://api.flattr.com/button/flattr-badge-large.png" alt="Flattr this" title="Flattr this" border="0" /></a> | |
16 |
</div> |
|
16 | </div> | |
17 | </div> |
|
17 | </div> | |
18 | {% endblock %}} |
|
18 | {% endblock %}} |
@@ -263,6 +263,11 b' class ReposGroupsController(BaseControll' | |||||
263 | raise HTTPInternalServerError() |
|
263 | raise HTTPInternalServerError() | |
264 |
|
264 | |||
265 | def show_by_name(self, group_name): |
|
265 | def show_by_name(self, group_name): | |
|
266 | """ | |||
|
267 | This is a proxy that does a lookup group_name -> id, and shows | |||
|
268 | the group by id view instead | |||
|
269 | """ | |||
|
270 | group_name = group_name.rstrip('/') | |||
266 | id_ = RepoGroup.get_by_group_name(group_name).group_id |
|
271 | id_ = RepoGroup.get_by_group_name(group_name).group_id | |
267 | return self.show(id_) |
|
272 | return self.show(id_) | |
268 |
|
273 |
@@ -160,11 +160,12 b' class UsersGroupsController(BaseControll' | |||||
160 |
|
160 | |||
161 | try: |
|
161 | try: | |
162 | UsersGroupModel().delete(id) |
|
162 | UsersGroupModel().delete(id) | |
|
163 | Session.commit() | |||
163 | h.flash(_('successfully deleted users group'), category='success') |
|
164 | h.flash(_('successfully deleted users group'), category='success') | |
164 | Session.commit() |
|
|||
165 | except UsersGroupsAssignedException, e: |
|
165 | except UsersGroupsAssignedException, e: | |
166 | h.flash(e, category='error') |
|
166 | h.flash(e, category='error') | |
167 | except Exception: |
|
167 | except Exception: | |
|
168 | log.error(traceback.format_exc()) | |||
168 | h.flash(_('An error occurred during deletion of users group'), |
|
169 | h.flash(_('An error occurred during deletion of users group'), | |
169 | category='error') |
|
170 | category='error') | |
170 | return redirect(url('users_groups')) |
|
171 | return redirect(url('users_groups')) |
@@ -231,7 +231,7 b' def safe_str(unicode_, to_encoding=None)' | |||||
231 | :rtype: str |
|
231 | :rtype: str | |
232 | :returns: str object |
|
232 | :returns: str object | |
233 | """ |
|
233 | """ | |
234 |
|
234 | |||
235 | # if it's not basestr cast to str |
|
235 | # if it's not basestr cast to str | |
236 | if not isinstance(unicode_, basestring): |
|
236 | if not isinstance(unicode_, basestring): | |
237 | return str(unicode_) |
|
237 | return str(unicode_) |
@@ -24,6 +24,7 b' from beaker.exceptions import BeakerExce' | |||||
24 | from sqlalchemy.orm.interfaces import MapperOption |
|
24 | from sqlalchemy.orm.interfaces import MapperOption | |
25 | from sqlalchemy.orm.query import Query |
|
25 | from sqlalchemy.orm.query import Query | |
26 | from sqlalchemy.sql import visitors |
|
26 | from sqlalchemy.sql import visitors | |
|
27 | from rhodecode.lib import safe_str | |||
27 |
|
28 | |||
28 |
|
29 | |||
29 | class CachingQuery(Query): |
|
30 | class CachingQuery(Query): | |
@@ -137,9 +138,10 b' def _get_cache_parameters(query):' | |||||
137 |
|
138 | |||
138 | if cache_key is None: |
|
139 | if cache_key is None: | |
139 | # cache key - the value arguments from this query's parameters. |
|
140 | # cache key - the value arguments from this query's parameters. | |
140 | args = [str(x) for x in _params_from_query(query)] |
|
141 | args = [safe_str(x) for x in _params_from_query(query)] | |
141 | args.extend(filter(lambda k:k not in ['None', None, u'None'], |
|
142 | args.extend(filter(lambda k: k not in ['None', None, u'None'], | |
142 | [str(query._limit), str(query._offset)])) |
|
143 | [str(query._limit), str(query._offset)])) | |
|
144 | ||||
143 | cache_key = " ".join(args) |
|
145 | cache_key = " ".join(args) | |
144 |
|
146 | |||
145 | if cache_key is None: |
|
147 | if cache_key is None: |
@@ -42,13 +42,21 b' class HttpsFixup(object):' | |||||
42 | middleware you should set this header inside your |
|
42 | middleware you should set this header inside your | |
43 | proxy ie. nginx, apache etc. |
|
43 | proxy ie. nginx, apache etc. | |
44 | """ |
|
44 | """ | |
45 | proto = environ.get('HTTP_X_URL_SCHEME') |
|
|||
46 |
|
45 | |||
47 | if str2bool(self.config.get('force_https')): |
|
46 | if str2bool(self.config.get('force_https')): | |
48 | proto = 'https' |
|
47 | proto = 'https' | |
49 |
|
48 | else: | ||
|
49 | if 'HTTP_X_URL_SCHEME' in environ: | |||
|
50 | proto = environ.get('HTTP_X_URL_SCHEME') | |||
|
51 | elif 'HTTP_X_FORWARDED_SCHEME' in environ: | |||
|
52 | proto = environ.get('HTTP_X_FORWARDED_SCHEME') | |||
|
53 | elif 'HTTP_X_FORWARDED_PROTO' in environ: | |||
|
54 | proto = environ.get('HTTP_X_FORWARDED_PROTO') | |||
|
55 | else: | |||
|
56 | proto = 'http' | |||
50 | if proto == 'https': |
|
57 | if proto == 'https': | |
51 | environ['wsgi.url_scheme'] = proto |
|
58 | environ['wsgi.url_scheme'] = proto | |
52 | else: |
|
59 | else: | |
53 | environ['wsgi.url_scheme'] = 'http' |
|
60 | environ['wsgi.url_scheme'] = 'http' | |
|
61 | ||||
54 | return None |
|
62 | return None |
@@ -25,6 +25,7 b'' | |||||
25 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
25 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
26 |
|
26 | |||
27 | import os |
|
27 | import os | |
|
28 | import re | |||
28 | import logging |
|
29 | import logging | |
29 | import traceback |
|
30 | import traceback | |
30 |
|
31 | |||
@@ -79,21 +80,20 b' from webob.exc import HTTPNotFound, HTTP' | |||||
79 | log = logging.getLogger(__name__) |
|
80 | log = logging.getLogger(__name__) | |
80 |
|
81 | |||
81 |
|
82 | |||
82 | def is_git(environ): |
|
83 | GIT_PROTO_PAT = re.compile(r'^/(.+)/(info/refs|git-upload-pack|git-receive-pack)') | |
83 | """Returns True if request's target is git server. |
|
84 | ||
84 | ``HTTP_USER_AGENT`` would then have git client version given. |
|
|||
85 |
|
85 | |||
86 | :param environ: |
|
86 | def is_git(environ): | |
87 | """ |
|
87 | path_info = environ['PATH_INFO'] | |
88 | http_user_agent = environ.get('HTTP_USER_AGENT') |
|
88 | isgit_path = GIT_PROTO_PAT.match(path_info) | |
89 | if http_user_agent and http_user_agent.startswith('git'): |
|
89 | log.debug('is a git path %s pathinfo : %s' % (isgit_path, path_info)) | |
90 | return True |
|
90 | return isgit_path | |
91 | return False |
|
|||
92 |
|
91 | |||
93 |
|
92 | |||
94 | class SimpleGit(BaseVCSController): |
|
93 | class SimpleGit(BaseVCSController): | |
95 |
|
94 | |||
96 | def _handle_request(self, environ, start_response): |
|
95 | def _handle_request(self, environ, start_response): | |
|
96 | ||||
97 | if not is_git(environ): |
|
97 | if not is_git(environ): | |
98 | return self.application(environ, start_response) |
|
98 | return self.application(environ, start_response) | |
99 |
|
99 | |||
@@ -218,13 +218,11 b' class SimpleGit(BaseVCSController):' | |||||
218 | """ |
|
218 | """ | |
219 | try: |
|
219 | try: | |
220 | environ['PATH_INFO'] = self._get_by_id(environ['PATH_INFO']) |
|
220 | environ['PATH_INFO'] = self._get_by_id(environ['PATH_INFO']) | |
221 |
repo_name = |
|
221 | repo_name = GIT_PROTO_PAT.match(environ['PATH_INFO']).group(1) | |
222 | if repo_name.endswith('/'): |
|
|||
223 | repo_name = repo_name.rstrip('/') |
|
|||
224 | except: |
|
222 | except: | |
225 | log.error(traceback.format_exc()) |
|
223 | log.error(traceback.format_exc()) | |
226 | raise |
|
224 | raise | |
227 | repo_name = repo_name.split('/')[0] |
|
225 | ||
228 | return repo_name |
|
226 | return repo_name | |
229 |
|
227 | |||
230 | def __get_user(self, username): |
|
228 | def __get_user(self, username): | |
@@ -238,9 +236,10 b' class SimpleGit(BaseVCSController):' | |||||
238 | service = environ['QUERY_STRING'].split('=') |
|
236 | service = environ['QUERY_STRING'].split('=') | |
239 | if len(service) > 1: |
|
237 | if len(service) > 1: | |
240 | service_cmd = service[1] |
|
238 | service_cmd = service[1] | |
241 |
mapping = { |
|
239 | mapping = { | |
242 |
|
|
240 | 'git-receive-pack': 'push', | |
243 | } |
|
241 | 'git-upload-pack': 'pull', | |
|
242 | } | |||
244 |
|
243 | |||
245 | return mapping.get(service_cmd, |
|
244 | return mapping.get(service_cmd, | |
246 | service_cmd if service_cmd else 'other') |
|
245 | service_cmd if service_cmd else 'other') |
@@ -92,11 +92,17 b' def repo_name_slug(value):' | |||||
92 |
|
92 | |||
93 |
|
93 | |||
94 | def get_repo_slug(request): |
|
94 | def get_repo_slug(request): | |
95 |
|
|
95 | _repo = request.environ['pylons.routes_dict'].get('repo_name') | |
|
96 | if _repo: | |||
|
97 | _repo = _repo.rstrip('/') | |||
|
98 | return _repo | |||
96 |
|
99 | |||
97 |
|
100 | |||
98 | def get_repos_group_slug(request): |
|
101 | def get_repos_group_slug(request): | |
99 |
|
|
102 | _group = request.environ['pylons.routes_dict'].get('group_name') | |
|
103 | if _group: | |||
|
104 | _group = _group.rstrip('/') | |||
|
105 | return _group | |||
100 |
|
106 | |||
101 |
|
107 | |||
102 | def action_logger(user, action, repo, ipaddr='', sa=None, commit=False): |
|
108 | def action_logger(user, action, repo, ipaddr='', sa=None, commit=False): |
@@ -44,6 +44,7 b' from rhodecode.lib.compat import json' | |||||
44 | from rhodecode.lib.caching_query import FromCache |
|
44 | from rhodecode.lib.caching_query import FromCache | |
45 |
|
45 | |||
46 | from rhodecode.model.meta import Base, Session |
|
46 | from rhodecode.model.meta import Base, Session | |
|
47 | import hashlib | |||
47 |
|
48 | |||
48 |
|
49 | |||
49 | log = logging.getLogger(__name__) |
|
50 | log = logging.getLogger(__name__) | |
@@ -52,6 +53,8 b' log = logging.getLogger(__name__)' | |||||
52 | # BASE CLASSES |
|
53 | # BASE CLASSES | |
53 | #============================================================================== |
|
54 | #============================================================================== | |
54 |
|
55 | |||
|
56 | _hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest() | |||
|
57 | ||||
55 |
|
58 | |||
56 | class ModelSerializer(json.JSONEncoder): |
|
59 | class ModelSerializer(json.JSONEncoder): | |
57 | """ |
|
60 | """ | |
@@ -337,8 +340,11 b' class User(Base, BaseModel):' | |||||
337 | q = cls.query().filter(cls.username == username) |
|
340 | q = cls.query().filter(cls.username == username) | |
338 |
|
341 | |||
339 | if cache: |
|
342 | if cache: | |
340 |
q = q.options(FromCache( |
|
343 | q = q.options(FromCache( | |
341 | "get_user_%s" % username)) |
|
344 | "sql_cache_short", | |
|
345 | "get_user_%s" % _hash_key(username) | |||
|
346 | ) | |||
|
347 | ) | |||
342 | return q.scalar() |
|
348 | return q.scalar() | |
343 |
|
349 | |||
344 | @classmethod |
|
350 | @classmethod | |
@@ -394,7 +400,7 b' class UserLog(Base, BaseModel):' | |||||
394 | return datetime.date(*self.action_date.timetuple()[:3]) |
|
400 | return datetime.date(*self.action_date.timetuple()[:3]) | |
395 |
|
401 | |||
396 | user = relationship('User') |
|
402 | user = relationship('User') | |
397 | repository = relationship('Repository',cascade='') |
|
403 | repository = relationship('Repository', cascade='') | |
398 |
|
404 | |||
399 |
|
405 | |||
400 | class UsersGroup(Base, BaseModel): |
|
406 | class UsersGroup(Base, BaseModel): | |
@@ -406,6 +412,7 b' class UsersGroup(Base, BaseModel):' | |||||
406 | users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None) |
|
412 | users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None) | |
407 |
|
413 | |||
408 | members = relationship('UsersGroupMember', cascade="all, delete, delete-orphan", lazy="joined") |
|
414 | members = relationship('UsersGroupMember', cascade="all, delete, delete-orphan", lazy="joined") | |
|
415 | users_group_to_perm = relationship('UsersGroupToPerm', cascade='all') | |||
409 |
|
416 | |||
410 | def __repr__(self): |
|
417 | def __repr__(self): | |
411 | return '<userGroup(%s)>' % (self.users_group_name) |
|
418 | return '<userGroup(%s)>' % (self.users_group_name) | |
@@ -418,8 +425,11 b' class UsersGroup(Base, BaseModel):' | |||||
418 | else: |
|
425 | else: | |
419 | q = cls.query().filter(cls.users_group_name == group_name) |
|
426 | q = cls.query().filter(cls.users_group_name == group_name) | |
420 | if cache: |
|
427 | if cache: | |
421 |
q = q.options(FromCache( |
|
428 | q = q.options(FromCache( | |
422 | "get_user_%s" % group_name)) |
|
429 | "sql_cache_short", | |
|
430 | "get_user_%s" % _hash_key(group_name) | |||
|
431 | ) | |||
|
432 | ) | |||
423 | return q.scalar() |
|
433 | return q.scalar() | |
424 |
|
434 | |||
425 | @classmethod |
|
435 | @classmethod | |
@@ -748,8 +758,11 b' class RepoGroup(Base, BaseModel):' | |||||
748 | gr = cls.query()\ |
|
758 | gr = cls.query()\ | |
749 | .filter(cls.group_name == group_name) |
|
759 | .filter(cls.group_name == group_name) | |
750 | if cache: |
|
760 | if cache: | |
751 |
gr = gr.options(FromCache( |
|
761 | gr = gr.options(FromCache( | |
752 | "get_group_%s" % group_name)) |
|
762 | "sql_cache_short", | |
|
763 | "get_group_%s" % _hash_key(group_name) | |||
|
764 | ) | |||
|
765 | ) | |||
753 | return gr.scalar() |
|
766 | return gr.scalar() | |
754 |
|
767 | |||
755 | @property |
|
768 | @property | |
@@ -1038,7 +1051,7 b' class CacheInvalidation(Base, BaseModel)' | |||||
1038 | prefix = '' |
|
1051 | prefix = '' | |
1039 | iid = rhodecode.CONFIG.get('instance_id') |
|
1052 | iid = rhodecode.CONFIG.get('instance_id') | |
1040 | if iid: |
|
1053 | if iid: | |
1041 |
prefix = iid |
|
1054 | prefix = iid | |
1042 | return "%s%s" % (prefix, key) |
|
1055 | return "%s%s" % (prefix, key) | |
1043 |
|
1056 | |||
1044 | @classmethod |
|
1057 | @classmethod |
@@ -345,32 +345,46 b' def SlugifyName():' | |||||
345 |
|
345 | |||
346 |
|
346 | |||
347 | def ValidCloneUri(): |
|
347 | def ValidCloneUri(): | |
348 | from mercurial.httprepo import httprepository, httpsrepository |
|
|||
349 | from rhodecode.lib.utils import make_ui |
|
348 | from rhodecode.lib.utils import make_ui | |
350 |
|
349 | |||
|
350 | def url_handler(repo_type, url, proto, ui=None): | |||
|
351 | if repo_type == 'hg': | |||
|
352 | from mercurial.httprepo import httprepository, httpsrepository | |||
|
353 | if proto == 'https': | |||
|
354 | httpsrepository(make_ui('db'), url).capabilities | |||
|
355 | elif proto == 'http': | |||
|
356 | httprepository(make_ui('db'), url).capabilities | |||
|
357 | elif repo_type == 'git': | |||
|
358 | #TODO: write a git url validator | |||
|
359 | pass | |||
|
360 | ||||
351 | class _ValidCloneUri(formencode.validators.FancyValidator): |
|
361 | class _ValidCloneUri(formencode.validators.FancyValidator): | |
352 |
|
362 | |||
353 | def to_python(self, value, state): |
|
363 | def to_python(self, value, state): | |
354 | if not value: |
|
364 | ||
|
365 | repo_type = value.get('repo_type') | |||
|
366 | url = value.get('clone_uri') | |||
|
367 | e_dict = {'clone_uri': _('invalid clone url')} | |||
|
368 | ||||
|
369 | if not url: | |||
355 | pass |
|
370 | pass | |
356 |
elif |
|
371 | elif url.startswith('https'): | |
357 | try: |
|
372 | try: | |
358 | httpsrepository(make_ui('db'), value).capabilities |
|
373 | url_handler(repo_type, url, 'https', make_ui('db')) | |
359 | except Exception: |
|
374 | except Exception: | |
360 | log.error(traceback.format_exc()) |
|
375 | log.error(traceback.format_exc()) | |
361 |
raise formencode.Invalid( |
|
376 | raise formencode.Invalid('', value, state, error_dict=e_dict) | |
362 | state) |
|
377 | elif url.startswith('http'): | |
363 | elif value.startswith('http'): |
|
|||
364 | try: |
|
378 | try: | |
365 | httprepository(make_ui('db'), value).capabilities |
|
379 | url_handler(repo_type, url, 'http', make_ui('db')) | |
366 | except Exception: |
|
380 | except Exception: | |
367 | log.error(traceback.format_exc()) |
|
381 | log.error(traceback.format_exc()) | |
368 |
raise formencode.Invalid( |
|
382 | raise formencode.Invalid('', value, state, error_dict=e_dict) | |
369 | state) |
|
|||
370 | else: |
|
383 | else: | |
371 |
|
|
384 | e_dict = {'clone_uri': _('Invalid clone url, provide a ' | |
372 |
|
|
385 | 'valid clone http\s url')} | |
373 | state) |
|
386 | raise formencode.Invalid('', value, state, error_dict=e_dict) | |
|
387 | ||||
374 | return value |
|
388 | return value | |
375 |
|
389 | |||
376 | return _ValidCloneUri |
|
390 | return _ValidCloneUri | |
@@ -645,8 +659,7 b' def RepoForm(edit=False, old_data={}, su' | |||||
645 | filter_extra_fields = False |
|
659 | filter_extra_fields = False | |
646 | repo_name = All(UnicodeString(strip=True, min=1, not_empty=True), |
|
660 | repo_name = All(UnicodeString(strip=True, min=1, not_empty=True), | |
647 | SlugifyName()) |
|
661 | SlugifyName()) | |
648 |
clone_uri = All(UnicodeString(strip=True, min=1, not_empty=False) |
|
662 | clone_uri = All(UnicodeString(strip=True, min=1, not_empty=False)) | |
649 | ValidCloneUri()()) |
|
|||
650 | repo_group = OneOf(repo_groups, hideList=True) |
|
663 | repo_group = OneOf(repo_groups, hideList=True) | |
651 | repo_type = OneOf(supported_backends) |
|
664 | repo_type = OneOf(supported_backends) | |
652 | description = UnicodeString(strip=True, min=1, not_empty=True) |
|
665 | description = UnicodeString(strip=True, min=1, not_empty=True) | |
@@ -658,7 +671,9 b' def RepoForm(edit=False, old_data={}, su' | |||||
658 | #this is repo owner |
|
671 | #this is repo owner | |
659 | user = All(UnicodeString(not_empty=True), ValidRepoUser) |
|
672 | user = All(UnicodeString(not_empty=True), ValidRepoUser) | |
660 |
|
673 | |||
661 |
chained_validators = [Valid |
|
674 | chained_validators = [ValidCloneUri()(), | |
|
675 | ValidRepoName(edit, old_data), | |||
|
676 | ValidPerms()] | |||
662 | return _RepoForm |
|
677 | return _RepoForm | |
663 |
|
678 | |||
664 |
|
679 |
@@ -187,20 +187,20 b' class ReposGroupModel(BaseModel):' | |||||
187 | # change properties |
|
187 | # change properties | |
188 | repos_group.group_description = form_data['group_description'] |
|
188 | repos_group.group_description = form_data['group_description'] | |
189 | repos_group.parent_group = RepoGroup.get(form_data['group_parent_id']) |
|
189 | repos_group.parent_group = RepoGroup.get(form_data['group_parent_id']) | |
|
190 | repos_group.group_parent_id = form_data['group_parent_id'] | |||
190 | repos_group.group_name = repos_group.get_new_name(form_data['group_name']) |
|
191 | repos_group.group_name = repos_group.get_new_name(form_data['group_name']) | |
191 |
|
||||
192 | new_path = repos_group.full_path |
|
192 | new_path = repos_group.full_path | |
193 |
|
193 | |||
194 | self.sa.add(repos_group) |
|
194 | self.sa.add(repos_group) | |
195 |
|
195 | |||
196 | self.__rename_group(old_path, new_path) |
|
|||
197 |
|
||||
198 | # we need to get all repositories from this new group and |
|
196 | # we need to get all repositories from this new group and | |
199 | # rename them accordingly to new group path |
|
197 | # rename them accordingly to new group path | |
200 | for r in repos_group.repositories: |
|
198 | for r in repos_group.repositories: | |
201 | r.repo_name = r.get_new_name(r.just_name) |
|
199 | r.repo_name = r.get_new_name(r.just_name) | |
202 | self.sa.add(r) |
|
200 | self.sa.add(r) | |
203 |
|
201 | |||
|
202 | self.__rename_group(old_path, new_path) | |||
|
203 | ||||
204 | return repos_group |
|
204 | return repos_group | |
205 | except: |
|
205 | except: | |
206 | log.error(traceback.format_exc()) |
|
206 | log.error(traceback.format_exc()) |
@@ -1,8 +1,9 b'' | |||||
1 | from rhodecode.tests import * |
|
1 | from rhodecode.tests import * | |
2 | from rhodecode.model.db import UsersGroup |
|
2 | from rhodecode.model.db import UsersGroup, UsersGroupToPerm, Permission | |
3 |
|
3 | |||
4 | TEST_USERS_GROUP = 'admins_test' |
|
4 | TEST_USERS_GROUP = 'admins_test' | |
5 |
|
5 | |||
|
6 | ||||
6 | class TestAdminUsersGroupsController(TestController): |
|
7 | class TestAdminUsersGroupsController(TestController): | |
7 |
|
8 | |||
8 | def test_index(self): |
|
9 | def test_index(self): | |
@@ -16,7 +17,7 b' class TestAdminUsersGroupsController(Tes' | |||||
16 | self.log_user() |
|
17 | self.log_user() | |
17 | users_group_name = TEST_USERS_GROUP |
|
18 | users_group_name = TEST_USERS_GROUP | |
18 | response = self.app.post(url('users_groups'), |
|
19 | response = self.app.post(url('users_groups'), | |
19 | {'users_group_name':users_group_name, |
|
20 | {'users_group_name': users_group_name, | |
20 | 'active':True}) |
|
21 | 'active':True}) | |
21 | response.follow() |
|
22 | response.follow() | |
22 |
|
23 | |||
@@ -47,7 +48,6 b' class TestAdminUsersGroupsController(Tes' | |||||
47 | self.checkSessionFlash(response, |
|
48 | self.checkSessionFlash(response, | |
48 | 'created users group %s' % users_group_name) |
|
49 | 'created users group %s' % users_group_name) | |
49 |
|
50 | |||
50 |
|
||||
51 | gr = self.Session.query(UsersGroup)\ |
|
51 | gr = self.Session.query(UsersGroup)\ | |
52 | .filter(UsersGroup.users_group_name == |
|
52 | .filter(UsersGroup.users_group_name == | |
53 | users_group_name).one() |
|
53 | users_group_name).one() | |
@@ -60,6 +60,53 b' class TestAdminUsersGroupsController(Tes' | |||||
60 |
|
60 | |||
61 | self.assertEqual(gr, None) |
|
61 | self.assertEqual(gr, None) | |
62 |
|
62 | |||
|
63 | def test_enable_repository_read_on_group(self): | |||
|
64 | self.log_user() | |||
|
65 | users_group_name = TEST_USERS_GROUP + 'another2' | |||
|
66 | response = self.app.post(url('users_groups'), | |||
|
67 | {'users_group_name': users_group_name, | |||
|
68 | 'active':True}) | |||
|
69 | response.follow() | |||
|
70 | ||||
|
71 | ug = UsersGroup.get_by_group_name(users_group_name) | |||
|
72 | self.checkSessionFlash(response, | |||
|
73 | 'created users group %s' % users_group_name) | |||
|
74 | ||||
|
75 | response = self.app.put(url('users_group_perm', id=ug.users_group_id), | |||
|
76 | {'create_repo_perm': True}) | |||
|
77 | ||||
|
78 | response.follow() | |||
|
79 | ug = UsersGroup.get_by_group_name(users_group_name) | |||
|
80 | p = Permission.get_by_key('hg.create.repository') | |||
|
81 | # check if user has this perm | |||
|
82 | perms = UsersGroupToPerm.query()\ | |||
|
83 | .filter(UsersGroupToPerm.users_group == ug).all() | |||
|
84 | perms = [[x.__dict__['users_group_id'], | |||
|
85 | x.__dict__['permission_id'],] for x in perms] | |||
|
86 | self.assertEqual( | |||
|
87 | perms, | |||
|
88 | [[ug.users_group_id, p.permission_id]] | |||
|
89 | ) | |||
|
90 | ||||
|
91 | # DELETE ! | |||
|
92 | ug = UsersGroup.get_by_group_name(users_group_name) | |||
|
93 | ugid = ug.users_group_id | |||
|
94 | response = self.app.delete(url('users_group', id=ug.users_group_id)) | |||
|
95 | response = response.follow() | |||
|
96 | gr = self.Session.query(UsersGroup)\ | |||
|
97 | .filter(UsersGroup.users_group_name == | |||
|
98 | users_group_name).scalar() | |||
|
99 | ||||
|
100 | self.assertEqual(gr, None) | |||
|
101 | p = Permission.get_by_key('hg.create.repository') | |||
|
102 | perms = UsersGroupToPerm.query()\ | |||
|
103 | .filter(UsersGroupToPerm.users_group_id == ugid).all() | |||
|
104 | perms = [[x.__dict__['users_group_id'], | |||
|
105 | x.__dict__['permission_id'],] for x in perms] | |||
|
106 | self.assertEqual( | |||
|
107 | perms, | |||
|
108 | [] | |||
|
109 | ) | |||
63 |
|
110 | |||
64 | def test_delete_browser_fakeout(self): |
|
111 | def test_delete_browser_fakeout(self): | |
65 | response = self.app.post(url('users_group', id=1), |
|
112 | response = self.app.post(url('users_group', id=1), |
@@ -23,7 +23,6 b" def _make_group(path, desc='desc', paren" | |||||
23 | return gr |
|
23 | return gr | |
24 |
|
24 | |||
25 | gr = ReposGroupModel().create(path, desc, parent_id) |
|
25 | gr = ReposGroupModel().create(path, desc, parent_id) | |
26 | Session.commit() |
|
|||
27 | return gr |
|
26 | return gr | |
28 |
|
27 | |||
29 |
|
28 | |||
@@ -31,13 +30,19 b' class TestReposGroups(unittest.TestCase)' | |||||
31 |
|
30 | |||
32 | def setUp(self): |
|
31 | def setUp(self): | |
33 | self.g1 = _make_group('test1', skip_if_exists=True) |
|
32 | self.g1 = _make_group('test1', skip_if_exists=True) | |
|
33 | Session.commit() | |||
34 | self.g2 = _make_group('test2', skip_if_exists=True) |
|
34 | self.g2 = _make_group('test2', skip_if_exists=True) | |
|
35 | Session.commit() | |||
35 | self.g3 = _make_group('test3', skip_if_exists=True) |
|
36 | self.g3 = _make_group('test3', skip_if_exists=True) | |
|
37 | Session.commit() | |||
36 |
|
38 | |||
37 | def tearDown(self): |
|
39 | def tearDown(self): | |
38 | print 'out' |
|
40 | print 'out' | |
39 |
|
41 | |||
40 | def __check_path(self, *path): |
|
42 | def __check_path(self, *path): | |
|
43 | """ | |||
|
44 | Checks the path for existance ! | |||
|
45 | """ | |||
41 | path = [TESTS_TMP_PATH] + list(path) |
|
46 | path = [TESTS_TMP_PATH] + list(path) | |
42 | path = os.path.join(*path) |
|
47 | path = os.path.join(*path) | |
43 | return os.path.isdir(path) |
|
48 | return os.path.isdir(path) | |
@@ -49,12 +54,13 b' class TestReposGroups(unittest.TestCase)' | |||||
49 | ReposGroupModel().delete(id_) |
|
54 | ReposGroupModel().delete(id_) | |
50 |
|
55 | |||
51 | def __update_group(self, id_, path, desc='desc', parent_id=None): |
|
56 | def __update_group(self, id_, path, desc='desc', parent_id=None): | |
52 |
form_data = dict( |
|
57 | form_data = dict( | |
53 | group_description=desc, |
|
58 | group_name=path, | |
54 | group_parent_id=parent_id, |
|
59 | group_description=desc, | |
55 | perms_updates=[], |
|
60 | group_parent_id=parent_id, | |
56 |
|
|
61 | perms_updates=[], | |
57 |
|
62 | perms_new=[] | ||
|
63 | ) | |||
58 | gr = ReposGroupModel().update(id_, form_data) |
|
64 | gr = ReposGroupModel().update(id_, form_data) | |
59 | return gr |
|
65 | return gr | |
60 |
|
66 | |||
@@ -150,6 +156,25 b' class TestReposGroups(unittest.TestCase)' | |||||
150 | self.assertEqual(r.repo_name, os.path.join('g2', 'g1', r.just_name)) |
|
156 | self.assertEqual(r.repo_name, os.path.join('g2', 'g1', r.just_name)) | |
151 |
|
157 | |||
152 |
|
158 | |||
|
159 | def test_move_to_root(self): | |||
|
160 | g1 = _make_group('t11') | |||
|
161 | Session.commit() | |||
|
162 | g2 = _make_group('t22',parent_id=g1.group_id) | |||
|
163 | Session.commit() | |||
|
164 | ||||
|
165 | self.assertEqual(g2.full_path,'t11/t22') | |||
|
166 | self.assertTrue(self.__check_path('t11', 't22')) | |||
|
167 | ||||
|
168 | g2 = self.__update_group(g2.group_id, 'g22', parent_id=None) | |||
|
169 | Session.commit() | |||
|
170 | ||||
|
171 | self.assertEqual(g2.group_name,'g22') | |||
|
172 | # we moved out group from t1 to '' so it's full path should be 'g2' | |||
|
173 | self.assertEqual(g2.full_path,'g22') | |||
|
174 | self.assertFalse(self.__check_path('t11', 't22')) | |||
|
175 | self.assertTrue(self.__check_path('g22')) | |||
|
176 | ||||
|
177 | ||||
153 | class TestUser(unittest.TestCase): |
|
178 | class TestUser(unittest.TestCase): | |
154 | def __init__(self, methodName='runTest'): |
|
179 | def __init__(self, methodName='runTest'): | |
155 | Session.remove() |
|
180 | Session.remove() |
General Comments 0
You need to be logged in to leave comments.
Login now