##// END OF EJS Templates
Permissions on group can be set in recursive mode setting defined permission to all children...
marcink -
r2820:c0cc8f8a beta
parent child Browse files
Show More
@@ -0,0 +1,116 b''
1 import os
2 import unittest
3 import functools
4 from rhodecode.tests import *
5
6
7 from rhodecode.model.repos_group import ReposGroupModel
8 from rhodecode.model.repo import RepoModel
9 from rhodecode.model.db import RepoGroup, Repository, User
10 from rhodecode.model.user import UserModel
11
12 from rhodecode.lib.auth import AuthUser
13 from rhodecode.model.meta import Session
14
15
16 def _make_group(path, desc='desc', parent_id=None,
17 skip_if_exists=False):
18
19 gr = RepoGroup.get_by_group_name(path)
20 if gr and skip_if_exists:
21 return gr
22 if isinstance(parent_id, RepoGroup):
23 parent_id = parent_id.group_id
24 gr = ReposGroupModel().create(path, desc, parent_id)
25 return gr
26
27
28 def _make_repo(name, repos_group=None, repo_type='hg'):
29 return RepoModel().create_repo(name, repo_type, 'desc',
30 TEST_USER_ADMIN_LOGIN,
31 repos_group=repos_group)
32
33
34 def _destroy_project_tree(test_u1_id):
35 Session.remove()
36 repos_group = RepoGroup.get_by_group_name(group_name='g0')
37 for el in reversed(repos_group.recursive_groups_and_repos()):
38 if isinstance(el, Repository):
39 RepoModel().delete(el)
40 elif isinstance(el, RepoGroup):
41 ReposGroupModel().delete(el, force_delete=True)
42
43 u = User.get(test_u1_id)
44 Session().delete(u)
45 Session().commit()
46
47
48 def _create_project_tree():
49 """
50 Creates a tree of groups and repositories to test permissions
51
52 structure
53 [g0] - group `g0` with 3 subgroups
54 |
55 |__[g0_1] group g0_1 with 2 groups 0 repos
56 | |
57 | |__[g0_1_1] group g0_1_1 with 1 group 2 repos
58 | | |__<g0/g0_1/g0_1_1/g0_1_1_r1>
59 | | |__<g0/g0_1/g0_1_1/g0_1_1_r2>
60 | |__<g0/g0_1/g0_1_r1>
61 |
62 |__[g0_2] 2 repos
63 | |
64 | |__<g0/g0_2/g0_2_r1>
65 | |__<g0/g0_2/g0_2_r2>
66 |
67 |__[g0_3] 1 repo
68 |
69 |_<g0/g0_3/g0_3_r1>
70
71 """
72 test_u1 = UserModel().create_or_update(
73 username=u'test_u1', password=u'qweqwe',
74 email=u'test_u1@rhodecode.org', firstname=u'test_u1', lastname=u'test_u1'
75 )
76 g0 = _make_group('g0')
77 g0_1 = _make_group('g0_1', parent_id=g0)
78 g0_1_1 = _make_group('g0_1_1', parent_id=g0_1)
79 g0_1_1_r1 = _make_repo('g0/g0_1/g0_1_1/g0_1_1_r1', repos_group=g0_1_1)
80 g0_1_1_r2 = _make_repo('g0/g0_1/g0_1_1/g0_1_1_r2', repos_group=g0_1_1)
81 g0_1_r1 = _make_repo('g0/g0_1/g0_1_r1', repos_group=g0_1)
82 g0_2 = _make_group('g0_2', parent_id=g0)
83 g0_2_r1 = _make_repo('g0/g0_2/g0_2_r1', repos_group=g0_2)
84 g0_2_r2 = _make_repo('g0/g0_2/g0_2_r2', repos_group=g0_2)
85 g0_3 = _make_group('g0_3', parent_id=g0)
86 g0_3_r1 = _make_repo('g0/g0_3/g0_3_r1', repos_group=g0_3)
87 return test_u1
88
89
90 def expected_count(group_name, objects=False):
91 repos_group = RepoGroup.get_by_group_name(group_name=group_name)
92 objs = repos_group.recursive_groups_and_repos()
93 if objects:
94 return objs
95 return len(objs)
96
97
98 def _check_expected_count(items, repo_items, expected):
99 should_be = len(items + repo_items)
100 there_are = len(expected)
101 assert should_be == there_are, ('%s != %s' % ((items + repo_items), expected))
102
103
104 def check_tree_perms(obj_name, repo_perm, prefix, expected_perm):
105 assert repo_perm == expected_perm, ('obj:`%s` got perm:`%s` should:`%s`'
106 % (obj_name, repo_perm, expected_perm))
107
108
109 def _get_perms(filter_='', recursive=True, key=None, test_u1_id=None):
110 test_u1 = AuthUser(user_id=test_u1_id)
111 for k, v in test_u1.permissions[key].items():
112 if recursive and k.startswith(filter_):
113 yield k, v
114 elif not recursive:
115 if k == filter_:
116 yield k, v
@@ -0,0 +1,161 b''
1 import os
2 import unittest
3 import functools
4 from rhodecode.tests import *
5
6 from rhodecode.model.repos_group import ReposGroupModel
7 from rhodecode.model.db import RepoGroup, Repository, User
8
9 from rhodecode.model.meta import Session
10 from nose.tools import with_setup
11 from rhodecode.tests.models.common import _create_project_tree, check_tree_perms, \
12 _get_perms, _check_expected_count, expected_count, _destroy_project_tree
13 from rhodecode.model.repo import RepoModel
14
15
16 test_u1_id = None
17 _get_repo_perms = None
18 _get_group_perms = None
19
20
21 def permissions_setup_func(group_name='g0', perm='group.read', recursive=True):
22 """
23 Resets all permissions to perm attribute
24 """
25 repos_group = RepoGroup.get_by_group_name(group_name=group_name)
26 if not repos_group:
27 raise Exception('Cannot get group %s' % group_name)
28 perms_updates = [[test_u1_id, perm, 'user']]
29 ReposGroupModel()._update_permissions(repos_group,
30 perms_updates=perms_updates,
31 recursive=recursive)
32 Session().commit()
33
34
35 def setup_module():
36 global test_u1_id, _get_repo_perms, _get_group_perms
37 test_u1 = _create_project_tree()
38 Session().commit()
39 test_u1_id = test_u1.user_id
40 _get_repo_perms = functools.partial(_get_perms, key='repositories',
41 test_u1_id=test_u1_id)
42 _get_group_perms = functools.partial(_get_perms, key='repositories_groups',
43 test_u1_id=test_u1_id)
44
45
46 def teardown_module():
47 _destroy_project_tree(test_u1_id)
48
49
50 @with_setup(permissions_setup_func)
51 def test_user_permissions_on_group_without_recursive_mode():
52 # set permission to g0 non-recursive mode
53 recursive = False
54 group = 'g0'
55 permissions_setup_func(group, 'group.write', recursive=recursive)
56
57 items = [x for x in _get_repo_perms(group, recursive)]
58 expected = 0
59 assert len(items) == expected, ' %s != %s' % (len(items), expected)
60 for name, perm in items:
61 yield check_tree_perms, name, perm, group, 'repository.read'
62
63 items = [x for x in _get_group_perms(group, recursive)]
64 expected = 1
65 assert len(items) == expected, ' %s != %s' % (len(items), expected)
66 for name, perm in items:
67 yield check_tree_perms, name, perm, group, 'group.write'
68
69
70 @with_setup(permissions_setup_func)
71 def test_user_permissions_on_group_without_recursive_mode_subgroup():
72 # set permission to g0 non-recursive mode
73 recursive = False
74 group = 'g0/g0_1'
75 permissions_setup_func(group, 'group.write', recursive=recursive)
76
77 items = [x for x in _get_repo_perms(group, recursive)]
78 expected = 0
79 assert len(items) == expected, ' %s != %s' % (len(items), expected)
80 for name, perm in items:
81 yield check_tree_perms, name, perm, group, 'repository.read'
82
83 items = [x for x in _get_group_perms(group, recursive)]
84 expected = 1
85 assert len(items) == expected, ' %s != %s' % (len(items), expected)
86 for name, perm in items:
87 yield check_tree_perms, name, perm, group, 'group.write'
88
89
90 @with_setup(permissions_setup_func)
91 def test_user_permissions_on_group_with_recursive_mode():
92
93 # set permission to g0 recursive mode, all children including
94 # other repos and groups should have this permission now set !
95 recursive = True
96 group = 'g0'
97 permissions_setup_func(group, 'group.write', recursive=recursive)
98
99 repo_items = [x for x in _get_repo_perms(group, recursive)]
100 items = [x for x in _get_group_perms(group, recursive)]
101 _check_expected_count(items, repo_items, expected_count(group, True))
102
103 for name, perm in repo_items:
104 yield check_tree_perms, name, perm, group, 'repository.write'
105
106 for name, perm in items:
107 yield check_tree_perms, name, perm, group, 'group.write'
108
109
110 @with_setup(permissions_setup_func)
111 def test_user_permissions_on_group_with_recursive_mode_inner_group():
112 ## set permission to g0_3 group to none
113 recursive = True
114 group = 'g0/g0_3'
115 permissions_setup_func(group, 'group.none', recursive=recursive)
116
117 repo_items = [x for x in _get_repo_perms(group, recursive)]
118 items = [x for x in _get_group_perms(group, recursive)]
119 _check_expected_count(items, repo_items, expected_count(group, True))
120
121 for name, perm in repo_items:
122 yield check_tree_perms, name, perm, group, 'repository.none'
123
124 for name, perm in items:
125 yield check_tree_perms, name, perm, group, 'group.none'
126
127
128 @with_setup(permissions_setup_func)
129 def test_user_permissions_on_group_with_recursive_mode_deepest():
130 ## set permission to g0_3 group to none
131 recursive = True
132 group = 'g0/g0_1/g0_1_1'
133 permissions_setup_func(group, 'group.write', recursive=recursive)
134
135 repo_items = [x for x in _get_repo_perms(group, recursive)]
136 items = [x for x in _get_group_perms(group, recursive)]
137 _check_expected_count(items, repo_items, expected_count(group, True))
138
139 for name, perm in repo_items:
140 yield check_tree_perms, name, perm, group, 'repository.write'
141
142 for name, perm in items:
143 yield check_tree_perms, name, perm, group, 'group.write'
144
145
146 @with_setup(permissions_setup_func)
147 def test_user_permissions_on_group_with_recursive_mode_only_with_repos():
148 ## set permission to g0_3 group to none
149 recursive = True
150 group = 'g0/g0_2'
151 permissions_setup_func(group, 'group.admin', recursive=recursive)
152
153 repo_items = [x for x in _get_repo_perms(group, recursive)]
154 items = [x for x in _get_group_perms(group, recursive)]
155 _check_expected_count(items, repo_items, expected_count(group, True))
156
157 for name, perm in repo_items:
158 yield check_tree_perms, name, perm, group, 'repository.admin'
159
160 for name, perm in items:
161 yield check_tree_perms, name, perm, group, 'group.admin'
@@ -0,0 +1,170 b''
1 import os
2 import unittest
3 import functools
4 from rhodecode.tests import *
5
6 from rhodecode.model.repos_group import ReposGroupModel
7 from rhodecode.model.db import RepoGroup, Repository, User
8
9 from rhodecode.model.meta import Session
10 from nose.tools import with_setup
11 from rhodecode.tests.models.common import _create_project_tree, check_tree_perms, \
12 _get_perms, _check_expected_count, expected_count, _destroy_project_tree
13 from rhodecode.model.users_group import UsersGroupModel
14 from rhodecode.model.repo import RepoModel
15
16
17 test_u2_id = None
18 test_u2_gr_id = None
19 _get_repo_perms = None
20 _get_group_perms = None
21
22
23 def permissions_setup_func(group_name='g0', perm='group.read', recursive=True):
24 """
25 Resets all permissions to perm attribute
26 """
27 repos_group = RepoGroup.get_by_group_name(group_name=group_name)
28 if not repos_group:
29 raise Exception('Cannot get group %s' % group_name)
30 perms_updates = [[test_u2_gr_id, perm, 'users_group']]
31 ReposGroupModel()._update_permissions(repos_group,
32 perms_updates=perms_updates,
33 recursive=recursive)
34 Session().commit()
35
36
37 def setup_module():
38 global test_u2_id, test_u2_gr_id, _get_repo_perms, _get_group_perms
39 test_u2 = _create_project_tree()
40 Session().commit()
41 test_u2_id = test_u2.user_id
42
43 gr1 = UsersGroupModel().create(name='perms_group_1')
44 Session().commit()
45 test_u2_gr_id = gr1.users_group_id
46 UsersGroupModel().add_user_to_group(gr1, user=test_u2_id)
47 Session().commit()
48
49 _get_repo_perms = functools.partial(_get_perms, key='repositories',
50 test_u1_id=test_u2_id)
51 _get_group_perms = functools.partial(_get_perms, key='repositories_groups',
52 test_u1_id=test_u2_id)
53
54
55 def teardown_module():
56 _destroy_project_tree(test_u2_id)
57
58
59 @with_setup(permissions_setup_func)
60 def test_user_permissions_on_group_without_recursive_mode():
61 # set permission to g0 non-recursive mode
62 recursive = False
63 group = 'g0'
64 permissions_setup_func(group, 'group.write', recursive=recursive)
65
66 items = [x for x in _get_repo_perms(group, recursive)]
67 expected = 0
68 assert len(items) == expected, ' %s != %s' % (len(items), expected)
69 for name, perm in items:
70 yield check_tree_perms, name, perm, group, 'repository.read'
71
72 items = [x for x in _get_group_perms(group, recursive)]
73 expected = 1
74 assert len(items) == expected, ' %s != %s' % (len(items), expected)
75 for name, perm in items:
76 yield check_tree_perms, name, perm, group, 'group.write'
77
78
79 @with_setup(permissions_setup_func)
80 def test_user_permissions_on_group_without_recursive_mode_subgroup():
81 # set permission to g0 non-recursive mode
82 recursive = False
83 group = 'g0/g0_1'
84 permissions_setup_func(group, 'group.write', recursive=recursive)
85
86 items = [x for x in _get_repo_perms(group, recursive)]
87 expected = 0
88 assert len(items) == expected, ' %s != %s' % (len(items), expected)
89 for name, perm in items:
90 yield check_tree_perms, name, perm, group, 'repository.read'
91
92 items = [x for x in _get_group_perms(group, recursive)]
93 expected = 1
94 assert len(items) == expected, ' %s != %s' % (len(items), expected)
95 for name, perm in items:
96 yield check_tree_perms, name, perm, group, 'group.write'
97
98
99 @with_setup(permissions_setup_func)
100 def test_user_permissions_on_group_with_recursive_mode():
101
102 # set permission to g0 recursive mode, all children including
103 # other repos and groups should have this permission now set !
104 recursive = True
105 group = 'g0'
106 permissions_setup_func(group, 'group.write', recursive=recursive)
107
108 repo_items = [x for x in _get_repo_perms(group, recursive)]
109 items = [x for x in _get_group_perms(group, recursive)]
110 _check_expected_count(items, repo_items, expected_count(group, True))
111
112 for name, perm in repo_items:
113 yield check_tree_perms, name, perm, group, 'repository.write'
114
115 for name, perm in items:
116 yield check_tree_perms, name, perm, group, 'group.write'
117
118
119 @with_setup(permissions_setup_func)
120 def test_user_permissions_on_group_with_recursive_mode_inner_group():
121 ## set permission to g0_3 group to none
122 recursive = True
123 group = 'g0/g0_3'
124 permissions_setup_func(group, 'group.none', recursive=recursive)
125
126 repo_items = [x for x in _get_repo_perms(group, recursive)]
127 items = [x for x in _get_group_perms(group, recursive)]
128 _check_expected_count(items, repo_items, expected_count(group, True))
129
130 for name, perm in repo_items:
131 yield check_tree_perms, name, perm, group, 'repository.none'
132
133 for name, perm in items:
134 yield check_tree_perms, name, perm, group, 'group.none'
135
136
137 @with_setup(permissions_setup_func)
138 def test_user_permissions_on_group_with_recursive_mode_deepest():
139 ## set permission to g0_3 group to none
140 recursive = True
141 group = 'g0/g0_1/g0_1_1'
142 permissions_setup_func(group, 'group.write', recursive=recursive)
143
144 repo_items = [x for x in _get_repo_perms(group, recursive)]
145 items = [x for x in _get_group_perms(group, recursive)]
146 _check_expected_count(items, repo_items, expected_count(group, True))
147
148 for name, perm in repo_items:
149 yield check_tree_perms, name, perm, group, 'repository.write'
150
151 for name, perm in items:
152 yield check_tree_perms, name, perm, group, 'group.write'
153
154
155 @with_setup(permissions_setup_func)
156 def test_user_permissions_on_group_with_recursive_mode_only_with_repos():
157 ## set permission to g0_3 group to none
158 recursive = True
159 group = 'g0/g0_2'
160 permissions_setup_func(group, 'group.admin', recursive=recursive)
161
162 repo_items = [x for x in _get_repo_perms(group, recursive)]
163 items = [x for x in _get_group_perms(group, recursive)]
164 _check_expected_count(items, repo_items, expected_count(group, True))
165
166 for name, perm in repo_items:
167 yield check_tree_perms, name, perm, group, 'repository.admin'
168
169 for name, perm in items:
170 yield check_tree_perms, name, perm, group, 'group.admin'
@@ -1,314 +1,317 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.admin.repos_groups
3 rhodecode.controllers.admin.repos_groups
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Repositories groups controller for RhodeCode
6 Repositories groups controller for RhodeCode
7
7
8 :created_on: Mar 23, 2010
8 :created_on: Mar 23, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import logging
26 import logging
27 import traceback
27 import traceback
28 import formencode
28 import formencode
29
29
30 from formencode import htmlfill
30 from formencode import htmlfill
31
31
32 from pylons import request, tmpl_context as c, url
32 from pylons import request, tmpl_context as c, url
33 from pylons.controllers.util import redirect
33 from pylons.controllers.util import redirect
34 from pylons.i18n.translation import _
34 from pylons.i18n.translation import _
35
35
36 from sqlalchemy.exc import IntegrityError
36 from sqlalchemy.exc import IntegrityError
37
37
38 from rhodecode.lib import helpers as h
38 from rhodecode.lib import helpers as h
39 from rhodecode.lib.auth import LoginRequired, HasPermissionAnyDecorator,\
39 from rhodecode.lib.auth import LoginRequired, HasPermissionAnyDecorator,\
40 HasReposGroupPermissionAnyDecorator
40 HasReposGroupPermissionAnyDecorator
41 from rhodecode.lib.base import BaseController, render
41 from rhodecode.lib.base import BaseController, render
42 from rhodecode.model.db import RepoGroup
42 from rhodecode.model.db import RepoGroup
43 from rhodecode.model.repos_group import ReposGroupModel
43 from rhodecode.model.repos_group import ReposGroupModel
44 from rhodecode.model.forms import ReposGroupForm
44 from rhodecode.model.forms import ReposGroupForm
45 from rhodecode.model.meta import Session
45 from rhodecode.model.meta import Session
46 from rhodecode.model.repo import RepoModel
46 from rhodecode.model.repo import RepoModel
47 from webob.exc import HTTPInternalServerError, HTTPNotFound
47 from webob.exc import HTTPInternalServerError, HTTPNotFound
48 from rhodecode.lib.utils2 import str2bool
48
49
49 log = logging.getLogger(__name__)
50 log = logging.getLogger(__name__)
50
51
51
52
52 class ReposGroupsController(BaseController):
53 class ReposGroupsController(BaseController):
53 """REST Controller styled on the Atom Publishing Protocol"""
54 """REST Controller styled on the Atom Publishing Protocol"""
54 # To properly map this controller, ensure your config/routing.py
55 # To properly map this controller, ensure your config/routing.py
55 # file has a resource setup:
56 # file has a resource setup:
56 # map.resource('repos_group', 'repos_groups')
57 # map.resource('repos_group', 'repos_groups')
57
58
58 @LoginRequired()
59 @LoginRequired()
59 def __before__(self):
60 def __before__(self):
60 super(ReposGroupsController, self).__before__()
61 super(ReposGroupsController, self).__before__()
61
62
62 def __load_defaults(self):
63 def __load_defaults(self):
63 c.repo_groups = RepoGroup.groups_choices()
64 c.repo_groups = RepoGroup.groups_choices()
64 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
65 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
65
66
66 repo_model = RepoModel()
67 repo_model = RepoModel()
67 c.users_array = repo_model.get_users_js()
68 c.users_array = repo_model.get_users_js()
68 c.users_groups_array = repo_model.get_users_groups_js()
69 c.users_groups_array = repo_model.get_users_groups_js()
69
70
70 def __load_data(self, group_id):
71 def __load_data(self, group_id):
71 """
72 """
72 Load defaults settings for edit, and update
73 Load defaults settings for edit, and update
73
74
74 :param group_id:
75 :param group_id:
75 """
76 """
76 self.__load_defaults()
77 self.__load_defaults()
77 repo_group = RepoGroup.get_or_404(group_id)
78 repo_group = RepoGroup.get_or_404(group_id)
78 data = repo_group.get_dict()
79 data = repo_group.get_dict()
79 data['group_name'] = repo_group.name
80 data['group_name'] = repo_group.name
80
81
81 # fill repository users
82 # fill repository users
82 for p in repo_group.repo_group_to_perm:
83 for p in repo_group.repo_group_to_perm:
83 data.update({'u_perm_%s' % p.user.username:
84 data.update({'u_perm_%s' % p.user.username:
84 p.permission.permission_name})
85 p.permission.permission_name})
85
86
86 # fill repository groups
87 # fill repository groups
87 for p in repo_group.users_group_to_perm:
88 for p in repo_group.users_group_to_perm:
88 data.update({'g_perm_%s' % p.users_group.users_group_name:
89 data.update({'g_perm_%s' % p.users_group.users_group_name:
89 p.permission.permission_name})
90 p.permission.permission_name})
90
91
91 return data
92 return data
92
93
93 @HasPermissionAnyDecorator('hg.admin')
94 @HasPermissionAnyDecorator('hg.admin')
94 def index(self, format='html'):
95 def index(self, format='html'):
95 """GET /repos_groups: All items in the collection"""
96 """GET /repos_groups: All items in the collection"""
96 # url('repos_groups')
97 # url('repos_groups')
97 sk = lambda g: g.parents[0].group_name if g.parents else g.group_name
98 sk = lambda g: g.parents[0].group_name if g.parents else g.group_name
98 c.groups = sorted(RepoGroup.query().all(), key=sk)
99 c.groups = sorted(RepoGroup.query().all(), key=sk)
99 return render('admin/repos_groups/repos_groups_show.html')
100 return render('admin/repos_groups/repos_groups_show.html')
100
101
101 @HasPermissionAnyDecorator('hg.admin')
102 @HasPermissionAnyDecorator('hg.admin')
102 def create(self):
103 def create(self):
103 """POST /repos_groups: Create a new item"""
104 """POST /repos_groups: Create a new item"""
104 # url('repos_groups')
105 # url('repos_groups')
105 self.__load_defaults()
106 self.__load_defaults()
106 repos_group_form = ReposGroupForm(available_groups =
107 repos_group_form = ReposGroupForm(available_groups =
107 c.repo_groups_choices)()
108 c.repo_groups_choices)()
108 try:
109 try:
109 form_result = repos_group_form.to_python(dict(request.POST))
110 form_result = repos_group_form.to_python(dict(request.POST))
110 ReposGroupModel().create(
111 ReposGroupModel().create(
111 group_name=form_result['group_name'],
112 group_name=form_result['group_name'],
112 group_description=form_result['group_description'],
113 group_description=form_result['group_description'],
113 parent=form_result['group_parent_id']
114 parent=form_result['group_parent_id']
114 )
115 )
115 Session().commit()
116 Session().commit()
116 h.flash(_('created repos group %s') \
117 h.flash(_('created repos group %s') \
117 % form_result['group_name'], category='success')
118 % form_result['group_name'], category='success')
118 #TODO: in futureaction_logger(, '', '', '', self.sa)
119 #TODO: in futureaction_logger(, '', '', '', self.sa)
119 except formencode.Invalid, errors:
120 except formencode.Invalid, errors:
120
121
121 return htmlfill.render(
122 return htmlfill.render(
122 render('admin/repos_groups/repos_groups_add.html'),
123 render('admin/repos_groups/repos_groups_add.html'),
123 defaults=errors.value,
124 defaults=errors.value,
124 errors=errors.error_dict or {},
125 errors=errors.error_dict or {},
125 prefix_error=False,
126 prefix_error=False,
126 encoding="UTF-8")
127 encoding="UTF-8")
127 except Exception:
128 except Exception:
128 log.error(traceback.format_exc())
129 log.error(traceback.format_exc())
129 h.flash(_('error occurred during creation of repos group %s') \
130 h.flash(_('error occurred during creation of repos group %s') \
130 % request.POST.get('group_name'), category='error')
131 % request.POST.get('group_name'), category='error')
131
132
132 return redirect(url('repos_groups'))
133 return redirect(url('repos_groups'))
133
134
134 @HasPermissionAnyDecorator('hg.admin')
135 @HasPermissionAnyDecorator('hg.admin')
135 def new(self, format='html'):
136 def new(self, format='html'):
136 """GET /repos_groups/new: Form to create a new item"""
137 """GET /repos_groups/new: Form to create a new item"""
137 # url('new_repos_group')
138 # url('new_repos_group')
138 self.__load_defaults()
139 self.__load_defaults()
139 return render('admin/repos_groups/repos_groups_add.html')
140 return render('admin/repos_groups/repos_groups_add.html')
140
141
141 @HasPermissionAnyDecorator('hg.admin')
142 @HasPermissionAnyDecorator('hg.admin')
142 def update(self, id):
143 def update(self, id):
143 """PUT /repos_groups/id: Update an existing item"""
144 """PUT /repos_groups/id: Update an existing item"""
144 # Forms posted to this method should contain a hidden field:
145 # Forms posted to this method should contain a hidden field:
145 # <input type="hidden" name="_method" value="PUT" />
146 # <input type="hidden" name="_method" value="PUT" />
146 # Or using helpers:
147 # Or using helpers:
147 # h.form(url('repos_group', id=ID),
148 # h.form(url('repos_group', id=ID),
148 # method='put')
149 # method='put')
149 # url('repos_group', id=ID)
150 # url('repos_group', id=ID)
150
151
151 self.__load_defaults()
152 self.__load_defaults()
152 c.repos_group = RepoGroup.get(id)
153 c.repos_group = RepoGroup.get(id)
153
154
154 repos_group_form = ReposGroupForm(
155 repos_group_form = ReposGroupForm(
155 edit=True,
156 edit=True,
156 old_data=c.repos_group.get_dict(),
157 old_data=c.repos_group.get_dict(),
157 available_groups=c.repo_groups_choices
158 available_groups=c.repo_groups_choices
158 )()
159 )()
159 try:
160 try:
160 form_result = repos_group_form.to_python(dict(request.POST))
161 form_result = repos_group_form.to_python(dict(request.POST))
161 ReposGroupModel().update(id, form_result)
162 ReposGroupModel().update(id, form_result)
162 Session().commit()
163 Session().commit()
163 h.flash(_('updated repos group %s') \
164 h.flash(_('updated repos group %s') \
164 % form_result['group_name'], category='success')
165 % form_result['group_name'], category='success')
165 #TODO: in futureaction_logger(, '', '', '', self.sa)
166 #TODO: in future action_logger(, '', '', '', self.sa)
166 except formencode.Invalid, errors:
167 except formencode.Invalid, errors:
167
168
168 return htmlfill.render(
169 return htmlfill.render(
169 render('admin/repos_groups/repos_groups_edit.html'),
170 render('admin/repos_groups/repos_groups_edit.html'),
170 defaults=errors.value,
171 defaults=errors.value,
171 errors=errors.error_dict or {},
172 errors=errors.error_dict or {},
172 prefix_error=False,
173 prefix_error=False,
173 encoding="UTF-8")
174 encoding="UTF-8")
174 except Exception:
175 except Exception:
175 log.error(traceback.format_exc())
176 log.error(traceback.format_exc())
176 h.flash(_('error occurred during update of repos group %s') \
177 h.flash(_('error occurred during update of repos group %s') \
177 % request.POST.get('group_name'), category='error')
178 % request.POST.get('group_name'), category='error')
178
179
179 return redirect(url('edit_repos_group', id=id))
180 return redirect(url('edit_repos_group', id=id))
180
181
181 @HasPermissionAnyDecorator('hg.admin')
182 @HasPermissionAnyDecorator('hg.admin')
182 def delete(self, id):
183 def delete(self, id):
183 """DELETE /repos_groups/id: Delete an existing item"""
184 """DELETE /repos_groups/id: Delete an existing item"""
184 # Forms posted to this method should contain a hidden field:
185 # Forms posted to this method should contain a hidden field:
185 # <input type="hidden" name="_method" value="DELETE" />
186 # <input type="hidden" name="_method" value="DELETE" />
186 # Or using helpers:
187 # Or using helpers:
187 # h.form(url('repos_group', id=ID),
188 # h.form(url('repos_group', id=ID),
188 # method='delete')
189 # method='delete')
189 # url('repos_group', id=ID)
190 # url('repos_group', id=ID)
190
191
191 gr = RepoGroup.get(id)
192 gr = RepoGroup.get(id)
192 repos = gr.repositories.all()
193 repos = gr.repositories.all()
193 if repos:
194 if repos:
194 h.flash(_('This group contains %s repositores and cannot be '
195 h.flash(_('This group contains %s repositores and cannot be '
195 'deleted') % len(repos),
196 'deleted') % len(repos),
196 category='error')
197 category='error')
197 return redirect(url('repos_groups'))
198 return redirect(url('repos_groups'))
198
199
199 try:
200 try:
200 ReposGroupModel().delete(id)
201 ReposGroupModel().delete(id)
201 Session().commit()
202 Session().commit()
202 h.flash(_('removed repos group %s') % gr.group_name,
203 h.flash(_('removed repos group %s') % gr.group_name,
203 category='success')
204 category='success')
204 #TODO: in future action_logger(, '', '', '', self.sa)
205 #TODO: in future action_logger(, '', '', '', self.sa)
205 except IntegrityError, e:
206 except IntegrityError, e:
206 if str(e.message).find('groups_group_parent_id_fkey') != -1:
207 if str(e.message).find('groups_group_parent_id_fkey') != -1:
207 log.error(traceback.format_exc())
208 log.error(traceback.format_exc())
208 h.flash(_('Cannot delete this group it still contains '
209 h.flash(_('Cannot delete this group it still contains '
209 'subgroups'),
210 'subgroups'),
210 category='warning')
211 category='warning')
211 else:
212 else:
212 log.error(traceback.format_exc())
213 log.error(traceback.format_exc())
213 h.flash(_('error occurred during deletion of repos '
214 h.flash(_('error occurred during deletion of repos '
214 'group %s') % gr.group_name, category='error')
215 'group %s') % gr.group_name, category='error')
215
216
216 except Exception:
217 except Exception:
217 log.error(traceback.format_exc())
218 log.error(traceback.format_exc())
218 h.flash(_('error occurred during deletion of repos '
219 h.flash(_('error occurred during deletion of repos '
219 'group %s') % gr.group_name, category='error')
220 'group %s') % gr.group_name, category='error')
220
221
221 return redirect(url('repos_groups'))
222 return redirect(url('repos_groups'))
222
223
223 @HasReposGroupPermissionAnyDecorator('group.admin')
224 @HasReposGroupPermissionAnyDecorator('group.admin')
224 def delete_repos_group_user_perm(self, group_name):
225 def delete_repos_group_user_perm(self, group_name):
225 """
226 """
226 DELETE an existing repositories group permission user
227 DELETE an existing repositories group permission user
227
228
228 :param group_name:
229 :param group_name:
229 """
230 """
230
231 try:
231 try:
232 ReposGroupModel().revoke_user_permission(
232 recursive = str2bool(request.POST.get('recursive', False))
233 repos_group=group_name, user=request.POST['user_id']
233 ReposGroupModel().delete_permission(
234 repos_group=group_name, obj=request.POST['user_id'],
235 obj_type='user', recursive=recursive
234 )
236 )
235 Session().commit()
237 Session().commit()
236 except Exception:
238 except Exception:
237 log.error(traceback.format_exc())
239 log.error(traceback.format_exc())
238 h.flash(_('An error occurred during deletion of group user'),
240 h.flash(_('An error occurred during deletion of group user'),
239 category='error')
241 category='error')
240 raise HTTPInternalServerError()
242 raise HTTPInternalServerError()
241
243
242 @HasReposGroupPermissionAnyDecorator('group.admin')
244 @HasReposGroupPermissionAnyDecorator('group.admin')
243 def delete_repos_group_users_group_perm(self, group_name):
245 def delete_repos_group_users_group_perm(self, group_name):
244 """
246 """
245 DELETE an existing repositories group permission users group
247 DELETE an existing repositories group permission users group
246
248
247 :param group_name:
249 :param group_name:
248 """
250 """
249
251
250 try:
252 try:
251 ReposGroupModel().revoke_users_group_permission(
253 recursive = str2bool(request.POST.get('recursive', False))
252 repos_group=group_name,
254 ReposGroupModel().delete_permission(
253 group_name=request.POST['users_group_id']
255 repos_group=group_name, obj=request.POST['users_group_id'],
256 obj_type='users_group', recursive=recursive
254 )
257 )
255 Session().commit()
258 Session().commit()
256 except Exception:
259 except Exception:
257 log.error(traceback.format_exc())
260 log.error(traceback.format_exc())
258 h.flash(_('An error occurred during deletion of group'
261 h.flash(_('An error occurred during deletion of group'
259 ' users groups'),
262 ' users groups'),
260 category='error')
263 category='error')
261 raise HTTPInternalServerError()
264 raise HTTPInternalServerError()
262
265
263 def show_by_name(self, group_name):
266 def show_by_name(self, group_name):
264 """
267 """
265 This is a proxy that does a lookup group_name -> id, and shows
268 This is a proxy that does a lookup group_name -> id, and shows
266 the group by id view instead
269 the group by id view instead
267 """
270 """
268 group_name = group_name.rstrip('/')
271 group_name = group_name.rstrip('/')
269 id_ = RepoGroup.get_by_group_name(group_name)
272 id_ = RepoGroup.get_by_group_name(group_name)
270 if id_:
273 if id_:
271 return self.show(id_.group_id)
274 return self.show(id_.group_id)
272 raise HTTPNotFound
275 raise HTTPNotFound
273
276
274 @HasReposGroupPermissionAnyDecorator('group.read', 'group.write',
277 @HasReposGroupPermissionAnyDecorator('group.read', 'group.write',
275 'group.admin')
278 'group.admin')
276 def show(self, id, format='html'):
279 def show(self, id, format='html'):
277 """GET /repos_groups/id: Show a specific item"""
280 """GET /repos_groups/id: Show a specific item"""
278 # url('repos_group', id=ID)
281 # url('repos_group', id=ID)
279
282
280 c.group = RepoGroup.get_or_404(id)
283 c.group = RepoGroup.get_or_404(id)
281
284
282 c.group_repos = c.group.repositories.all()
285 c.group_repos = c.group.repositories.all()
283
286
284 #overwrite our cached list with current filter
287 #overwrite our cached list with current filter
285 gr_filter = c.group_repos
288 gr_filter = c.group_repos
286 c.cached_repo_list = self.scm_model.get_repos(all_repos=gr_filter)
289 c.cached_repo_list = self.scm_model.get_repos(all_repos=gr_filter)
287
290
288 c.repos_list = c.cached_repo_list
291 c.repos_list = c.cached_repo_list
289
292
290 c.repo_cnt = 0
293 c.repo_cnt = 0
291
294
292 c.groups = RepoGroup.query().order_by(RepoGroup.group_name)\
295 c.groups = RepoGroup.query().order_by(RepoGroup.group_name)\
293 .filter(RepoGroup.group_parent_id == id).all()
296 .filter(RepoGroup.group_parent_id == id).all()
294
297
295 return render('admin/repos_groups/repos_groups.html')
298 return render('admin/repos_groups/repos_groups.html')
296
299
297 @HasPermissionAnyDecorator('hg.admin')
300 @HasPermissionAnyDecorator('hg.admin')
298 def edit(self, id, format='html'):
301 def edit(self, id, format='html'):
299 """GET /repos_groups/id/edit: Form to edit an existing item"""
302 """GET /repos_groups/id/edit: Form to edit an existing item"""
300 # url('edit_repos_group', id=ID)
303 # url('edit_repos_group', id=ID)
301
304
302 c.repos_group = ReposGroupModel()._get_repos_group(id)
305 c.repos_group = ReposGroupModel()._get_repos_group(id)
303 defaults = self.__load_data(c.repos_group.group_id)
306 defaults = self.__load_data(c.repos_group.group_id)
304
307
305 # we need to exclude this group from the group list for editing
308 # we need to exclude this group from the group list for editing
306 c.repo_groups = filter(lambda x: x[0] != c.repos_group.group_id,
309 c.repo_groups = filter(lambda x: x[0] != c.repos_group.group_id,
307 c.repo_groups)
310 c.repo_groups)
308
311
309 return htmlfill.render(
312 return htmlfill.render(
310 render('admin/repos_groups/repos_groups_edit.html'),
313 render('admin/repos_groups/repos_groups_edit.html'),
311 defaults=defaults,
314 defaults=defaults,
312 encoding="UTF-8",
315 encoding="UTF-8",
313 force_defaults=False
316 force_defaults=False
314 )
317 )
@@ -1,343 +1,344 b''
1 """ this is forms validation classes
1 """ this is forms validation classes
2 http://formencode.org/module-formencode.validators.html
2 http://formencode.org/module-formencode.validators.html
3 for list off all availible validators
3 for list off all availible validators
4
4
5 we can create our own validators
5 we can create our own validators
6
6
7 The table below outlines the options which can be used in a schema in addition to the validators themselves
7 The table below outlines the options which can be used in a schema in addition to the validators themselves
8 pre_validators [] These validators will be applied before the schema
8 pre_validators [] These validators will be applied before the schema
9 chained_validators [] These validators will be applied after the schema
9 chained_validators [] These validators will be applied after the schema
10 allow_extra_fields False If True, then it is not an error when keys that aren't associated with a validator are present
10 allow_extra_fields False If True, then it is not an error when keys that aren't associated with a validator are present
11 filter_extra_fields False If True, then keys that aren't associated with a validator are removed
11 filter_extra_fields False If True, then keys that aren't associated with a validator are removed
12 if_key_missing NoDefault If this is given, then any keys that aren't available but are expected will be replaced with this value (and then validated). This does not override a present .if_missing attribute on validators. NoDefault is a special FormEncode class to mean that no default values has been specified and therefore missing keys shouldn't take a default value.
12 if_key_missing NoDefault If this is given, then any keys that aren't available but are expected will be replaced with this value (and then validated). This does not override a present .if_missing attribute on validators. NoDefault is a special FormEncode class to mean that no default values has been specified and therefore missing keys shouldn't take a default value.
13 ignore_key_missing False If True, then missing keys will be missing in the result, if the validator doesn't have .if_missing on it already
13 ignore_key_missing False If True, then missing keys will be missing in the result, if the validator doesn't have .if_missing on it already
14
14
15
15
16 <name> = formencode.validators.<name of validator>
16 <name> = formencode.validators.<name of validator>
17 <name> must equal form name
17 <name> must equal form name
18 list=[1,2,3,4,5]
18 list=[1,2,3,4,5]
19 for SELECT use formencode.All(OneOf(list), Int())
19 for SELECT use formencode.All(OneOf(list), Int())
20
20
21 """
21 """
22 import logging
22 import logging
23
23
24 import formencode
24 import formencode
25 from formencode import All
25 from formencode import All
26
26
27 from pylons.i18n.translation import _
27 from pylons.i18n.translation import _
28
28
29 from rhodecode.model import validators as v
29 from rhodecode.model import validators as v
30 from rhodecode import BACKENDS
30 from rhodecode import BACKENDS
31
31
32 log = logging.getLogger(__name__)
32 log = logging.getLogger(__name__)
33
33
34
34
35 class LoginForm(formencode.Schema):
35 class LoginForm(formencode.Schema):
36 allow_extra_fields = True
36 allow_extra_fields = True
37 filter_extra_fields = True
37 filter_extra_fields = True
38 username = v.UnicodeString(
38 username = v.UnicodeString(
39 strip=True,
39 strip=True,
40 min=1,
40 min=1,
41 not_empty=True,
41 not_empty=True,
42 messages={
42 messages={
43 'empty': _(u'Please enter a login'),
43 'empty': _(u'Please enter a login'),
44 'tooShort': _(u'Enter a value %(min)i characters long or more')}
44 'tooShort': _(u'Enter a value %(min)i characters long or more')}
45 )
45 )
46
46
47 password = v.UnicodeString(
47 password = v.UnicodeString(
48 strip=False,
48 strip=False,
49 min=3,
49 min=3,
50 not_empty=True,
50 not_empty=True,
51 messages={
51 messages={
52 'empty': _(u'Please enter a password'),
52 'empty': _(u'Please enter a password'),
53 'tooShort': _(u'Enter %(min)i characters or more')}
53 'tooShort': _(u'Enter %(min)i characters or more')}
54 )
54 )
55
55
56 remember = v.StringBoolean(if_missing=False)
56 remember = v.StringBoolean(if_missing=False)
57
57
58 chained_validators = [v.ValidAuth()]
58 chained_validators = [v.ValidAuth()]
59
59
60
60
61 def UserForm(edit=False, old_data={}):
61 def UserForm(edit=False, old_data={}):
62 class _UserForm(formencode.Schema):
62 class _UserForm(formencode.Schema):
63 allow_extra_fields = True
63 allow_extra_fields = True
64 filter_extra_fields = True
64 filter_extra_fields = True
65 username = All(v.UnicodeString(strip=True, min=1, not_empty=True),
65 username = All(v.UnicodeString(strip=True, min=1, not_empty=True),
66 v.ValidUsername(edit, old_data))
66 v.ValidUsername(edit, old_data))
67 if edit:
67 if edit:
68 new_password = All(
68 new_password = All(
69 v.ValidPassword(),
69 v.ValidPassword(),
70 v.UnicodeString(strip=False, min=6, not_empty=False)
70 v.UnicodeString(strip=False, min=6, not_empty=False)
71 )
71 )
72 password_confirmation = All(
72 password_confirmation = All(
73 v.ValidPassword(),
73 v.ValidPassword(),
74 v.UnicodeString(strip=False, min=6, not_empty=False),
74 v.UnicodeString(strip=False, min=6, not_empty=False),
75 )
75 )
76 admin = v.StringBoolean(if_missing=False)
76 admin = v.StringBoolean(if_missing=False)
77 else:
77 else:
78 password = All(
78 password = All(
79 v.ValidPassword(),
79 v.ValidPassword(),
80 v.UnicodeString(strip=False, min=6, not_empty=True)
80 v.UnicodeString(strip=False, min=6, not_empty=True)
81 )
81 )
82 password_confirmation = All(
82 password_confirmation = All(
83 v.ValidPassword(),
83 v.ValidPassword(),
84 v.UnicodeString(strip=False, min=6, not_empty=False)
84 v.UnicodeString(strip=False, min=6, not_empty=False)
85 )
85 )
86
86
87 active = v.StringBoolean(if_missing=False)
87 active = v.StringBoolean(if_missing=False)
88 firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
88 firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
89 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
89 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
90 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
90 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
91
91
92 chained_validators = [v.ValidPasswordsMatch()]
92 chained_validators = [v.ValidPasswordsMatch()]
93
93
94 return _UserForm
94 return _UserForm
95
95
96
96
97 def UsersGroupForm(edit=False, old_data={}, available_members=[]):
97 def UsersGroupForm(edit=False, old_data={}, available_members=[]):
98 class _UsersGroupForm(formencode.Schema):
98 class _UsersGroupForm(formencode.Schema):
99 allow_extra_fields = True
99 allow_extra_fields = True
100 filter_extra_fields = True
100 filter_extra_fields = True
101
101
102 users_group_name = All(
102 users_group_name = All(
103 v.UnicodeString(strip=True, min=1, not_empty=True),
103 v.UnicodeString(strip=True, min=1, not_empty=True),
104 v.ValidUsersGroup(edit, old_data)
104 v.ValidUsersGroup(edit, old_data)
105 )
105 )
106
106
107 users_group_active = v.StringBoolean(if_missing=False)
107 users_group_active = v.StringBoolean(if_missing=False)
108
108
109 if edit:
109 if edit:
110 users_group_members = v.OneOf(
110 users_group_members = v.OneOf(
111 available_members, hideList=False, testValueList=True,
111 available_members, hideList=False, testValueList=True,
112 if_missing=None, not_empty=False
112 if_missing=None, not_empty=False
113 )
113 )
114
114
115 return _UsersGroupForm
115 return _UsersGroupForm
116
116
117
117
118 def ReposGroupForm(edit=False, old_data={}, available_groups=[]):
118 def ReposGroupForm(edit=False, old_data={}, available_groups=[]):
119 class _ReposGroupForm(formencode.Schema):
119 class _ReposGroupForm(formencode.Schema):
120 allow_extra_fields = True
120 allow_extra_fields = True
121 filter_extra_fields = False
121 filter_extra_fields = False
122
122
123 group_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
123 group_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
124 v.SlugifyName())
124 v.SlugifyName())
125 group_description = v.UnicodeString(strip=True, min=1,
125 group_description = v.UnicodeString(strip=True, min=1,
126 not_empty=True)
126 not_empty=True)
127 group_parent_id = v.OneOf(available_groups, hideList=False,
127 group_parent_id = v.OneOf(available_groups, hideList=False,
128 testValueList=True,
128 testValueList=True,
129 if_missing=None, not_empty=False)
129 if_missing=None, not_empty=False)
130 enable_locking = v.StringBoolean(if_missing=False)
130 enable_locking = v.StringBoolean(if_missing=False)
131 recursive = v.StringBoolean(if_missing=False)
131 chained_validators = [v.ValidReposGroup(edit, old_data),
132 chained_validators = [v.ValidReposGroup(edit, old_data),
132 v.ValidPerms('group')]
133 v.ValidPerms('group')]
133
134
134 return _ReposGroupForm
135 return _ReposGroupForm
135
136
136
137
137 def RegisterForm(edit=False, old_data={}):
138 def RegisterForm(edit=False, old_data={}):
138 class _RegisterForm(formencode.Schema):
139 class _RegisterForm(formencode.Schema):
139 allow_extra_fields = True
140 allow_extra_fields = True
140 filter_extra_fields = True
141 filter_extra_fields = True
141 username = All(
142 username = All(
142 v.ValidUsername(edit, old_data),
143 v.ValidUsername(edit, old_data),
143 v.UnicodeString(strip=True, min=1, not_empty=True)
144 v.UnicodeString(strip=True, min=1, not_empty=True)
144 )
145 )
145 password = All(
146 password = All(
146 v.ValidPassword(),
147 v.ValidPassword(),
147 v.UnicodeString(strip=False, min=6, not_empty=True)
148 v.UnicodeString(strip=False, min=6, not_empty=True)
148 )
149 )
149 password_confirmation = All(
150 password_confirmation = All(
150 v.ValidPassword(),
151 v.ValidPassword(),
151 v.UnicodeString(strip=False, min=6, not_empty=True)
152 v.UnicodeString(strip=False, min=6, not_empty=True)
152 )
153 )
153 active = v.StringBoolean(if_missing=False)
154 active = v.StringBoolean(if_missing=False)
154 firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
155 firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
155 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
156 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
156 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
157 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
157
158
158 chained_validators = [v.ValidPasswordsMatch()]
159 chained_validators = [v.ValidPasswordsMatch()]
159
160
160 return _RegisterForm
161 return _RegisterForm
161
162
162
163
163 def PasswordResetForm():
164 def PasswordResetForm():
164 class _PasswordResetForm(formencode.Schema):
165 class _PasswordResetForm(formencode.Schema):
165 allow_extra_fields = True
166 allow_extra_fields = True
166 filter_extra_fields = True
167 filter_extra_fields = True
167 email = All(v.ValidSystemEmail(), v.Email(not_empty=True))
168 email = All(v.ValidSystemEmail(), v.Email(not_empty=True))
168 return _PasswordResetForm
169 return _PasswordResetForm
169
170
170
171
171 def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
172 def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
172 repo_groups=[], landing_revs=[]):
173 repo_groups=[], landing_revs=[]):
173 class _RepoForm(formencode.Schema):
174 class _RepoForm(formencode.Schema):
174 allow_extra_fields = True
175 allow_extra_fields = True
175 filter_extra_fields = False
176 filter_extra_fields = False
176 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
177 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
177 v.SlugifyName())
178 v.SlugifyName())
178 clone_uri = All(v.UnicodeString(strip=True, min=1, not_empty=False))
179 clone_uri = All(v.UnicodeString(strip=True, min=1, not_empty=False))
179 repo_group = v.OneOf(repo_groups, hideList=True)
180 repo_group = v.OneOf(repo_groups, hideList=True)
180 repo_type = v.OneOf(supported_backends)
181 repo_type = v.OneOf(supported_backends)
181 description = v.UnicodeString(strip=True, min=1, not_empty=False)
182 description = v.UnicodeString(strip=True, min=1, not_empty=False)
182 private = v.StringBoolean(if_missing=False)
183 private = v.StringBoolean(if_missing=False)
183 enable_statistics = v.StringBoolean(if_missing=False)
184 enable_statistics = v.StringBoolean(if_missing=False)
184 enable_downloads = v.StringBoolean(if_missing=False)
185 enable_downloads = v.StringBoolean(if_missing=False)
185 enable_locking = v.StringBoolean(if_missing=False)
186 enable_locking = v.StringBoolean(if_missing=False)
186 landing_rev = v.OneOf(landing_revs, hideList=True)
187 landing_rev = v.OneOf(landing_revs, hideList=True)
187
188
188 if edit:
189 if edit:
189 #this is repo owner
190 #this is repo owner
190 user = All(v.UnicodeString(not_empty=True), v.ValidRepoUser())
191 user = All(v.UnicodeString(not_empty=True), v.ValidRepoUser())
191
192
192 chained_validators = [v.ValidCloneUri(),
193 chained_validators = [v.ValidCloneUri(),
193 v.ValidRepoName(edit, old_data),
194 v.ValidRepoName(edit, old_data),
194 v.ValidPerms()]
195 v.ValidPerms()]
195 return _RepoForm
196 return _RepoForm
196
197
197
198
198 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
199 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
199 repo_groups=[], landing_revs=[]):
200 repo_groups=[], landing_revs=[]):
200 class _RepoForkForm(formencode.Schema):
201 class _RepoForkForm(formencode.Schema):
201 allow_extra_fields = True
202 allow_extra_fields = True
202 filter_extra_fields = False
203 filter_extra_fields = False
203 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
204 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
204 v.SlugifyName())
205 v.SlugifyName())
205 repo_group = v.OneOf(repo_groups, hideList=True)
206 repo_group = v.OneOf(repo_groups, hideList=True)
206 repo_type = All(v.ValidForkType(old_data), v.OneOf(supported_backends))
207 repo_type = All(v.ValidForkType(old_data), v.OneOf(supported_backends))
207 description = v.UnicodeString(strip=True, min=1, not_empty=True)
208 description = v.UnicodeString(strip=True, min=1, not_empty=True)
208 private = v.StringBoolean(if_missing=False)
209 private = v.StringBoolean(if_missing=False)
209 copy_permissions = v.StringBoolean(if_missing=False)
210 copy_permissions = v.StringBoolean(if_missing=False)
210 update_after_clone = v.StringBoolean(if_missing=False)
211 update_after_clone = v.StringBoolean(if_missing=False)
211 fork_parent_id = v.UnicodeString()
212 fork_parent_id = v.UnicodeString()
212 chained_validators = [v.ValidForkName(edit, old_data)]
213 chained_validators = [v.ValidForkName(edit, old_data)]
213 landing_rev = v.OneOf(landing_revs, hideList=True)
214 landing_rev = v.OneOf(landing_revs, hideList=True)
214
215
215 return _RepoForkForm
216 return _RepoForkForm
216
217
217
218
218 def RepoSettingsForm(edit=False, old_data={},
219 def RepoSettingsForm(edit=False, old_data={},
219 supported_backends=BACKENDS.keys(), repo_groups=[],
220 supported_backends=BACKENDS.keys(), repo_groups=[],
220 landing_revs=[]):
221 landing_revs=[]):
221 class _RepoForm(formencode.Schema):
222 class _RepoForm(formencode.Schema):
222 allow_extra_fields = True
223 allow_extra_fields = True
223 filter_extra_fields = False
224 filter_extra_fields = False
224 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
225 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
225 v.SlugifyName())
226 v.SlugifyName())
226 description = v.UnicodeString(strip=True, min=1, not_empty=True)
227 description = v.UnicodeString(strip=True, min=1, not_empty=True)
227 repo_group = v.OneOf(repo_groups, hideList=True)
228 repo_group = v.OneOf(repo_groups, hideList=True)
228 private = v.StringBoolean(if_missing=False)
229 private = v.StringBoolean(if_missing=False)
229 landing_rev = v.OneOf(landing_revs, hideList=True)
230 landing_rev = v.OneOf(landing_revs, hideList=True)
230 chained_validators = [v.ValidRepoName(edit, old_data), v.ValidPerms(),
231 chained_validators = [v.ValidRepoName(edit, old_data), v.ValidPerms(),
231 v.ValidSettings()]
232 v.ValidSettings()]
232 return _RepoForm
233 return _RepoForm
233
234
234
235
235 def ApplicationSettingsForm():
236 def ApplicationSettingsForm():
236 class _ApplicationSettingsForm(formencode.Schema):
237 class _ApplicationSettingsForm(formencode.Schema):
237 allow_extra_fields = True
238 allow_extra_fields = True
238 filter_extra_fields = False
239 filter_extra_fields = False
239 rhodecode_title = v.UnicodeString(strip=True, min=1, not_empty=True)
240 rhodecode_title = v.UnicodeString(strip=True, min=1, not_empty=True)
240 rhodecode_realm = v.UnicodeString(strip=True, min=1, not_empty=True)
241 rhodecode_realm = v.UnicodeString(strip=True, min=1, not_empty=True)
241 rhodecode_ga_code = v.UnicodeString(strip=True, min=1, not_empty=False)
242 rhodecode_ga_code = v.UnicodeString(strip=True, min=1, not_empty=False)
242
243
243 return _ApplicationSettingsForm
244 return _ApplicationSettingsForm
244
245
245
246
246 def ApplicationVisualisationForm():
247 def ApplicationVisualisationForm():
247 class _ApplicationVisualisationForm(formencode.Schema):
248 class _ApplicationVisualisationForm(formencode.Schema):
248 allow_extra_fields = True
249 allow_extra_fields = True
249 filter_extra_fields = False
250 filter_extra_fields = False
250 rhodecode_show_public_icon = v.StringBoolean(if_missing=False)
251 rhodecode_show_public_icon = v.StringBoolean(if_missing=False)
251 rhodecode_show_private_icon = v.StringBoolean(if_missing=False)
252 rhodecode_show_private_icon = v.StringBoolean(if_missing=False)
252 rhodecode_stylify_metatags = v.StringBoolean(if_missing=False)
253 rhodecode_stylify_metatags = v.StringBoolean(if_missing=False)
253
254
254 return _ApplicationVisualisationForm
255 return _ApplicationVisualisationForm
255
256
256
257
257 def ApplicationUiSettingsForm():
258 def ApplicationUiSettingsForm():
258 class _ApplicationUiSettingsForm(formencode.Schema):
259 class _ApplicationUiSettingsForm(formencode.Schema):
259 allow_extra_fields = True
260 allow_extra_fields = True
260 filter_extra_fields = False
261 filter_extra_fields = False
261 web_push_ssl = v.StringBoolean(if_missing=False)
262 web_push_ssl = v.StringBoolean(if_missing=False)
262 paths_root_path = All(
263 paths_root_path = All(
263 v.ValidPath(),
264 v.ValidPath(),
264 v.UnicodeString(strip=True, min=1, not_empty=True)
265 v.UnicodeString(strip=True, min=1, not_empty=True)
265 )
266 )
266 hooks_changegroup_update = v.StringBoolean(if_missing=False)
267 hooks_changegroup_update = v.StringBoolean(if_missing=False)
267 hooks_changegroup_repo_size = v.StringBoolean(if_missing=False)
268 hooks_changegroup_repo_size = v.StringBoolean(if_missing=False)
268 hooks_changegroup_push_logger = v.StringBoolean(if_missing=False)
269 hooks_changegroup_push_logger = v.StringBoolean(if_missing=False)
269 hooks_outgoing_pull_logger = v.StringBoolean(if_missing=False)
270 hooks_outgoing_pull_logger = v.StringBoolean(if_missing=False)
270
271
271 extensions_largefiles = v.StringBoolean(if_missing=False)
272 extensions_largefiles = v.StringBoolean(if_missing=False)
272 extensions_hgsubversion = v.StringBoolean(if_missing=False)
273 extensions_hgsubversion = v.StringBoolean(if_missing=False)
273 extensions_hggit = v.StringBoolean(if_missing=False)
274 extensions_hggit = v.StringBoolean(if_missing=False)
274
275
275 return _ApplicationUiSettingsForm
276 return _ApplicationUiSettingsForm
276
277
277
278
278 def DefaultPermissionsForm(perms_choices, register_choices, create_choices,
279 def DefaultPermissionsForm(perms_choices, register_choices, create_choices,
279 fork_choices):
280 fork_choices):
280 class _DefaultPermissionsForm(formencode.Schema):
281 class _DefaultPermissionsForm(formencode.Schema):
281 allow_extra_fields = True
282 allow_extra_fields = True
282 filter_extra_fields = True
283 filter_extra_fields = True
283 overwrite_default = v.StringBoolean(if_missing=False)
284 overwrite_default = v.StringBoolean(if_missing=False)
284 anonymous = v.StringBoolean(if_missing=False)
285 anonymous = v.StringBoolean(if_missing=False)
285 default_perm = v.OneOf(perms_choices)
286 default_perm = v.OneOf(perms_choices)
286 default_register = v.OneOf(register_choices)
287 default_register = v.OneOf(register_choices)
287 default_create = v.OneOf(create_choices)
288 default_create = v.OneOf(create_choices)
288 default_fork = v.OneOf(fork_choices)
289 default_fork = v.OneOf(fork_choices)
289
290
290 return _DefaultPermissionsForm
291 return _DefaultPermissionsForm
291
292
292
293
293 def LdapSettingsForm(tls_reqcert_choices, search_scope_choices,
294 def LdapSettingsForm(tls_reqcert_choices, search_scope_choices,
294 tls_kind_choices):
295 tls_kind_choices):
295 class _LdapSettingsForm(formencode.Schema):
296 class _LdapSettingsForm(formencode.Schema):
296 allow_extra_fields = True
297 allow_extra_fields = True
297 filter_extra_fields = True
298 filter_extra_fields = True
298 #pre_validators = [LdapLibValidator]
299 #pre_validators = [LdapLibValidator]
299 ldap_active = v.StringBoolean(if_missing=False)
300 ldap_active = v.StringBoolean(if_missing=False)
300 ldap_host = v.UnicodeString(strip=True,)
301 ldap_host = v.UnicodeString(strip=True,)
301 ldap_port = v.Number(strip=True,)
302 ldap_port = v.Number(strip=True,)
302 ldap_tls_kind = v.OneOf(tls_kind_choices)
303 ldap_tls_kind = v.OneOf(tls_kind_choices)
303 ldap_tls_reqcert = v.OneOf(tls_reqcert_choices)
304 ldap_tls_reqcert = v.OneOf(tls_reqcert_choices)
304 ldap_dn_user = v.UnicodeString(strip=True,)
305 ldap_dn_user = v.UnicodeString(strip=True,)
305 ldap_dn_pass = v.UnicodeString(strip=True,)
306 ldap_dn_pass = v.UnicodeString(strip=True,)
306 ldap_base_dn = v.UnicodeString(strip=True,)
307 ldap_base_dn = v.UnicodeString(strip=True,)
307 ldap_filter = v.UnicodeString(strip=True,)
308 ldap_filter = v.UnicodeString(strip=True,)
308 ldap_search_scope = v.OneOf(search_scope_choices)
309 ldap_search_scope = v.OneOf(search_scope_choices)
309 ldap_attr_login = All(
310 ldap_attr_login = All(
310 v.AttrLoginValidator(),
311 v.AttrLoginValidator(),
311 v.UnicodeString(strip=True,)
312 v.UnicodeString(strip=True,)
312 )
313 )
313 ldap_attr_firstname = v.UnicodeString(strip=True,)
314 ldap_attr_firstname = v.UnicodeString(strip=True,)
314 ldap_attr_lastname = v.UnicodeString(strip=True,)
315 ldap_attr_lastname = v.UnicodeString(strip=True,)
315 ldap_attr_email = v.UnicodeString(strip=True,)
316 ldap_attr_email = v.UnicodeString(strip=True,)
316
317
317 return _LdapSettingsForm
318 return _LdapSettingsForm
318
319
319
320
320 def UserExtraEmailForm():
321 def UserExtraEmailForm():
321 class _UserExtraEmailForm(formencode.Schema):
322 class _UserExtraEmailForm(formencode.Schema):
322 email = All(v.UniqSystemEmail(), v.Email)
323 email = All(v.UniqSystemEmail(), v.Email)
323
324
324 return _UserExtraEmailForm
325 return _UserExtraEmailForm
325
326
326
327
327 def PullRequestForm():
328 def PullRequestForm():
328 class _PullRequestForm(formencode.Schema):
329 class _PullRequestForm(formencode.Schema):
329 allow_extra_fields = True
330 allow_extra_fields = True
330 filter_extra_fields = True
331 filter_extra_fields = True
331
332
332 user = v.UnicodeString(strip=True, required=True)
333 user = v.UnicodeString(strip=True, required=True)
333 org_repo = v.UnicodeString(strip=True, required=True)
334 org_repo = v.UnicodeString(strip=True, required=True)
334 org_ref = v.UnicodeString(strip=True, required=True)
335 org_ref = v.UnicodeString(strip=True, required=True)
335 other_repo = v.UnicodeString(strip=True, required=True)
336 other_repo = v.UnicodeString(strip=True, required=True)
336 other_ref = v.UnicodeString(strip=True, required=True)
337 other_ref = v.UnicodeString(strip=True, required=True)
337 revisions = All(v.NotReviewedRevisions()(), v.UniqueList(not_empty=True))
338 revisions = All(v.NotReviewedRevisions()(), v.UniqueList(not_empty=True))
338 review_members = v.UniqueList(not_empty=True)
339 review_members = v.UniqueList(not_empty=True)
339
340
340 pullrequest_title = v.UnicodeString(strip=True, required=True, min=3)
341 pullrequest_title = v.UnicodeString(strip=True, required=True, min=3)
341 pullrequest_desc = v.UnicodeString(strip=True, required=False)
342 pullrequest_desc = v.UnicodeString(strip=True, required=False)
342
343
343 return _PullRequestForm
344 return _PullRequestForm
@@ -1,538 +1,544 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.model.repo
3 rhodecode.model.repo
4 ~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~
5
5
6 Repository model for rhodecode
6 Repository model for rhodecode
7
7
8 :created_on: Jun 5, 2010
8 :created_on: Jun 5, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 from __future__ import with_statement
25 from __future__ import with_statement
26 import os
26 import os
27 import shutil
27 import shutil
28 import logging
28 import logging
29 import traceback
29 import traceback
30 from datetime import datetime
30 from datetime import datetime
31
31
32 from rhodecode.lib.vcs.backends import get_backend
32 from rhodecode.lib.vcs.backends import get_backend
33 from rhodecode.lib.compat import json
33 from rhodecode.lib.compat import json
34 from rhodecode.lib.utils2 import LazyProperty, safe_str, safe_unicode
34 from rhodecode.lib.utils2 import LazyProperty, safe_str, safe_unicode
35 from rhodecode.lib.caching_query import FromCache
35 from rhodecode.lib.caching_query import FromCache
36 from rhodecode.lib.hooks import log_create_repository
36 from rhodecode.lib.hooks import log_create_repository
37
37
38 from rhodecode.model import BaseModel
38 from rhodecode.model import BaseModel
39 from rhodecode.model.db import Repository, UserRepoToPerm, User, Permission, \
39 from rhodecode.model.db import Repository, UserRepoToPerm, User, Permission, \
40 Statistics, UsersGroup, UsersGroupRepoToPerm, RhodeCodeUi, RepoGroup
40 Statistics, UsersGroup, UsersGroupRepoToPerm, RhodeCodeUi, RepoGroup
41 from rhodecode.lib import helpers as h
41 from rhodecode.lib import helpers as h
42
42
43
43
44 log = logging.getLogger(__name__)
44 log = logging.getLogger(__name__)
45
45
46
46
47 class RepoModel(BaseModel):
47 class RepoModel(BaseModel):
48
48
49 cls = Repository
49 cls = Repository
50 URL_SEPARATOR = Repository.url_sep()
50 URL_SEPARATOR = Repository.url_sep()
51
51
52 def __get_users_group(self, users_group):
52 def __get_users_group(self, users_group):
53 return self._get_instance(UsersGroup, users_group,
53 return self._get_instance(UsersGroup, users_group,
54 callback=UsersGroup.get_by_group_name)
54 callback=UsersGroup.get_by_group_name)
55
55
56 def _get_repos_group(self, repos_group):
56 def _get_repos_group(self, repos_group):
57 return self._get_instance(RepoGroup, repos_group,
57 return self._get_instance(RepoGroup, repos_group,
58 callback=RepoGroup.get_by_group_name)
58 callback=RepoGroup.get_by_group_name)
59
59
60 @LazyProperty
60 @LazyProperty
61 def repos_path(self):
61 def repos_path(self):
62 """
62 """
63 Get's the repositories root path from database
63 Get's the repositories root path from database
64 """
64 """
65
65
66 q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
66 q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
67 return q.ui_value
67 return q.ui_value
68
68
69 def get(self, repo_id, cache=False):
69 def get(self, repo_id, cache=False):
70 repo = self.sa.query(Repository)\
70 repo = self.sa.query(Repository)\
71 .filter(Repository.repo_id == repo_id)
71 .filter(Repository.repo_id == repo_id)
72
72
73 if cache:
73 if cache:
74 repo = repo.options(FromCache("sql_cache_short",
74 repo = repo.options(FromCache("sql_cache_short",
75 "get_repo_%s" % repo_id))
75 "get_repo_%s" % repo_id))
76 return repo.scalar()
76 return repo.scalar()
77
77
78 def get_repo(self, repository):
78 def get_repo(self, repository):
79 return self._get_repo(repository)
79 return self._get_repo(repository)
80
80
81 def get_by_repo_name(self, repo_name, cache=False):
81 def get_by_repo_name(self, repo_name, cache=False):
82 repo = self.sa.query(Repository)\
82 repo = self.sa.query(Repository)\
83 .filter(Repository.repo_name == repo_name)
83 .filter(Repository.repo_name == repo_name)
84
84
85 if cache:
85 if cache:
86 repo = repo.options(FromCache("sql_cache_short",
86 repo = repo.options(FromCache("sql_cache_short",
87 "get_repo_%s" % repo_name))
87 "get_repo_%s" % repo_name))
88 return repo.scalar()
88 return repo.scalar()
89
89
90 def get_users_js(self):
90 def get_users_js(self):
91 users = self.sa.query(User).filter(User.active == True).all()
91 users = self.sa.query(User).filter(User.active == True).all()
92 return json.dumps([
92 return json.dumps([
93 {
93 {
94 'id': u.user_id,
94 'id': u.user_id,
95 'fname': u.name,
95 'fname': u.name,
96 'lname': u.lastname,
96 'lname': u.lastname,
97 'nname': u.username,
97 'nname': u.username,
98 'gravatar_lnk': h.gravatar_url(u.email, 14)
98 'gravatar_lnk': h.gravatar_url(u.email, 14)
99 } for u in users]
99 } for u in users]
100 )
100 )
101
101
102 def get_users_groups_js(self):
102 def get_users_groups_js(self):
103 users_groups = self.sa.query(UsersGroup)\
103 users_groups = self.sa.query(UsersGroup)\
104 .filter(UsersGroup.users_group_active == True).all()
104 .filter(UsersGroup.users_group_active == True).all()
105
105
106 return json.dumps([
106 return json.dumps([
107 {
107 {
108 'id': gr.users_group_id,
108 'id': gr.users_group_id,
109 'grname': gr.users_group_name,
109 'grname': gr.users_group_name,
110 'grmembers': len(gr.members),
110 'grmembers': len(gr.members),
111 } for gr in users_groups]
111 } for gr in users_groups]
112 )
112 )
113
113
114 def _get_defaults(self, repo_name):
114 def _get_defaults(self, repo_name):
115 """
115 """
116 Get's information about repository, and returns a dict for
116 Get's information about repository, and returns a dict for
117 usage in forms
117 usage in forms
118
118
119 :param repo_name:
119 :param repo_name:
120 """
120 """
121
121
122 repo_info = Repository.get_by_repo_name(repo_name)
122 repo_info = Repository.get_by_repo_name(repo_name)
123
123
124 if repo_info is None:
124 if repo_info is None:
125 return None
125 return None
126
126
127 defaults = repo_info.get_dict()
127 defaults = repo_info.get_dict()
128 group, repo_name = repo_info.groups_and_repo
128 group, repo_name = repo_info.groups_and_repo
129 defaults['repo_name'] = repo_name
129 defaults['repo_name'] = repo_name
130 defaults['repo_group'] = getattr(group[-1] if group else None,
130 defaults['repo_group'] = getattr(group[-1] if group else None,
131 'group_id', None)
131 'group_id', None)
132
132
133 # fill owner
133 # fill owner
134 if repo_info.user:
134 if repo_info.user:
135 defaults.update({'user': repo_info.user.username})
135 defaults.update({'user': repo_info.user.username})
136 else:
136 else:
137 replacement_user = User.query().filter(User.admin ==
137 replacement_user = User.query().filter(User.admin ==
138 True).first().username
138 True).first().username
139 defaults.update({'user': replacement_user})
139 defaults.update({'user': replacement_user})
140
140
141 # fill repository users
141 # fill repository users
142 for p in repo_info.repo_to_perm:
142 for p in repo_info.repo_to_perm:
143 defaults.update({'u_perm_%s' % p.user.username:
143 defaults.update({'u_perm_%s' % p.user.username:
144 p.permission.permission_name})
144 p.permission.permission_name})
145
145
146 # fill repository groups
146 # fill repository groups
147 for p in repo_info.users_group_to_perm:
147 for p in repo_info.users_group_to_perm:
148 defaults.update({'g_perm_%s' % p.users_group.users_group_name:
148 defaults.update({'g_perm_%s' % p.users_group.users_group_name:
149 p.permission.permission_name})
149 p.permission.permission_name})
150
150
151 return defaults
151 return defaults
152
152
153 def update(self, repo_name, form_data):
153 def update(self, repo_name, form_data):
154 try:
154 try:
155 cur_repo = self.get_by_repo_name(repo_name, cache=False)
155 cur_repo = self.get_by_repo_name(repo_name, cache=False)
156
156
157 # update permissions
157 # update permissions
158 for member, perm, member_type in form_data['perms_updates']:
158 for member, perm, member_type in form_data['perms_updates']:
159 if member_type == 'user':
159 if member_type == 'user':
160 # this updates existing one
160 # this updates existing one
161 RepoModel().grant_user_permission(
161 RepoModel().grant_user_permission(
162 repo=cur_repo, user=member, perm=perm
162 repo=cur_repo, user=member, perm=perm
163 )
163 )
164 else:
164 else:
165 RepoModel().grant_users_group_permission(
165 RepoModel().grant_users_group_permission(
166 repo=cur_repo, group_name=member, perm=perm
166 repo=cur_repo, group_name=member, perm=perm
167 )
167 )
168 # set new permissions
168 # set new permissions
169 for member, perm, member_type in form_data['perms_new']:
169 for member, perm, member_type in form_data['perms_new']:
170 if member_type == 'user':
170 if member_type == 'user':
171 RepoModel().grant_user_permission(
171 RepoModel().grant_user_permission(
172 repo=cur_repo, user=member, perm=perm
172 repo=cur_repo, user=member, perm=perm
173 )
173 )
174 else:
174 else:
175 RepoModel().grant_users_group_permission(
175 RepoModel().grant_users_group_permission(
176 repo=cur_repo, group_name=member, perm=perm
176 repo=cur_repo, group_name=member, perm=perm
177 )
177 )
178
178
179 # update current repo
179 # update current repo
180 for k, v in form_data.items():
180 for k, v in form_data.items():
181 if k == 'user':
181 if k == 'user':
182 cur_repo.user = User.get_by_username(v)
182 cur_repo.user = User.get_by_username(v)
183 elif k == 'repo_name':
183 elif k == 'repo_name':
184 pass
184 pass
185 elif k == 'repo_group':
185 elif k == 'repo_group':
186 cur_repo.group = RepoGroup.get(v)
186 cur_repo.group = RepoGroup.get(v)
187
187
188 else:
188 else:
189 setattr(cur_repo, k, v)
189 setattr(cur_repo, k, v)
190
190
191 new_name = cur_repo.get_new_name(form_data['repo_name'])
191 new_name = cur_repo.get_new_name(form_data['repo_name'])
192 cur_repo.repo_name = new_name
192 cur_repo.repo_name = new_name
193
193
194 self.sa.add(cur_repo)
194 self.sa.add(cur_repo)
195
195
196 if repo_name != new_name:
196 if repo_name != new_name:
197 # rename repository
197 # rename repository
198 self.__rename_repo(old=repo_name, new=new_name)
198 self.__rename_repo(old=repo_name, new=new_name)
199
199
200 return cur_repo
200 return cur_repo
201 except:
201 except:
202 log.error(traceback.format_exc())
202 log.error(traceback.format_exc())
203 raise
203 raise
204
204
205 def create_repo(self, repo_name, repo_type, description, owner,
205 def create_repo(self, repo_name, repo_type, description, owner,
206 private=False, clone_uri=None, repos_group=None,
206 private=False, clone_uri=None, repos_group=None,
207 landing_rev='tip', just_db=False, fork_of=None,
207 landing_rev='tip', just_db=False, fork_of=None,
208 copy_fork_permissions=False):
208 copy_fork_permissions=False):
209 """
209 """
210 Create repository
210 Create repository
211
211
212 """
212 """
213 from rhodecode.model.scm import ScmModel
213 from rhodecode.model.scm import ScmModel
214
214
215 owner = self._get_user(owner)
215 owner = self._get_user(owner)
216 fork_of = self._get_repo(fork_of)
216 fork_of = self._get_repo(fork_of)
217 repos_group = self._get_repos_group(repos_group)
217 repos_group = self._get_repos_group(repos_group)
218 try:
218 try:
219
219
220 # repo name is just a name of repository
220 # repo name is just a name of repository
221 # while repo_name_full is a full qualified name that is combined
221 # while repo_name_full is a full qualified name that is combined
222 # with name and path of group
222 # with name and path of group
223 repo_name_full = repo_name
223 repo_name_full = repo_name
224 repo_name = repo_name.split(self.URL_SEPARATOR)[-1]
224 repo_name = repo_name.split(self.URL_SEPARATOR)[-1]
225
225
226 new_repo = Repository()
226 new_repo = Repository()
227 new_repo.enable_statistics = False
227 new_repo.enable_statistics = False
228 new_repo.repo_name = repo_name_full
228 new_repo.repo_name = repo_name_full
229 new_repo.repo_type = repo_type
229 new_repo.repo_type = repo_type
230 new_repo.user = owner
230 new_repo.user = owner
231 new_repo.group = repos_group
231 new_repo.group = repos_group
232 new_repo.description = description or repo_name
232 new_repo.description = description or repo_name
233 new_repo.private = private
233 new_repo.private = private
234 new_repo.clone_uri = clone_uri
234 new_repo.clone_uri = clone_uri
235 new_repo.landing_rev = landing_rev
235 new_repo.landing_rev = landing_rev
236
236
237 if repos_group:
237 if repos_group:
238 new_repo.enable_locking = repos_group.enable_locking
238 new_repo.enable_locking = repos_group.enable_locking
239
239
240 if fork_of:
240 if fork_of:
241 parent_repo = fork_of
241 parent_repo = fork_of
242 new_repo.fork = parent_repo
242 new_repo.fork = parent_repo
243
243
244 self.sa.add(new_repo)
244 self.sa.add(new_repo)
245
245
246 def _create_default_perms():
246 def _create_default_perms():
247 # create default permission
247 # create default permission
248 repo_to_perm = UserRepoToPerm()
248 repo_to_perm = UserRepoToPerm()
249 default = 'repository.read'
249 default = 'repository.read'
250 for p in User.get_by_username('default').user_perms:
250 for p in User.get_by_username('default').user_perms:
251 if p.permission.permission_name.startswith('repository.'):
251 if p.permission.permission_name.startswith('repository.'):
252 default = p.permission.permission_name
252 default = p.permission.permission_name
253 break
253 break
254
254
255 default_perm = 'repository.none' if private else default
255 default_perm = 'repository.none' if private else default
256
256
257 repo_to_perm.permission_id = self.sa.query(Permission)\
257 repo_to_perm.permission_id = self.sa.query(Permission)\
258 .filter(Permission.permission_name == default_perm)\
258 .filter(Permission.permission_name == default_perm)\
259 .one().permission_id
259 .one().permission_id
260
260
261 repo_to_perm.repository = new_repo
261 repo_to_perm.repository = new_repo
262 repo_to_perm.user_id = User.get_by_username('default').user_id
262 repo_to_perm.user_id = User.get_by_username('default').user_id
263
263
264 self.sa.add(repo_to_perm)
264 self.sa.add(repo_to_perm)
265
265
266 if fork_of:
266 if fork_of:
267 if copy_fork_permissions:
267 if copy_fork_permissions:
268 repo = fork_of
268 repo = fork_of
269 user_perms = UserRepoToPerm.query()\
269 user_perms = UserRepoToPerm.query()\
270 .filter(UserRepoToPerm.repository == repo).all()
270 .filter(UserRepoToPerm.repository == repo).all()
271 group_perms = UsersGroupRepoToPerm.query()\
271 group_perms = UsersGroupRepoToPerm.query()\
272 .filter(UsersGroupRepoToPerm.repository == repo).all()
272 .filter(UsersGroupRepoToPerm.repository == repo).all()
273
273
274 for perm in user_perms:
274 for perm in user_perms:
275 UserRepoToPerm.create(perm.user, new_repo,
275 UserRepoToPerm.create(perm.user, new_repo,
276 perm.permission)
276 perm.permission)
277
277
278 for perm in group_perms:
278 for perm in group_perms:
279 UsersGroupRepoToPerm.create(perm.users_group, new_repo,
279 UsersGroupRepoToPerm.create(perm.users_group, new_repo,
280 perm.permission)
280 perm.permission)
281 else:
281 else:
282 _create_default_perms()
282 _create_default_perms()
283 else:
283 else:
284 _create_default_perms()
284 _create_default_perms()
285
285
286 if not just_db:
286 if not just_db:
287 self.__create_repo(repo_name, repo_type,
287 self.__create_repo(repo_name, repo_type,
288 repos_group,
288 repos_group,
289 clone_uri)
289 clone_uri)
290 log_create_repository(new_repo.get_dict(),
290 log_create_repository(new_repo.get_dict(),
291 created_by=owner.username)
291 created_by=owner.username)
292
292
293 # now automatically start following this repository as owner
293 # now automatically start following this repository as owner
294 ScmModel(self.sa).toggle_following_repo(new_repo.repo_id,
294 ScmModel(self.sa).toggle_following_repo(new_repo.repo_id,
295 owner.user_id)
295 owner.user_id)
296 return new_repo
296 return new_repo
297 except:
297 except:
298 log.error(traceback.format_exc())
298 log.error(traceback.format_exc())
299 raise
299 raise
300
300
301 def create(self, form_data, cur_user, just_db=False, fork=None):
301 def create(self, form_data, cur_user, just_db=False, fork=None):
302 """
302 """
303 Backward compatibility function, just a wrapper on top of create_repo
303 Backward compatibility function, just a wrapper on top of create_repo
304
304
305 :param form_data:
305 :param form_data:
306 :param cur_user:
306 :param cur_user:
307 :param just_db:
307 :param just_db:
308 :param fork:
308 :param fork:
309 """
309 """
310
310
311 repo_name = form_data['repo_name_full']
311 repo_name = form_data['repo_name_full']
312 repo_type = form_data['repo_type']
312 repo_type = form_data['repo_type']
313 description = form_data['description']
313 description = form_data['description']
314 owner = cur_user
314 owner = cur_user
315 private = form_data['private']
315 private = form_data['private']
316 clone_uri = form_data.get('clone_uri')
316 clone_uri = form_data.get('clone_uri')
317 repos_group = form_data['repo_group']
317 repos_group = form_data['repo_group']
318 landing_rev = form_data['landing_rev']
318 landing_rev = form_data['landing_rev']
319 copy_fork_permissions = form_data.get('copy_permissions')
319 copy_fork_permissions = form_data.get('copy_permissions')
320 fork_of = form_data.get('fork_parent_id')
320 fork_of = form_data.get('fork_parent_id')
321 return self.create_repo(
321 return self.create_repo(
322 repo_name, repo_type, description, owner, private, clone_uri,
322 repo_name, repo_type, description, owner, private, clone_uri,
323 repos_group, landing_rev, just_db, fork_of, copy_fork_permissions
323 repos_group, landing_rev, just_db, fork_of, copy_fork_permissions
324 )
324 )
325
325
326 def create_fork(self, form_data, cur_user):
326 def create_fork(self, form_data, cur_user):
327 """
327 """
328 Simple wrapper into executing celery task for fork creation
328 Simple wrapper into executing celery task for fork creation
329
329
330 :param form_data:
330 :param form_data:
331 :param cur_user:
331 :param cur_user:
332 """
332 """
333 from rhodecode.lib.celerylib import tasks, run_task
333 from rhodecode.lib.celerylib import tasks, run_task
334 run_task(tasks.create_repo_fork, form_data, cur_user)
334 run_task(tasks.create_repo_fork, form_data, cur_user)
335
335
336 def delete(self, repo):
336 def delete(self, repo):
337 repo = self._get_repo(repo)
337 repo = self._get_repo(repo)
338 if repo:
338 if repo:
339 try:
339 try:
340 self.sa.delete(repo)
340 self.sa.delete(repo)
341 self.__delete_repo(repo)
341 self.__delete_repo(repo)
342 except:
342 except:
343 log.error(traceback.format_exc())
343 log.error(traceback.format_exc())
344 raise
344 raise
345
345
346 def grant_user_permission(self, repo, user, perm):
346 def grant_user_permission(self, repo, user, perm):
347 """
347 """
348 Grant permission for user on given repository, or update existing one
348 Grant permission for user on given repository, or update existing one
349 if found
349 if found
350
350
351 :param repo: Instance of Repository, repository_id, or repository name
351 :param repo: Instance of Repository, repository_id, or repository name
352 :param user: Instance of User, user_id or username
352 :param user: Instance of User, user_id or username
353 :param perm: Instance of Permission, or permission_name
353 :param perm: Instance of Permission, or permission_name
354 """
354 """
355 user = self._get_user(user)
355 user = self._get_user(user)
356 repo = self._get_repo(repo)
356 repo = self._get_repo(repo)
357 permission = self._get_perm(perm)
357 permission = self._get_perm(perm)
358
358
359 # check if we have that permission already
359 # check if we have that permission already
360 obj = self.sa.query(UserRepoToPerm)\
360 obj = self.sa.query(UserRepoToPerm)\
361 .filter(UserRepoToPerm.user == user)\
361 .filter(UserRepoToPerm.user == user)\
362 .filter(UserRepoToPerm.repository == repo)\
362 .filter(UserRepoToPerm.repository == repo)\
363 .scalar()
363 .scalar()
364 if obj is None:
364 if obj is None:
365 # create new !
365 # create new !
366 obj = UserRepoToPerm()
366 obj = UserRepoToPerm()
367 obj.repository = repo
367 obj.repository = repo
368 obj.user = user
368 obj.user = user
369 obj.permission = permission
369 obj.permission = permission
370 self.sa.add(obj)
370 self.sa.add(obj)
371 log.debug('Granted perm %s to %s on %s' % (perm, user, repo))
371
372
372 def revoke_user_permission(self, repo, user):
373 def revoke_user_permission(self, repo, user):
373 """
374 """
374 Revoke permission for user on given repository
375 Revoke permission for user on given repository
375
376
376 :param repo: Instance of Repository, repository_id, or repository name
377 :param repo: Instance of Repository, repository_id, or repository name
377 :param user: Instance of User, user_id or username
378 :param user: Instance of User, user_id or username
378 """
379 """
379
380
380 user = self._get_user(user)
381 user = self._get_user(user)
381 repo = self._get_repo(repo)
382 repo = self._get_repo(repo)
382
383
383 obj = self.sa.query(UserRepoToPerm)\
384 obj = self.sa.query(UserRepoToPerm)\
384 .filter(UserRepoToPerm.repository == repo)\
385 .filter(UserRepoToPerm.repository == repo)\
385 .filter(UserRepoToPerm.user == user)\
386 .filter(UserRepoToPerm.user == user)\
386 .one()
387 .scalar()
387 self.sa.delete(obj)
388 if obj:
389 self.sa.delete(obj)
390 log.debug('Revoked perm on %s on %s' % (repo, user))
388
391
389 def grant_users_group_permission(self, repo, group_name, perm):
392 def grant_users_group_permission(self, repo, group_name, perm):
390 """
393 """
391 Grant permission for users group on given repository, or update
394 Grant permission for users group on given repository, or update
392 existing one if found
395 existing one if found
393
396
394 :param repo: Instance of Repository, repository_id, or repository name
397 :param repo: Instance of Repository, repository_id, or repository name
395 :param group_name: Instance of UserGroup, users_group_id,
398 :param group_name: Instance of UserGroup, users_group_id,
396 or users group name
399 or users group name
397 :param perm: Instance of Permission, or permission_name
400 :param perm: Instance of Permission, or permission_name
398 """
401 """
399 repo = self._get_repo(repo)
402 repo = self._get_repo(repo)
400 group_name = self.__get_users_group(group_name)
403 group_name = self.__get_users_group(group_name)
401 permission = self._get_perm(perm)
404 permission = self._get_perm(perm)
402
405
403 # check if we have that permission already
406 # check if we have that permission already
404 obj = self.sa.query(UsersGroupRepoToPerm)\
407 obj = self.sa.query(UsersGroupRepoToPerm)\
405 .filter(UsersGroupRepoToPerm.users_group == group_name)\
408 .filter(UsersGroupRepoToPerm.users_group == group_name)\
406 .filter(UsersGroupRepoToPerm.repository == repo)\
409 .filter(UsersGroupRepoToPerm.repository == repo)\
407 .scalar()
410 .scalar()
408
411
409 if obj is None:
412 if obj is None:
410 # create new
413 # create new
411 obj = UsersGroupRepoToPerm()
414 obj = UsersGroupRepoToPerm()
412
415
413 obj.repository = repo
416 obj.repository = repo
414 obj.users_group = group_name
417 obj.users_group = group_name
415 obj.permission = permission
418 obj.permission = permission
416 self.sa.add(obj)
419 self.sa.add(obj)
420 log.debug('Granted perm %s to %s on %s' % (perm, group_name, repo))
417
421
418 def revoke_users_group_permission(self, repo, group_name):
422 def revoke_users_group_permission(self, repo, group_name):
419 """
423 """
420 Revoke permission for users group on given repository
424 Revoke permission for users group on given repository
421
425
422 :param repo: Instance of Repository, repository_id, or repository name
426 :param repo: Instance of Repository, repository_id, or repository name
423 :param group_name: Instance of UserGroup, users_group_id,
427 :param group_name: Instance of UserGroup, users_group_id,
424 or users group name
428 or users group name
425 """
429 """
426 repo = self._get_repo(repo)
430 repo = self._get_repo(repo)
427 group_name = self.__get_users_group(group_name)
431 group_name = self.__get_users_group(group_name)
428
432
429 obj = self.sa.query(UsersGroupRepoToPerm)\
433 obj = self.sa.query(UsersGroupRepoToPerm)\
430 .filter(UsersGroupRepoToPerm.repository == repo)\
434 .filter(UsersGroupRepoToPerm.repository == repo)\
431 .filter(UsersGroupRepoToPerm.users_group == group_name)\
435 .filter(UsersGroupRepoToPerm.users_group == group_name)\
432 .one()
436 .scalar()
433 self.sa.delete(obj)
437 if obj:
438 self.sa.delete(obj)
439 log.debug('Revoked perm to %s on %s' % (repo, group_name))
434
440
435 def delete_stats(self, repo_name):
441 def delete_stats(self, repo_name):
436 """
442 """
437 removes stats for given repo
443 removes stats for given repo
438
444
439 :param repo_name:
445 :param repo_name:
440 """
446 """
441 try:
447 try:
442 obj = self.sa.query(Statistics)\
448 obj = self.sa.query(Statistics)\
443 .filter(Statistics.repository ==
449 .filter(Statistics.repository ==
444 self.get_by_repo_name(repo_name))\
450 self.get_by_repo_name(repo_name))\
445 .one()
451 .one()
446 self.sa.delete(obj)
452 self.sa.delete(obj)
447 except:
453 except:
448 log.error(traceback.format_exc())
454 log.error(traceback.format_exc())
449 raise
455 raise
450
456
451 def __create_repo(self, repo_name, alias, parent, clone_uri=False):
457 def __create_repo(self, repo_name, alias, parent, clone_uri=False):
452 """
458 """
453 makes repository on filesystem. It's group aware means it'll create
459 makes repository on filesystem. It's group aware means it'll create
454 a repository within a group, and alter the paths accordingly of
460 a repository within a group, and alter the paths accordingly of
455 group location
461 group location
456
462
457 :param repo_name:
463 :param repo_name:
458 :param alias:
464 :param alias:
459 :param parent_id:
465 :param parent_id:
460 :param clone_uri:
466 :param clone_uri:
461 """
467 """
462 from rhodecode.lib.utils import is_valid_repo, is_valid_repos_group
468 from rhodecode.lib.utils import is_valid_repo, is_valid_repos_group
463 from rhodecode.model.scm import ScmModel
469 from rhodecode.model.scm import ScmModel
464
470
465 if parent:
471 if parent:
466 new_parent_path = os.sep.join(parent.full_path_splitted)
472 new_parent_path = os.sep.join(parent.full_path_splitted)
467 else:
473 else:
468 new_parent_path = ''
474 new_parent_path = ''
469
475
470 # we need to make it str for mercurial
476 # we need to make it str for mercurial
471 repo_path = os.path.join(*map(lambda x: safe_str(x),
477 repo_path = os.path.join(*map(lambda x: safe_str(x),
472 [self.repos_path, new_parent_path, repo_name]))
478 [self.repos_path, new_parent_path, repo_name]))
473
479
474 # check if this path is not a repository
480 # check if this path is not a repository
475 if is_valid_repo(repo_path, self.repos_path):
481 if is_valid_repo(repo_path, self.repos_path):
476 raise Exception('This path %s is a valid repository' % repo_path)
482 raise Exception('This path %s is a valid repository' % repo_path)
477
483
478 # check if this path is a group
484 # check if this path is a group
479 if is_valid_repos_group(repo_path, self.repos_path):
485 if is_valid_repos_group(repo_path, self.repos_path):
480 raise Exception('This path %s is a valid group' % repo_path)
486 raise Exception('This path %s is a valid group' % repo_path)
481
487
482 log.info('creating repo %s in %s @ %s' % (
488 log.info('creating repo %s in %s @ %s' % (
483 repo_name, safe_unicode(repo_path), clone_uri
489 repo_name, safe_unicode(repo_path), clone_uri
484 )
490 )
485 )
491 )
486 backend = get_backend(alias)
492 backend = get_backend(alias)
487 if alias == 'hg':
493 if alias == 'hg':
488 backend(repo_path, create=True, src_url=clone_uri)
494 backend(repo_path, create=True, src_url=clone_uri)
489 elif alias == 'git':
495 elif alias == 'git':
490 r = backend(repo_path, create=True, src_url=clone_uri, bare=True)
496 r = backend(repo_path, create=True, src_url=clone_uri, bare=True)
491 # add rhodecode hook into this repo
497 # add rhodecode hook into this repo
492 ScmModel().install_git_hook(repo=r)
498 ScmModel().install_git_hook(repo=r)
493 else:
499 else:
494 raise Exception('Undefined alias %s' % alias)
500 raise Exception('Undefined alias %s' % alias)
495
501
496 def __rename_repo(self, old, new):
502 def __rename_repo(self, old, new):
497 """
503 """
498 renames repository on filesystem
504 renames repository on filesystem
499
505
500 :param old: old name
506 :param old: old name
501 :param new: new name
507 :param new: new name
502 """
508 """
503 log.info('renaming repo from %s to %s' % (old, new))
509 log.info('renaming repo from %s to %s' % (old, new))
504
510
505 old_path = os.path.join(self.repos_path, old)
511 old_path = os.path.join(self.repos_path, old)
506 new_path = os.path.join(self.repos_path, new)
512 new_path = os.path.join(self.repos_path, new)
507 if os.path.isdir(new_path):
513 if os.path.isdir(new_path):
508 raise Exception(
514 raise Exception(
509 'Was trying to rename to already existing dir %s' % new_path
515 'Was trying to rename to already existing dir %s' % new_path
510 )
516 )
511 shutil.move(old_path, new_path)
517 shutil.move(old_path, new_path)
512
518
513 def __delete_repo(self, repo):
519 def __delete_repo(self, repo):
514 """
520 """
515 removes repo from filesystem, the removal is acctually made by
521 removes repo from filesystem, the removal is acctually made by
516 added rm__ prefix into dir, and rename internat .hg/.git dirs so this
522 added rm__ prefix into dir, and rename internat .hg/.git dirs so this
517 repository is no longer valid for rhodecode, can be undeleted later on
523 repository is no longer valid for rhodecode, can be undeleted later on
518 by reverting the renames on this repository
524 by reverting the renames on this repository
519
525
520 :param repo: repo object
526 :param repo: repo object
521 """
527 """
522 rm_path = os.path.join(self.repos_path, repo.repo_name)
528 rm_path = os.path.join(self.repos_path, repo.repo_name)
523 log.info("Removing %s" % (rm_path))
529 log.info("Removing %s" % (rm_path))
524 # disable hg/git internal that it doesn't get detected as repo
530 # disable hg/git internal that it doesn't get detected as repo
525 alias = repo.repo_type
531 alias = repo.repo_type
526
532
527 bare = getattr(repo.scm_instance, 'bare', False)
533 bare = getattr(repo.scm_instance, 'bare', False)
528
534
529 if not bare:
535 if not bare:
530 # skip this for bare git repos
536 # skip this for bare git repos
531 shutil.move(os.path.join(rm_path, '.%s' % alias),
537 shutil.move(os.path.join(rm_path, '.%s' % alias),
532 os.path.join(rm_path, 'rm__.%s' % alias))
538 os.path.join(rm_path, 'rm__.%s' % alias))
533 # disable repo
539 # disable repo
534 _now = datetime.now()
540 _now = datetime.now()
535 _ms = str(_now.microsecond).rjust(6, '0')
541 _ms = str(_now.microsecond).rjust(6, '0')
536 _d = 'rm__%s__%s' % (_now.strftime('%Y%m%d_%H%M%S_' + _ms),
542 _d = 'rm__%s__%s' % (_now.strftime('%Y%m%d_%H%M%S_' + _ms),
537 repo.repo_name)
543 repo.repo_name)
538 shutil.move(rm_path, os.path.join(self.repos_path, _d))
544 shutil.move(rm_path, os.path.join(self.repos_path, _d))
@@ -1,314 +1,409 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.model.user_group
3 rhodecode.model.user_group
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 users groups model for RhodeCode
6 users groups model for RhodeCode
7
7
8 :created_on: Jan 25, 2011
8 :created_on: Jan 25, 2011
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2011-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2011-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import os
26 import os
27 import logging
27 import logging
28 import traceback
28 import traceback
29 import shutil
29 import shutil
30
30
31 from rhodecode.lib.utils2 import LazyProperty
31 from rhodecode.lib.utils2 import LazyProperty
32
32
33 from rhodecode.model import BaseModel
33 from rhodecode.model import BaseModel
34 from rhodecode.model.db import RepoGroup, RhodeCodeUi, UserRepoGroupToPerm, \
34 from rhodecode.model.db import RepoGroup, RhodeCodeUi, UserRepoGroupToPerm, \
35 User, Permission, UsersGroupRepoGroupToPerm, UsersGroup
35 User, Permission, UsersGroupRepoGroupToPerm, UsersGroup, Repository
36
36
37 log = logging.getLogger(__name__)
37 log = logging.getLogger(__name__)
38
38
39
39
40 class ReposGroupModel(BaseModel):
40 class ReposGroupModel(BaseModel):
41
41
42 cls = RepoGroup
42 cls = RepoGroup
43
43
44 def __get_users_group(self, users_group):
44 def __get_users_group(self, users_group):
45 return self._get_instance(UsersGroup, users_group,
45 return self._get_instance(UsersGroup, users_group,
46 callback=UsersGroup.get_by_group_name)
46 callback=UsersGroup.get_by_group_name)
47
47
48 def _get_repos_group(self, repos_group):
48 def _get_repos_group(self, repos_group):
49 return self._get_instance(RepoGroup, repos_group,
49 return self._get_instance(RepoGroup, repos_group,
50 callback=RepoGroup.get_by_group_name)
50 callback=RepoGroup.get_by_group_name)
51
51
52 @LazyProperty
52 @LazyProperty
53 def repos_path(self):
53 def repos_path(self):
54 """
54 """
55 Get's the repositories root path from database
55 Get's the repositories root path from database
56 """
56 """
57
57
58 q = RhodeCodeUi.get_by_key('/')
58 q = RhodeCodeUi.get_by_key('/')
59 return q.ui_value
59 return q.ui_value
60
60
61 def _create_default_perms(self, new_group):
61 def _create_default_perms(self, new_group):
62 # create default permission
62 # create default permission
63 repo_group_to_perm = UserRepoGroupToPerm()
63 repo_group_to_perm = UserRepoGroupToPerm()
64 default_perm = 'group.read'
64 default_perm = 'group.read'
65 for p in User.get_by_username('default').user_perms:
65 for p in User.get_by_username('default').user_perms:
66 if p.permission.permission_name.startswith('group.'):
66 if p.permission.permission_name.startswith('group.'):
67 default_perm = p.permission.permission_name
67 default_perm = p.permission.permission_name
68 break
68 break
69
69
70 repo_group_to_perm.permission_id = self.sa.query(Permission)\
70 repo_group_to_perm.permission_id = self.sa.query(Permission)\
71 .filter(Permission.permission_name == default_perm)\
71 .filter(Permission.permission_name == default_perm)\
72 .one().permission_id
72 .one().permission_id
73
73
74 repo_group_to_perm.group = new_group
74 repo_group_to_perm.group = new_group
75 repo_group_to_perm.user_id = User.get_by_username('default').user_id
75 repo_group_to_perm.user_id = User.get_by_username('default').user_id
76
76
77 self.sa.add(repo_group_to_perm)
77 self.sa.add(repo_group_to_perm)
78
78
79 def __create_group(self, group_name):
79 def __create_group(self, group_name):
80 """
80 """
81 makes repositories group on filesystem
81 makes repositories group on filesystem
82
82
83 :param repo_name:
83 :param repo_name:
84 :param parent_id:
84 :param parent_id:
85 """
85 """
86
86
87 create_path = os.path.join(self.repos_path, group_name)
87 create_path = os.path.join(self.repos_path, group_name)
88 log.debug('creating new group in %s' % create_path)
88 log.debug('creating new group in %s' % create_path)
89
89
90 if os.path.isdir(create_path):
90 if os.path.isdir(create_path):
91 raise Exception('That directory already exists !')
91 raise Exception('That directory already exists !')
92
92
93 os.makedirs(create_path)
93 os.makedirs(create_path)
94
94
95 def __rename_group(self, old, new):
95 def __rename_group(self, old, new):
96 """
96 """
97 Renames a group on filesystem
97 Renames a group on filesystem
98
98
99 :param group_name:
99 :param group_name:
100 """
100 """
101
101
102 if old == new:
102 if old == new:
103 log.debug('skipping group rename')
103 log.debug('skipping group rename')
104 return
104 return
105
105
106 log.debug('renaming repos group from %s to %s' % (old, new))
106 log.debug('renaming repos group from %s to %s' % (old, new))
107
107
108 old_path = os.path.join(self.repos_path, old)
108 old_path = os.path.join(self.repos_path, old)
109 new_path = os.path.join(self.repos_path, new)
109 new_path = os.path.join(self.repos_path, new)
110
110
111 log.debug('renaming repos paths from %s to %s' % (old_path, new_path))
111 log.debug('renaming repos paths from %s to %s' % (old_path, new_path))
112
112
113 if os.path.isdir(new_path):
113 if os.path.isdir(new_path):
114 raise Exception('Was trying to rename to already '
114 raise Exception('Was trying to rename to already '
115 'existing dir %s' % new_path)
115 'existing dir %s' % new_path)
116 shutil.move(old_path, new_path)
116 shutil.move(old_path, new_path)
117
117
118 def __delete_group(self, group):
118 def __delete_group(self, group, force_delete=False):
119 """
119 """
120 Deletes a group from a filesystem
120 Deletes a group from a filesystem
121
121
122 :param group: instance of group from database
122 :param group: instance of group from database
123 :param force_delete: use shutil rmtree to remove all objects
123 """
124 """
124 paths = group.full_path.split(RepoGroup.url_sep())
125 paths = group.full_path.split(RepoGroup.url_sep())
125 paths = os.sep.join(paths)
126 paths = os.sep.join(paths)
126
127
127 rm_path = os.path.join(self.repos_path, paths)
128 rm_path = os.path.join(self.repos_path, paths)
128 if os.path.isdir(rm_path):
129 if os.path.isdir(rm_path):
129 # delete only if that path really exists
130 # delete only if that path really exists
130 os.rmdir(rm_path)
131 if force_delete:
132 shutil.rmtree(rm_path)
133 else:
134 os.rmdir(rm_path) # this raises an exception when there are still objects inside
131
135
132 def create(self, group_name, group_description, parent=None, just_db=False):
136 def create(self, group_name, group_description, parent=None, just_db=False):
133 try:
137 try:
134 new_repos_group = RepoGroup()
138 new_repos_group = RepoGroup()
135 new_repos_group.group_description = group_description
139 new_repos_group.group_description = group_description
136 new_repos_group.parent_group = self._get_repos_group(parent)
140 new_repos_group.parent_group = self._get_repos_group(parent)
137 new_repos_group.group_name = new_repos_group.get_new_name(group_name)
141 new_repos_group.group_name = new_repos_group.get_new_name(group_name)
138
142
139 self.sa.add(new_repos_group)
143 self.sa.add(new_repos_group)
140 self._create_default_perms(new_repos_group)
144 self._create_default_perms(new_repos_group)
141
145
142 if not just_db:
146 if not just_db:
143 # we need to flush here, in order to check if database won't
147 # we need to flush here, in order to check if database won't
144 # throw any exceptions, create filesystem dirs at the very end
148 # throw any exceptions, create filesystem dirs at the very end
145 self.sa.flush()
149 self.sa.flush()
146 self.__create_group(new_repos_group.group_name)
150 self.__create_group(new_repos_group.group_name)
147
151
148 return new_repos_group
152 return new_repos_group
149 except:
153 except:
150 log.error(traceback.format_exc())
154 log.error(traceback.format_exc())
151 raise
155 raise
152
156
157 def _update_permissions(self, repos_group, perms_new=None,
158 perms_updates=None, recursive=False):
159 from rhodecode.model.repo import RepoModel
160 if not perms_new:
161 perms_new = []
162 if not perms_updates:
163 perms_updates = []
164
165 def _set_perm_user(obj, user, perm):
166 if isinstance(obj, RepoGroup):
167 ReposGroupModel().grant_user_permission(
168 repos_group=obj, user=user, perm=perm
169 )
170 elif isinstance(obj, Repository):
171 # we set group permission but we have to switch to repo
172 # permission
173 perm = perm.replace('group.', 'repository.')
174 RepoModel().grant_user_permission(
175 repo=obj, user=user, perm=perm
176 )
177
178 def _set_perm_group(obj, users_group, perm):
179 if isinstance(obj, RepoGroup):
180 ReposGroupModel().grant_users_group_permission(
181 repos_group=obj, group_name=users_group, perm=perm
182 )
183 elif isinstance(obj, Repository):
184 # we set group permission but we have to switch to repo
185 # permission
186 perm = perm.replace('group.', 'repository.')
187 RepoModel().grant_users_group_permission(
188 repo=obj, group_name=users_group, perm=perm
189 )
190 updates = []
191 log.debug('Now updating permissions for %s in recursive mode:%s'
192 % (repos_group, recursive))
193
194 for obj in repos_group.recursive_groups_and_repos():
195 if not recursive:
196 obj = repos_group
197
198 # update permissions
199 for member, perm, member_type in perms_updates:
200 ## set for user
201 if member_type == 'user':
202 # this updates also current one if found
203 _set_perm_user(obj, user=member, perm=perm)
204 ## set for users group
205 else:
206 _set_perm_group(obj, users_group=member, perm=perm)
207 # set new permissions
208 for member, perm, member_type in perms_new:
209 if member_type == 'user':
210 _set_perm_user(obj, user=member, perm=perm)
211 else:
212 _set_perm_group(obj, users_group=member, perm=perm)
213 updates.append(obj)
214 #if it's not recursive call
215 # break the loop and don't proceed with other changes
216 if not recursive:
217 break
218 return updates
219
153 def update(self, repos_group_id, form_data):
220 def update(self, repos_group_id, form_data):
154
221
155 try:
222 try:
156 repos_group = RepoGroup.get(repos_group_id)
223 repos_group = RepoGroup.get(repos_group_id)
157
224 recursive = form_data['recursive']
158 # update permissions
225 # iterate over all members(if in recursive mode) of this groups and
159 for member, perm, member_type in form_data['perms_updates']:
226 # set the permissions !
160 if member_type == 'user':
227 # this can be potentially heavy operation
161 # this updates also current one if found
228 self._update_permissions(repos_group, form_data['perms_new'],
162 ReposGroupModel().grant_user_permission(
229 form_data['perms_updates'], recursive)
163 repos_group=repos_group, user=member, perm=perm
164 )
165 else:
166 ReposGroupModel().grant_users_group_permission(
167 repos_group=repos_group, group_name=member, perm=perm
168 )
169 # set new permissions
170 for member, perm, member_type in form_data['perms_new']:
171 if member_type == 'user':
172 ReposGroupModel().grant_user_permission(
173 repos_group=repos_group, user=member, perm=perm
174 )
175 else:
176 ReposGroupModel().grant_users_group_permission(
177 repos_group=repos_group, group_name=member, perm=perm
178 )
179
230
180 old_path = repos_group.full_path
231 old_path = repos_group.full_path
181
232
182 # change properties
233 # change properties
183 repos_group.group_description = form_data['group_description']
234 repos_group.group_description = form_data['group_description']
184 repos_group.parent_group = RepoGroup.get(form_data['group_parent_id'])
235 repos_group.parent_group = RepoGroup.get(form_data['group_parent_id'])
185 repos_group.group_parent_id = form_data['group_parent_id']
236 repos_group.group_parent_id = form_data['group_parent_id']
186 repos_group.enable_locking = form_data['enable_locking']
237 repos_group.enable_locking = form_data['enable_locking']
187 repos_group.group_name = repos_group.get_new_name(form_data['group_name'])
238 repos_group.group_name = repos_group.get_new_name(form_data['group_name'])
188 new_path = repos_group.full_path
239 new_path = repos_group.full_path
189
240
190 self.sa.add(repos_group)
241 self.sa.add(repos_group)
191
242
192 # iterate over all members of this groups and set the locking !
243 # iterate over all members of this groups and set the locking !
193 # this can be potentially heavy operation
244 # this can be potentially heavy operation
194
195 for obj in repos_group.recursive_groups_and_repos():
245 for obj in repos_group.recursive_groups_and_repos():
196 #set the value from it's parent
246 #set the value from it's parent
197 obj.enable_locking = repos_group.enable_locking
247 obj.enable_locking = repos_group.enable_locking
198 self.sa.add(obj)
248 self.sa.add(obj)
199
249
200 # we need to get all repositories from this new group and
250 # we need to get all repositories from this new group and
201 # rename them accordingly to new group path
251 # rename them accordingly to new group path
202 for r in repos_group.repositories:
252 for r in repos_group.repositories:
203 r.repo_name = r.get_new_name(r.just_name)
253 r.repo_name = r.get_new_name(r.just_name)
204 self.sa.add(r)
254 self.sa.add(r)
205
255
206 self.__rename_group(old_path, new_path)
256 self.__rename_group(old_path, new_path)
207
257
208 return repos_group
258 return repos_group
209 except:
259 except:
210 log.error(traceback.format_exc())
260 log.error(traceback.format_exc())
211 raise
261 raise
212
262
213 def delete(self, repos_group):
263 def delete(self, repos_group, force_delete=False):
214 repos_group = self._get_repos_group(repos_group)
264 repos_group = self._get_repos_group(repos_group)
215 try:
265 try:
216 self.sa.delete(repos_group)
266 self.sa.delete(repos_group)
217 self.__delete_group(repos_group)
267 self.__delete_group(repos_group, force_delete)
218 except:
268 except:
219 log.exception('Error removing repos_group %s' % repos_group)
269 log.exception('Error removing repos_group %s' % repos_group)
220 raise
270 raise
221
271
272 def delete_permission(self, repos_group, obj, obj_type, recursive):
273 """
274 Revokes permission for repos_group for given obj(user or users_group),
275 obj_type can be user or users group
276
277 :param repos_group:
278 :param obj: user or users group id
279 :param obj_type: user or users group type
280 :param recursive: recurse to all children of group
281 """
282 from rhodecode.model.repo import RepoModel
283 repos_group = self._get_repos_group(repos_group)
284
285 for el in repos_group.recursive_groups_and_repos():
286 if not recursive:
287 # if we don't recurse set the permission on only the top level
288 # object
289 el = repos_group
290
291 if isinstance(el, RepoGroup):
292 if obj_type == 'user':
293 ReposGroupModel().revoke_user_permission(el, user=obj)
294 elif obj_type == 'users_group':
295 ReposGroupModel().revoke_users_group_permission(el, group_name=obj)
296 else:
297 raise Exception('undefined object type %s' % obj_type)
298 elif isinstance(el, Repository):
299 if obj_type == 'user':
300 RepoModel().revoke_user_permission(el, user=obj)
301 elif obj_type == 'users_group':
302 RepoModel().revoke_users_group_permission(el, group_name=obj)
303 else:
304 raise Exception('undefined object type %s' % obj_type)
305
306 #if it's not recursive call
307 # break the loop and don't proceed with other changes
308 if not recursive:
309 break
310
222 def grant_user_permission(self, repos_group, user, perm):
311 def grant_user_permission(self, repos_group, user, perm):
223 """
312 """
224 Grant permission for user on given repositories group, or update
313 Grant permission for user on given repositories group, or update
225 existing one if found
314 existing one if found
226
315
227 :param repos_group: Instance of ReposGroup, repositories_group_id,
316 :param repos_group: Instance of ReposGroup, repositories_group_id,
228 or repositories_group name
317 or repositories_group name
229 :param user: Instance of User, user_id or username
318 :param user: Instance of User, user_id or username
230 :param perm: Instance of Permission, or permission_name
319 :param perm: Instance of Permission, or permission_name
231 """
320 """
232
321
233 repos_group = self._get_repos_group(repos_group)
322 repos_group = self._get_repos_group(repos_group)
234 user = self._get_user(user)
323 user = self._get_user(user)
235 permission = self._get_perm(perm)
324 permission = self._get_perm(perm)
236
325
237 # check if we have that permission already
326 # check if we have that permission already
238 obj = self.sa.query(UserRepoGroupToPerm)\
327 obj = self.sa.query(UserRepoGroupToPerm)\
239 .filter(UserRepoGroupToPerm.user == user)\
328 .filter(UserRepoGroupToPerm.user == user)\
240 .filter(UserRepoGroupToPerm.group == repos_group)\
329 .filter(UserRepoGroupToPerm.group == repos_group)\
241 .scalar()
330 .scalar()
242 if obj is None:
331 if obj is None:
243 # create new !
332 # create new !
244 obj = UserRepoGroupToPerm()
333 obj = UserRepoGroupToPerm()
245 obj.group = repos_group
334 obj.group = repos_group
246 obj.user = user
335 obj.user = user
247 obj.permission = permission
336 obj.permission = permission
248 self.sa.add(obj)
337 self.sa.add(obj)
338 log.debug('Granted perm %s to %s on %s' % (perm, user, repos_group))
249
339
250 def revoke_user_permission(self, repos_group, user):
340 def revoke_user_permission(self, repos_group, user):
251 """
341 """
252 Revoke permission for user on given repositories group
342 Revoke permission for user on given repositories group
253
343
254 :param repos_group: Instance of ReposGroup, repositories_group_id,
344 :param repos_group: Instance of ReposGroup, repositories_group_id,
255 or repositories_group name
345 or repositories_group name
256 :param user: Instance of User, user_id or username
346 :param user: Instance of User, user_id or username
257 """
347 """
258
348
259 repos_group = self._get_repos_group(repos_group)
349 repos_group = self._get_repos_group(repos_group)
260 user = self._get_user(user)
350 user = self._get_user(user)
261
351
262 obj = self.sa.query(UserRepoGroupToPerm)\
352 obj = self.sa.query(UserRepoGroupToPerm)\
263 .filter(UserRepoGroupToPerm.user == user)\
353 .filter(UserRepoGroupToPerm.user == user)\
264 .filter(UserRepoGroupToPerm.group == repos_group)\
354 .filter(UserRepoGroupToPerm.group == repos_group)\
265 .one()
355 .scalar()
266 self.sa.delete(obj)
356 if obj:
357 self.sa.delete(obj)
358 log.debug('Revoked perm on %s on %s' % (repos_group, user))
267
359
268 def grant_users_group_permission(self, repos_group, group_name, perm):
360 def grant_users_group_permission(self, repos_group, group_name, perm):
269 """
361 """
270 Grant permission for users group on given repositories group, or update
362 Grant permission for users group on given repositories group, or update
271 existing one if found
363 existing one if found
272
364
273 :param repos_group: Instance of ReposGroup, repositories_group_id,
365 :param repos_group: Instance of ReposGroup, repositories_group_id,
274 or repositories_group name
366 or repositories_group name
275 :param group_name: Instance of UserGroup, users_group_id,
367 :param group_name: Instance of UserGroup, users_group_id,
276 or users group name
368 or users group name
277 :param perm: Instance of Permission, or permission_name
369 :param perm: Instance of Permission, or permission_name
278 """
370 """
279 repos_group = self._get_repos_group(repos_group)
371 repos_group = self._get_repos_group(repos_group)
280 group_name = self.__get_users_group(group_name)
372 group_name = self.__get_users_group(group_name)
281 permission = self._get_perm(perm)
373 permission = self._get_perm(perm)
282
374
283 # check if we have that permission already
375 # check if we have that permission already
284 obj = self.sa.query(UsersGroupRepoGroupToPerm)\
376 obj = self.sa.query(UsersGroupRepoGroupToPerm)\
285 .filter(UsersGroupRepoGroupToPerm.group == repos_group)\
377 .filter(UsersGroupRepoGroupToPerm.group == repos_group)\
286 .filter(UsersGroupRepoGroupToPerm.users_group == group_name)\
378 .filter(UsersGroupRepoGroupToPerm.users_group == group_name)\
287 .scalar()
379 .scalar()
288
380
289 if obj is None:
381 if obj is None:
290 # create new
382 # create new
291 obj = UsersGroupRepoGroupToPerm()
383 obj = UsersGroupRepoGroupToPerm()
292
384
293 obj.group = repos_group
385 obj.group = repos_group
294 obj.users_group = group_name
386 obj.users_group = group_name
295 obj.permission = permission
387 obj.permission = permission
296 self.sa.add(obj)
388 self.sa.add(obj)
389 log.debug('Granted perm %s to %s on %s' % (perm, group_name, repos_group))
297
390
298 def revoke_users_group_permission(self, repos_group, group_name):
391 def revoke_users_group_permission(self, repos_group, group_name):
299 """
392 """
300 Revoke permission for users group on given repositories group
393 Revoke permission for users group on given repositories group
301
394
302 :param repos_group: Instance of ReposGroup, repositories_group_id,
395 :param repos_group: Instance of ReposGroup, repositories_group_id,
303 or repositories_group name
396 or repositories_group name
304 :param group_name: Instance of UserGroup, users_group_id,
397 :param group_name: Instance of UserGroup, users_group_id,
305 or users group name
398 or users group name
306 """
399 """
307 repos_group = self._get_repos_group(repos_group)
400 repos_group = self._get_repos_group(repos_group)
308 group_name = self.__get_users_group(group_name)
401 group_name = self.__get_users_group(group_name)
309
402
310 obj = self.sa.query(UsersGroupRepoGroupToPerm)\
403 obj = self.sa.query(UsersGroupRepoGroupToPerm)\
311 .filter(UsersGroupRepoGroupToPerm.group == repos_group)\
404 .filter(UsersGroupRepoGroupToPerm.group == repos_group)\
312 .filter(UsersGroupRepoGroupToPerm.users_group == group_name)\
405 .filter(UsersGroupRepoGroupToPerm.users_group == group_name)\
313 .one()
406 .scalar()
314 self.sa.delete(obj)
407 if obj:
408 self.sa.delete(obj)
409 log.debug('Revoked perm to %s on %s' % (repos_group, group_name))
@@ -1,669 +1,669 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.model.user
3 rhodecode.model.user
4 ~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~
5
5
6 users model for RhodeCode
6 users model for RhodeCode
7
7
8 :created_on: Apr 9, 2010
8 :created_on: Apr 9, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import logging
26 import logging
27 import traceback
27 import traceback
28 import itertools
28 import itertools
29 from pylons import url
29 from pylons import url
30 from pylons.i18n.translation import _
30 from pylons.i18n.translation import _
31
31
32 from sqlalchemy.exc import DatabaseError
32 from sqlalchemy.exc import DatabaseError
33 from sqlalchemy.orm import joinedload
33 from sqlalchemy.orm import joinedload
34
34
35 from rhodecode.lib.utils2 import safe_unicode, generate_api_key
35 from rhodecode.lib.utils2 import safe_unicode, generate_api_key
36 from rhodecode.lib.caching_query import FromCache
36 from rhodecode.lib.caching_query import FromCache
37 from rhodecode.model import BaseModel
37 from rhodecode.model import BaseModel
38 from rhodecode.model.db import User, UserRepoToPerm, Repository, Permission, \
38 from rhodecode.model.db import User, UserRepoToPerm, Repository, Permission, \
39 UserToPerm, UsersGroupRepoToPerm, UsersGroupToPerm, UsersGroupMember, \
39 UserToPerm, UsersGroupRepoToPerm, UsersGroupToPerm, UsersGroupMember, \
40 Notification, RepoGroup, UserRepoGroupToPerm, UsersGroupRepoGroupToPerm, \
40 Notification, RepoGroup, UserRepoGroupToPerm, UsersGroupRepoGroupToPerm, \
41 UserEmailMap
41 UserEmailMap
42 from rhodecode.lib.exceptions import DefaultUserException, \
42 from rhodecode.lib.exceptions import DefaultUserException, \
43 UserOwnsReposException
43 UserOwnsReposException
44
44
45
45
46 log = logging.getLogger(__name__)
46 log = logging.getLogger(__name__)
47
47
48 PERM_WEIGHTS = Permission.PERM_WEIGHTS
48 PERM_WEIGHTS = Permission.PERM_WEIGHTS
49
49
50
50
51 class UserModel(BaseModel):
51 class UserModel(BaseModel):
52 cls = User
52 cls = User
53
53
54 def get(self, user_id, cache=False):
54 def get(self, user_id, cache=False):
55 user = self.sa.query(User)
55 user = self.sa.query(User)
56 if cache:
56 if cache:
57 user = user.options(FromCache("sql_cache_short",
57 user = user.options(FromCache("sql_cache_short",
58 "get_user_%s" % user_id))
58 "get_user_%s" % user_id))
59 return user.get(user_id)
59 return user.get(user_id)
60
60
61 def get_user(self, user):
61 def get_user(self, user):
62 return self._get_user(user)
62 return self._get_user(user)
63
63
64 def get_by_username(self, username, cache=False, case_insensitive=False):
64 def get_by_username(self, username, cache=False, case_insensitive=False):
65
65
66 if case_insensitive:
66 if case_insensitive:
67 user = self.sa.query(User).filter(User.username.ilike(username))
67 user = self.sa.query(User).filter(User.username.ilike(username))
68 else:
68 else:
69 user = self.sa.query(User)\
69 user = self.sa.query(User)\
70 .filter(User.username == username)
70 .filter(User.username == username)
71 if cache:
71 if cache:
72 user = user.options(FromCache("sql_cache_short",
72 user = user.options(FromCache("sql_cache_short",
73 "get_user_%s" % username))
73 "get_user_%s" % username))
74 return user.scalar()
74 return user.scalar()
75
75
76 def get_by_email(self, email, cache=False, case_insensitive=False):
76 def get_by_email(self, email, cache=False, case_insensitive=False):
77 return User.get_by_email(email, case_insensitive, cache)
77 return User.get_by_email(email, case_insensitive, cache)
78
78
79 def get_by_api_key(self, api_key, cache=False):
79 def get_by_api_key(self, api_key, cache=False):
80 return User.get_by_api_key(api_key, cache)
80 return User.get_by_api_key(api_key, cache)
81
81
82 def create(self, form_data):
82 def create(self, form_data):
83 from rhodecode.lib.auth import get_crypt_password
83 from rhodecode.lib.auth import get_crypt_password
84 try:
84 try:
85 new_user = User()
85 new_user = User()
86 for k, v in form_data.items():
86 for k, v in form_data.items():
87 if k == 'password':
87 if k == 'password':
88 v = get_crypt_password(v)
88 v = get_crypt_password(v)
89 if k == 'firstname':
89 if k == 'firstname':
90 k = 'name'
90 k = 'name'
91 setattr(new_user, k, v)
91 setattr(new_user, k, v)
92
92
93 new_user.api_key = generate_api_key(form_data['username'])
93 new_user.api_key = generate_api_key(form_data['username'])
94 self.sa.add(new_user)
94 self.sa.add(new_user)
95 return new_user
95 return new_user
96 except:
96 except:
97 log.error(traceback.format_exc())
97 log.error(traceback.format_exc())
98 raise
98 raise
99
99
100 def create_or_update(self, username, password, email, firstname='',
100 def create_or_update(self, username, password, email, firstname='',
101 lastname='', active=True, admin=False, ldap_dn=None):
101 lastname='', active=True, admin=False, ldap_dn=None):
102 """
102 """
103 Creates a new instance if not found, or updates current one
103 Creates a new instance if not found, or updates current one
104
104
105 :param username:
105 :param username:
106 :param password:
106 :param password:
107 :param email:
107 :param email:
108 :param active:
108 :param active:
109 :param firstname:
109 :param firstname:
110 :param lastname:
110 :param lastname:
111 :param active:
111 :param active:
112 :param admin:
112 :param admin:
113 :param ldap_dn:
113 :param ldap_dn:
114 """
114 """
115
115
116 from rhodecode.lib.auth import get_crypt_password
116 from rhodecode.lib.auth import get_crypt_password
117
117
118 log.debug('Checking for %s account in RhodeCode database' % username)
118 log.debug('Checking for %s account in RhodeCode database' % username)
119 user = User.get_by_username(username, case_insensitive=True)
119 user = User.get_by_username(username, case_insensitive=True)
120 if user is None:
120 if user is None:
121 log.debug('creating new user %s' % username)
121 log.debug('creating new user %s' % username)
122 new_user = User()
122 new_user = User()
123 edit = False
123 edit = False
124 else:
124 else:
125 log.debug('updating user %s' % username)
125 log.debug('updating user %s' % username)
126 new_user = user
126 new_user = user
127 edit = True
127 edit = True
128
128
129 try:
129 try:
130 new_user.username = username
130 new_user.username = username
131 new_user.admin = admin
131 new_user.admin = admin
132 # set password only if creating an user or password is changed
132 # set password only if creating an user or password is changed
133 if edit is False or user.password != password:
133 if edit is False or user.password != password:
134 new_user.password = get_crypt_password(password)
134 new_user.password = get_crypt_password(password)
135 new_user.api_key = generate_api_key(username)
135 new_user.api_key = generate_api_key(username)
136 new_user.email = email
136 new_user.email = email
137 new_user.active = active
137 new_user.active = active
138 new_user.ldap_dn = safe_unicode(ldap_dn) if ldap_dn else None
138 new_user.ldap_dn = safe_unicode(ldap_dn) if ldap_dn else None
139 new_user.name = firstname
139 new_user.name = firstname
140 new_user.lastname = lastname
140 new_user.lastname = lastname
141 self.sa.add(new_user)
141 self.sa.add(new_user)
142 return new_user
142 return new_user
143 except (DatabaseError,):
143 except (DatabaseError,):
144 log.error(traceback.format_exc())
144 log.error(traceback.format_exc())
145 raise
145 raise
146
146
147 def create_for_container_auth(self, username, attrs):
147 def create_for_container_auth(self, username, attrs):
148 """
148 """
149 Creates the given user if it's not already in the database
149 Creates the given user if it's not already in the database
150
150
151 :param username:
151 :param username:
152 :param attrs:
152 :param attrs:
153 """
153 """
154 if self.get_by_username(username, case_insensitive=True) is None:
154 if self.get_by_username(username, case_insensitive=True) is None:
155
155
156 # autogenerate email for container account without one
156 # autogenerate email for container account without one
157 generate_email = lambda usr: '%s@container_auth.account' % usr
157 generate_email = lambda usr: '%s@container_auth.account' % usr
158
158
159 try:
159 try:
160 new_user = User()
160 new_user = User()
161 new_user.username = username
161 new_user.username = username
162 new_user.password = None
162 new_user.password = None
163 new_user.api_key = generate_api_key(username)
163 new_user.api_key = generate_api_key(username)
164 new_user.email = attrs['email']
164 new_user.email = attrs['email']
165 new_user.active = attrs.get('active', True)
165 new_user.active = attrs.get('active', True)
166 new_user.name = attrs['name'] or generate_email(username)
166 new_user.name = attrs['name'] or generate_email(username)
167 new_user.lastname = attrs['lastname']
167 new_user.lastname = attrs['lastname']
168
168
169 self.sa.add(new_user)
169 self.sa.add(new_user)
170 return new_user
170 return new_user
171 except (DatabaseError,):
171 except (DatabaseError,):
172 log.error(traceback.format_exc())
172 log.error(traceback.format_exc())
173 self.sa.rollback()
173 self.sa.rollback()
174 raise
174 raise
175 log.debug('User %s already exists. Skipping creation of account'
175 log.debug('User %s already exists. Skipping creation of account'
176 ' for container auth.', username)
176 ' for container auth.', username)
177 return None
177 return None
178
178
179 def create_ldap(self, username, password, user_dn, attrs):
179 def create_ldap(self, username, password, user_dn, attrs):
180 """
180 """
181 Checks if user is in database, if not creates this user marked
181 Checks if user is in database, if not creates this user marked
182 as ldap user
182 as ldap user
183
183
184 :param username:
184 :param username:
185 :param password:
185 :param password:
186 :param user_dn:
186 :param user_dn:
187 :param attrs:
187 :param attrs:
188 """
188 """
189 from rhodecode.lib.auth import get_crypt_password
189 from rhodecode.lib.auth import get_crypt_password
190 log.debug('Checking for such ldap account in RhodeCode database')
190 log.debug('Checking for such ldap account in RhodeCode database')
191 if self.get_by_username(username, case_insensitive=True) is None:
191 if self.get_by_username(username, case_insensitive=True) is None:
192
192
193 # autogenerate email for ldap account without one
193 # autogenerate email for ldap account without one
194 generate_email = lambda usr: '%s@ldap.account' % usr
194 generate_email = lambda usr: '%s@ldap.account' % usr
195
195
196 try:
196 try:
197 new_user = User()
197 new_user = User()
198 username = username.lower()
198 username = username.lower()
199 # add ldap account always lowercase
199 # add ldap account always lowercase
200 new_user.username = username
200 new_user.username = username
201 new_user.password = get_crypt_password(password)
201 new_user.password = get_crypt_password(password)
202 new_user.api_key = generate_api_key(username)
202 new_user.api_key = generate_api_key(username)
203 new_user.email = attrs['email'] or generate_email(username)
203 new_user.email = attrs['email'] or generate_email(username)
204 new_user.active = attrs.get('active', True)
204 new_user.active = attrs.get('active', True)
205 new_user.ldap_dn = safe_unicode(user_dn)
205 new_user.ldap_dn = safe_unicode(user_dn)
206 new_user.name = attrs['name']
206 new_user.name = attrs['name']
207 new_user.lastname = attrs['lastname']
207 new_user.lastname = attrs['lastname']
208
208
209 self.sa.add(new_user)
209 self.sa.add(new_user)
210 return new_user
210 return new_user
211 except (DatabaseError,):
211 except (DatabaseError,):
212 log.error(traceback.format_exc())
212 log.error(traceback.format_exc())
213 self.sa.rollback()
213 self.sa.rollback()
214 raise
214 raise
215 log.debug('this %s user exists skipping creation of ldap account',
215 log.debug('this %s user exists skipping creation of ldap account',
216 username)
216 username)
217 return None
217 return None
218
218
219 def create_registration(self, form_data):
219 def create_registration(self, form_data):
220 from rhodecode.model.notification import NotificationModel
220 from rhodecode.model.notification import NotificationModel
221
221
222 try:
222 try:
223 form_data['admin'] = False
223 form_data['admin'] = False
224 new_user = self.create(form_data)
224 new_user = self.create(form_data)
225
225
226 self.sa.add(new_user)
226 self.sa.add(new_user)
227 self.sa.flush()
227 self.sa.flush()
228
228
229 # notification to admins
229 # notification to admins
230 subject = _('new user registration')
230 subject = _('new user registration')
231 body = ('New user registration\n'
231 body = ('New user registration\n'
232 '---------------------\n'
232 '---------------------\n'
233 '- Username: %s\n'
233 '- Username: %s\n'
234 '- Full Name: %s\n'
234 '- Full Name: %s\n'
235 '- Email: %s\n')
235 '- Email: %s\n')
236 body = body % (new_user.username, new_user.full_name,
236 body = body % (new_user.username, new_user.full_name,
237 new_user.email)
237 new_user.email)
238 edit_url = url('edit_user', id=new_user.user_id, qualified=True)
238 edit_url = url('edit_user', id=new_user.user_id, qualified=True)
239 kw = {'registered_user_url': edit_url}
239 kw = {'registered_user_url': edit_url}
240 NotificationModel().create(created_by=new_user, subject=subject,
240 NotificationModel().create(created_by=new_user, subject=subject,
241 body=body, recipients=None,
241 body=body, recipients=None,
242 type_=Notification.TYPE_REGISTRATION,
242 type_=Notification.TYPE_REGISTRATION,
243 email_kwargs=kw)
243 email_kwargs=kw)
244
244
245 except:
245 except:
246 log.error(traceback.format_exc())
246 log.error(traceback.format_exc())
247 raise
247 raise
248
248
249 def update(self, user_id, form_data):
249 def update(self, user_id, form_data):
250 from rhodecode.lib.auth import get_crypt_password
250 from rhodecode.lib.auth import get_crypt_password
251 try:
251 try:
252 user = self.get(user_id, cache=False)
252 user = self.get(user_id, cache=False)
253 if user.username == 'default':
253 if user.username == 'default':
254 raise DefaultUserException(
254 raise DefaultUserException(
255 _("You can't Edit this user since it's"
255 _("You can't Edit this user since it's"
256 " crucial for entire application"))
256 " crucial for entire application"))
257
257
258 for k, v in form_data.items():
258 for k, v in form_data.items():
259 if k == 'new_password' and v:
259 if k == 'new_password' and v:
260 user.password = get_crypt_password(v)
260 user.password = get_crypt_password(v)
261 user.api_key = generate_api_key(user.username)
261 user.api_key = generate_api_key(user.username)
262 else:
262 else:
263 if k == 'firstname':
263 if k == 'firstname':
264 k = 'name'
264 k = 'name'
265 setattr(user, k, v)
265 setattr(user, k, v)
266 self.sa.add(user)
266 self.sa.add(user)
267 except:
267 except:
268 log.error(traceback.format_exc())
268 log.error(traceback.format_exc())
269 raise
269 raise
270
270
271 def update_user(self, user, **kwargs):
271 def update_user(self, user, **kwargs):
272 from rhodecode.lib.auth import get_crypt_password
272 from rhodecode.lib.auth import get_crypt_password
273 try:
273 try:
274 user = self._get_user(user)
274 user = self._get_user(user)
275 if user.username == 'default':
275 if user.username == 'default':
276 raise DefaultUserException(
276 raise DefaultUserException(
277 _("You can't Edit this user since it's"
277 _("You can't Edit this user since it's"
278 " crucial for entire application")
278 " crucial for entire application")
279 )
279 )
280
280
281 for k, v in kwargs.items():
281 for k, v in kwargs.items():
282 if k == 'password' and v:
282 if k == 'password' and v:
283 v = get_crypt_password(v)
283 v = get_crypt_password(v)
284 user.api_key = generate_api_key(user.username)
284 user.api_key = generate_api_key(user.username)
285
285
286 setattr(user, k, v)
286 setattr(user, k, v)
287 self.sa.add(user)
287 self.sa.add(user)
288 return user
288 return user
289 except:
289 except:
290 log.error(traceback.format_exc())
290 log.error(traceback.format_exc())
291 raise
291 raise
292
292
293 def update_my_account(self, user_id, form_data):
293 def update_my_account(self, user_id, form_data):
294 from rhodecode.lib.auth import get_crypt_password
294 from rhodecode.lib.auth import get_crypt_password
295 try:
295 try:
296 user = self.get(user_id, cache=False)
296 user = self.get(user_id, cache=False)
297 if user.username == 'default':
297 if user.username == 'default':
298 raise DefaultUserException(
298 raise DefaultUserException(
299 _("You can't Edit this user since it's"
299 _("You can't Edit this user since it's"
300 " crucial for entire application")
300 " crucial for entire application")
301 )
301 )
302 for k, v in form_data.items():
302 for k, v in form_data.items():
303 if k == 'new_password' and v:
303 if k == 'new_password' and v:
304 user.password = get_crypt_password(v)
304 user.password = get_crypt_password(v)
305 user.api_key = generate_api_key(user.username)
305 user.api_key = generate_api_key(user.username)
306 else:
306 else:
307 if k == 'firstname':
307 if k == 'firstname':
308 k = 'name'
308 k = 'name'
309 if k not in ['admin', 'active']:
309 if k not in ['admin', 'active']:
310 setattr(user, k, v)
310 setattr(user, k, v)
311
311
312 self.sa.add(user)
312 self.sa.add(user)
313 except:
313 except:
314 log.error(traceback.format_exc())
314 log.error(traceback.format_exc())
315 raise
315 raise
316
316
317 def delete(self, user):
317 def delete(self, user):
318 user = self._get_user(user)
318 user = self._get_user(user)
319
319
320 try:
320 try:
321 if user.username == 'default':
321 if user.username == 'default':
322 raise DefaultUserException(
322 raise DefaultUserException(
323 _(u"You can't remove this user since it's"
323 _(u"You can't remove this user since it's"
324 " crucial for entire application")
324 " crucial for entire application")
325 )
325 )
326 if user.repositories:
326 if user.repositories:
327 repos = [x.repo_name for x in user.repositories]
327 repos = [x.repo_name for x in user.repositories]
328 raise UserOwnsReposException(
328 raise UserOwnsReposException(
329 _(u'user "%s" still owns %s repositories and cannot be '
329 _(u'user "%s" still owns %s repositories and cannot be '
330 'removed. Switch owners or remove those repositories. %s')
330 'removed. Switch owners or remove those repositories. %s')
331 % (user.username, len(repos), ', '.join(repos))
331 % (user.username, len(repos), ', '.join(repos))
332 )
332 )
333 self.sa.delete(user)
333 self.sa.delete(user)
334 except:
334 except:
335 log.error(traceback.format_exc())
335 log.error(traceback.format_exc())
336 raise
336 raise
337
337
338 def reset_password_link(self, data):
338 def reset_password_link(self, data):
339 from rhodecode.lib.celerylib import tasks, run_task
339 from rhodecode.lib.celerylib import tasks, run_task
340 run_task(tasks.send_password_link, data['email'])
340 run_task(tasks.send_password_link, data['email'])
341
341
342 def reset_password(self, data):
342 def reset_password(self, data):
343 from rhodecode.lib.celerylib import tasks, run_task
343 from rhodecode.lib.celerylib import tasks, run_task
344 run_task(tasks.reset_user_password, data['email'])
344 run_task(tasks.reset_user_password, data['email'])
345
345
346 def fill_data(self, auth_user, user_id=None, api_key=None):
346 def fill_data(self, auth_user, user_id=None, api_key=None):
347 """
347 """
348 Fetches auth_user by user_id,or api_key if present.
348 Fetches auth_user by user_id,or api_key if present.
349 Fills auth_user attributes with those taken from database.
349 Fills auth_user attributes with those taken from database.
350 Additionally set's is_authenitated if lookup fails
350 Additionally set's is_authenitated if lookup fails
351 present in database
351 present in database
352
352
353 :param auth_user: instance of user to set attributes
353 :param auth_user: instance of user to set attributes
354 :param user_id: user id to fetch by
354 :param user_id: user id to fetch by
355 :param api_key: api key to fetch by
355 :param api_key: api key to fetch by
356 """
356 """
357 if user_id is None and api_key is None:
357 if user_id is None and api_key is None:
358 raise Exception('You need to pass user_id or api_key')
358 raise Exception('You need to pass user_id or api_key')
359
359
360 try:
360 try:
361 if api_key:
361 if api_key:
362 dbuser = self.get_by_api_key(api_key)
362 dbuser = self.get_by_api_key(api_key)
363 else:
363 else:
364 dbuser = self.get(user_id)
364 dbuser = self.get(user_id)
365
365
366 if dbuser is not None and dbuser.active:
366 if dbuser is not None and dbuser.active:
367 log.debug('filling %s data' % dbuser)
367 log.debug('filling %s data' % dbuser)
368 for k, v in dbuser.get_dict().items():
368 for k, v in dbuser.get_dict().items():
369 setattr(auth_user, k, v)
369 setattr(auth_user, k, v)
370 else:
370 else:
371 return False
371 return False
372
372
373 except:
373 except:
374 log.error(traceback.format_exc())
374 log.error(traceback.format_exc())
375 auth_user.is_authenticated = False
375 auth_user.is_authenticated = False
376 return False
376 return False
377
377
378 return True
378 return True
379
379
380 def fill_perms(self, user):
380 def fill_perms(self, user):
381 """
381 """
382 Fills user permission attribute with permissions taken from database
382 Fills user permission attribute with permissions taken from database
383 works for permissions given for repositories, and for permissions that
383 works for permissions given for repositories, and for permissions that
384 are granted to groups
384 are granted to groups
385
385
386 :param user: user instance to fill his perms
386 :param user: user instance to fill his perms
387 """
387 """
388 RK = 'repositories'
388 RK = 'repositories'
389 GK = 'repositories_groups'
389 GK = 'repositories_groups'
390 GLOBAL = 'global'
390 GLOBAL = 'global'
391 user.permissions[RK] = {}
391 user.permissions[RK] = {}
392 user.permissions[GK] = {}
392 user.permissions[GK] = {}
393 user.permissions[GLOBAL] = set()
393 user.permissions[GLOBAL] = set()
394
394
395 #======================================================================
395 #======================================================================
396 # fetch default permissions
396 # fetch default permissions
397 #======================================================================
397 #======================================================================
398 default_user = User.get_by_username('default', cache=True)
398 default_user = User.get_by_username('default', cache=True)
399 default_user_id = default_user.user_id
399 default_user_id = default_user.user_id
400
400
401 default_repo_perms = Permission.get_default_perms(default_user_id)
401 default_repo_perms = Permission.get_default_perms(default_user_id)
402 default_repo_groups_perms = Permission.get_default_group_perms(default_user_id)
402 default_repo_groups_perms = Permission.get_default_group_perms(default_user_id)
403
403
404 if user.is_admin:
404 if user.is_admin:
405 #==================================================================
405 #==================================================================
406 # admin user have all default rights for repositories
406 # admin user have all default rights for repositories
407 # and groups set to admin
407 # and groups set to admin
408 #==================================================================
408 #==================================================================
409 user.permissions[GLOBAL].add('hg.admin')
409 user.permissions[GLOBAL].add('hg.admin')
410
410
411 # repositories
411 # repositories
412 for perm in default_repo_perms:
412 for perm in default_repo_perms:
413 r_k = perm.UserRepoToPerm.repository.repo_name
413 r_k = perm.UserRepoToPerm.repository.repo_name
414 p = 'repository.admin'
414 p = 'repository.admin'
415 user.permissions[RK][r_k] = p
415 user.permissions[RK][r_k] = p
416
416
417 # repositories groups
417 # repositories groups
418 for perm in default_repo_groups_perms:
418 for perm in default_repo_groups_perms:
419 rg_k = perm.UserRepoGroupToPerm.group.group_name
419 rg_k = perm.UserRepoGroupToPerm.group.group_name
420 p = 'group.admin'
420 p = 'group.admin'
421 user.permissions[GK][rg_k] = p
421 user.permissions[GK][rg_k] = p
422 return user
422 return user
423
423
424 #==================================================================
424 #==================================================================
425 # SET DEFAULTS GLOBAL, REPOS, REPOS GROUPS
425 # SET DEFAULTS GLOBAL, REPOS, REPOS GROUPS
426 #==================================================================
426 #==================================================================
427 uid = user.user_id
427 uid = user.user_id
428
428
429 # default global permissions taken fron the default user
429 # default global permissions taken fron the default user
430 default_global_perms = self.sa.query(UserToPerm)\
430 default_global_perms = self.sa.query(UserToPerm)\
431 .filter(UserToPerm.user_id == default_user_id)
431 .filter(UserToPerm.user_id == default_user_id)
432
432
433 for perm in default_global_perms:
433 for perm in default_global_perms:
434 user.permissions[GLOBAL].add(perm.permission.permission_name)
434 user.permissions[GLOBAL].add(perm.permission.permission_name)
435
435
436 # defaults for repositories, taken from default user
436 # defaults for repositories, taken from default user
437 for perm in default_repo_perms:
437 for perm in default_repo_perms:
438 r_k = perm.UserRepoToPerm.repository.repo_name
438 r_k = perm.UserRepoToPerm.repository.repo_name
439 if perm.Repository.private and not (perm.Repository.user_id == uid):
439 if perm.Repository.private and not (perm.Repository.user_id == uid):
440 # disable defaults for private repos,
440 # disable defaults for private repos,
441 p = 'repository.none'
441 p = 'repository.none'
442 elif perm.Repository.user_id == uid:
442 elif perm.Repository.user_id == uid:
443 # set admin if owner
443 # set admin if owner
444 p = 'repository.admin'
444 p = 'repository.admin'
445 else:
445 else:
446 p = perm.Permission.permission_name
446 p = perm.Permission.permission_name
447
447
448 user.permissions[RK][r_k] = p
448 user.permissions[RK][r_k] = p
449
449
450 # defaults for repositories groups taken from default user permission
450 # defaults for repositories groups taken from default user permission
451 # on given group
451 # on given group
452 for perm in default_repo_groups_perms:
452 for perm in default_repo_groups_perms:
453 rg_k = perm.UserRepoGroupToPerm.group.group_name
453 rg_k = perm.UserRepoGroupToPerm.group.group_name
454 p = perm.Permission.permission_name
454 p = perm.Permission.permission_name
455 user.permissions[GK][rg_k] = p
455 user.permissions[GK][rg_k] = p
456
456
457 #======================================================================
457 #======================================================================
458 # !! OVERRIDE GLOBALS !! with user permissions if any found
458 # !! OVERRIDE GLOBALS !! with user permissions if any found
459 #======================================================================
459 #======================================================================
460 # those can be configured from groups or users explicitly
460 # those can be configured from groups or users explicitly
461 _configurable = set(['hg.fork.none', 'hg.fork.repository',
461 _configurable = set(['hg.fork.none', 'hg.fork.repository',
462 'hg.create.none', 'hg.create.repository'])
462 'hg.create.none', 'hg.create.repository'])
463
463
464 # USER GROUPS comes first
464 # USER GROUPS comes first
465 # users group global permissions
465 # users group global permissions
466 user_perms_from_users_groups = self.sa.query(UsersGroupToPerm)\
466 user_perms_from_users_groups = self.sa.query(UsersGroupToPerm)\
467 .options(joinedload(UsersGroupToPerm.permission))\
467 .options(joinedload(UsersGroupToPerm.permission))\
468 .join((UsersGroupMember, UsersGroupToPerm.users_group_id ==
468 .join((UsersGroupMember, UsersGroupToPerm.users_group_id ==
469 UsersGroupMember.users_group_id))\
469 UsersGroupMember.users_group_id))\
470 .filter(UsersGroupMember.user_id == uid)\
470 .filter(UsersGroupMember.user_id == uid)\
471 .order_by(UsersGroupToPerm.users_group_id)\
471 .order_by(UsersGroupToPerm.users_group_id)\
472 .all()
472 .all()
473 #need to group here by groups since user can be in more than one group
473 #need to group here by groups since user can be in more than one group
474 _grouped = [[x, list(y)] for x, y in
474 _grouped = [[x, list(y)] for x, y in
475 itertools.groupby(user_perms_from_users_groups,
475 itertools.groupby(user_perms_from_users_groups,
476 lambda x:x.users_group)]
476 lambda x:x.users_group)]
477 for gr, perms in _grouped:
477 for gr, perms in _grouped:
478 # since user can be in multiple groups iterate over them and
478 # since user can be in multiple groups iterate over them and
479 # select the lowest permissions first (more explicit)
479 # select the lowest permissions first (more explicit)
480 ##TODO: do this^^
480 ##TODO: do this^^
481 if not gr.inherit_default_permissions:
481 if not gr.inherit_default_permissions:
482 # NEED TO IGNORE all configurable permissions and
482 # NEED TO IGNORE all configurable permissions and
483 # replace them with explicitly set
483 # replace them with explicitly set
484 user.permissions[GLOBAL] = user.permissions[GLOBAL]\
484 user.permissions[GLOBAL] = user.permissions[GLOBAL]\
485 .difference(_configurable)
485 .difference(_configurable)
486 for perm in perms:
486 for perm in perms:
487 user.permissions[GLOBAL].add(perm.permission.permission_name)
487 user.permissions[GLOBAL].add(perm.permission.permission_name)
488
488
489 # user specific global permissions
489 # user specific global permissions
490 user_perms = self.sa.query(UserToPerm)\
490 user_perms = self.sa.query(UserToPerm)\
491 .options(joinedload(UserToPerm.permission))\
491 .options(joinedload(UserToPerm.permission))\
492 .filter(UserToPerm.user_id == uid).all()
492 .filter(UserToPerm.user_id == uid).all()
493
493
494 if not user.inherit_default_permissions:
494 if not user.inherit_default_permissions:
495 # NEED TO IGNORE all configurable permissions and
495 # NEED TO IGNORE all configurable permissions and
496 # replace them with explicitly set
496 # replace them with explicitly set
497 user.permissions[GLOBAL] = user.permissions[GLOBAL]\
497 user.permissions[GLOBAL] = user.permissions[GLOBAL]\
498 .difference(_configurable)
498 .difference(_configurable)
499
499
500 for perm in user_perms:
500 for perm in user_perms:
501 user.permissions[GLOBAL].add(perm.permission.permission_name)
501 user.permissions[GLOBAL].add(perm.permission.permission_name)
502
502
503 #======================================================================
503 #======================================================================
504 # !! REPO PERMISSIONS !!
504 # !! REPO PERMISSIONS !!
505 #======================================================================
505 #======================================================================
506 #======================================================================
506 #======================================================================
507 # check if user is part of user groups for this repository and
507 # check if user is part of user groups for this repository and
508 # fill in (or NOT replace with higher `or 1` permissions
508 # fill in (or NOT replace with higher `or 1` permissions
509 #======================================================================
509 #======================================================================
510 # users group for repositories permissions
510 # users group for repositories permissions
511 user_repo_perms_from_users_groups = \
511 user_repo_perms_from_users_groups = \
512 self.sa.query(UsersGroupRepoToPerm, Permission, Repository,)\
512 self.sa.query(UsersGroupRepoToPerm, Permission, Repository,)\
513 .join((Repository, UsersGroupRepoToPerm.repository_id ==
513 .join((Repository, UsersGroupRepoToPerm.repository_id ==
514 Repository.repo_id))\
514 Repository.repo_id))\
515 .join((Permission, UsersGroupRepoToPerm.permission_id ==
515 .join((Permission, UsersGroupRepoToPerm.permission_id ==
516 Permission.permission_id))\
516 Permission.permission_id))\
517 .join((UsersGroupMember, UsersGroupRepoToPerm.users_group_id ==
517 .join((UsersGroupMember, UsersGroupRepoToPerm.users_group_id ==
518 UsersGroupMember.users_group_id))\
518 UsersGroupMember.users_group_id))\
519 .filter(UsersGroupMember.user_id == uid)\
519 .filter(UsersGroupMember.user_id == uid)\
520 .all()
520 .all()
521
521
522 for perm in user_repo_perms_from_users_groups:
522 for perm in user_repo_perms_from_users_groups:
523 r_k = perm.UsersGroupRepoToPerm.repository.repo_name
523 r_k = perm.UsersGroupRepoToPerm.repository.repo_name
524 p = perm.Permission.permission_name
524 p = perm.Permission.permission_name
525 cur_perm = user.permissions[RK][r_k]
525 cur_perm = user.permissions[RK][r_k]
526 # overwrite permission only if it's greater than permission
526 # overwrite permission only if it's greater than permission
527 # given from other sources
527 # given from other sources
528 if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm] or 1: # disable check
528 if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm] or 1: # disable check
529 user.permissions[RK][r_k] = p
529 user.permissions[RK][r_k] = p
530
530
531 # user explicit permissions for repositories
531 # user explicit permissions for repositories
532 user_repo_perms = \
532 user_repo_perms = \
533 self.sa.query(UserRepoToPerm, Permission, Repository)\
533 self.sa.query(UserRepoToPerm, Permission, Repository)\
534 .join((Repository, UserRepoToPerm.repository_id ==
534 .join((Repository, UserRepoToPerm.repository_id ==
535 Repository.repo_id))\
535 Repository.repo_id))\
536 .join((Permission, UserRepoToPerm.permission_id ==
536 .join((Permission, UserRepoToPerm.permission_id ==
537 Permission.permission_id))\
537 Permission.permission_id))\
538 .filter(UserRepoToPerm.user_id == uid)\
538 .filter(UserRepoToPerm.user_id == uid)\
539 .all()
539 .all()
540
540
541 for perm in user_repo_perms:
541 for perm in user_repo_perms:
542 # set admin if owner
542 # set admin if owner
543 r_k = perm.UserRepoToPerm.repository.repo_name
543 r_k = perm.UserRepoToPerm.repository.repo_name
544 if perm.Repository.user_id == uid:
544 if perm.Repository.user_id == uid:
545 p = 'repository.admin'
545 p = 'repository.admin'
546 else:
546 else:
547 p = perm.Permission.permission_name
547 p = perm.Permission.permission_name
548 user.permissions[RK][r_k] = p
548 user.permissions[RK][r_k] = p
549
549
550 # REPO GROUP
550 # REPO GROUP
551 #==================================================================
551 #==================================================================
552 # get access for this user for repos group and override defaults
552 # get access for this user for repos group and override defaults
553 #==================================================================
553 #==================================================================
554
554
555 # user explicit permissions for repository
555 # user explicit permissions for repository
556 user_repo_groups_perms = \
556 user_repo_groups_perms = \
557 self.sa.query(UserRepoGroupToPerm, Permission, RepoGroup)\
557 self.sa.query(UserRepoGroupToPerm, Permission, RepoGroup)\
558 .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
558 .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
559 .join((Permission, UserRepoGroupToPerm.permission_id == Permission.permission_id))\
559 .join((Permission, UserRepoGroupToPerm.permission_id == Permission.permission_id))\
560 .filter(UserRepoGroupToPerm.user_id == uid)\
560 .filter(UserRepoGroupToPerm.user_id == uid)\
561 .all()
561 .all()
562
562
563 for perm in user_repo_groups_perms:
563 for perm in user_repo_groups_perms:
564 rg_k = perm.UserRepoGroupToPerm.group.group_name
564 rg_k = perm.UserRepoGroupToPerm.group.group_name
565 p = perm.Permission.permission_name
565 p = perm.Permission.permission_name
566 cur_perm = user.permissions[GK][rg_k]
566 cur_perm = user.permissions[GK][rg_k]
567 if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm]:
567 if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm] or 1: # disable check
568 user.permissions[GK][rg_k] = p
568 user.permissions[GK][rg_k] = p
569
569
570 # REPO GROUP + USER GROUP
570 # REPO GROUP + USER GROUP
571 #==================================================================
571 #==================================================================
572 # check if user is part of user groups for this repo group and
572 # check if user is part of user groups for this repo group and
573 # fill in (or replace with higher) permissions
573 # fill in (or replace with higher) permissions
574 #==================================================================
574 #==================================================================
575
575
576 # users group for repositories permissions
576 # users group for repositories permissions
577 user_repo_group_perms_from_users_groups = \
577 user_repo_group_perms_from_users_groups = \
578 self.sa.query(UsersGroupRepoGroupToPerm, Permission, RepoGroup)\
578 self.sa.query(UsersGroupRepoGroupToPerm, Permission, RepoGroup)\
579 .join((RepoGroup, UsersGroupRepoGroupToPerm.group_id == RepoGroup.group_id))\
579 .join((RepoGroup, UsersGroupRepoGroupToPerm.group_id == RepoGroup.group_id))\
580 .join((Permission, UsersGroupRepoGroupToPerm.permission_id == Permission.permission_id))\
580 .join((Permission, UsersGroupRepoGroupToPerm.permission_id == Permission.permission_id))\
581 .join((UsersGroupMember, UsersGroupRepoGroupToPerm.users_group_id == UsersGroupMember.users_group_id))\
581 .join((UsersGroupMember, UsersGroupRepoGroupToPerm.users_group_id == UsersGroupMember.users_group_id))\
582 .filter(UsersGroupMember.user_id == uid)\
582 .filter(UsersGroupMember.user_id == uid)\
583 .all()
583 .all()
584
584
585 for perm in user_repo_group_perms_from_users_groups:
585 for perm in user_repo_group_perms_from_users_groups:
586 g_k = perm.UsersGroupRepoGroupToPerm.group.group_name
586 g_k = perm.UsersGroupRepoGroupToPerm.group.group_name
587 p = perm.Permission.permission_name
587 p = perm.Permission.permission_name
588 cur_perm = user.permissions[GK][g_k]
588 cur_perm = user.permissions[GK][g_k]
589 # overwrite permission only if it's greater than permission
589 # overwrite permission only if it's greater than permission
590 # given from other sources
590 # given from other sources
591 if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm]:
591 if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm] or 1: # disable check
592 user.permissions[GK][g_k] = p
592 user.permissions[GK][g_k] = p
593
593
594 return user
594 return user
595
595
596 def has_perm(self, user, perm):
596 def has_perm(self, user, perm):
597 perm = self._get_perm(perm)
597 perm = self._get_perm(perm)
598 user = self._get_user(user)
598 user = self._get_user(user)
599
599
600 return UserToPerm.query().filter(UserToPerm.user == user)\
600 return UserToPerm.query().filter(UserToPerm.user == user)\
601 .filter(UserToPerm.permission == perm).scalar() is not None
601 .filter(UserToPerm.permission == perm).scalar() is not None
602
602
603 def grant_perm(self, user, perm):
603 def grant_perm(self, user, perm):
604 """
604 """
605 Grant user global permissions
605 Grant user global permissions
606
606
607 :param user:
607 :param user:
608 :param perm:
608 :param perm:
609 """
609 """
610 user = self._get_user(user)
610 user = self._get_user(user)
611 perm = self._get_perm(perm)
611 perm = self._get_perm(perm)
612 # if this permission is already granted skip it
612 # if this permission is already granted skip it
613 _perm = UserToPerm.query()\
613 _perm = UserToPerm.query()\
614 .filter(UserToPerm.user == user)\
614 .filter(UserToPerm.user == user)\
615 .filter(UserToPerm.permission == perm)\
615 .filter(UserToPerm.permission == perm)\
616 .scalar()
616 .scalar()
617 if _perm:
617 if _perm:
618 return
618 return
619 new = UserToPerm()
619 new = UserToPerm()
620 new.user = user
620 new.user = user
621 new.permission = perm
621 new.permission = perm
622 self.sa.add(new)
622 self.sa.add(new)
623
623
624 def revoke_perm(self, user, perm):
624 def revoke_perm(self, user, perm):
625 """
625 """
626 Revoke users global permissions
626 Revoke users global permissions
627
627
628 :param user:
628 :param user:
629 :param perm:
629 :param perm:
630 """
630 """
631 user = self._get_user(user)
631 user = self._get_user(user)
632 perm = self._get_perm(perm)
632 perm = self._get_perm(perm)
633
633
634 obj = UserToPerm.query()\
634 obj = UserToPerm.query()\
635 .filter(UserToPerm.user == user)\
635 .filter(UserToPerm.user == user)\
636 .filter(UserToPerm.permission == perm)\
636 .filter(UserToPerm.permission == perm)\
637 .scalar()
637 .scalar()
638 if obj:
638 if obj:
639 self.sa.delete(obj)
639 self.sa.delete(obj)
640
640
641 def add_extra_email(self, user, email):
641 def add_extra_email(self, user, email):
642 """
642 """
643 Adds email address to UserEmailMap
643 Adds email address to UserEmailMap
644
644
645 :param user:
645 :param user:
646 :param email:
646 :param email:
647 """
647 """
648 from rhodecode.model import forms
648 from rhodecode.model import forms
649 form = forms.UserExtraEmailForm()()
649 form = forms.UserExtraEmailForm()()
650 data = form.to_python(dict(email=email))
650 data = form.to_python(dict(email=email))
651 user = self._get_user(user)
651 user = self._get_user(user)
652
652
653 obj = UserEmailMap()
653 obj = UserEmailMap()
654 obj.user = user
654 obj.user = user
655 obj.email = data['email']
655 obj.email = data['email']
656 self.sa.add(obj)
656 self.sa.add(obj)
657 return obj
657 return obj
658
658
659 def delete_extra_email(self, user, email_id):
659 def delete_extra_email(self, user, email_id):
660 """
660 """
661 Removes email address from UserEmailMap
661 Removes email address from UserEmailMap
662
662
663 :param user:
663 :param user:
664 :param email_id:
664 :param email_id:
665 """
665 """
666 user = self._get_user(user)
666 user = self._get_user(user)
667 obj = UserEmailMap.query().get(email_id)
667 obj = UserEmailMap.query().get(email_id)
668 if obj:
668 if obj:
669 self.sa.delete(obj)
669 self.sa.delete(obj)
@@ -1,676 +1,676 b''
1 """
1 """
2 Set of generic validators
2 Set of generic validators
3 """
3 """
4 import os
4 import os
5 import re
5 import re
6 import formencode
6 import formencode
7 import logging
7 import logging
8 from collections import defaultdict
8 from collections import defaultdict
9 from pylons.i18n.translation import _
9 from pylons.i18n.translation import _
10 from webhelpers.pylonslib.secure_form import authentication_token
10 from webhelpers.pylonslib.secure_form import authentication_token
11
11
12 from formencode.validators import (
12 from formencode.validators import (
13 UnicodeString, OneOf, Int, Number, Regex, Email, Bool, StringBoolean, Set,
13 UnicodeString, OneOf, Int, Number, Regex, Email, Bool, StringBoolean, Set,
14 NotEmpty
14 NotEmpty
15 )
15 )
16 from rhodecode.lib.compat import OrderedSet
16 from rhodecode.lib.compat import OrderedSet
17 from rhodecode.lib.utils import repo_name_slug
17 from rhodecode.lib.utils import repo_name_slug
18 from rhodecode.model.db import RepoGroup, Repository, UsersGroup, User,\
18 from rhodecode.model.db import RepoGroup, Repository, UsersGroup, User,\
19 ChangesetStatus
19 ChangesetStatus
20 from rhodecode.lib.exceptions import LdapImportError
20 from rhodecode.lib.exceptions import LdapImportError
21 from rhodecode.config.routing import ADMIN_PREFIX
21 from rhodecode.config.routing import ADMIN_PREFIX
22
22
23 # silence warnings and pylint
23 # silence warnings and pylint
24 UnicodeString, OneOf, Int, Number, Regex, Email, Bool, StringBoolean, Set, \
24 UnicodeString, OneOf, Int, Number, Regex, Email, Bool, StringBoolean, Set, \
25 NotEmpty
25 NotEmpty
26
26
27 log = logging.getLogger(__name__)
27 log = logging.getLogger(__name__)
28
28
29
29
30 class UniqueList(formencode.FancyValidator):
30 class UniqueList(formencode.FancyValidator):
31 """
31 """
32 Unique List !
32 Unique List !
33 """
33 """
34 messages = dict(
34 messages = dict(
35 empty=_('Value cannot be an empty list'),
35 empty=_('Value cannot be an empty list'),
36 missing_value=_('Value cannot be an empty list'),
36 missing_value=_('Value cannot be an empty list'),
37 )
37 )
38
38
39 def _to_python(self, value, state):
39 def _to_python(self, value, state):
40 if isinstance(value, list):
40 if isinstance(value, list):
41 return value
41 return value
42 elif isinstance(value, set):
42 elif isinstance(value, set):
43 return list(value)
43 return list(value)
44 elif isinstance(value, tuple):
44 elif isinstance(value, tuple):
45 return list(value)
45 return list(value)
46 elif value is None:
46 elif value is None:
47 return []
47 return []
48 else:
48 else:
49 return [value]
49 return [value]
50
50
51 def empty_value(self, value):
51 def empty_value(self, value):
52 return []
52 return []
53
53
54
54
55 class StateObj(object):
55 class StateObj(object):
56 """
56 """
57 this is needed to translate the messages using _() in validators
57 this is needed to translate the messages using _() in validators
58 """
58 """
59 _ = staticmethod(_)
59 _ = staticmethod(_)
60
60
61
61
62 def M(self, key, state=None, **kwargs):
62 def M(self, key, state=None, **kwargs):
63 """
63 """
64 returns string from self.message based on given key,
64 returns string from self.message based on given key,
65 passed kw params are used to substitute %(named)s params inside
65 passed kw params are used to substitute %(named)s params inside
66 translated strings
66 translated strings
67
67
68 :param msg:
68 :param msg:
69 :param state:
69 :param state:
70 """
70 """
71 if state is None:
71 if state is None:
72 state = StateObj()
72 state = StateObj()
73 else:
73 else:
74 state._ = staticmethod(_)
74 state._ = staticmethod(_)
75 #inject validator into state object
75 #inject validator into state object
76 return self.message(key, state, **kwargs)
76 return self.message(key, state, **kwargs)
77
77
78
78
79 def ValidUsername(edit=False, old_data={}):
79 def ValidUsername(edit=False, old_data={}):
80 class _validator(formencode.validators.FancyValidator):
80 class _validator(formencode.validators.FancyValidator):
81 messages = {
81 messages = {
82 'username_exists': _(u'Username "%(username)s" already exists'),
82 'username_exists': _(u'Username "%(username)s" already exists'),
83 'system_invalid_username':
83 'system_invalid_username':
84 _(u'Username "%(username)s" is forbidden'),
84 _(u'Username "%(username)s" is forbidden'),
85 'invalid_username':
85 'invalid_username':
86 _(u'Username may only contain alphanumeric characters '
86 _(u'Username may only contain alphanumeric characters '
87 'underscores, periods or dashes and must begin with '
87 'underscores, periods or dashes and must begin with '
88 'alphanumeric character')
88 'alphanumeric character')
89 }
89 }
90
90
91 def validate_python(self, value, state):
91 def validate_python(self, value, state):
92 if value in ['default', 'new_user']:
92 if value in ['default', 'new_user']:
93 msg = M(self, 'system_invalid_username', state, username=value)
93 msg = M(self, 'system_invalid_username', state, username=value)
94 raise formencode.Invalid(msg, value, state)
94 raise formencode.Invalid(msg, value, state)
95 #check if user is unique
95 #check if user is unique
96 old_un = None
96 old_un = None
97 if edit:
97 if edit:
98 old_un = User.get(old_data.get('user_id')).username
98 old_un = User.get(old_data.get('user_id')).username
99
99
100 if old_un != value or not edit:
100 if old_un != value or not edit:
101 if User.get_by_username(value, case_insensitive=True):
101 if User.get_by_username(value, case_insensitive=True):
102 msg = M(self, 'username_exists', state, username=value)
102 msg = M(self, 'username_exists', state, username=value)
103 raise formencode.Invalid(msg, value, state)
103 raise formencode.Invalid(msg, value, state)
104
104
105 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
105 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
106 msg = M(self, 'invalid_username', state)
106 msg = M(self, 'invalid_username', state)
107 raise formencode.Invalid(msg, value, state)
107 raise formencode.Invalid(msg, value, state)
108 return _validator
108 return _validator
109
109
110
110
111 def ValidRepoUser():
111 def ValidRepoUser():
112 class _validator(formencode.validators.FancyValidator):
112 class _validator(formencode.validators.FancyValidator):
113 messages = {
113 messages = {
114 'invalid_username': _(u'Username %(username)s is not valid')
114 'invalid_username': _(u'Username %(username)s is not valid')
115 }
115 }
116
116
117 def validate_python(self, value, state):
117 def validate_python(self, value, state):
118 try:
118 try:
119 User.query().filter(User.active == True)\
119 User.query().filter(User.active == True)\
120 .filter(User.username == value).one()
120 .filter(User.username == value).one()
121 except Exception:
121 except Exception:
122 msg = M(self, 'invalid_username', state, username=value)
122 msg = M(self, 'invalid_username', state, username=value)
123 raise formencode.Invalid(msg, value, state,
123 raise formencode.Invalid(msg, value, state,
124 error_dict=dict(username=msg)
124 error_dict=dict(username=msg)
125 )
125 )
126
126
127 return _validator
127 return _validator
128
128
129
129
130 def ValidUsersGroup(edit=False, old_data={}):
130 def ValidUsersGroup(edit=False, old_data={}):
131 class _validator(formencode.validators.FancyValidator):
131 class _validator(formencode.validators.FancyValidator):
132 messages = {
132 messages = {
133 'invalid_group': _(u'Invalid users group name'),
133 'invalid_group': _(u'Invalid users group name'),
134 'group_exist': _(u'Users group "%(usersgroup)s" already exists'),
134 'group_exist': _(u'Users group "%(usersgroup)s" already exists'),
135 'invalid_usersgroup_name':
135 'invalid_usersgroup_name':
136 _(u'users group name may only contain alphanumeric '
136 _(u'users group name may only contain alphanumeric '
137 'characters underscores, periods or dashes and must begin '
137 'characters underscores, periods or dashes and must begin '
138 'with alphanumeric character')
138 'with alphanumeric character')
139 }
139 }
140
140
141 def validate_python(self, value, state):
141 def validate_python(self, value, state):
142 if value in ['default']:
142 if value in ['default']:
143 msg = M(self, 'invalid_group', state)
143 msg = M(self, 'invalid_group', state)
144 raise formencode.Invalid(msg, value, state,
144 raise formencode.Invalid(msg, value, state,
145 error_dict=dict(users_group_name=msg)
145 error_dict=dict(users_group_name=msg)
146 )
146 )
147 #check if group is unique
147 #check if group is unique
148 old_ugname = None
148 old_ugname = None
149 if edit:
149 if edit:
150 old_id = old_data.get('users_group_id')
150 old_id = old_data.get('users_group_id')
151 old_ugname = UsersGroup.get(old_id).users_group_name
151 old_ugname = UsersGroup.get(old_id).users_group_name
152
152
153 if old_ugname != value or not edit:
153 if old_ugname != value or not edit:
154 is_existing_group = UsersGroup.get_by_group_name(value,
154 is_existing_group = UsersGroup.get_by_group_name(value,
155 case_insensitive=True)
155 case_insensitive=True)
156 if is_existing_group:
156 if is_existing_group:
157 msg = M(self, 'group_exist', state, usersgroup=value)
157 msg = M(self, 'group_exist', state, usersgroup=value)
158 raise formencode.Invalid(msg, value, state,
158 raise formencode.Invalid(msg, value, state,
159 error_dict=dict(users_group_name=msg)
159 error_dict=dict(users_group_name=msg)
160 )
160 )
161
161
162 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
162 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
163 msg = M(self, 'invalid_usersgroup_name', state)
163 msg = M(self, 'invalid_usersgroup_name', state)
164 raise formencode.Invalid(msg, value, state,
164 raise formencode.Invalid(msg, value, state,
165 error_dict=dict(users_group_name=msg)
165 error_dict=dict(users_group_name=msg)
166 )
166 )
167
167
168 return _validator
168 return _validator
169
169
170
170
171 def ValidReposGroup(edit=False, old_data={}):
171 def ValidReposGroup(edit=False, old_data={}):
172 class _validator(formencode.validators.FancyValidator):
172 class _validator(formencode.validators.FancyValidator):
173 messages = {
173 messages = {
174 'group_parent_id': _(u'Cannot assign this group as parent'),
174 'group_parent_id': _(u'Cannot assign this group as parent'),
175 'group_exists': _(u'Group "%(group_name)s" already exists'),
175 'group_exists': _(u'Group "%(group_name)s" already exists'),
176 'repo_exists':
176 'repo_exists':
177 _(u'Repository with name "%(group_name)s" already exists')
177 _(u'Repository with name "%(group_name)s" already exists')
178 }
178 }
179
179
180 def validate_python(self, value, state):
180 def validate_python(self, value, state):
181 # TODO WRITE VALIDATIONS
181 # TODO WRITE VALIDATIONS
182 group_name = value.get('group_name')
182 group_name = value.get('group_name')
183 group_parent_id = value.get('group_parent_id')
183 group_parent_id = value.get('group_parent_id')
184
184
185 # slugify repo group just in case :)
185 # slugify repo group just in case :)
186 slug = repo_name_slug(group_name)
186 slug = repo_name_slug(group_name)
187
187
188 # check for parent of self
188 # check for parent of self
189 parent_of_self = lambda: (
189 parent_of_self = lambda: (
190 old_data['group_id'] == int(group_parent_id)
190 old_data['group_id'] == int(group_parent_id)
191 if group_parent_id else False
191 if group_parent_id else False
192 )
192 )
193 if edit and parent_of_self():
193 if edit and parent_of_self():
194 msg = M(self, 'group_parent_id', state)
194 msg = M(self, 'group_parent_id', state)
195 raise formencode.Invalid(msg, value, state,
195 raise formencode.Invalid(msg, value, state,
196 error_dict=dict(group_parent_id=msg)
196 error_dict=dict(group_parent_id=msg)
197 )
197 )
198
198
199 old_gname = None
199 old_gname = None
200 if edit:
200 if edit:
201 old_gname = RepoGroup.get(old_data.get('group_id')).group_name
201 old_gname = RepoGroup.get(old_data.get('group_id')).group_name
202
202
203 if old_gname != group_name or not edit:
203 if old_gname != group_name or not edit:
204
204
205 # check group
205 # check group
206 gr = RepoGroup.query()\
206 gr = RepoGroup.query()\
207 .filter(RepoGroup.group_name == slug)\
207 .filter(RepoGroup.group_name == slug)\
208 .filter(RepoGroup.group_parent_id == group_parent_id)\
208 .filter(RepoGroup.group_parent_id == group_parent_id)\
209 .scalar()
209 .scalar()
210
210
211 if gr:
211 if gr:
212 msg = M(self, 'group_exists', state, group_name=slug)
212 msg = M(self, 'group_exists', state, group_name=slug)
213 raise formencode.Invalid(msg, value, state,
213 raise formencode.Invalid(msg, value, state,
214 error_dict=dict(group_name=msg)
214 error_dict=dict(group_name=msg)
215 )
215 )
216
216
217 # check for same repo
217 # check for same repo
218 repo = Repository.query()\
218 repo = Repository.query()\
219 .filter(Repository.repo_name == slug)\
219 .filter(Repository.repo_name == slug)\
220 .scalar()
220 .scalar()
221
221
222 if repo:
222 if repo:
223 msg = M(self, 'repo_exists', state, group_name=slug)
223 msg = M(self, 'repo_exists', state, group_name=slug)
224 raise formencode.Invalid(msg, value, state,
224 raise formencode.Invalid(msg, value, state,
225 error_dict=dict(group_name=msg)
225 error_dict=dict(group_name=msg)
226 )
226 )
227
227
228 return _validator
228 return _validator
229
229
230
230
231 def ValidPassword():
231 def ValidPassword():
232 class _validator(formencode.validators.FancyValidator):
232 class _validator(formencode.validators.FancyValidator):
233 messages = {
233 messages = {
234 'invalid_password':
234 'invalid_password':
235 _(u'Invalid characters (non-ascii) in password')
235 _(u'Invalid characters (non-ascii) in password')
236 }
236 }
237
237
238 def validate_python(self, value, state):
238 def validate_python(self, value, state):
239 try:
239 try:
240 (value or '').decode('ascii')
240 (value or '').decode('ascii')
241 except UnicodeError:
241 except UnicodeError:
242 msg = M(self, 'invalid_password', state)
242 msg = M(self, 'invalid_password', state)
243 raise formencode.Invalid(msg, value, state,)
243 raise formencode.Invalid(msg, value, state,)
244 return _validator
244 return _validator
245
245
246
246
247 def ValidPasswordsMatch():
247 def ValidPasswordsMatch():
248 class _validator(formencode.validators.FancyValidator):
248 class _validator(formencode.validators.FancyValidator):
249 messages = {
249 messages = {
250 'password_mismatch': _(u'Passwords do not match'),
250 'password_mismatch': _(u'Passwords do not match'),
251 }
251 }
252
252
253 def validate_python(self, value, state):
253 def validate_python(self, value, state):
254
254
255 pass_val = value.get('password') or value.get('new_password')
255 pass_val = value.get('password') or value.get('new_password')
256 if pass_val != value['password_confirmation']:
256 if pass_val != value['password_confirmation']:
257 msg = M(self, 'password_mismatch', state)
257 msg = M(self, 'password_mismatch', state)
258 raise formencode.Invalid(msg, value, state,
258 raise formencode.Invalid(msg, value, state,
259 error_dict=dict(password_confirmation=msg)
259 error_dict=dict(password_confirmation=msg)
260 )
260 )
261 return _validator
261 return _validator
262
262
263
263
264 def ValidAuth():
264 def ValidAuth():
265 class _validator(formencode.validators.FancyValidator):
265 class _validator(formencode.validators.FancyValidator):
266 messages = {
266 messages = {
267 'invalid_password': _(u'invalid password'),
267 'invalid_password': _(u'invalid password'),
268 'invalid_username': _(u'invalid user name'),
268 'invalid_username': _(u'invalid user name'),
269 'disabled_account': _(u'Your account is disabled')
269 'disabled_account': _(u'Your account is disabled')
270 }
270 }
271
271
272 def validate_python(self, value, state):
272 def validate_python(self, value, state):
273 from rhodecode.lib.auth import authenticate
273 from rhodecode.lib.auth import authenticate
274
274
275 password = value['password']
275 password = value['password']
276 username = value['username']
276 username = value['username']
277
277
278 if not authenticate(username, password):
278 if not authenticate(username, password):
279 user = User.get_by_username(username)
279 user = User.get_by_username(username)
280 if user and user.active is False:
280 if user and user.active is False:
281 log.warning('user %s is disabled' % username)
281 log.warning('user %s is disabled' % username)
282 msg = M(self, 'disabled_account', state)
282 msg = M(self, 'disabled_account', state)
283 raise formencode.Invalid(msg, value, state,
283 raise formencode.Invalid(msg, value, state,
284 error_dict=dict(username=msg)
284 error_dict=dict(username=msg)
285 )
285 )
286 else:
286 else:
287 log.warning('user %s failed to authenticate' % username)
287 log.warning('user %s failed to authenticate' % username)
288 msg = M(self, 'invalid_username', state)
288 msg = M(self, 'invalid_username', state)
289 msg2 = M(self, 'invalid_password', state)
289 msg2 = M(self, 'invalid_password', state)
290 raise formencode.Invalid(msg, value, state,
290 raise formencode.Invalid(msg, value, state,
291 error_dict=dict(username=msg, password=msg2)
291 error_dict=dict(username=msg, password=msg2)
292 )
292 )
293 return _validator
293 return _validator
294
294
295
295
296 def ValidAuthToken():
296 def ValidAuthToken():
297 class _validator(formencode.validators.FancyValidator):
297 class _validator(formencode.validators.FancyValidator):
298 messages = {
298 messages = {
299 'invalid_token': _(u'Token mismatch')
299 'invalid_token': _(u'Token mismatch')
300 }
300 }
301
301
302 def validate_python(self, value, state):
302 def validate_python(self, value, state):
303 if value != authentication_token():
303 if value != authentication_token():
304 msg = M(self, 'invalid_token', state)
304 msg = M(self, 'invalid_token', state)
305 raise formencode.Invalid(msg, value, state)
305 raise formencode.Invalid(msg, value, state)
306 return _validator
306 return _validator
307
307
308
308
309 def ValidRepoName(edit=False, old_data={}):
309 def ValidRepoName(edit=False, old_data={}):
310 class _validator(formencode.validators.FancyValidator):
310 class _validator(formencode.validators.FancyValidator):
311 messages = {
311 messages = {
312 'invalid_repo_name':
312 'invalid_repo_name':
313 _(u'Repository name %(repo)s is disallowed'),
313 _(u'Repository name %(repo)s is disallowed'),
314 'repository_exists':
314 'repository_exists':
315 _(u'Repository named %(repo)s already exists'),
315 _(u'Repository named %(repo)s already exists'),
316 'repository_in_group_exists': _(u'Repository "%(repo)s" already '
316 'repository_in_group_exists': _(u'Repository "%(repo)s" already '
317 'exists in group "%(group)s"'),
317 'exists in group "%(group)s"'),
318 'same_group_exists': _(u'Repositories group with name "%(repo)s" '
318 'same_group_exists': _(u'Repositories group with name "%(repo)s" '
319 'already exists')
319 'already exists')
320 }
320 }
321
321
322 def _to_python(self, value, state):
322 def _to_python(self, value, state):
323 repo_name = repo_name_slug(value.get('repo_name', ''))
323 repo_name = repo_name_slug(value.get('repo_name', ''))
324 repo_group = value.get('repo_group')
324 repo_group = value.get('repo_group')
325 if repo_group:
325 if repo_group:
326 gr = RepoGroup.get(repo_group)
326 gr = RepoGroup.get(repo_group)
327 group_path = gr.full_path
327 group_path = gr.full_path
328 group_name = gr.group_name
328 group_name = gr.group_name
329 # value needs to be aware of group name in order to check
329 # value needs to be aware of group name in order to check
330 # db key This is an actual just the name to store in the
330 # db key This is an actual just the name to store in the
331 # database
331 # database
332 repo_name_full = group_path + RepoGroup.url_sep() + repo_name
332 repo_name_full = group_path + RepoGroup.url_sep() + repo_name
333 else:
333 else:
334 group_name = group_path = ''
334 group_name = group_path = ''
335 repo_name_full = repo_name
335 repo_name_full = repo_name
336
336
337 value['repo_name'] = repo_name
337 value['repo_name'] = repo_name
338 value['repo_name_full'] = repo_name_full
338 value['repo_name_full'] = repo_name_full
339 value['group_path'] = group_path
339 value['group_path'] = group_path
340 value['group_name'] = group_name
340 value['group_name'] = group_name
341 return value
341 return value
342
342
343 def validate_python(self, value, state):
343 def validate_python(self, value, state):
344
344
345 repo_name = value.get('repo_name')
345 repo_name = value.get('repo_name')
346 repo_name_full = value.get('repo_name_full')
346 repo_name_full = value.get('repo_name_full')
347 group_path = value.get('group_path')
347 group_path = value.get('group_path')
348 group_name = value.get('group_name')
348 group_name = value.get('group_name')
349
349
350 if repo_name in [ADMIN_PREFIX, '']:
350 if repo_name in [ADMIN_PREFIX, '']:
351 msg = M(self, 'invalid_repo_name', state, repo=repo_name)
351 msg = M(self, 'invalid_repo_name', state, repo=repo_name)
352 raise formencode.Invalid(msg, value, state,
352 raise formencode.Invalid(msg, value, state,
353 error_dict=dict(repo_name=msg)
353 error_dict=dict(repo_name=msg)
354 )
354 )
355
355
356 rename = old_data.get('repo_name') != repo_name_full
356 rename = old_data.get('repo_name') != repo_name_full
357 create = not edit
357 create = not edit
358 if rename or create:
358 if rename or create:
359
359
360 if group_path != '':
360 if group_path != '':
361 if Repository.get_by_repo_name(repo_name_full):
361 if Repository.get_by_repo_name(repo_name_full):
362 msg = M(self, 'repository_in_group_exists', state,
362 msg = M(self, 'repository_in_group_exists', state,
363 repo=repo_name, group=group_name)
363 repo=repo_name, group=group_name)
364 raise formencode.Invalid(msg, value, state,
364 raise formencode.Invalid(msg, value, state,
365 error_dict=dict(repo_name=msg)
365 error_dict=dict(repo_name=msg)
366 )
366 )
367 elif RepoGroup.get_by_group_name(repo_name_full):
367 elif RepoGroup.get_by_group_name(repo_name_full):
368 msg = M(self, 'same_group_exists', state,
368 msg = M(self, 'same_group_exists', state,
369 repo=repo_name)
369 repo=repo_name)
370 raise formencode.Invalid(msg, value, state,
370 raise formencode.Invalid(msg, value, state,
371 error_dict=dict(repo_name=msg)
371 error_dict=dict(repo_name=msg)
372 )
372 )
373
373
374 elif Repository.get_by_repo_name(repo_name_full):
374 elif Repository.get_by_repo_name(repo_name_full):
375 msg = M(self, 'repository_exists', state,
375 msg = M(self, 'repository_exists', state,
376 repo=repo_name)
376 repo=repo_name)
377 raise formencode.Invalid(msg, value, state,
377 raise formencode.Invalid(msg, value, state,
378 error_dict=dict(repo_name=msg)
378 error_dict=dict(repo_name=msg)
379 )
379 )
380 return value
380 return value
381 return _validator
381 return _validator
382
382
383
383
384 def ValidForkName(*args, **kwargs):
384 def ValidForkName(*args, **kwargs):
385 return ValidRepoName(*args, **kwargs)
385 return ValidRepoName(*args, **kwargs)
386
386
387
387
388 def SlugifyName():
388 def SlugifyName():
389 class _validator(formencode.validators.FancyValidator):
389 class _validator(formencode.validators.FancyValidator):
390
390
391 def _to_python(self, value, state):
391 def _to_python(self, value, state):
392 return repo_name_slug(value)
392 return repo_name_slug(value)
393
393
394 def validate_python(self, value, state):
394 def validate_python(self, value, state):
395 pass
395 pass
396
396
397 return _validator
397 return _validator
398
398
399
399
400 def ValidCloneUri():
400 def ValidCloneUri():
401 from rhodecode.lib.utils import make_ui
401 from rhodecode.lib.utils import make_ui
402
402
403 def url_handler(repo_type, url, ui=None):
403 def url_handler(repo_type, url, ui=None):
404 if repo_type == 'hg':
404 if repo_type == 'hg':
405 from rhodecode.lib.vcs.backends.hg.repository import MercurialRepository
405 from rhodecode.lib.vcs.backends.hg.repository import MercurialRepository
406 from mercurial.httppeer import httppeer
406 from mercurial.httppeer import httppeer
407 if url.startswith('http'):
407 if url.startswith('http'):
408 ## initially check if it's at least the proper URL
408 ## initially check if it's at least the proper URL
409 ## or does it pass basic auth
409 ## or does it pass basic auth
410 MercurialRepository._check_url(url)
410 MercurialRepository._check_url(url)
411 httppeer(ui, url)._capabilities()
411 httppeer(ui, url)._capabilities()
412 elif url.startswith('svn+http'):
412 elif url.startswith('svn+http'):
413 from hgsubversion.svnrepo import svnremoterepo
413 from hgsubversion.svnrepo import svnremoterepo
414 svnremoterepo(ui, url).capabilities
414 svnremoterepo(ui, url).capabilities
415 elif url.startswith('git+http'):
415 elif url.startswith('git+http'):
416 raise NotImplementedError()
416 raise NotImplementedError()
417
417
418 elif repo_type == 'git':
418 elif repo_type == 'git':
419 from rhodecode.lib.vcs.backends.git.repository import GitRepository
419 from rhodecode.lib.vcs.backends.git.repository import GitRepository
420 if url.startswith('http'):
420 if url.startswith('http'):
421 ## initially check if it's at least the proper URL
421 ## initially check if it's at least the proper URL
422 ## or does it pass basic auth
422 ## or does it pass basic auth
423 GitRepository._check_url(url)
423 GitRepository._check_url(url)
424 elif url.startswith('svn+http'):
424 elif url.startswith('svn+http'):
425 raise NotImplementedError()
425 raise NotImplementedError()
426 elif url.startswith('hg+http'):
426 elif url.startswith('hg+http'):
427 raise NotImplementedError()
427 raise NotImplementedError()
428
428
429 class _validator(formencode.validators.FancyValidator):
429 class _validator(formencode.validators.FancyValidator):
430 messages = {
430 messages = {
431 'clone_uri': _(u'invalid clone url'),
431 'clone_uri': _(u'invalid clone url'),
432 'invalid_clone_uri': _(u'Invalid clone url, provide a '
432 'invalid_clone_uri': _(u'Invalid clone url, provide a '
433 'valid clone http(s)/svn+http(s) url')
433 'valid clone http(s)/svn+http(s) url')
434 }
434 }
435
435
436 def validate_python(self, value, state):
436 def validate_python(self, value, state):
437 repo_type = value.get('repo_type')
437 repo_type = value.get('repo_type')
438 url = value.get('clone_uri')
438 url = value.get('clone_uri')
439
439
440 if not url:
440 if not url:
441 pass
441 pass
442 else:
442 else:
443 try:
443 try:
444 url_handler(repo_type, url, make_ui('db', clear_session=False))
444 url_handler(repo_type, url, make_ui('db', clear_session=False))
445 except Exception:
445 except Exception:
446 log.exception('Url validation failed')
446 log.exception('Url validation failed')
447 msg = M(self, 'clone_uri')
447 msg = M(self, 'clone_uri')
448 raise formencode.Invalid(msg, value, state,
448 raise formencode.Invalid(msg, value, state,
449 error_dict=dict(clone_uri=msg)
449 error_dict=dict(clone_uri=msg)
450 )
450 )
451 return _validator
451 return _validator
452
452
453
453
454 def ValidForkType(old_data={}):
454 def ValidForkType(old_data={}):
455 class _validator(formencode.validators.FancyValidator):
455 class _validator(formencode.validators.FancyValidator):
456 messages = {
456 messages = {
457 'invalid_fork_type': _(u'Fork have to be the same type as parent')
457 'invalid_fork_type': _(u'Fork have to be the same type as parent')
458 }
458 }
459
459
460 def validate_python(self, value, state):
460 def validate_python(self, value, state):
461 if old_data['repo_type'] != value:
461 if old_data['repo_type'] != value:
462 msg = M(self, 'invalid_fork_type', state)
462 msg = M(self, 'invalid_fork_type', state)
463 raise formencode.Invalid(msg, value, state,
463 raise formencode.Invalid(msg, value, state,
464 error_dict=dict(repo_type=msg)
464 error_dict=dict(repo_type=msg)
465 )
465 )
466 return _validator
466 return _validator
467
467
468
468
469 def ValidPerms(type_='repo'):
469 def ValidPerms(type_='repo'):
470 if type_ == 'group':
470 if type_ == 'group':
471 EMPTY_PERM = 'group.none'
471 EMPTY_PERM = 'group.none'
472 elif type_ == 'repo':
472 elif type_ == 'repo':
473 EMPTY_PERM = 'repository.none'
473 EMPTY_PERM = 'repository.none'
474
474
475 class _validator(formencode.validators.FancyValidator):
475 class _validator(formencode.validators.FancyValidator):
476 messages = {
476 messages = {
477 'perm_new_member_name':
477 'perm_new_member_name':
478 _(u'This username or users group name is not valid')
478 _(u'This username or users group name is not valid')
479 }
479 }
480
480
481 def to_python(self, value, state):
481 def to_python(self, value, state):
482 perms_update = OrderedSet()
482 perms_update = OrderedSet()
483 perms_new = OrderedSet()
483 perms_new = OrderedSet()
484 # build a list of permission to update and new permission to create
484 # build a list of permission to update and new permission to create
485
485
486 #CLEAN OUT ORG VALUE FROM NEW MEMBERS, and group them using
486 #CLEAN OUT ORG VALUE FROM NEW MEMBERS, and group them using
487 new_perms_group = defaultdict(dict)
487 new_perms_group = defaultdict(dict)
488 for k, v in value.copy().iteritems():
488 for k, v in value.copy().iteritems():
489 if k.startswith('perm_new_member'):
489 if k.startswith('perm_new_member'):
490 del value[k]
490 del value[k]
491 _type, part = k.split('perm_new_member_')
491 _type, part = k.split('perm_new_member_')
492 args = part.split('_')
492 args = part.split('_')
493 if len(args) == 1:
493 if len(args) == 1:
494 new_perms_group[args[0]]['perm'] = v
494 new_perms_group[args[0]]['perm'] = v
495 elif len(args) == 2:
495 elif len(args) == 2:
496 _key, pos = args
496 _key, pos = args
497 new_perms_group[pos][_key] = v
497 new_perms_group[pos][_key] = v
498
498
499 # fill new permissions in order of how they were added
499 # fill new permissions in order of how they were added
500 for k in sorted(map(int, new_perms_group.keys())):
500 for k in sorted(map(int, new_perms_group.keys())):
501 perm_dict = new_perms_group[str(k)]
501 perm_dict = new_perms_group[str(k)]
502 new_member = perm_dict['name']
502 new_member = perm_dict.get('name')
503 new_perm = perm_dict['perm']
503 new_perm = perm_dict.get('perm')
504 new_type = perm_dict['type']
504 new_type = perm_dict.get('type')
505 if new_member and new_perm and new_type:
505 if new_member and new_perm and new_type:
506 perms_new.add((new_member, new_perm, new_type))
506 perms_new.add((new_member, new_perm, new_type))
507
507
508 for k, v in value.iteritems():
508 for k, v in value.iteritems():
509 if k.startswith('u_perm_') or k.startswith('g_perm_'):
509 if k.startswith('u_perm_') or k.startswith('g_perm_'):
510 member = k[7:]
510 member = k[7:]
511 t = {'u': 'user',
511 t = {'u': 'user',
512 'g': 'users_group'
512 'g': 'users_group'
513 }[k[0]]
513 }[k[0]]
514 if member == 'default':
514 if member == 'default':
515 if value.get('private'):
515 if value.get('private'):
516 # set none for default when updating to
516 # set none for default when updating to
517 # private repo
517 # private repo
518 v = EMPTY_PERM
518 v = EMPTY_PERM
519 perms_update.add((member, v, t))
519 perms_update.add((member, v, t))
520
520
521 value['perms_updates'] = list(perms_update)
521 value['perms_updates'] = list(perms_update)
522 value['perms_new'] = list(perms_new)
522 value['perms_new'] = list(perms_new)
523
523
524 # update permissions
524 # update permissions
525 for k, v, t in perms_new:
525 for k, v, t in perms_new:
526 try:
526 try:
527 if t is 'user':
527 if t is 'user':
528 self.user_db = User.query()\
528 self.user_db = User.query()\
529 .filter(User.active == True)\
529 .filter(User.active == True)\
530 .filter(User.username == k).one()
530 .filter(User.username == k).one()
531 if t is 'users_group':
531 if t is 'users_group':
532 self.user_db = UsersGroup.query()\
532 self.user_db = UsersGroup.query()\
533 .filter(UsersGroup.users_group_active == True)\
533 .filter(UsersGroup.users_group_active == True)\
534 .filter(UsersGroup.users_group_name == k).one()
534 .filter(UsersGroup.users_group_name == k).one()
535
535
536 except Exception:
536 except Exception:
537 log.exception('Updated permission failed')
537 log.exception('Updated permission failed')
538 msg = M(self, 'perm_new_member_type', state)
538 msg = M(self, 'perm_new_member_type', state)
539 raise formencode.Invalid(msg, value, state,
539 raise formencode.Invalid(msg, value, state,
540 error_dict=dict(perm_new_member_name=msg)
540 error_dict=dict(perm_new_member_name=msg)
541 )
541 )
542 return value
542 return value
543 return _validator
543 return _validator
544
544
545
545
546 def ValidSettings():
546 def ValidSettings():
547 class _validator(formencode.validators.FancyValidator):
547 class _validator(formencode.validators.FancyValidator):
548 def _to_python(self, value, state):
548 def _to_python(self, value, state):
549 # settings form can't edit user
549 # settings form can't edit user
550 if 'user' in value:
550 if 'user' in value:
551 del value['user']
551 del value['user']
552 return value
552 return value
553
553
554 def validate_python(self, value, state):
554 def validate_python(self, value, state):
555 pass
555 pass
556 return _validator
556 return _validator
557
557
558
558
559 def ValidPath():
559 def ValidPath():
560 class _validator(formencode.validators.FancyValidator):
560 class _validator(formencode.validators.FancyValidator):
561 messages = {
561 messages = {
562 'invalid_path': _(u'This is not a valid path')
562 'invalid_path': _(u'This is not a valid path')
563 }
563 }
564
564
565 def validate_python(self, value, state):
565 def validate_python(self, value, state):
566 if not os.path.isdir(value):
566 if not os.path.isdir(value):
567 msg = M(self, 'invalid_path', state)
567 msg = M(self, 'invalid_path', state)
568 raise formencode.Invalid(msg, value, state,
568 raise formencode.Invalid(msg, value, state,
569 error_dict=dict(paths_root_path=msg)
569 error_dict=dict(paths_root_path=msg)
570 )
570 )
571 return _validator
571 return _validator
572
572
573
573
574 def UniqSystemEmail(old_data={}):
574 def UniqSystemEmail(old_data={}):
575 class _validator(formencode.validators.FancyValidator):
575 class _validator(formencode.validators.FancyValidator):
576 messages = {
576 messages = {
577 'email_taken': _(u'This e-mail address is already taken')
577 'email_taken': _(u'This e-mail address is already taken')
578 }
578 }
579
579
580 def _to_python(self, value, state):
580 def _to_python(self, value, state):
581 return value.lower()
581 return value.lower()
582
582
583 def validate_python(self, value, state):
583 def validate_python(self, value, state):
584 if (old_data.get('email') or '').lower() != value:
584 if (old_data.get('email') or '').lower() != value:
585 user = User.get_by_email(value, case_insensitive=True)
585 user = User.get_by_email(value, case_insensitive=True)
586 if user:
586 if user:
587 msg = M(self, 'email_taken', state)
587 msg = M(self, 'email_taken', state)
588 raise formencode.Invalid(msg, value, state,
588 raise formencode.Invalid(msg, value, state,
589 error_dict=dict(email=msg)
589 error_dict=dict(email=msg)
590 )
590 )
591 return _validator
591 return _validator
592
592
593
593
594 def ValidSystemEmail():
594 def ValidSystemEmail():
595 class _validator(formencode.validators.FancyValidator):
595 class _validator(formencode.validators.FancyValidator):
596 messages = {
596 messages = {
597 'non_existing_email': _(u'e-mail "%(email)s" does not exist.')
597 'non_existing_email': _(u'e-mail "%(email)s" does not exist.')
598 }
598 }
599
599
600 def _to_python(self, value, state):
600 def _to_python(self, value, state):
601 return value.lower()
601 return value.lower()
602
602
603 def validate_python(self, value, state):
603 def validate_python(self, value, state):
604 user = User.get_by_email(value, case_insensitive=True)
604 user = User.get_by_email(value, case_insensitive=True)
605 if user is None:
605 if user is None:
606 msg = M(self, 'non_existing_email', state, email=value)
606 msg = M(self, 'non_existing_email', state, email=value)
607 raise formencode.Invalid(msg, value, state,
607 raise formencode.Invalid(msg, value, state,
608 error_dict=dict(email=msg)
608 error_dict=dict(email=msg)
609 )
609 )
610
610
611 return _validator
611 return _validator
612
612
613
613
614 def LdapLibValidator():
614 def LdapLibValidator():
615 class _validator(formencode.validators.FancyValidator):
615 class _validator(formencode.validators.FancyValidator):
616 messages = {
616 messages = {
617
617
618 }
618 }
619
619
620 def validate_python(self, value, state):
620 def validate_python(self, value, state):
621 try:
621 try:
622 import ldap
622 import ldap
623 ldap # pyflakes silence !
623 ldap # pyflakes silence !
624 except ImportError:
624 except ImportError:
625 raise LdapImportError()
625 raise LdapImportError()
626
626
627 return _validator
627 return _validator
628
628
629
629
630 def AttrLoginValidator():
630 def AttrLoginValidator():
631 class _validator(formencode.validators.FancyValidator):
631 class _validator(formencode.validators.FancyValidator):
632 messages = {
632 messages = {
633 'invalid_cn':
633 'invalid_cn':
634 _(u'The LDAP Login attribute of the CN must be specified - '
634 _(u'The LDAP Login attribute of the CN must be specified - '
635 'this is the name of the attribute that is equivalent '
635 'this is the name of the attribute that is equivalent '
636 'to "username"')
636 'to "username"')
637 }
637 }
638
638
639 def validate_python(self, value, state):
639 def validate_python(self, value, state):
640 if not value or not isinstance(value, (str, unicode)):
640 if not value or not isinstance(value, (str, unicode)):
641 msg = M(self, 'invalid_cn', state)
641 msg = M(self, 'invalid_cn', state)
642 raise formencode.Invalid(msg, value, state,
642 raise formencode.Invalid(msg, value, state,
643 error_dict=dict(ldap_attr_login=msg)
643 error_dict=dict(ldap_attr_login=msg)
644 )
644 )
645
645
646 return _validator
646 return _validator
647
647
648
648
649 def NotReviewedRevisions():
649 def NotReviewedRevisions():
650 class _validator(formencode.validators.FancyValidator):
650 class _validator(formencode.validators.FancyValidator):
651 messages = {
651 messages = {
652 'rev_already_reviewed':
652 'rev_already_reviewed':
653 _(u'Revisions %(revs)s are already part of pull request '
653 _(u'Revisions %(revs)s are already part of pull request '
654 'or have set status')
654 'or have set status')
655 }
655 }
656
656
657 def validate_python(self, value, state):
657 def validate_python(self, value, state):
658 # check revisions if they are not reviewed, or a part of another
658 # check revisions if they are not reviewed, or a part of another
659 # pull request
659 # pull request
660 statuses = ChangesetStatus.query()\
660 statuses = ChangesetStatus.query()\
661 .filter(ChangesetStatus.revision.in_(value)).all()
661 .filter(ChangesetStatus.revision.in_(value)).all()
662 errors = []
662 errors = []
663 for cs in statuses:
663 for cs in statuses:
664 if cs.pull_request_id:
664 if cs.pull_request_id:
665 errors.append(['pull_req', cs.revision[:12]])
665 errors.append(['pull_req', cs.revision[:12]])
666 elif cs.status:
666 elif cs.status:
667 errors.append(['status', cs.revision[:12]])
667 errors.append(['status', cs.revision[:12]])
668
668
669 if errors:
669 if errors:
670 revs = ','.join([x[1] for x in errors])
670 revs = ','.join([x[1] for x in errors])
671 msg = M(self, 'rev_already_reviewed', state, revs=revs)
671 msg = M(self, 'rev_already_reviewed', state, revs=revs)
672 raise formencode.Invalid(msg, value, state,
672 raise formencode.Invalid(msg, value, state,
673 error_dict=dict(revisions=revs)
673 error_dict=dict(revisions=revs)
674 )
674 )
675
675
676 return _validator
676 return _validator
@@ -1,112 +1,120 b''
1 <table id="permissions_manage" class="noborder">
1 <table id="permissions_manage" class="noborder">
2 <tr>
2 <tr>
3 <td>${_('none')}</td>
3 <td>${_('none')}</td>
4 <td>${_('read')}</td>
4 <td>${_('read')}</td>
5 <td>${_('write')}</td>
5 <td>${_('write')}</td>
6 <td>${_('admin')}</td>
6 <td>${_('admin')}</td>
7 <td>${_('member')}</td>
7 <td>${_('member')}</td>
8 <td></td>
8 <td></td>
9 </tr>
9 </tr>
10 ## USERS
10 ## USERS
11 %for r2p in c.repos_group.repo_group_to_perm:
11 %for r2p in c.repos_group.repo_group_to_perm:
12 <tr id="id${id(r2p.user.username)}">
12 <tr id="id${id(r2p.user.username)}">
13 <td>${h.radio('u_perm_%s' % r2p.user.username,'group.none')}</td>
13 <td>${h.radio('u_perm_%s' % r2p.user.username,'group.none')}</td>
14 <td>${h.radio('u_perm_%s' % r2p.user.username,'group.read')}</td>
14 <td>${h.radio('u_perm_%s' % r2p.user.username,'group.read')}</td>
15 <td>${h.radio('u_perm_%s' % r2p.user.username,'group.write')}</td>
15 <td>${h.radio('u_perm_%s' % r2p.user.username,'group.write')}</td>
16 <td>${h.radio('u_perm_%s' % r2p.user.username,'group.admin')}</td>
16 <td>${h.radio('u_perm_%s' % r2p.user.username,'group.admin')}</td>
17 <td style="white-space: nowrap;">
17 <td style="white-space: nowrap;">
18 <img class="perm-gravatar" src="${h.gravatar_url(r2p.user.email,14)}"/>${r2p.user.username if r2p.user.username != 'default' else _('default')}
18 <img class="perm-gravatar" src="${h.gravatar_url(r2p.user.email,14)}"/>${r2p.user.username if r2p.user.username != 'default' else _('default')}
19 </td>
19 </td>
20 <td>
20 <td>
21 %if r2p.user.username !='default':
21 %if r2p.user.username !='default':
22 <span class="delete_icon action_button" onclick="ajaxActionUser(${r2p.user.user_id},'${'id%s'%id(r2p.user.username)}')">
22 <span class="delete_icon action_button" onclick="ajaxActionUser(${r2p.user.user_id},'${'id%s'%id(r2p.user.username)}')">
23 ${_('revoke')}
23 ${_('revoke')}
24 </span>
24 </span>
25 %endif
25 %endif
26 </td>
26 </td>
27 </tr>
27 </tr>
28 %endfor
28 %endfor
29
29
30 ## USERS GROUPS
30 ## USERS GROUPS
31 %for g2p in c.repos_group.users_group_to_perm:
31 %for g2p in c.repos_group.users_group_to_perm:
32 <tr id="id${id(g2p.users_group.users_group_name)}">
32 <tr id="id${id(g2p.users_group.users_group_name)}">
33 <td>${h.radio('g_perm_%s' % g2p.users_group.users_group_name,'group.none')}</td>
33 <td>${h.radio('g_perm_%s' % g2p.users_group.users_group_name,'group.none')}</td>
34 <td>${h.radio('g_perm_%s' % g2p.users_group.users_group_name,'group.read')}</td>
34 <td>${h.radio('g_perm_%s' % g2p.users_group.users_group_name,'group.read')}</td>
35 <td>${h.radio('g_perm_%s' % g2p.users_group.users_group_name,'group.write')}</td>
35 <td>${h.radio('g_perm_%s' % g2p.users_group.users_group_name,'group.write')}</td>
36 <td>${h.radio('g_perm_%s' % g2p.users_group.users_group_name,'group.admin')}</td>
36 <td>${h.radio('g_perm_%s' % g2p.users_group.users_group_name,'group.admin')}</td>
37 <td style="white-space: nowrap;">
37 <td style="white-space: nowrap;">
38 <img class="perm-gravatar" src="${h.url('/images/icons/group.png')}"/>${g2p.users_group.users_group_name}
38 <img class="perm-gravatar" src="${h.url('/images/icons/group.png')}"/>${g2p.users_group.users_group_name}
39 </td>
39 </td>
40 <td>
40 <td>
41 <span class="delete_icon action_button" onclick="ajaxActionUsersGroup(${g2p.users_group.users_group_id},'${'id%s'%id(g2p.users_group.users_group_name)}')">
41 <span class="delete_icon action_button" onclick="ajaxActionUsersGroup(${g2p.users_group.users_group_id},'${'id%s'%id(g2p.users_group.users_group_name)}')">
42 ${_('revoke')}
42 ${_('revoke')}
43 </span>
43 </span>
44 </td>
44 </td>
45 </tr>
45 </tr>
46 %endfor
46 %endfor
47 <%
47 <%
48 _tmpl = h.literal("""' \
48 _tmpl = h.literal("""' \
49 <td><input type="radio" value="group.none" name="perm_new_member_{0}" id="perm_new_member_{0}"></td> \
49 <td><input type="radio" value="group.none" name="perm_new_member_{0}" id="perm_new_member_{0}"></td> \
50 <td><input type="radio" value="group.read" name="perm_new_member_{0}" id="perm_new_member_{0}"></td> \
50 <td><input type="radio" value="group.read" name="perm_new_member_{0}" id="perm_new_member_{0}"></td> \
51 <td><input type="radio" value="group.write" name="perm_new_member_{0}" id="perm_new_member_{0}"></td> \
51 <td><input type="radio" value="group.write" name="perm_new_member_{0}" id="perm_new_member_{0}"></td> \
52 <td><input type="radio" value="group.admin" name="perm_new_member_{0}" id="perm_new_member_{0}"></td> \
52 <td><input type="radio" value="group.admin" name="perm_new_member_{0}" id="perm_new_member_{0}"></td> \
53 <td class="ac"> \
53 <td class="ac"> \
54 <div class="perm_ac" id="perm_ac_{0}"> \
54 <div class="perm_ac" id="perm_ac_{0}"> \
55 <input class="yui-ac-input" id="perm_new_member_name_{0}" name="perm_new_member_name_{0}" value="" type="text"> \
55 <input class="yui-ac-input" id="perm_new_member_name_{0}" name="perm_new_member_name_{0}" value="" type="text"> \
56 <input id="perm_new_member_type_{0}" name="perm_new_member_type_{0}" value="" type="hidden"> \
56 <input id="perm_new_member_type_{0}" name="perm_new_member_type_{0}" value="" type="hidden"> \
57 <div id="perm_container_{0}"></div> \
57 <div id="perm_container_{0}"></div> \
58 </div> \
58 </div> \
59 </td> \
59 </td> \
60 <td></td>'""")
60 <td></td>'""")
61 %>
61 %>
62 ## ADD HERE DYNAMICALLY NEW INPUTS FROM THE '_tmpl'
62 ## ADD HERE DYNAMICALLY NEW INPUTS FROM THE '_tmpl'
63 <tr class="new_members last_new_member" id="add_perm_input"></tr>
63 <tr class="new_members last_new_member" id="add_perm_input"></tr>
64 <tr>
64 <tr>
65 <td colspan="6">
65 <td colspan="6">
66 <span id="add_perm" class="add_icon" style="cursor: pointer;">
66 <span id="add_perm" class="add_icon" style="cursor: pointer;">
67 ${_('Add another member')}
67 ${_('Add another member')}
68 </span>
68 </span>
69 </td>
69 </td>
70 </tr>
70 </tr>
71 <tr>
72 <td colspan="6">
73 ${h.checkbox('recursive',value="True", label=_('apply to parents'))}
74 <span class="help-block">${_('Set or revoke permission to all children of that group, including repositories and other groups')}</span>
75 </td>
76 </tr>
71 </table>
77 </table>
72 <script type="text/javascript">
78 <script type="text/javascript">
73 function ajaxActionUser(user_id, field_id) {
79 function ajaxActionUser(user_id, field_id) {
74 var sUrl = "${h.url('delete_repos_group_user_perm',group_name=c.repos_group.group_name)}";
80 var sUrl = "${h.url('delete_repos_group_user_perm',group_name=c.repos_group.group_name)}";
75 var callback = {
81 var callback = {
76 success: function (o) {
82 success: function (o) {
77 var tr = YUD.get(String(field_id));
83 var tr = YUD.get(String(field_id));
78 tr.parentNode.removeChild(tr);
84 tr.parentNode.removeChild(tr);
79 },
85 },
80 failure: function (o) {
86 failure: function (o) {
81 alert("${_('Failed to remove user')}");
87 alert("${_('Failed to remove user')}");
82 },
88 },
83 };
89 };
84 var postData = '_method=delete&user_id=' + user_id;
90 var recursive = YUD.get('recursive').checked;
91 var postData = '_method=delete&recursive={0}&user_id={1}'.format(recursive,user_id);
85 var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData);
92 var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData);
86 };
93 };
87
94
88 function ajaxActionUsersGroup(users_group_id,field_id){
95 function ajaxActionUsersGroup(users_group_id,field_id){
89 var sUrl = "${h.url('delete_repos_group_users_group_perm',group_name=c.repos_group.group_name)}";
96 var sUrl = "${h.url('delete_repos_group_users_group_perm',group_name=c.repos_group.group_name)}";
90 var callback = {
97 var callback = {
91 success:function(o){
98 success:function(o){
92 var tr = YUD.get(String(field_id));
99 var tr = YUD.get(String(field_id));
93 tr.parentNode.removeChild(tr);
100 tr.parentNode.removeChild(tr);
94 },
101 },
95 failure:function(o){
102 failure:function(o){
96 alert("${_('Failed to remove users group')}");
103 alert("${_('Failed to remove users group')}");
97 },
104 },
98 };
105 };
99 var postData = '_method=delete&users_group_id='+users_group_id;
106 var recursive = YUD.get('recursive').checked;
107 var postData = '_method=delete&recursive={0}&users_group_id={1}'.format(recursive,users_group_id);
100 var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData);
108 var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData);
101 };
109 };
102
110
103 YUE.onDOMReady(function () {
111 YUE.onDOMReady(function () {
104 if (!YUD.hasClass('perm_new_member_name', 'error')) {
112 if (!YUD.hasClass('perm_new_member_name', 'error')) {
105 YUD.setStyle('add_perm_input', 'display', 'none');
113 YUD.setStyle('add_perm_input', 'display', 'none');
106 }
114 }
107 YAHOO.util.Event.addListener('add_perm', 'click', function () {
115 YAHOO.util.Event.addListener('add_perm', 'click', function () {
108 addPermAction(${_tmpl}, ${c.users_array|n}, ${c.users_groups_array|n});
116 addPermAction(${_tmpl}, ${c.users_array|n}, ${c.users_groups_array|n});
109 });
117 });
110 });
118 });
111
119
112 </script>
120 </script>
@@ -1,294 +1,293 b''
1 from rhodecode.tests import *
1 from rhodecode.tests import *
2 from rhodecode.model.repo import RepoModel
2 from rhodecode.model.repo import RepoModel
3 from rhodecode.model.meta import Session
3 from rhodecode.model.meta import Session
4 from rhodecode.model.db import Repository
4 from rhodecode.model.db import Repository
5 from rhodecode.model.scm import ScmModel
5 from rhodecode.model.scm import ScmModel
6 from rhodecode.lib.vcs.backends.base import EmptyChangeset
6 from rhodecode.lib.vcs.backends.base import EmptyChangeset
7
7
8
8
9 class TestCompareController(TestController):
9 class TestCompareController(TestController):
10
10
11 def test_index_tag(self):
11 def test_index_tag(self):
12 self.log_user()
12 self.log_user()
13 tag1 = '0.1.3'
13 tag1 = '0.1.3'
14 tag2 = '0.1.2'
14 tag2 = '0.1.2'
15 response = self.app.get(url(controller='compare', action='index',
15 response = self.app.get(url(controller='compare', action='index',
16 repo_name=HG_REPO,
16 repo_name=HG_REPO,
17 org_ref_type="tag",
17 org_ref_type="tag",
18 org_ref=tag1,
18 org_ref=tag1,
19 other_ref_type="tag",
19 other_ref_type="tag",
20 other_ref=tag2,
20 other_ref=tag2,
21 ))
21 ))
22 response.mustcontain('%s@%s -> %s@%s' % (HG_REPO, tag1, HG_REPO, tag2))
22 response.mustcontain('%s@%s -> %s@%s' % (HG_REPO, tag1, HG_REPO, tag2))
23 ## outgoing changesets between tags
23 ## outgoing changesets between tags
24 response.mustcontain('''<a href="/%s/changeset/17544fbfcd33ffb439e2b728b5d526b1ef30bfcf">r120:17544fbfcd33</a>''' % HG_REPO)
24 response.mustcontain('''<a href="/%s/changeset/17544fbfcd33ffb439e2b728b5d526b1ef30bfcf">r120:17544fbfcd33</a>''' % HG_REPO)
25 response.mustcontain('''<a href="/%s/changeset/36e0fc9d2808c5022a24f49d6658330383ed8666">r119:36e0fc9d2808</a>''' % HG_REPO)
25 response.mustcontain('''<a href="/%s/changeset/36e0fc9d2808c5022a24f49d6658330383ed8666">r119:36e0fc9d2808</a>''' % HG_REPO)
26 response.mustcontain('''<a href="/%s/changeset/bb1a3ab98cc45cb934a77dcabf87a5a598b59e97">r118:bb1a3ab98cc4</a>''' % HG_REPO)
26 response.mustcontain('''<a href="/%s/changeset/bb1a3ab98cc45cb934a77dcabf87a5a598b59e97">r118:bb1a3ab98cc4</a>''' % HG_REPO)
27 response.mustcontain('''<a href="/%s/changeset/41fda979f02fda216374bf8edac4e83f69e7581c">r117:41fda979f02f</a>''' % HG_REPO)
27 response.mustcontain('''<a href="/%s/changeset/41fda979f02fda216374bf8edac4e83f69e7581c">r117:41fda979f02f</a>''' % HG_REPO)
28 response.mustcontain('''<a href="/%s/changeset/9749bfbfc0d2eba208d7947de266303b67c87cda">r116:9749bfbfc0d2</a>''' % HG_REPO)
28 response.mustcontain('''<a href="/%s/changeset/9749bfbfc0d2eba208d7947de266303b67c87cda">r116:9749bfbfc0d2</a>''' % HG_REPO)
29 response.mustcontain('''<a href="/%s/changeset/70d4cef8a37657ee4cf5aabb3bd9f68879769816">r115:70d4cef8a376</a>''' % HG_REPO)
29 response.mustcontain('''<a href="/%s/changeset/70d4cef8a37657ee4cf5aabb3bd9f68879769816">r115:70d4cef8a376</a>''' % HG_REPO)
30 response.mustcontain('''<a href="/%s/changeset/c5ddebc06eaaba3010c2d66ea6ec9d074eb0f678">r112:c5ddebc06eaa</a>''' % HG_REPO)
30 response.mustcontain('''<a href="/%s/changeset/c5ddebc06eaaba3010c2d66ea6ec9d074eb0f678">r112:c5ddebc06eaa</a>''' % HG_REPO)
31
31
32 ## files diff
32 ## files diff
33 response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--1c5cf9e91c12">docs/api/utils/index.rst</a></div>''' % (HG_REPO, tag1, tag2))
33 response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--1c5cf9e91c12">docs/api/utils/index.rst</a></div>''' % (HG_REPO, tag1, tag2))
34 response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--e3305437df55">test_and_report.sh</a></div>''' % (HG_REPO, tag1, tag2))
34 response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--e3305437df55">test_and_report.sh</a></div>''' % (HG_REPO, tag1, tag2))
35 response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--c8e92ef85cd1">.hgignore</a></div>''' % (HG_REPO, tag1, tag2))
35 response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--c8e92ef85cd1">.hgignore</a></div>''' % (HG_REPO, tag1, tag2))
36 response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--6e08b694d687">.hgtags</a></div>''' % (HG_REPO, tag1, tag2))
36 response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--6e08b694d687">.hgtags</a></div>''' % (HG_REPO, tag1, tag2))
37 response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--2c14b00f3393">docs/api/index.rst</a></div>''' % (HG_REPO, tag1, tag2))
37 response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--2c14b00f3393">docs/api/index.rst</a></div>''' % (HG_REPO, tag1, tag2))
38 response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--430ccbc82bdf">vcs/__init__.py</a></div>''' % (HG_REPO, tag1, tag2))
38 response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--430ccbc82bdf">vcs/__init__.py</a></div>''' % (HG_REPO, tag1, tag2))
39 response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--9c390eb52cd6">vcs/backends/hg.py</a></div>''' % (HG_REPO, tag1, tag2))
39 response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--9c390eb52cd6">vcs/backends/hg.py</a></div>''' % (HG_REPO, tag1, tag2))
40 response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--ebb592c595c0">vcs/utils/__init__.py</a></div>''' % (HG_REPO, tag1, tag2))
40 response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--ebb592c595c0">vcs/utils/__init__.py</a></div>''' % (HG_REPO, tag1, tag2))
41 response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--7abc741b5052">vcs/utils/annotate.py</a></div>''' % (HG_REPO, tag1, tag2))
41 response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--7abc741b5052">vcs/utils/annotate.py</a></div>''' % (HG_REPO, tag1, tag2))
42 response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--2ef0ef106c56">vcs/utils/diffs.py</a></div>''' % (HG_REPO, tag1, tag2))
42 response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--2ef0ef106c56">vcs/utils/diffs.py</a></div>''' % (HG_REPO, tag1, tag2))
43 response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--3150cb87d4b7">vcs/utils/lazy.py</a></div>''' % (HG_REPO, tag1, tag2))
43 response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--3150cb87d4b7">vcs/utils/lazy.py</a></div>''' % (HG_REPO, tag1, tag2))
44
44
45 def test_index_branch(self):
45 def test_index_branch(self):
46 self.log_user()
46 self.log_user()
47 response = self.app.get(url(controller='compare', action='index',
47 response = self.app.get(url(controller='compare', action='index',
48 repo_name=HG_REPO,
48 repo_name=HG_REPO,
49 org_ref_type="branch",
49 org_ref_type="branch",
50 org_ref='default',
50 org_ref='default',
51 other_ref_type="branch",
51 other_ref_type="branch",
52 other_ref='default',
52 other_ref='default',
53 ))
53 ))
54
54
55 response.mustcontain('%s@default -> %s@default' % (HG_REPO, HG_REPO))
55 response.mustcontain('%s@default -> %s@default' % (HG_REPO, HG_REPO))
56 # branch are equal
56 # branch are equal
57 response.mustcontain('<tr><td>No changesets</td></tr>')
57 response.mustcontain('<tr><td>No changesets</td></tr>')
58
58
59 def test_compare_revisions(self):
59 def test_compare_revisions(self):
60 self.log_user()
60 self.log_user()
61 rev1 = '3d8f361e72ab'
61 rev1 = '3d8f361e72ab'
62 rev2 = 'b986218ba1c9'
62 rev2 = 'b986218ba1c9'
63 response = self.app.get(url(controller='compare', action='index',
63 response = self.app.get(url(controller='compare', action='index',
64 repo_name=HG_REPO,
64 repo_name=HG_REPO,
65 org_ref_type="rev",
65 org_ref_type="rev",
66 org_ref=rev1,
66 org_ref=rev1,
67 other_ref_type="rev",
67 other_ref_type="rev",
68 other_ref=rev2,
68 other_ref=rev2,
69 ))
69 ))
70 response.mustcontain('%s@%s -> %s@%s' % (HG_REPO, rev1, HG_REPO, rev2))
70 response.mustcontain('%s@%s -> %s@%s' % (HG_REPO, rev1, HG_REPO, rev2))
71 ## outgoing changesets between those revisions
71 ## outgoing changesets between those revisions
72 response.mustcontain("""<a href="/%s/changeset/3d8f361e72ab303da48d799ff1ac40d5ac37c67e">r1:%s</a>""" % (HG_REPO, rev1))
72 response.mustcontain("""<a href="/%s/changeset/3d8f361e72ab303da48d799ff1ac40d5ac37c67e">r1:%s</a>""" % (HG_REPO, rev1))
73
73
74 ## files
74 ## files
75 response.mustcontain("""<a href="/%s/compare/rev@%s...rev@%s#C--c8e92ef85cd1">.hgignore</a>""" % (HG_REPO, rev1, rev2))
75 response.mustcontain("""<a href="/%s/compare/rev@%s...rev@%s#C--c8e92ef85cd1">.hgignore</a>""" % (HG_REPO, rev1, rev2))
76
76
77 def test_compare_remote_repos(self):
77 def test_compare_remote_repos(self):
78 self.log_user()
78 self.log_user()
79
79
80 form_data = dict(
80 form_data = dict(
81 repo_name=HG_FORK,
81 repo_name=HG_FORK,
82 repo_name_full=HG_FORK,
82 repo_name_full=HG_FORK,
83 repo_group=None,
83 repo_group=None,
84 repo_type='hg',
84 repo_type='hg',
85 description='',
85 description='',
86 private=False,
86 private=False,
87 copy_permissions=False,
87 copy_permissions=False,
88 landing_rev='tip',
88 landing_rev='tip',
89 update_after_clone=False,
89 update_after_clone=False,
90 fork_parent_id=Repository.get_by_repo_name(HG_REPO),
90 fork_parent_id=Repository.get_by_repo_name(HG_REPO),
91 )
91 )
92 RepoModel().create_fork(form_data, cur_user=TEST_USER_ADMIN_LOGIN)
92 RepoModel().create_fork(form_data, cur_user=TEST_USER_ADMIN_LOGIN)
93
93
94 Session().commit()
94 Session().commit()
95
95
96 rev1 = '7d4bc8ec6be5'
96 rev1 = '7d4bc8ec6be5'
97 rev2 = '56349e29c2af'
97 rev2 = '56349e29c2af'
98
98
99 response = self.app.get(url(controller='compare', action='index',
99 response = self.app.get(url(controller='compare', action='index',
100 repo_name=HG_REPO,
100 repo_name=HG_REPO,
101 org_ref_type="rev",
101 org_ref_type="rev",
102 org_ref=rev1,
102 org_ref=rev1,
103 other_ref_type="rev",
103 other_ref_type="rev",
104 other_ref=rev2,
104 other_ref=rev2,
105 repo=HG_FORK
105 repo=HG_FORK
106 ))
106 ))
107
107
108 try:
108 try:
109 response.mustcontain('%s@%s -> %s@%s' % (HG_REPO, rev1, HG_FORK, rev2))
109 response.mustcontain('%s@%s -> %s@%s' % (HG_REPO, rev1, HG_FORK, rev2))
110 ## outgoing changesets between those revisions
110 ## outgoing changesets between those revisions
111
111
112 response.mustcontain("""<a href="/%s/changeset/7d4bc8ec6be56c0f10425afb40b6fc315a4c25e7">r6:%s</a>""" % (HG_REPO, rev1))
112 response.mustcontain("""<a href="/%s/changeset/7d4bc8ec6be56c0f10425afb40b6fc315a4c25e7">r6:%s</a>""" % (HG_REPO, rev1))
113 response.mustcontain("""<a href="/%s/changeset/6fff84722075f1607a30f436523403845f84cd9e">r5:6fff84722075</a>""" % (HG_REPO))
113 response.mustcontain("""<a href="/%s/changeset/6fff84722075f1607a30f436523403845f84cd9e">r5:6fff84722075</a>""" % (HG_REPO))
114 response.mustcontain("""<a href="/%s/changeset/2dda4e345facb0ccff1a191052dd1606dba6781d">r4:2dda4e345fac</a>""" % (HG_REPO))
114 response.mustcontain("""<a href="/%s/changeset/2dda4e345facb0ccff1a191052dd1606dba6781d">r4:2dda4e345fac</a>""" % (HG_REPO))
115
115
116 ## files
116 ## files
117 response.mustcontain("""<a href="/%s/compare/rev@%s...rev@%s#C--9c390eb52cd6">vcs/backends/hg.py</a>""" % (HG_REPO, rev1, rev2))
117 response.mustcontain("""<a href="/%s/compare/rev@%s...rev@%s#C--9c390eb52cd6">vcs/backends/hg.py</a>""" % (HG_REPO, rev1, rev2))
118 response.mustcontain("""<a href="/%s/compare/rev@%s...rev@%s#C--41b41c1f2796">vcs/backends/__init__.py</a>""" % (HG_REPO, rev1, rev2))
118 response.mustcontain("""<a href="/%s/compare/rev@%s...rev@%s#C--41b41c1f2796">vcs/backends/__init__.py</a>""" % (HG_REPO, rev1, rev2))
119 response.mustcontain("""<a href="/%s/compare/rev@%s...rev@%s#C--2f574d260608">vcs/backends/base.py</a>""" % (HG_REPO, rev1, rev2))
119 response.mustcontain("""<a href="/%s/compare/rev@%s...rev@%s#C--2f574d260608">vcs/backends/base.py</a>""" % (HG_REPO, rev1, rev2))
120 finally:
120 finally:
121 RepoModel().delete(HG_FORK)
121 RepoModel().delete(HG_FORK)
122
122
123 def test_compare_extra_commits(self):
123 def test_compare_extra_commits(self):
124 self.log_user()
124 self.log_user()
125
125
126 repo1 = RepoModel().create_repo(repo_name='one', repo_type='hg',
126 repo1 = RepoModel().create_repo(repo_name='one', repo_type='hg',
127 description='diff-test',
127 description='diff-test',
128 owner=TEST_USER_ADMIN_LOGIN)
128 owner=TEST_USER_ADMIN_LOGIN)
129
129
130 repo2 = RepoModel().create_repo(repo_name='one-fork', repo_type='hg',
130 repo2 = RepoModel().create_repo(repo_name='one-fork', repo_type='hg',
131 description='diff-test',
131 description='diff-test',
132 owner=TEST_USER_ADMIN_LOGIN)
132 owner=TEST_USER_ADMIN_LOGIN)
133
133
134 Session().commit()
134 Session().commit()
135 r1_id = repo1.repo_id
135 r1_id = repo1.repo_id
136 r1_name = repo1.repo_name
136 r1_name = repo1.repo_name
137 r2_id = repo2.repo_id
137 r2_id = repo2.repo_id
138 r2_name = repo2.repo_name
138 r2_name = repo2.repo_name
139
139
140 #commit something !
140 #commit something !
141 cs0 = ScmModel().create_node(
141 cs0 = ScmModel().create_node(
142 repo=repo1.scm_instance, repo_name=r1_name,
142 repo=repo1.scm_instance, repo_name=r1_name,
143 cs=EmptyChangeset(alias='hg'), user=TEST_USER_ADMIN_LOGIN,
143 cs=EmptyChangeset(alias='hg'), user=TEST_USER_ADMIN_LOGIN,
144 author=TEST_USER_ADMIN_LOGIN,
144 author=TEST_USER_ADMIN_LOGIN,
145 message='commit1',
145 message='commit1',
146 content='line1',
146 content='line1',
147 f_path='file1'
147 f_path='file1'
148 )
148 )
149
149
150 cs0_prim = ScmModel().create_node(
150 cs0_prim = ScmModel().create_node(
151 repo=repo2.scm_instance, repo_name=r2_name,
151 repo=repo2.scm_instance, repo_name=r2_name,
152 cs=EmptyChangeset(alias='hg'), user=TEST_USER_ADMIN_LOGIN,
152 cs=EmptyChangeset(alias='hg'), user=TEST_USER_ADMIN_LOGIN,
153 author=TEST_USER_ADMIN_LOGIN,
153 author=TEST_USER_ADMIN_LOGIN,
154 message='commit1',
154 message='commit1',
155 content='line1',
155 content='line1',
156 f_path='file1'
156 f_path='file1'
157 )
157 )
158
158
159 cs1 = ScmModel().commit_change(
159 cs1 = ScmModel().commit_change(
160 repo=repo2.scm_instance, repo_name=r2_name,
160 repo=repo2.scm_instance, repo_name=r2_name,
161 cs=cs0_prim, user=TEST_USER_ADMIN_LOGIN, author=TEST_USER_ADMIN_LOGIN,
161 cs=cs0_prim, user=TEST_USER_ADMIN_LOGIN, author=TEST_USER_ADMIN_LOGIN,
162 message='commit2',
162 message='commit2',
163 content='line1\nline2',
163 content='line1\nline2',
164 f_path='file1'
164 f_path='file1'
165 )
165 )
166
166
167 rev1 = 'default'
167 rev1 = 'default'
168 rev2 = 'default'
168 rev2 = 'default'
169 response = self.app.get(url(controller='compare', action='index',
169 response = self.app.get(url(controller='compare', action='index',
170 repo_name=r2_name,
170 repo_name=r2_name,
171 org_ref_type="branch",
171 org_ref_type="branch",
172 org_ref=rev1,
172 org_ref=rev1,
173 other_ref_type="branch",
173 other_ref_type="branch",
174 other_ref=rev2,
174 other_ref=rev2,
175 repo=r1_name
175 repo=r1_name
176 ))
176 ))
177
177
178 try:
178 try:
179 response.mustcontain('%s@%s -> %s@%s' % (r2_name, rev1, r1_name, rev2))
179 response.mustcontain('%s@%s -> %s@%s' % (r2_name, rev1, r1_name, rev2))
180
180
181 response.mustcontain("""<div class="message">commit2</div>""")
181 response.mustcontain("""<div class="message">commit2</div>""")
182 response.mustcontain("""<a href="/%s/changeset/%s">r1:%s</a>""" % (r2_name, cs1.raw_id, cs1.short_id))
182 response.mustcontain("""<a href="/%s/changeset/%s">r1:%s</a>""" % (r2_name, cs1.raw_id, cs1.short_id))
183 ## files
183 ## files
184 response.mustcontain("""<a href="/%s/compare/branch@%s...branch@%s#C--826e8142e6ba">file1</a>""" % (r2_name, rev1, rev2))
184 response.mustcontain("""<a href="/%s/compare/branch@%s...branch@%s#C--826e8142e6ba">file1</a>""" % (r2_name, rev1, rev2))
185
185
186 finally:
186 finally:
187 RepoModel().delete(r1_id)
187 RepoModel().delete(r1_id)
188 RepoModel().delete(r2_id)
188 RepoModel().delete(r2_id)
189
189
190 def test_org_repo_new_commits_after_forking(self):
190 def test_org_repo_new_commits_after_forking(self):
191 self.log_user()
191 self.log_user()
192
192
193 repo1 = RepoModel().create_repo(repo_name='one', repo_type='hg',
193 repo1 = RepoModel().create_repo(repo_name='one', repo_type='hg',
194 description='diff-test',
194 description='diff-test',
195 owner=TEST_USER_ADMIN_LOGIN)
195 owner=TEST_USER_ADMIN_LOGIN)
196
196
197 Session().commit()
197 Session().commit()
198 r1_id = repo1.repo_id
198 r1_id = repo1.repo_id
199 r1_name = repo1.repo_name
199 r1_name = repo1.repo_name
200
200
201 #commit something initially !
201 #commit something initially !
202 cs0 = ScmModel().create_node(
202 cs0 = ScmModel().create_node(
203 repo=repo1.scm_instance, repo_name=r1_name,
203 repo=repo1.scm_instance, repo_name=r1_name,
204 cs=EmptyChangeset(alias='hg'), user=TEST_USER_ADMIN_LOGIN,
204 cs=EmptyChangeset(alias='hg'), user=TEST_USER_ADMIN_LOGIN,
205 author=TEST_USER_ADMIN_LOGIN,
205 author=TEST_USER_ADMIN_LOGIN,
206 message='commit1',
206 message='commit1',
207 content='line1',
207 content='line1',
208 f_path='file1'
208 f_path='file1'
209 )
209 )
210 Session().commit()
210 Session().commit()
211 self.assertEqual(repo1.scm_instance.revisions, [cs0.raw_id])
211 self.assertEqual(repo1.scm_instance.revisions, [cs0.raw_id])
212 #fork the repo1
212 #fork the repo1
213 repo2 = RepoModel().create_repo(repo_name='one-fork', repo_type='hg',
213 repo2 = RepoModel().create_repo(repo_name='one-fork', repo_type='hg',
214 description='compare-test',
214 description='compare-test',
215 clone_uri=repo1.repo_full_path,
215 clone_uri=repo1.repo_full_path,
216 owner=TEST_USER_ADMIN_LOGIN, fork_of='one')
216 owner=TEST_USER_ADMIN_LOGIN, fork_of='one')
217 Session().commit()
217 Session().commit()
218 self.assertEqual(repo2.scm_instance.revisions, [cs0.raw_id])
218 self.assertEqual(repo2.scm_instance.revisions, [cs0.raw_id])
219 r2_id = repo2.repo_id
219 r2_id = repo2.repo_id
220 r2_name = repo2.repo_name
220 r2_name = repo2.repo_name
221
221
222 #make 3 new commits in fork
222 #make 3 new commits in fork
223 cs1 = ScmModel().create_node(
223 cs1 = ScmModel().create_node(
224 repo=repo2.scm_instance, repo_name=r2_name,
224 repo=repo2.scm_instance, repo_name=r2_name,
225 cs=repo2.scm_instance[-1], user=TEST_USER_ADMIN_LOGIN,
225 cs=repo2.scm_instance[-1], user=TEST_USER_ADMIN_LOGIN,
226 author=TEST_USER_ADMIN_LOGIN,
226 author=TEST_USER_ADMIN_LOGIN,
227 message='commit1-fork',
227 message='commit1-fork',
228 content='file1-line1-from-fork',
228 content='file1-line1-from-fork',
229 f_path='file1-fork'
229 f_path='file1-fork'
230 )
230 )
231 cs2 = ScmModel().create_node(
231 cs2 = ScmModel().create_node(
232 repo=repo2.scm_instance, repo_name=r2_name,
232 repo=repo2.scm_instance, repo_name=r2_name,
233 cs=cs1, user=TEST_USER_ADMIN_LOGIN,
233 cs=cs1, user=TEST_USER_ADMIN_LOGIN,
234 author=TEST_USER_ADMIN_LOGIN,
234 author=TEST_USER_ADMIN_LOGIN,
235 message='commit2-fork',
235 message='commit2-fork',
236 content='file2-line1-from-fork',
236 content='file2-line1-from-fork',
237 f_path='file2-fork'
237 f_path='file2-fork'
238 )
238 )
239 cs3 = ScmModel().create_node(
239 cs3 = ScmModel().create_node(
240 repo=repo2.scm_instance, repo_name=r2_name,
240 repo=repo2.scm_instance, repo_name=r2_name,
241 cs=cs2, user=TEST_USER_ADMIN_LOGIN,
241 cs=cs2, user=TEST_USER_ADMIN_LOGIN,
242 author=TEST_USER_ADMIN_LOGIN,
242 author=TEST_USER_ADMIN_LOGIN,
243 message='commit3-fork',
243 message='commit3-fork',
244 content='file3-line1-from-fork',
244 content='file3-line1-from-fork',
245 f_path='file3-fork'
245 f_path='file3-fork'
246 )
246 )
247
247
248 #compare !
248 #compare !
249 rev1 = 'default'
249 rev1 = 'default'
250 rev2 = 'default'
250 rev2 = 'default'
251 response = self.app.get(url(controller='compare', action='index',
251 response = self.app.get(url(controller='compare', action='index',
252 repo_name=r2_name,
252 repo_name=r2_name,
253 org_ref_type="branch",
253 org_ref_type="branch",
254 org_ref=rev1,
254 org_ref=rev1,
255 other_ref_type="branch",
255 other_ref_type="branch",
256 other_ref=rev2,
256 other_ref=rev2,
257 repo=r1_name
257 repo=r1_name
258 ))
258 ))
259
259
260 try:
260 try:
261 response.mustcontain('%s@%s -> %s@%s' % (r2_name, rev1, r1_name, rev2))
261 response.mustcontain('%s@%s -> %s@%s' % (r2_name, rev1, r1_name, rev2))
262 response.mustcontain("""file1-line1-from-fork""")
262 response.mustcontain("""file1-line1-from-fork""")
263 response.mustcontain("""file2-line1-from-fork""")
263 response.mustcontain("""file2-line1-from-fork""")
264 response.mustcontain("""file3-line1-from-fork""")
264 response.mustcontain("""file3-line1-from-fork""")
265
265
266 #add new commit into parent !
266 #add new commit into parent !
267 cs0 = ScmModel().create_node(
267 cs0 = ScmModel().create_node(
268 repo=repo1.scm_instance, repo_name=r1_name,
268 repo=repo1.scm_instance, repo_name=r1_name,
269 cs=EmptyChangeset(alias='hg'), user=TEST_USER_ADMIN_LOGIN,
269 cs=EmptyChangeset(alias='hg'), user=TEST_USER_ADMIN_LOGIN,
270 author=TEST_USER_ADMIN_LOGIN,
270 author=TEST_USER_ADMIN_LOGIN,
271 message='commit2',
271 message='commit2',
272 content='line1',
272 content='line1',
273 f_path='file2'
273 f_path='file2'
274 )
274 )
275 #compare !
275 #compare !
276 rev1 = 'default'
276 rev1 = 'default'
277 rev2 = 'default'
277 rev2 = 'default'
278 response = self.app.get(url(controller='compare', action='index',
278 response = self.app.get(url(controller='compare', action='index',
279 repo_name=r2_name,
279 repo_name=r2_name,
280 org_ref_type="branch",
280 org_ref_type="branch",
281 org_ref=rev1,
281 org_ref=rev1,
282 other_ref_type="branch",
282 other_ref_type="branch",
283 other_ref=rev2,
283 other_ref=rev2,
284 repo=r1_name
284 repo=r1_name
285 ))
285 ))
286
286
287 response.mustcontain('%s@%s -> %s@%s' % (r2_name, rev1, r1_name, rev2))
287 response.mustcontain('%s@%s -> %s@%s' % (r2_name, rev1, r1_name, rev2))
288 response.mustcontain("""file1-line1-from-fork""")
288 response.mustcontain("""file1-line1-from-fork""")
289 response.mustcontain("""file2-line1-from-fork""")
289 response.mustcontain("""file2-line1-from-fork""")
290 response.mustcontain("""file3-line1-from-fork""")
290 response.mustcontain("""file3-line1-from-fork""")
291 finally:
291 finally:
292 RepoModel().delete(r2_id)
292 RepoModel().delete(r2_id)
293 RepoModel().delete(r1_id)
293 RepoModel().delete(r1_id)
294
@@ -1,437 +1,427 b''
1 import os
1 import os
2 import unittest
2 import unittest
3 from rhodecode.tests import *
3 from rhodecode.tests import *
4
4 from rhodecode.tests.models.common import _make_group
5 from rhodecode.model.repos_group import ReposGroupModel
5 from rhodecode.model.repos_group import ReposGroupModel
6 from rhodecode.model.repo import RepoModel
6 from rhodecode.model.repo import RepoModel
7 from rhodecode.model.db import RepoGroup, User, UsersGroupRepoGroupToPerm
7 from rhodecode.model.db import RepoGroup, User, UsersGroupRepoGroupToPerm
8 from rhodecode.model.user import UserModel
8 from rhodecode.model.user import UserModel
9
9
10 from rhodecode.model.meta import Session
10 from rhodecode.model.meta import Session
11 from rhodecode.model.users_group import UsersGroupModel
11 from rhodecode.model.users_group import UsersGroupModel
12 from rhodecode.lib.auth import AuthUser
12 from rhodecode.lib.auth import AuthUser
13
13
14
14
15 def _make_group(path, desc='desc', parent_id=None,
16 skip_if_exists=False):
17
18 gr = RepoGroup.get_by_group_name(path)
19 if gr and skip_if_exists:
20 return gr
21
22 gr = ReposGroupModel().create(path, desc, parent_id)
23 return gr
24
25
15
26 class TestPermissions(unittest.TestCase):
16 class TestPermissions(unittest.TestCase):
27 def __init__(self, methodName='runTest'):
17 def __init__(self, methodName='runTest'):
28 super(TestPermissions, self).__init__(methodName=methodName)
18 super(TestPermissions, self).__init__(methodName=methodName)
29
19
30 def setUp(self):
20 def setUp(self):
31 self.u1 = UserModel().create_or_update(
21 self.u1 = UserModel().create_or_update(
32 username=u'u1', password=u'qweqwe',
22 username=u'u1', password=u'qweqwe',
33 email=u'u1@rhodecode.org', firstname=u'u1', lastname=u'u1'
23 email=u'u1@rhodecode.org', firstname=u'u1', lastname=u'u1'
34 )
24 )
35 self.u2 = UserModel().create_or_update(
25 self.u2 = UserModel().create_or_update(
36 username=u'u2', password=u'qweqwe',
26 username=u'u2', password=u'qweqwe',
37 email=u'u2@rhodecode.org', firstname=u'u2', lastname=u'u2'
27 email=u'u2@rhodecode.org', firstname=u'u2', lastname=u'u2'
38 )
28 )
39 self.u3 = UserModel().create_or_update(
29 self.u3 = UserModel().create_or_update(
40 username=u'u3', password=u'qweqwe',
30 username=u'u3', password=u'qweqwe',
41 email=u'u3@rhodecode.org', firstname=u'u3', lastname=u'u3'
31 email=u'u3@rhodecode.org', firstname=u'u3', lastname=u'u3'
42 )
32 )
43 self.anon = User.get_by_username('default')
33 self.anon = User.get_by_username('default')
44 self.a1 = UserModel().create_or_update(
34 self.a1 = UserModel().create_or_update(
45 username=u'a1', password=u'qweqwe',
35 username=u'a1', password=u'qweqwe',
46 email=u'a1@rhodecode.org', firstname=u'a1', lastname=u'a1', admin=True
36 email=u'a1@rhodecode.org', firstname=u'a1', lastname=u'a1', admin=True
47 )
37 )
48 Session().commit()
38 Session().commit()
49
39
50 def tearDown(self):
40 def tearDown(self):
51 if hasattr(self, 'test_repo'):
41 if hasattr(self, 'test_repo'):
52 RepoModel().delete(repo=self.test_repo)
42 RepoModel().delete(repo=self.test_repo)
53 UserModel().delete(self.u1)
43 UserModel().delete(self.u1)
54 UserModel().delete(self.u2)
44 UserModel().delete(self.u2)
55 UserModel().delete(self.u3)
45 UserModel().delete(self.u3)
56 UserModel().delete(self.a1)
46 UserModel().delete(self.a1)
57 if hasattr(self, 'g1'):
47 if hasattr(self, 'g1'):
58 ReposGroupModel().delete(self.g1.group_id)
48 ReposGroupModel().delete(self.g1.group_id)
59 if hasattr(self, 'g2'):
49 if hasattr(self, 'g2'):
60 ReposGroupModel().delete(self.g2.group_id)
50 ReposGroupModel().delete(self.g2.group_id)
61
51
62 if hasattr(self, 'ug1'):
52 if hasattr(self, 'ug1'):
63 UsersGroupModel().delete(self.ug1, force=True)
53 UsersGroupModel().delete(self.ug1, force=True)
64
54
65 Session().commit()
55 Session().commit()
66
56
67 def test_default_perms_set(self):
57 def test_default_perms_set(self):
68 u1_auth = AuthUser(user_id=self.u1.user_id)
58 u1_auth = AuthUser(user_id=self.u1.user_id)
69 perms = {
59 perms = {
70 'repositories_groups': {},
60 'repositories_groups': {},
71 'global': set([u'hg.create.repository', u'repository.read',
61 'global': set([u'hg.create.repository', u'repository.read',
72 u'hg.register.manual_activate']),
62 u'hg.register.manual_activate']),
73 'repositories': {u'vcs_test_hg': u'repository.read'}
63 'repositories': {u'vcs_test_hg': u'repository.read'}
74 }
64 }
75 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
65 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
76 perms['repositories'][HG_REPO])
66 perms['repositories'][HG_REPO])
77 new_perm = 'repository.write'
67 new_perm = 'repository.write'
78 RepoModel().grant_user_permission(repo=HG_REPO, user=self.u1,
68 RepoModel().grant_user_permission(repo=HG_REPO, user=self.u1,
79 perm=new_perm)
69 perm=new_perm)
80 Session().commit()
70 Session().commit()
81
71
82 u1_auth = AuthUser(user_id=self.u1.user_id)
72 u1_auth = AuthUser(user_id=self.u1.user_id)
83 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
73 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
84 new_perm)
74 new_perm)
85
75
86 def test_default_admin_perms_set(self):
76 def test_default_admin_perms_set(self):
87 a1_auth = AuthUser(user_id=self.a1.user_id)
77 a1_auth = AuthUser(user_id=self.a1.user_id)
88 perms = {
78 perms = {
89 'repositories_groups': {},
79 'repositories_groups': {},
90 'global': set([u'hg.admin']),
80 'global': set([u'hg.admin']),
91 'repositories': {u'vcs_test_hg': u'repository.admin'}
81 'repositories': {u'vcs_test_hg': u'repository.admin'}
92 }
82 }
93 self.assertEqual(a1_auth.permissions['repositories'][HG_REPO],
83 self.assertEqual(a1_auth.permissions['repositories'][HG_REPO],
94 perms['repositories'][HG_REPO])
84 perms['repositories'][HG_REPO])
95 new_perm = 'repository.write'
85 new_perm = 'repository.write'
96 RepoModel().grant_user_permission(repo=HG_REPO, user=self.a1,
86 RepoModel().grant_user_permission(repo=HG_REPO, user=self.a1,
97 perm=new_perm)
87 perm=new_perm)
98 Session().commit()
88 Session().commit()
99 # cannot really downgrade admins permissions !? they still get's set as
89 # cannot really downgrade admins permissions !? they still get's set as
100 # admin !
90 # admin !
101 u1_auth = AuthUser(user_id=self.a1.user_id)
91 u1_auth = AuthUser(user_id=self.a1.user_id)
102 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
92 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
103 perms['repositories'][HG_REPO])
93 perms['repositories'][HG_REPO])
104
94
105 def test_default_group_perms(self):
95 def test_default_group_perms(self):
106 self.g1 = _make_group('test1', skip_if_exists=True)
96 self.g1 = _make_group('test1', skip_if_exists=True)
107 self.g2 = _make_group('test2', skip_if_exists=True)
97 self.g2 = _make_group('test2', skip_if_exists=True)
108 u1_auth = AuthUser(user_id=self.u1.user_id)
98 u1_auth = AuthUser(user_id=self.u1.user_id)
109 perms = {
99 perms = {
110 'repositories_groups': {u'test1': 'group.read', u'test2': 'group.read'},
100 'repositories_groups': {u'test1': 'group.read', u'test2': 'group.read'},
111 'global': set([u'hg.create.repository', u'repository.read', u'hg.register.manual_activate']),
101 'global': set([u'hg.create.repository', u'repository.read', u'hg.register.manual_activate']),
112 'repositories': {u'vcs_test_hg': u'repository.read'}
102 'repositories': {u'vcs_test_hg': u'repository.read'}
113 }
103 }
114 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
104 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
115 perms['repositories'][HG_REPO])
105 perms['repositories'][HG_REPO])
116 self.assertEqual(u1_auth.permissions['repositories_groups'],
106 self.assertEqual(u1_auth.permissions['repositories_groups'],
117 perms['repositories_groups'])
107 perms['repositories_groups'])
118
108
119 def test_default_admin_group_perms(self):
109 def test_default_admin_group_perms(self):
120 self.g1 = _make_group('test1', skip_if_exists=True)
110 self.g1 = _make_group('test1', skip_if_exists=True)
121 self.g2 = _make_group('test2', skip_if_exists=True)
111 self.g2 = _make_group('test2', skip_if_exists=True)
122 a1_auth = AuthUser(user_id=self.a1.user_id)
112 a1_auth = AuthUser(user_id=self.a1.user_id)
123 perms = {
113 perms = {
124 'repositories_groups': {u'test1': 'group.admin', u'test2': 'group.admin'},
114 'repositories_groups': {u'test1': 'group.admin', u'test2': 'group.admin'},
125 'global': set(['hg.admin']),
115 'global': set(['hg.admin']),
126 'repositories': {u'vcs_test_hg': 'repository.admin'}
116 'repositories': {u'vcs_test_hg': 'repository.admin'}
127 }
117 }
128
118
129 self.assertEqual(a1_auth.permissions['repositories'][HG_REPO],
119 self.assertEqual(a1_auth.permissions['repositories'][HG_REPO],
130 perms['repositories'][HG_REPO])
120 perms['repositories'][HG_REPO])
131 self.assertEqual(a1_auth.permissions['repositories_groups'],
121 self.assertEqual(a1_auth.permissions['repositories_groups'],
132 perms['repositories_groups'])
122 perms['repositories_groups'])
133
123
134 def test_propagated_permission_from_users_group_by_explicit_perms_exist(self):
124 def test_propagated_permission_from_users_group_by_explicit_perms_exist(self):
135 # make group
125 # make group
136 self.ug1 = UsersGroupModel().create('G1')
126 self.ug1 = UsersGroupModel().create('G1')
137 # add user to group
127 # add user to group
138
128
139 UsersGroupModel().add_user_to_group(self.ug1, self.u1)
129 UsersGroupModel().add_user_to_group(self.ug1, self.u1)
140
130
141 # set permission to lower
131 # set permission to lower
142 new_perm = 'repository.none'
132 new_perm = 'repository.none'
143 RepoModel().grant_user_permission(repo=HG_REPO, user=self.u1, perm=new_perm)
133 RepoModel().grant_user_permission(repo=HG_REPO, user=self.u1, perm=new_perm)
144 Session().commit()
134 Session().commit()
145 u1_auth = AuthUser(user_id=self.u1.user_id)
135 u1_auth = AuthUser(user_id=self.u1.user_id)
146 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
136 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
147 new_perm)
137 new_perm)
148
138
149 # grant perm for group this should not override permission from user
139 # grant perm for group this should not override permission from user
150 # since it has explicitly set
140 # since it has explicitly set
151 new_perm_gr = 'repository.write'
141 new_perm_gr = 'repository.write'
152 RepoModel().grant_users_group_permission(repo=HG_REPO,
142 RepoModel().grant_users_group_permission(repo=HG_REPO,
153 group_name=self.ug1,
143 group_name=self.ug1,
154 perm=new_perm_gr)
144 perm=new_perm_gr)
155 # check perms
145 # check perms
156 u1_auth = AuthUser(user_id=self.u1.user_id)
146 u1_auth = AuthUser(user_id=self.u1.user_id)
157 perms = {
147 perms = {
158 'repositories_groups': {},
148 'repositories_groups': {},
159 'global': set([u'hg.create.repository', u'repository.read',
149 'global': set([u'hg.create.repository', u'repository.read',
160 u'hg.register.manual_activate']),
150 u'hg.register.manual_activate']),
161 'repositories': {u'vcs_test_hg': u'repository.read'}
151 'repositories': {u'vcs_test_hg': u'repository.read'}
162 }
152 }
163 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
153 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
164 new_perm)
154 new_perm)
165 self.assertEqual(u1_auth.permissions['repositories_groups'],
155 self.assertEqual(u1_auth.permissions['repositories_groups'],
166 perms['repositories_groups'])
156 perms['repositories_groups'])
167
157
168 def test_propagated_permission_from_users_group(self):
158 def test_propagated_permission_from_users_group(self):
169 # make group
159 # make group
170 self.ug1 = UsersGroupModel().create('G1')
160 self.ug1 = UsersGroupModel().create('G1')
171 # add user to group
161 # add user to group
172
162
173 UsersGroupModel().add_user_to_group(self.ug1, self.u3)
163 UsersGroupModel().add_user_to_group(self.ug1, self.u3)
174
164
175 # grant perm for group this should override default permission from user
165 # grant perm for group this should override default permission from user
176 new_perm_gr = 'repository.write'
166 new_perm_gr = 'repository.write'
177 RepoModel().grant_users_group_permission(repo=HG_REPO,
167 RepoModel().grant_users_group_permission(repo=HG_REPO,
178 group_name=self.ug1,
168 group_name=self.ug1,
179 perm=new_perm_gr)
169 perm=new_perm_gr)
180 # check perms
170 # check perms
181 u3_auth = AuthUser(user_id=self.u3.user_id)
171 u3_auth = AuthUser(user_id=self.u3.user_id)
182 perms = {
172 perms = {
183 'repositories_groups': {},
173 'repositories_groups': {},
184 'global': set([u'hg.create.repository', u'repository.read',
174 'global': set([u'hg.create.repository', u'repository.read',
185 u'hg.register.manual_activate']),
175 u'hg.register.manual_activate']),
186 'repositories': {u'vcs_test_hg': u'repository.read'}
176 'repositories': {u'vcs_test_hg': u'repository.read'}
187 }
177 }
188 self.assertEqual(u3_auth.permissions['repositories'][HG_REPO],
178 self.assertEqual(u3_auth.permissions['repositories'][HG_REPO],
189 new_perm_gr)
179 new_perm_gr)
190 self.assertEqual(u3_auth.permissions['repositories_groups'],
180 self.assertEqual(u3_auth.permissions['repositories_groups'],
191 perms['repositories_groups'])
181 perms['repositories_groups'])
192
182
193 def test_propagated_permission_from_users_group_lower_weight(self):
183 def test_propagated_permission_from_users_group_lower_weight(self):
194 # make group
184 # make group
195 self.ug1 = UsersGroupModel().create('G1')
185 self.ug1 = UsersGroupModel().create('G1')
196 # add user to group
186 # add user to group
197 UsersGroupModel().add_user_to_group(self.ug1, self.u1)
187 UsersGroupModel().add_user_to_group(self.ug1, self.u1)
198
188
199 # set permission to lower
189 # set permission to lower
200 new_perm_h = 'repository.write'
190 new_perm_h = 'repository.write'
201 RepoModel().grant_user_permission(repo=HG_REPO, user=self.u1,
191 RepoModel().grant_user_permission(repo=HG_REPO, user=self.u1,
202 perm=new_perm_h)
192 perm=new_perm_h)
203 Session().commit()
193 Session().commit()
204 u1_auth = AuthUser(user_id=self.u1.user_id)
194 u1_auth = AuthUser(user_id=self.u1.user_id)
205 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
195 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
206 new_perm_h)
196 new_perm_h)
207
197
208 # grant perm for group this should NOT override permission from user
198 # grant perm for group this should NOT override permission from user
209 # since it's lower than granted
199 # since it's lower than granted
210 new_perm_l = 'repository.read'
200 new_perm_l = 'repository.read'
211 RepoModel().grant_users_group_permission(repo=HG_REPO,
201 RepoModel().grant_users_group_permission(repo=HG_REPO,
212 group_name=self.ug1,
202 group_name=self.ug1,
213 perm=new_perm_l)
203 perm=new_perm_l)
214 # check perms
204 # check perms
215 u1_auth = AuthUser(user_id=self.u1.user_id)
205 u1_auth = AuthUser(user_id=self.u1.user_id)
216 perms = {
206 perms = {
217 'repositories_groups': {},
207 'repositories_groups': {},
218 'global': set([u'hg.create.repository', u'repository.read',
208 'global': set([u'hg.create.repository', u'repository.read',
219 u'hg.register.manual_activate']),
209 u'hg.register.manual_activate']),
220 'repositories': {u'vcs_test_hg': u'repository.write'}
210 'repositories': {u'vcs_test_hg': u'repository.write'}
221 }
211 }
222 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
212 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
223 new_perm_h)
213 new_perm_h)
224 self.assertEqual(u1_auth.permissions['repositories_groups'],
214 self.assertEqual(u1_auth.permissions['repositories_groups'],
225 perms['repositories_groups'])
215 perms['repositories_groups'])
226
216
227 def test_repo_in_group_permissions(self):
217 def test_repo_in_group_permissions(self):
228 self.g1 = _make_group('group1', skip_if_exists=True)
218 self.g1 = _make_group('group1', skip_if_exists=True)
229 self.g2 = _make_group('group2', skip_if_exists=True)
219 self.g2 = _make_group('group2', skip_if_exists=True)
230 Session().commit()
220 Session().commit()
231 # both perms should be read !
221 # both perms should be read !
232 u1_auth = AuthUser(user_id=self.u1.user_id)
222 u1_auth = AuthUser(user_id=self.u1.user_id)
233 self.assertEqual(u1_auth.permissions['repositories_groups'],
223 self.assertEqual(u1_auth.permissions['repositories_groups'],
234 {u'group1': u'group.read', u'group2': u'group.read'})
224 {u'group1': u'group.read', u'group2': u'group.read'})
235
225
236 a1_auth = AuthUser(user_id=self.anon.user_id)
226 a1_auth = AuthUser(user_id=self.anon.user_id)
237 self.assertEqual(a1_auth.permissions['repositories_groups'],
227 self.assertEqual(a1_auth.permissions['repositories_groups'],
238 {u'group1': u'group.read', u'group2': u'group.read'})
228 {u'group1': u'group.read', u'group2': u'group.read'})
239
229
240 #Change perms to none for both groups
230 #Change perms to none for both groups
241 ReposGroupModel().grant_user_permission(repos_group=self.g1,
231 ReposGroupModel().grant_user_permission(repos_group=self.g1,
242 user=self.anon,
232 user=self.anon,
243 perm='group.none')
233 perm='group.none')
244 ReposGroupModel().grant_user_permission(repos_group=self.g2,
234 ReposGroupModel().grant_user_permission(repos_group=self.g2,
245 user=self.anon,
235 user=self.anon,
246 perm='group.none')
236 perm='group.none')
247
237
248 u1_auth = AuthUser(user_id=self.u1.user_id)
238 u1_auth = AuthUser(user_id=self.u1.user_id)
249 self.assertEqual(u1_auth.permissions['repositories_groups'],
239 self.assertEqual(u1_auth.permissions['repositories_groups'],
250 {u'group1': u'group.none', u'group2': u'group.none'})
240 {u'group1': u'group.none', u'group2': u'group.none'})
251
241
252 a1_auth = AuthUser(user_id=self.anon.user_id)
242 a1_auth = AuthUser(user_id=self.anon.user_id)
253 self.assertEqual(a1_auth.permissions['repositories_groups'],
243 self.assertEqual(a1_auth.permissions['repositories_groups'],
254 {u'group1': u'group.none', u'group2': u'group.none'})
244 {u'group1': u'group.none', u'group2': u'group.none'})
255
245
256 # add repo to group
246 # add repo to group
257 name = RepoGroup.url_sep().join([self.g1.group_name, 'test_perm'])
247 name = RepoGroup.url_sep().join([self.g1.group_name, 'test_perm'])
258 self.test_repo = RepoModel().create_repo(
248 self.test_repo = RepoModel().create_repo(
259 repo_name=name,
249 repo_name=name,
260 repo_type='hg',
250 repo_type='hg',
261 description='',
251 description='',
262 repos_group=self.g1,
252 repos_group=self.g1,
263 owner=self.u1,
253 owner=self.u1,
264 )
254 )
265 Session().commit()
255 Session().commit()
266
256
267 u1_auth = AuthUser(user_id=self.u1.user_id)
257 u1_auth = AuthUser(user_id=self.u1.user_id)
268 self.assertEqual(u1_auth.permissions['repositories_groups'],
258 self.assertEqual(u1_auth.permissions['repositories_groups'],
269 {u'group1': u'group.none', u'group2': u'group.none'})
259 {u'group1': u'group.none', u'group2': u'group.none'})
270
260
271 a1_auth = AuthUser(user_id=self.anon.user_id)
261 a1_auth = AuthUser(user_id=self.anon.user_id)
272 self.assertEqual(a1_auth.permissions['repositories_groups'],
262 self.assertEqual(a1_auth.permissions['repositories_groups'],
273 {u'group1': u'group.none', u'group2': u'group.none'})
263 {u'group1': u'group.none', u'group2': u'group.none'})
274
264
275 #grant permission for u2 !
265 #grant permission for u2 !
276 ReposGroupModel().grant_user_permission(repos_group=self.g1,
266 ReposGroupModel().grant_user_permission(repos_group=self.g1,
277 user=self.u2,
267 user=self.u2,
278 perm='group.read')
268 perm='group.read')
279 ReposGroupModel().grant_user_permission(repos_group=self.g2,
269 ReposGroupModel().grant_user_permission(repos_group=self.g2,
280 user=self.u2,
270 user=self.u2,
281 perm='group.read')
271 perm='group.read')
282 Session().commit()
272 Session().commit()
283 self.assertNotEqual(self.u1, self.u2)
273 self.assertNotEqual(self.u1, self.u2)
284 #u1 and anon should have not change perms while u2 should !
274 #u1 and anon should have not change perms while u2 should !
285 u1_auth = AuthUser(user_id=self.u1.user_id)
275 u1_auth = AuthUser(user_id=self.u1.user_id)
286 self.assertEqual(u1_auth.permissions['repositories_groups'],
276 self.assertEqual(u1_auth.permissions['repositories_groups'],
287 {u'group1': u'group.none', u'group2': u'group.none'})
277 {u'group1': u'group.none', u'group2': u'group.none'})
288
278
289 u2_auth = AuthUser(user_id=self.u2.user_id)
279 u2_auth = AuthUser(user_id=self.u2.user_id)
290 self.assertEqual(u2_auth.permissions['repositories_groups'],
280 self.assertEqual(u2_auth.permissions['repositories_groups'],
291 {u'group1': u'group.read', u'group2': u'group.read'})
281 {u'group1': u'group.read', u'group2': u'group.read'})
292
282
293 a1_auth = AuthUser(user_id=self.anon.user_id)
283 a1_auth = AuthUser(user_id=self.anon.user_id)
294 self.assertEqual(a1_auth.permissions['repositories_groups'],
284 self.assertEqual(a1_auth.permissions['repositories_groups'],
295 {u'group1': u'group.none', u'group2': u'group.none'})
285 {u'group1': u'group.none', u'group2': u'group.none'})
296
286
297 def test_repo_group_user_as_user_group_member(self):
287 def test_repo_group_user_as_user_group_member(self):
298 # create Group1
288 # create Group1
299 self.g1 = _make_group('group1', skip_if_exists=True)
289 self.g1 = _make_group('group1', skip_if_exists=True)
300 Session().commit()
290 Session().commit()
301 a1_auth = AuthUser(user_id=self.anon.user_id)
291 a1_auth = AuthUser(user_id=self.anon.user_id)
302
292
303 self.assertEqual(a1_auth.permissions['repositories_groups'],
293 self.assertEqual(a1_auth.permissions['repositories_groups'],
304 {u'group1': u'group.read'})
294 {u'group1': u'group.read'})
305
295
306 # set default permission to none
296 # set default permission to none
307 ReposGroupModel().grant_user_permission(repos_group=self.g1,
297 ReposGroupModel().grant_user_permission(repos_group=self.g1,
308 user=self.anon,
298 user=self.anon,
309 perm='group.none')
299 perm='group.none')
310 # make group
300 # make group
311 self.ug1 = UsersGroupModel().create('G1')
301 self.ug1 = UsersGroupModel().create('G1')
312 # add user to group
302 # add user to group
313 UsersGroupModel().add_user_to_group(self.ug1, self.u1)
303 UsersGroupModel().add_user_to_group(self.ug1, self.u1)
314 Session().commit()
304 Session().commit()
315
305
316 # check if user is in the group
306 # check if user is in the group
317 membrs = [x.user_id for x in UsersGroupModel().get(self.ug1.users_group_id).members]
307 membrs = [x.user_id for x in UsersGroupModel().get(self.ug1.users_group_id).members]
318 self.assertEqual(membrs, [self.u1.user_id])
308 self.assertEqual(membrs, [self.u1.user_id])
319 # add some user to that group
309 # add some user to that group
320
310
321 # check his permissions
311 # check his permissions
322 a1_auth = AuthUser(user_id=self.anon.user_id)
312 a1_auth = AuthUser(user_id=self.anon.user_id)
323 self.assertEqual(a1_auth.permissions['repositories_groups'],
313 self.assertEqual(a1_auth.permissions['repositories_groups'],
324 {u'group1': u'group.none'})
314 {u'group1': u'group.none'})
325
315
326 u1_auth = AuthUser(user_id=self.u1.user_id)
316 u1_auth = AuthUser(user_id=self.u1.user_id)
327 self.assertEqual(u1_auth.permissions['repositories_groups'],
317 self.assertEqual(u1_auth.permissions['repositories_groups'],
328 {u'group1': u'group.none'})
318 {u'group1': u'group.none'})
329
319
330 # grant ug1 read permissions for
320 # grant ug1 read permissions for
331 ReposGroupModel().grant_users_group_permission(repos_group=self.g1,
321 ReposGroupModel().grant_users_group_permission(repos_group=self.g1,
332 group_name=self.ug1,
322 group_name=self.ug1,
333 perm='group.read')
323 perm='group.read')
334 Session().commit()
324 Session().commit()
335 # check if the
325 # check if the
336 obj = Session().query(UsersGroupRepoGroupToPerm)\
326 obj = Session().query(UsersGroupRepoGroupToPerm)\
337 .filter(UsersGroupRepoGroupToPerm.group == self.g1)\
327 .filter(UsersGroupRepoGroupToPerm.group == self.g1)\
338 .filter(UsersGroupRepoGroupToPerm.users_group == self.ug1)\
328 .filter(UsersGroupRepoGroupToPerm.users_group == self.ug1)\
339 .scalar()
329 .scalar()
340 self.assertEqual(obj.permission.permission_name, 'group.read')
330 self.assertEqual(obj.permission.permission_name, 'group.read')
341
331
342 a1_auth = AuthUser(user_id=self.anon.user_id)
332 a1_auth = AuthUser(user_id=self.anon.user_id)
343
333
344 self.assertEqual(a1_auth.permissions['repositories_groups'],
334 self.assertEqual(a1_auth.permissions['repositories_groups'],
345 {u'group1': u'group.none'})
335 {u'group1': u'group.none'})
346
336
347 u1_auth = AuthUser(user_id=self.u1.user_id)
337 u1_auth = AuthUser(user_id=self.u1.user_id)
348 self.assertEqual(u1_auth.permissions['repositories_groups'],
338 self.assertEqual(u1_auth.permissions['repositories_groups'],
349 {u'group1': u'group.read'})
339 {u'group1': u'group.read'})
350
340
351 def test_inherited_permissions_from_default_on_user_enabled(self):
341 def test_inherited_permissions_from_default_on_user_enabled(self):
352 user_model = UserModel()
342 user_model = UserModel()
353 # enable fork and create on default user
343 # enable fork and create on default user
354 usr = 'default'
344 usr = 'default'
355 user_model.revoke_perm(usr, 'hg.create.none')
345 user_model.revoke_perm(usr, 'hg.create.none')
356 user_model.grant_perm(usr, 'hg.create.repository')
346 user_model.grant_perm(usr, 'hg.create.repository')
357 user_model.revoke_perm(usr, 'hg.fork.none')
347 user_model.revoke_perm(usr, 'hg.fork.none')
358 user_model.grant_perm(usr, 'hg.fork.repository')
348 user_model.grant_perm(usr, 'hg.fork.repository')
359 # make sure inherit flag is turned on
349 # make sure inherit flag is turned on
360 self.u1.inherit_default_permissions = True
350 self.u1.inherit_default_permissions = True
361 Session().commit()
351 Session().commit()
362 u1_auth = AuthUser(user_id=self.u1.user_id)
352 u1_auth = AuthUser(user_id=self.u1.user_id)
363 # this user will have inherited permissions from default user
353 # this user will have inherited permissions from default user
364 self.assertEqual(u1_auth.permissions['global'],
354 self.assertEqual(u1_auth.permissions['global'],
365 set(['hg.create.repository', 'hg.fork.repository',
355 set(['hg.create.repository', 'hg.fork.repository',
366 'hg.register.manual_activate',
356 'hg.register.manual_activate',
367 'repository.read']))
357 'repository.read']))
368
358
369 def test_inherited_permissions_from_default_on_user_disabled(self):
359 def test_inherited_permissions_from_default_on_user_disabled(self):
370 user_model = UserModel()
360 user_model = UserModel()
371 # disable fork and create on default user
361 # disable fork and create on default user
372 usr = 'default'
362 usr = 'default'
373 user_model.revoke_perm(usr, 'hg.create.repository')
363 user_model.revoke_perm(usr, 'hg.create.repository')
374 user_model.grant_perm(usr, 'hg.create.none')
364 user_model.grant_perm(usr, 'hg.create.none')
375 user_model.revoke_perm(usr, 'hg.fork.repository')
365 user_model.revoke_perm(usr, 'hg.fork.repository')
376 user_model.grant_perm(usr, 'hg.fork.none')
366 user_model.grant_perm(usr, 'hg.fork.none')
377 # make sure inherit flag is turned on
367 # make sure inherit flag is turned on
378 self.u1.inherit_default_permissions = True
368 self.u1.inherit_default_permissions = True
379 Session().commit()
369 Session().commit()
380 u1_auth = AuthUser(user_id=self.u1.user_id)
370 u1_auth = AuthUser(user_id=self.u1.user_id)
381 # this user will have inherited permissions from default user
371 # this user will have inherited permissions from default user
382 self.assertEqual(u1_auth.permissions['global'],
372 self.assertEqual(u1_auth.permissions['global'],
383 set(['hg.create.none', 'hg.fork.none',
373 set(['hg.create.none', 'hg.fork.none',
384 'hg.register.manual_activate',
374 'hg.register.manual_activate',
385 'repository.read']))
375 'repository.read']))
386
376
387 def test_non_inherited_permissions_from_default_on_user_enabled(self):
377 def test_non_inherited_permissions_from_default_on_user_enabled(self):
388 user_model = UserModel()
378 user_model = UserModel()
389 # enable fork and create on default user
379 # enable fork and create on default user
390 usr = 'default'
380 usr = 'default'
391 user_model.revoke_perm(usr, 'hg.create.none')
381 user_model.revoke_perm(usr, 'hg.create.none')
392 user_model.grant_perm(usr, 'hg.create.repository')
382 user_model.grant_perm(usr, 'hg.create.repository')
393 user_model.revoke_perm(usr, 'hg.fork.none')
383 user_model.revoke_perm(usr, 'hg.fork.none')
394 user_model.grant_perm(usr, 'hg.fork.repository')
384 user_model.grant_perm(usr, 'hg.fork.repository')
395
385
396 #disable global perms on specific user
386 #disable global perms on specific user
397 user_model.revoke_perm(self.u1, 'hg.create.repository')
387 user_model.revoke_perm(self.u1, 'hg.create.repository')
398 user_model.grant_perm(self.u1, 'hg.create.none')
388 user_model.grant_perm(self.u1, 'hg.create.none')
399 user_model.revoke_perm(self.u1, 'hg.fork.repository')
389 user_model.revoke_perm(self.u1, 'hg.fork.repository')
400 user_model.grant_perm(self.u1, 'hg.fork.none')
390 user_model.grant_perm(self.u1, 'hg.fork.none')
401
391
402 # make sure inherit flag is turned off
392 # make sure inherit flag is turned off
403 self.u1.inherit_default_permissions = False
393 self.u1.inherit_default_permissions = False
404 Session().commit()
394 Session().commit()
405 u1_auth = AuthUser(user_id=self.u1.user_id)
395 u1_auth = AuthUser(user_id=self.u1.user_id)
406 # this user will have non inherited permissions from he's
396 # this user will have non inherited permissions from he's
407 # explicitly set permissions
397 # explicitly set permissions
408 self.assertEqual(u1_auth.permissions['global'],
398 self.assertEqual(u1_auth.permissions['global'],
409 set(['hg.create.none', 'hg.fork.none',
399 set(['hg.create.none', 'hg.fork.none',
410 'hg.register.manual_activate',
400 'hg.register.manual_activate',
411 'repository.read']))
401 'repository.read']))
412
402
413 def test_non_inherited_permissions_from_default_on_user_disabled(self):
403 def test_non_inherited_permissions_from_default_on_user_disabled(self):
414 user_model = UserModel()
404 user_model = UserModel()
415 # disable fork and create on default user
405 # disable fork and create on default user
416 usr = 'default'
406 usr = 'default'
417 user_model.revoke_perm(usr, 'hg.create.repository')
407 user_model.revoke_perm(usr, 'hg.create.repository')
418 user_model.grant_perm(usr, 'hg.create.none')
408 user_model.grant_perm(usr, 'hg.create.none')
419 user_model.revoke_perm(usr, 'hg.fork.repository')
409 user_model.revoke_perm(usr, 'hg.fork.repository')
420 user_model.grant_perm(usr, 'hg.fork.none')
410 user_model.grant_perm(usr, 'hg.fork.none')
421
411
422 #enable global perms on specific user
412 #enable global perms on specific user
423 user_model.revoke_perm(self.u1, 'hg.create.none')
413 user_model.revoke_perm(self.u1, 'hg.create.none')
424 user_model.grant_perm(self.u1, 'hg.create.repository')
414 user_model.grant_perm(self.u1, 'hg.create.repository')
425 user_model.revoke_perm(self.u1, 'hg.fork.none')
415 user_model.revoke_perm(self.u1, 'hg.fork.none')
426 user_model.grant_perm(self.u1, 'hg.fork.repository')
416 user_model.grant_perm(self.u1, 'hg.fork.repository')
427
417
428 # make sure inherit flag is turned off
418 # make sure inherit flag is turned off
429 self.u1.inherit_default_permissions = False
419 self.u1.inherit_default_permissions = False
430 Session().commit()
420 Session().commit()
431 u1_auth = AuthUser(user_id=self.u1.user_id)
421 u1_auth = AuthUser(user_id=self.u1.user_id)
432 # this user will have non inherited permissions from he's
422 # this user will have non inherited permissions from he's
433 # explicitly set permissions
423 # explicitly set permissions
434 self.assertEqual(u1_auth.permissions['global'],
424 self.assertEqual(u1_auth.permissions['global'],
435 set(['hg.create.repository', 'hg.fork.repository',
425 set(['hg.create.repository', 'hg.fork.repository',
436 'hg.register.manual_activate',
426 'hg.register.manual_activate',
437 'repository.read']))
427 'repository.read']))
@@ -1,172 +1,175 b''
1 import os
1 import os
2 import unittest
2 import unittest
3 from rhodecode.tests import *
3 from rhodecode.tests import *
4
4
5 from rhodecode.model.repos_group import ReposGroupModel
5 from rhodecode.model.repos_group import ReposGroupModel
6 from rhodecode.model.repo import RepoModel
6 from rhodecode.model.repo import RepoModel
7 from rhodecode.model.db import RepoGroup, User
7 from rhodecode.model.db import RepoGroup, User, Repository
8 from rhodecode.model.meta import Session
8 from rhodecode.model.meta import Session
9 from sqlalchemy.exc import IntegrityError
9 from sqlalchemy.exc import IntegrityError
10
10
11
11
12 def _make_group(path, desc='desc', parent_id=None,
12 def _make_group(path, desc='desc', parent_id=None,
13 skip_if_exists=False):
13 skip_if_exists=False):
14
14
15 gr = RepoGroup.get_by_group_name(path)
15 gr = RepoGroup.get_by_group_name(path)
16 if gr and skip_if_exists:
16 if gr and skip_if_exists:
17 return gr
17 return gr
18
18 if isinstance(parent_id, RepoGroup):
19 parent_id = parent_id.group_id
19 gr = ReposGroupModel().create(path, desc, parent_id)
20 gr = ReposGroupModel().create(path, desc, parent_id)
20 return gr
21 return gr
21
22
22
23
23 class TestReposGroups(unittest.TestCase):
24 class TestReposGroups(unittest.TestCase):
24
25
25 def setUp(self):
26 def setUp(self):
26 self.g1 = _make_group('test1', skip_if_exists=True)
27 self.g1 = _make_group('test1', skip_if_exists=True)
27 Session().commit()
28 Session().commit()
28 self.g2 = _make_group('test2', skip_if_exists=True)
29 self.g2 = _make_group('test2', skip_if_exists=True)
29 Session().commit()
30 Session().commit()
30 self.g3 = _make_group('test3', skip_if_exists=True)
31 self.g3 = _make_group('test3', skip_if_exists=True)
31 Session().commit()
32 Session().commit()
32
33
33 def tearDown(self):
34 def tearDown(self):
34 print 'out'
35 print 'out'
35
36
36 def __check_path(self, *path):
37 def __check_path(self, *path):
37 """
38 """
38 Checks the path for existance !
39 Checks the path for existance !
39 """
40 """
40 path = [TESTS_TMP_PATH] + list(path)
41 path = [TESTS_TMP_PATH] + list(path)
41 path = os.path.join(*path)
42 path = os.path.join(*path)
42 return os.path.isdir(path)
43 return os.path.isdir(path)
43
44
44 def _check_folders(self):
45 def _check_folders(self):
45 print os.listdir(TESTS_TMP_PATH)
46 print os.listdir(TESTS_TMP_PATH)
46
47
47 def __delete_group(self, id_):
48 def __delete_group(self, id_):
48 ReposGroupModel().delete(id_)
49 ReposGroupModel().delete(id_)
49
50
50 def __update_group(self, id_, path, desc='desc', parent_id=None):
51 def __update_group(self, id_, path, desc='desc', parent_id=None):
51 form_data = dict(
52 form_data = dict(
52 group_name=path,
53 group_name=path,
53 group_description=desc,
54 group_description=desc,
54 group_parent_id=parent_id,
55 group_parent_id=parent_id,
55 perms_updates=[],
56 perms_updates=[],
56 perms_new=[],
57 perms_new=[],
57 enable_locking=False
58 enable_locking=False,
59 recursive=False
58 )
60 )
59 gr = ReposGroupModel().update(id_, form_data)
61 gr = ReposGroupModel().update(id_, form_data)
60 return gr
62 return gr
61
63
62 def test_create_group(self):
64 def test_create_group(self):
63 g = _make_group('newGroup')
65 g = _make_group('newGroup')
64 self.assertEqual(g.full_path, 'newGroup')
66 self.assertEqual(g.full_path, 'newGroup')
65
67
66 self.assertTrue(self.__check_path('newGroup'))
68 self.assertTrue(self.__check_path('newGroup'))
67
69
68 def test_create_same_name_group(self):
70 def test_create_same_name_group(self):
69 self.assertRaises(IntegrityError, lambda: _make_group('newGroup'))
71 self.assertRaises(IntegrityError, lambda: _make_group('newGroup'))
70 Session().rollback()
72 Session().rollback()
71
73
72 def test_same_subgroup(self):
74 def test_same_subgroup(self):
73 sg1 = _make_group('sub1', parent_id=self.g1.group_id)
75 sg1 = _make_group('sub1', parent_id=self.g1.group_id)
74 self.assertEqual(sg1.parent_group, self.g1)
76 self.assertEqual(sg1.parent_group, self.g1)
75 self.assertEqual(sg1.full_path, 'test1/sub1')
77 self.assertEqual(sg1.full_path, 'test1/sub1')
76 self.assertTrue(self.__check_path('test1', 'sub1'))
78 self.assertTrue(self.__check_path('test1', 'sub1'))
77
79
78 ssg1 = _make_group('subsub1', parent_id=sg1.group_id)
80 ssg1 = _make_group('subsub1', parent_id=sg1.group_id)
79 self.assertEqual(ssg1.parent_group, sg1)
81 self.assertEqual(ssg1.parent_group, sg1)
80 self.assertEqual(ssg1.full_path, 'test1/sub1/subsub1')
82 self.assertEqual(ssg1.full_path, 'test1/sub1/subsub1')
81 self.assertTrue(self.__check_path('test1', 'sub1', 'subsub1'))
83 self.assertTrue(self.__check_path('test1', 'sub1', 'subsub1'))
82
84
83 def test_remove_group(self):
85 def test_remove_group(self):
84 sg1 = _make_group('deleteme')
86 sg1 = _make_group('deleteme')
85 self.__delete_group(sg1.group_id)
87 self.__delete_group(sg1.group_id)
86
88
87 self.assertEqual(RepoGroup.get(sg1.group_id), None)
89 self.assertEqual(RepoGroup.get(sg1.group_id), None)
88 self.assertFalse(self.__check_path('deteteme'))
90 self.assertFalse(self.__check_path('deteteme'))
89
91
90 sg1 = _make_group('deleteme', parent_id=self.g1.group_id)
92 sg1 = _make_group('deleteme', parent_id=self.g1.group_id)
91 self.__delete_group(sg1.group_id)
93 self.__delete_group(sg1.group_id)
92
94
93 self.assertEqual(RepoGroup.get(sg1.group_id), None)
95 self.assertEqual(RepoGroup.get(sg1.group_id), None)
94 self.assertFalse(self.__check_path('test1', 'deteteme'))
96 self.assertFalse(self.__check_path('test1', 'deteteme'))
95
97
96 def test_rename_single_group(self):
98 def test_rename_single_group(self):
97 sg1 = _make_group('initial')
99 sg1 = _make_group('initial')
98
100
99 new_sg1 = self.__update_group(sg1.group_id, 'after')
101 new_sg1 = self.__update_group(sg1.group_id, 'after')
100 self.assertTrue(self.__check_path('after'))
102 self.assertTrue(self.__check_path('after'))
101 self.assertEqual(RepoGroup.get_by_group_name('initial'), None)
103 self.assertEqual(RepoGroup.get_by_group_name('initial'), None)
102
104
103 def test_update_group_parent(self):
105 def test_update_group_parent(self):
104
106
105 sg1 = _make_group('initial', parent_id=self.g1.group_id)
107 sg1 = _make_group('initial', parent_id=self.g1.group_id)
106
108
107 new_sg1 = self.__update_group(sg1.group_id, 'after', parent_id=self.g1.group_id)
109 new_sg1 = self.__update_group(sg1.group_id, 'after', parent_id=self.g1.group_id)
108 self.assertTrue(self.__check_path('test1', 'after'))
110 self.assertTrue(self.__check_path('test1', 'after'))
109 self.assertEqual(RepoGroup.get_by_group_name('test1/initial'), None)
111 self.assertEqual(RepoGroup.get_by_group_name('test1/initial'), None)
110
112
111 new_sg1 = self.__update_group(sg1.group_id, 'after', parent_id=self.g3.group_id)
113 new_sg1 = self.__update_group(sg1.group_id, 'after', parent_id=self.g3.group_id)
112 self.assertTrue(self.__check_path('test3', 'after'))
114 self.assertTrue(self.__check_path('test3', 'after'))
113 self.assertEqual(RepoGroup.get_by_group_name('test3/initial'), None)
115 self.assertEqual(RepoGroup.get_by_group_name('test3/initial'), None)
114
116
115 new_sg1 = self.__update_group(sg1.group_id, 'hello')
117 new_sg1 = self.__update_group(sg1.group_id, 'hello')
116 self.assertTrue(self.__check_path('hello'))
118 self.assertTrue(self.__check_path('hello'))
117
119
118 self.assertEqual(RepoGroup.get_by_group_name('hello'), new_sg1)
120 self.assertEqual(RepoGroup.get_by_group_name('hello'), new_sg1)
119
121
120 def test_subgrouping_with_repo(self):
122 def test_subgrouping_with_repo(self):
121
123
122 g1 = _make_group('g1')
124 g1 = _make_group('g1')
123 g2 = _make_group('g2')
125 g2 = _make_group('g2')
124
126
125 # create new repo
127 # create new repo
126 form_data = dict(repo_name='john',
128 form_data = dict(repo_name='john',
127 repo_name_full='john',
129 repo_name_full='john',
128 fork_name=None,
130 fork_name=None,
129 description=None,
131 description=None,
130 repo_group=None,
132 repo_group=None,
131 private=False,
133 private=False,
132 repo_type='hg',
134 repo_type='hg',
133 clone_uri=None,
135 clone_uri=None,
134 landing_rev='tip',
136 landing_rev='tip',
135 enable_locking=False)
137 enable_locking=False,
138 recursive=False)
136 cur_user = User.get_by_username(TEST_USER_ADMIN_LOGIN)
139 cur_user = User.get_by_username(TEST_USER_ADMIN_LOGIN)
137 r = RepoModel().create(form_data, cur_user)
140 r = RepoModel().create(form_data, cur_user)
138
141
139 self.assertEqual(r.repo_name, 'john')
142 self.assertEqual(r.repo_name, 'john')
140
143
141 # put repo into group
144 # put repo into group
142 form_data = form_data
145 form_data = form_data
143 form_data['repo_group'] = g1.group_id
146 form_data['repo_group'] = g1.group_id
144 form_data['perms_new'] = []
147 form_data['perms_new'] = []
145 form_data['perms_updates'] = []
148 form_data['perms_updates'] = []
146 RepoModel().update(r.repo_name, form_data)
149 RepoModel().update(r.repo_name, form_data)
147 self.assertEqual(r.repo_name, 'g1/john')
150 self.assertEqual(r.repo_name, 'g1/john')
148
151
149 self.__update_group(g1.group_id, 'g1', parent_id=g2.group_id)
152 self.__update_group(g1.group_id, 'g1', parent_id=g2.group_id)
150 self.assertTrue(self.__check_path('g2', 'g1'))
153 self.assertTrue(self.__check_path('g2', 'g1'))
151
154
152 # test repo
155 # test repo
153 self.assertEqual(r.repo_name, RepoGroup.url_sep().join(['g2', 'g1',
156 self.assertEqual(r.repo_name, RepoGroup.url_sep().join(['g2', 'g1',
154 r.just_name]))
157 r.just_name]))
155
158
156 def test_move_to_root(self):
159 def test_move_to_root(self):
157 g1 = _make_group('t11')
160 g1 = _make_group('t11')
158 Session().commit()
161 Session().commit()
159 g2 = _make_group('t22', parent_id=g1.group_id)
162 g2 = _make_group('t22', parent_id=g1.group_id)
160 Session().commit()
163 Session().commit()
161
164
162 self.assertEqual(g2.full_path, 't11/t22')
165 self.assertEqual(g2.full_path, 't11/t22')
163 self.assertTrue(self.__check_path('t11', 't22'))
166 self.assertTrue(self.__check_path('t11', 't22'))
164
167
165 g2 = self.__update_group(g2.group_id, 'g22', parent_id=None)
168 g2 = self.__update_group(g2.group_id, 'g22', parent_id=None)
166 Session().commit()
169 Session().commit()
167
170
168 self.assertEqual(g2.group_name, 'g22')
171 self.assertEqual(g2.group_name, 'g22')
169 # we moved out group from t1 to '' so it's full path should be 'g2'
172 # we moved out group from t1 to '' so it's full path should be 'g2'
170 self.assertEqual(g2.full_path, 'g22')
173 self.assertEqual(g2.full_path, 'g22')
171 self.assertFalse(self.__check_path('t11', 't22'))
174 self.assertFalse(self.__check_path('t11', 't22'))
172 self.assertTrue(self.__check_path('g22'))
175 self.assertTrue(self.__check_path('g22'))
General Comments 0
You need to be logged in to leave comments. Login now