Show More
@@ -54,7 +54,6 b' def make_map(config):' | |||
|
54 | 54 | :param match_dict: |
|
55 | 55 | """ |
|
56 | 56 | repos_group_name = match_dict.get('group_name') |
|
57 | ||
|
58 | 57 | return is_valid_repos_group(repos_group_name, config['base_path']) |
|
59 | 58 | |
|
60 | 59 | def check_int(environ, match_dict): |
@@ -158,33 +157,33 b' def make_map(config):' | |||
|
158 | 157 | action="new", conditions=dict(method=["GET"])) |
|
159 | 158 | m.connect("formatted_new_repos_group", "/repos_groups/new.{format}", |
|
160 | 159 | action="new", conditions=dict(method=["GET"])) |
|
161 |
m.connect("update_repos_group", "/repos_groups/{ |
|
|
160 | m.connect("update_repos_group", "/repos_groups/{group_name:.*?}", | |
|
162 | 161 | action="update", conditions=dict(method=["PUT"], |
|
163 |
function=check_ |
|
|
164 |
m.connect("delete_repos_group", "/repos_groups/{ |
|
|
162 | function=check_group)) | |
|
163 | m.connect("delete_repos_group", "/repos_groups/{group_name:.*?}", | |
|
165 | 164 | action="delete", conditions=dict(method=["DELETE"], |
|
166 |
function=check_ |
|
|
167 |
m.connect("edit_repos_group", "/repos_groups/{ |
|
|
165 | function=check_group)) | |
|
166 | m.connect("edit_repos_group", "/repos_groups/{group_name:.*?}/edit", | |
|
168 | 167 | action="edit", conditions=dict(method=["GET"],)) |
|
169 | 168 | m.connect("formatted_edit_repos_group", |
|
170 |
"/repos_groups/{ |
|
|
169 | "/repos_groups/{group_name:.*?}.{format}/edit", | |
|
171 | 170 | action="edit", conditions=dict(method=["GET"], |
|
172 |
function=check_ |
|
|
173 |
m.connect("repos_group", "/repos_groups/{ |
|
|
171 | function=check_group)) | |
|
172 | m.connect("repos_group", "/repos_groups/{group_name:.*?}", | |
|
174 | 173 | action="show", conditions=dict(method=["GET"], |
|
175 |
function=check_ |
|
|
176 |
m.connect("formatted_repos_group", "/repos_groups/{ |
|
|
174 | function=check_group)) | |
|
175 | m.connect("formatted_repos_group", "/repos_groups/{group_name:.*?}.{format}", | |
|
177 | 176 | action="show", conditions=dict(method=["GET"], |
|
178 |
function=check_ |
|
|
177 | function=check_group)) | |
|
179 | 178 | # ajax delete repos group perm user |
|
180 | 179 | m.connect('delete_repos_group_user_perm', |
|
181 | "/delete_repos_group_user_perm/{group_name:.*}", | |
|
180 | "/delete_repos_group_user_perm/{group_name:.*?}", | |
|
182 | 181 | action="delete_repos_group_user_perm", |
|
183 | 182 | conditions=dict(method=["DELETE"], function=check_group)) |
|
184 | 183 | |
|
185 | 184 | # ajax delete repos group perm users_group |
|
186 | 185 | m.connect('delete_repos_group_users_group_perm', |
|
187 | "/delete_repos_group_users_group_perm/{group_name:.*}", | |
|
186 | "/delete_repos_group_users_group_perm/{group_name:.*?}", | |
|
188 | 187 | action="delete_repos_group_users_group_perm", |
|
189 | 188 | conditions=dict(method=["DELETE"], function=check_group)) |
|
190 | 189 |
@@ -30,7 +30,7 b' import formencode' | |||
|
30 | 30 | from formencode import htmlfill |
|
31 | 31 | |
|
32 | 32 | from pylons import request, tmpl_context as c, url |
|
33 | from pylons.controllers.util import redirect | |
|
33 | from pylons.controllers.util import abort, redirect | |
|
34 | 34 | from pylons.i18n.translation import _ |
|
35 | 35 | |
|
36 | 36 | from sqlalchemy.exc import IntegrityError |
@@ -39,7 +39,8 b' import rhodecode' | |||
|
39 | 39 | from rhodecode.lib import helpers as h |
|
40 | 40 | from rhodecode.lib.ext_json import json |
|
41 | 41 | from rhodecode.lib.auth import LoginRequired, HasPermissionAnyDecorator,\ |
|
42 | HasReposGroupPermissionAnyDecorator | |
|
42 | HasReposGroupPermissionAnyDecorator, HasReposGroupPermissionAll,\ | |
|
43 | HasPermissionAll | |
|
43 | 44 | from rhodecode.lib.base import BaseController, render |
|
44 | 45 | from rhodecode.model.db import RepoGroup, Repository |
|
45 | 46 | from rhodecode.model.repos_group import ReposGroupModel |
@@ -47,8 +48,9 b' from rhodecode.model.forms import ReposG' | |||
|
47 | 48 | from rhodecode.model.meta import Session |
|
48 | 49 | from rhodecode.model.repo import RepoModel |
|
49 | 50 | from webob.exc import HTTPInternalServerError, HTTPNotFound |
|
50 | from rhodecode.lib.utils2 import str2bool | |
|
51 | from rhodecode.lib.utils2 import str2bool, safe_int | |
|
51 | 52 | from sqlalchemy.sql.expression import func |
|
53 | from rhodecode.model.scm import GroupList | |
|
52 | 54 | |
|
53 | 55 | log = logging.getLogger(__name__) |
|
54 | 56 | |
@@ -63,10 +65,21 b' class ReposGroupsController(BaseControll' | |||
|
63 | 65 | def __before__(self): |
|
64 | 66 | super(ReposGroupsController, self).__before__() |
|
65 | 67 | |
|
66 | def __load_defaults(self): | |
|
67 | c.repo_groups = RepoGroup.groups_choices() | |
|
68 | def __load_defaults(self, allow_empty_group=False, exclude_group_ids=[]): | |
|
69 | if HasPermissionAll('hg.admin')('group edit'): | |
|
70 | #we're global admin, we're ok and we can create TOP level groups | |
|
71 | allow_empty_group = True | |
|
72 | ||
|
73 | #override the choices for this form, we need to filter choices | |
|
74 | #and display only those we have ADMIN right | |
|
75 | groups_with_admin_rights = GroupList(RepoGroup.query().all(), | |
|
76 | perm_set=['group.admin']) | |
|
77 | c.repo_groups = RepoGroup.groups_choices(groups=groups_with_admin_rights, | |
|
78 | show_empty_group=allow_empty_group) | |
|
79 | # exclude filtered ids | |
|
80 | c.repo_groups = filter(lambda x: x[0] not in exclude_group_ids, | |
|
81 | c.repo_groups) | |
|
68 | 82 | c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups) |
|
69 | ||
|
70 | 83 | repo_model = RepoModel() |
|
71 | 84 | c.users_array = repo_model.get_users_js() |
|
72 | 85 | c.users_groups_array = repo_model.get_users_groups_js() |
@@ -77,7 +90,6 b' class ReposGroupsController(BaseControll' | |||
|
77 | 90 | |
|
78 | 91 | :param group_id: |
|
79 | 92 | """ |
|
80 | self.__load_defaults() | |
|
81 | 93 | repo_group = RepoGroup.get_or_404(group_id) |
|
82 | 94 | data = repo_group.get_dict() |
|
83 | 95 | data['group_name'] = repo_group.name |
@@ -94,34 +106,37 b' class ReposGroupsController(BaseControll' | |||
|
94 | 106 | |
|
95 | 107 | return data |
|
96 | 108 | |
|
97 | @HasPermissionAnyDecorator('hg.admin') | |
|
98 | 109 | def index(self, format='html'): |
|
99 | 110 | """GET /repos_groups: All items in the collection""" |
|
100 | 111 | # url('repos_groups') |
|
112 | group_iter = GroupList(RepoGroup.query().all(), perm_set=['group.admin']) | |
|
101 | 113 | sk = lambda g: g.parents[0].group_name if g.parents else g.group_name |
|
102 |
c.groups = sorted( |
|
|
114 | c.groups = sorted(group_iter, key=sk) | |
|
103 | 115 | return render('admin/repos_groups/repos_groups_show.html') |
|
104 | 116 | |
|
105 | @HasPermissionAnyDecorator('hg.admin') | |
|
106 | 117 | def create(self): |
|
107 | 118 | """POST /repos_groups: Create a new item""" |
|
108 | 119 | # url('repos_groups') |
|
120 | ||
|
109 | 121 | self.__load_defaults() |
|
110 | repos_group_form = ReposGroupForm(available_groups = | |
|
111 | c.repo_groups_choices)() | |
|
122 | ||
|
123 | # permissions for can create group based on parent_id are checked | |
|
124 | # here in the Form | |
|
125 | repos_group_form = ReposGroupForm(available_groups= | |
|
126 | map(lambda k: unicode(k[0]), c.repo_groups))() | |
|
112 | 127 | try: |
|
113 | 128 | form_result = repos_group_form.to_python(dict(request.POST)) |
|
114 | 129 | ReposGroupModel().create( |
|
115 | 130 | group_name=form_result['group_name'], |
|
116 | 131 | group_description=form_result['group_description'], |
|
117 | parent=form_result['group_parent_id'] | |
|
132 | parent=form_result['group_parent_id'], | |
|
133 | owner=self.rhodecode_user.user_id | |
|
118 | 134 | ) |
|
119 | 135 | Session().commit() |
|
120 | 136 | h.flash(_('created repos group %s') \ |
|
121 | 137 | % form_result['group_name'], category='success') |
|
122 | 138 | #TODO: in futureaction_logger(, '', '', '', self.sa) |
|
123 | 139 | except formencode.Invalid, errors: |
|
124 | ||
|
125 | 140 | return htmlfill.render( |
|
126 | 141 | render('admin/repos_groups/repos_groups_add.html'), |
|
127 | 142 | defaults=errors.value, |
@@ -132,40 +147,65 b' class ReposGroupsController(BaseControll' | |||
|
132 | 147 | log.error(traceback.format_exc()) |
|
133 | 148 | h.flash(_('error occurred during creation of repos group %s') \ |
|
134 | 149 | % request.POST.get('group_name'), category='error') |
|
150 | parent_group_id = form_result['group_parent_id'] | |
|
151 | #TODO: maybe we should get back to the main view, not the admin one | |
|
152 | return redirect(url('repos_groups', parent_group=parent_group_id)) | |
|
135 | 153 | |
|
136 | return redirect(url('repos_groups')) | |
|
137 | ||
|
138 | @HasPermissionAnyDecorator('hg.admin') | |
|
139 | 154 | def new(self, format='html'): |
|
140 | 155 | """GET /repos_groups/new: Form to create a new item""" |
|
141 | 156 | # url('new_repos_group') |
|
157 | if HasPermissionAll('hg.admin')('group create'): | |
|
158 | #we're global admin, we're ok and we can create TOP level groups | |
|
159 | pass | |
|
160 | else: | |
|
161 | # we pass in parent group into creation form, thus we know | |
|
162 | # what would be the group, we can check perms here ! | |
|
163 | group_id = safe_int(request.GET.get('parent_group')) | |
|
164 | group = RepoGroup.get(group_id) if group_id else None | |
|
165 | group_name = group.group_name if group else None | |
|
166 | if HasReposGroupPermissionAll('group.admin')(group_name, 'group create'): | |
|
167 | pass | |
|
168 | else: | |
|
169 | return abort(403) | |
|
170 | ||
|
142 | 171 | self.__load_defaults() |
|
143 | 172 | return render('admin/repos_groups/repos_groups_add.html') |
|
144 | 173 | |
|
145 |
@HasPermissionAnyDecorator(' |
|
|
146 |
def update(self, |
|
|
147 |
"""PUT /repos_groups/ |
|
|
174 | @HasReposGroupPermissionAnyDecorator('group.admin') | |
|
175 | def update(self, group_name): | |
|
176 | """PUT /repos_groups/group_name: Update an existing item""" | |
|
148 | 177 | # Forms posted to this method should contain a hidden field: |
|
149 | 178 | # <input type="hidden" name="_method" value="PUT" /> |
|
150 | 179 | # Or using helpers: |
|
151 |
# h.form(url('repos_group', |
|
|
180 | # h.form(url('repos_group', group_name=GROUP_NAME), | |
|
152 | 181 | # method='put') |
|
153 |
# url('repos_group', |
|
|
182 | # url('repos_group', group_name=GROUP_NAME) | |
|
154 | 183 | |
|
155 | self.__load_defaults() | |
|
156 | c.repos_group = RepoGroup.get(id) | |
|
184 | c.repos_group = ReposGroupModel()._get_repos_group(group_name) | |
|
185 | if HasPermissionAll('hg.admin')('group edit'): | |
|
186 | #we're global admin, we're ok and we can create TOP level groups | |
|
187 | allow_empty_group = True | |
|
188 | elif not c.repos_group.parent_group: | |
|
189 | allow_empty_group = True | |
|
190 | else: | |
|
191 | allow_empty_group = False | |
|
192 | self.__load_defaults(allow_empty_group=allow_empty_group, | |
|
193 | exclude_group_ids=[c.repos_group.group_id]) | |
|
157 | 194 | |
|
158 | 195 | repos_group_form = ReposGroupForm( |
|
159 | 196 | edit=True, |
|
160 | 197 | old_data=c.repos_group.get_dict(), |
|
161 | available_groups=c.repo_groups_choices | |
|
198 | available_groups=c.repo_groups_choices, | |
|
199 | can_create_in_root=allow_empty_group, | |
|
162 | 200 | )() |
|
163 | 201 | try: |
|
164 | 202 | form_result = repos_group_form.to_python(dict(request.POST)) |
|
165 |
ReposGroupModel().update( |
|
|
203 | new_gr = ReposGroupModel().update(group_name, form_result) | |
|
166 | 204 | Session().commit() |
|
167 | 205 | h.flash(_('updated repos group %s') \ |
|
168 | 206 | % form_result['group_name'], category='success') |
|
207 | # we now have new name ! | |
|
208 | group_name = new_gr.group_name | |
|
169 | 209 | #TODO: in future action_logger(, '', '', '', self.sa) |
|
170 | 210 | except formencode.Invalid, errors: |
|
171 | 211 | |
@@ -180,19 +220,19 b' class ReposGroupsController(BaseControll' | |||
|
180 | 220 | h.flash(_('error occurred during update of repos group %s') \ |
|
181 | 221 | % request.POST.get('group_name'), category='error') |
|
182 | 222 | |
|
183 |
return redirect(url('edit_repos_group', |
|
|
223 | return redirect(url('edit_repos_group', group_name=group_name)) | |
|
184 | 224 | |
|
185 |
@HasPermissionAnyDecorator(' |
|
|
186 |
def delete(self, |
|
|
187 |
"""DELETE /repos_groups/ |
|
|
225 | @HasReposGroupPermissionAnyDecorator('group.admin') | |
|
226 | def delete(self, group_name): | |
|
227 | """DELETE /repos_groups/group_name: Delete an existing item""" | |
|
188 | 228 | # Forms posted to this method should contain a hidden field: |
|
189 | 229 | # <input type="hidden" name="_method" value="DELETE" /> |
|
190 | 230 | # Or using helpers: |
|
191 |
# h.form(url('repos_group', |
|
|
231 | # h.form(url('repos_group', group_name=GROUP_NAME), | |
|
192 | 232 | # method='delete') |
|
193 |
# url('repos_group', |
|
|
233 | # url('repos_group', group_name=GROUP_NAME) | |
|
194 | 234 | |
|
195 | gr = RepoGroup.get(id) | |
|
235 | gr = c.repos_group = ReposGroupModel()._get_repos_group(group_name) | |
|
196 | 236 | repos = gr.repositories.all() |
|
197 | 237 | if repos: |
|
198 | 238 | h.flash(_('This group contains %s repositores and cannot be ' |
@@ -201,7 +241,7 b' class ReposGroupsController(BaseControll' | |||
|
201 | 241 | return redirect(url('repos_groups')) |
|
202 | 242 | |
|
203 | 243 | try: |
|
204 |
ReposGroupModel().delete( |
|
|
244 | ReposGroupModel().delete(group_name) | |
|
205 | 245 | Session().commit() |
|
206 | 246 | h.flash(_('removed repos group %s') % gr.group_name, |
|
207 | 247 | category='success') |
@@ -279,11 +319,11 b' class ReposGroupsController(BaseControll' | |||
|
279 | 319 | |
|
280 | 320 | @HasReposGroupPermissionAnyDecorator('group.read', 'group.write', |
|
281 | 321 | 'group.admin') |
|
282 |
def show(self, |
|
|
283 |
"""GET /repos_groups/ |
|
|
284 |
# url('repos_group', |
|
|
322 | def show(self, group_name, format='html'): | |
|
323 | """GET /repos_groups/group_name: Show a specific item""" | |
|
324 | # url('repos_group', group_name=GROUP_NAME) | |
|
285 | 325 | |
|
286 | c.group = RepoGroup.get_or_404(id) | |
|
326 | c.group = c.repos_group = ReposGroupModel()._get_repos_group(group_name) | |
|
287 | 327 | c.group_repos = c.group.repositories.all() |
|
288 | 328 | |
|
289 | 329 | #overwrite our cached list with current filter |
@@ -291,7 +331,7 b' class ReposGroupsController(BaseControll' | |||
|
291 | 331 | c.repo_cnt = 0 |
|
292 | 332 | |
|
293 | 333 | groups = RepoGroup.query().order_by(RepoGroup.group_name)\ |
|
294 | .filter(RepoGroup.group_parent_id == id).all() | |
|
334 | .filter(RepoGroup.group_parent_id == c.group.group_id).all() | |
|
295 | 335 | c.groups = self.scm_model.get_repos_groups(groups) |
|
296 | 336 | |
|
297 | 337 | if c.visual.lightweight_dashboard is False: |
@@ -299,7 +339,7 b' class ReposGroupsController(BaseControll' | |||
|
299 | 339 | ## lightweight version of dashboard |
|
300 | 340 | else: |
|
301 | 341 | c.repos_list = Repository.query()\ |
|
302 | .filter(Repository.group_id == id)\ | |
|
342 | .filter(Repository.group_id == c.group.group_id)\ | |
|
303 | 343 | .order_by(func.lower(Repository.repo_name))\ |
|
304 | 344 | .all() |
|
305 | 345 | |
@@ -310,17 +350,25 b' class ReposGroupsController(BaseControll' | |||
|
310 | 350 | |
|
311 | 351 | return render('admin/repos_groups/repos_groups.html') |
|
312 | 352 | |
|
313 |
@HasPermissionAnyDecorator(' |
|
|
314 |
def edit(self, |
|
|
315 |
"""GET /repos_groups/ |
|
|
316 |
# url('edit_repos_group', |
|
|
353 | @HasReposGroupPermissionAnyDecorator('group.admin') | |
|
354 | def edit(self, group_name, format='html'): | |
|
355 | """GET /repos_groups/group_name/edit: Form to edit an existing item""" | |
|
356 | # url('edit_repos_group', group_name=GROUP_NAME) | |
|
317 | 357 | |
|
318 |
c.repos_group = ReposGroupModel()._get_repos_group( |
|
|
319 | defaults = self.__load_data(c.repos_group.group_id) | |
|
358 | c.repos_group = ReposGroupModel()._get_repos_group(group_name) | |
|
359 | #we can only allow moving empty group if it's already a top-level | |
|
360 | #group, ie has no parents, or we're admin | |
|
361 | if HasPermissionAll('hg.admin')('group edit'): | |
|
362 | #we're global admin, we're ok and we can create TOP level groups | |
|
363 | allow_empty_group = True | |
|
364 | elif not c.repos_group.parent_group: | |
|
365 | allow_empty_group = True | |
|
366 | else: | |
|
367 | allow_empty_group = False | |
|
320 | 368 | |
|
321 | # we need to exclude this group from the group list for editing | |
|
322 | c.repo_groups = filter(lambda x: x[0] != c.repos_group.group_id, | |
|
323 | c.repo_groups) | |
|
369 | self.__load_defaults(allow_empty_group=allow_empty_group, | |
|
370 | exclude_group_ids=[c.repos_group.group_id]) | |
|
371 | defaults = self.__load_data(c.repos_group.group_id) | |
|
324 | 372 | |
|
325 | 373 | return htmlfill.render( |
|
326 | 374 | render('admin/repos_groups/repos_groups_edit.html'), |
@@ -659,7 +659,6 b' class HasRepoPermissionAnyDecorator(Perm' | |||
|
659 | 659 | |
|
660 | 660 | def check_permissions(self): |
|
661 | 661 | repo_name = get_repo_slug(request) |
|
662 | ||
|
663 | 662 | try: |
|
664 | 663 | user_perms = set([self.user_perms['repositories'][repo_name]]) |
|
665 | 664 | except KeyError: |
@@ -682,6 +681,7 b' class HasReposGroupPermissionAllDecorato' | |||
|
682 | 681 | user_perms = set([self.user_perms['repositories_groups'][group_name]]) |
|
683 | 682 | except KeyError: |
|
684 | 683 | return False |
|
684 | ||
|
685 | 685 | if self.required_perms.issubset(user_perms): |
|
686 | 686 | return True |
|
687 | 687 | return False |
@@ -695,11 +695,11 b' class HasReposGroupPermissionAnyDecorato' | |||
|
695 | 695 | |
|
696 | 696 | def check_permissions(self): |
|
697 | 697 | group_name = get_repos_group_slug(request) |
|
698 | ||
|
699 | 698 | try: |
|
700 | 699 | user_perms = set([self.user_perms['repositories_groups'][group_name]]) |
|
701 | 700 | except KeyError: |
|
702 | 701 | return False |
|
702 | ||
|
703 | 703 | if self.required_perms.intersection(user_perms): |
|
704 | 704 | return True |
|
705 | 705 | return False |
@@ -741,7 +741,8 b' def action_parser(user_log, feed=False, ' | |||
|
741 | 741 | # PERMS |
|
742 | 742 | #============================================================================== |
|
743 | 743 | from rhodecode.lib.auth import HasPermissionAny, HasPermissionAll, \ |
|
744 | HasRepoPermissionAny, HasRepoPermissionAll | |
|
744 | HasRepoPermissionAny, HasRepoPermissionAll, HasReposGroupPermissionAll, \ | |
|
745 | HasReposGroupPermissionAny | |
|
745 | 746 | |
|
746 | 747 | |
|
747 | 748 | #============================================================================== |
@@ -1172,15 +1172,18 b' class RepoGroup(Base, BaseModel):' | |||
|
1172 | 1172 | self.group_name) |
|
1173 | 1173 | |
|
1174 | 1174 | @classmethod |
|
1175 | def groups_choices(cls, check_perms=False): | |
|
1175 | def groups_choices(cls, groups=None, check_perms=False, show_empty_group=True): | |
|
1176 | 1176 | from webhelpers.html import literal as _literal |
|
1177 | 1177 | from rhodecode.model.scm import ScmModel |
|
1178 | groups = cls.query().all() | |
|
1178 | if not groups: | |
|
1179 | groups = cls.query().all() | |
|
1179 | 1180 | if check_perms: |
|
1180 | 1181 | #filter group user have access to, it's done |
|
1181 | 1182 | #magically inside ScmModel based on current user |
|
1182 | 1183 | groups = ScmModel().get_repos_groups(groups) |
|
1183 |
repo_groups = [ |
|
|
1184 | repo_groups = [] | |
|
1185 | if show_empty_group: | |
|
1186 | repo_groups = [('-1', '-- no parent --')] | |
|
1184 | 1187 | sep = ' » ' |
|
1185 | 1188 | _name = lambda k: _literal(sep.join(k)) |
|
1186 | 1189 |
@@ -115,7 +115,8 b' def UsersGroupForm(edit=False, old_data=' | |||
|
115 | 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 | can_create_in_root=False): | |
|
119 | 120 | class _ReposGroupForm(formencode.Schema): |
|
120 | 121 | allow_extra_fields = True |
|
121 | 122 | filter_extra_fields = False |
@@ -123,10 +124,15 b' def ReposGroupForm(edit=False, old_data=' | |||
|
123 | 124 | group_name = All(v.UnicodeString(strip=True, min=1, not_empty=True), |
|
124 | 125 | v.SlugifyName()) |
|
125 | 126 | group_description = v.UnicodeString(strip=True, min=1, |
|
126 |
not_empty= |
|
|
127 | group_parent_id = v.OneOf(available_groups, hideList=False, | |
|
128 | testValueList=True, | |
|
129 | if_missing=None, not_empty=False) | |
|
127 | not_empty=False) | |
|
128 | if edit: | |
|
129 | #FIXME: do a special check that we cannot move a group to one of | |
|
130 | #it's children | |
|
131 | pass | |
|
132 | group_parent_id = All(v.CanCreateGroup(can_create_in_root), | |
|
133 | v.OneOf(available_groups, hideList=False, | |
|
134 | testValueList=True, | |
|
135 | if_missing=None, not_empty=True)) | |
|
130 | 136 | enable_locking = v.StringBoolean(if_missing=False) |
|
131 | 137 | recursive = v.StringBoolean(if_missing=False) |
|
132 | 138 | chained_validators = [v.ValidReposGroup(edit, old_data), |
@@ -140,16 +140,21 b' class ReposGroupModel(BaseModel):' | |||
|
140 | 140 | group.name) |
|
141 | 141 | shutil.move(rm_path, os.path.join(self.repos_path, _d)) |
|
142 | 142 | |
|
143 | def create(self, group_name, group_description, parent=None, just_db=False): | |
|
143 | def create(self, group_name, group_description, owner, parent=None, just_db=False): | |
|
144 | 144 | try: |
|
145 | 145 | new_repos_group = RepoGroup() |
|
146 | new_repos_group.group_description = group_description | |
|
146 | new_repos_group.group_description = group_description or group_name | |
|
147 | 147 | new_repos_group.parent_group = self._get_repos_group(parent) |
|
148 | 148 | new_repos_group.group_name = new_repos_group.get_new_name(group_name) |
|
149 | 149 | |
|
150 | 150 | self.sa.add(new_repos_group) |
|
151 | 151 | self._create_default_perms(new_repos_group) |
|
152 | 152 | |
|
153 | #create an ADMIN permission for owner, later owner should go into | |
|
154 | #the owner field of groups | |
|
155 | self.grant_user_permission(repos_group=new_repos_group, | |
|
156 | user=owner, perm='group.admin') | |
|
157 | ||
|
153 | 158 | if not just_db: |
|
154 | 159 | # we need to flush here, in order to check if database won't |
|
155 | 160 | # throw any exceptions, create filesystem dirs at the very end |
@@ -229,10 +234,10 b' class ReposGroupModel(BaseModel):' | |||
|
229 | 234 | break |
|
230 | 235 | return updates |
|
231 | 236 | |
|
232 |
def update(self, repos_group |
|
|
237 | def update(self, repos_group, form_data): | |
|
233 | 238 | |
|
234 | 239 | try: |
|
235 |
repos_group = |
|
|
240 | repos_group = self._get_repos_group(repos_group) | |
|
236 | 241 | recursive = form_data['recursive'] |
|
237 | 242 | # iterate over all members(if in recursive mode) of this groups and |
|
238 | 243 | # set the permissions ! |
@@ -77,11 +77,15 b' class CachedRepoList(object):' | |||
|
77 | 77 | super fast |
|
78 | 78 | """ |
|
79 | 79 | |
|
80 | def __init__(self, db_repo_list, repos_path, order_by=None): | |
|
80 | def __init__(self, db_repo_list, repos_path, order_by=None, perm_set=None): | |
|
81 | 81 | self.db_repo_list = db_repo_list |
|
82 | 82 | self.repos_path = repos_path |
|
83 | 83 | self.order_by = order_by |
|
84 | 84 | self.reversed = (order_by or '').startswith('-') |
|
85 | if not perm_set: | |
|
86 | perm_set = ['repository.read', 'repository.write', | |
|
87 | 'repository.admin'] | |
|
88 | self.perm_set = perm_set | |
|
85 | 89 | |
|
86 | 90 | def __len__(self): |
|
87 | 91 | return len(self.db_repo_list) |
@@ -98,7 +102,7 b' class CachedRepoList(object):' | |||
|
98 | 102 | scmr = dbr.scm_instance_cached(cache_map) |
|
99 | 103 | # check permission at this level |
|
100 | 104 | if not HasRepoPermissionAny( |
|
101 | 'repository.read', 'repository.write', 'repository.admin' | |
|
105 | *self.perm_set | |
|
102 | 106 | )(dbr.repo_name, 'get repo check'): |
|
103 | 107 | continue |
|
104 | 108 | |
@@ -143,7 +147,7 b' class SimpleCachedRepoList(CachedRepoLis' | |||
|
143 | 147 | for dbr in self.db_repo_list: |
|
144 | 148 | # check permission at this level |
|
145 | 149 | if not HasRepoPermissionAny( |
|
146 | 'repository.read', 'repository.write', 'repository.admin' | |
|
150 | *self.perm_set | |
|
147 | 151 | )(dbr.repo_name, 'get repo check'): |
|
148 | 152 | continue |
|
149 | 153 | |
@@ -160,8 +164,18 b' class SimpleCachedRepoList(CachedRepoLis' | |||
|
160 | 164 | |
|
161 | 165 | class GroupList(object): |
|
162 | 166 | |
|
163 | def __init__(self, db_repo_group_list): | |
|
167 | def __init__(self, db_repo_group_list, perm_set=None): | |
|
168 | """ | |
|
169 | Creates iterator from given list of group objects, additionally | |
|
170 | checking permission for them from perm_set var | |
|
171 | ||
|
172 | :param db_repo_group_list: | |
|
173 | :param perm_set: list of permissons to check | |
|
174 | """ | |
|
164 | 175 | self.db_repo_group_list = db_repo_group_list |
|
176 | if not perm_set: | |
|
177 | perm_set = ['group.read', 'group.write', 'group.admin'] | |
|
178 | self.perm_set = perm_set | |
|
165 | 179 | |
|
166 | 180 | def __len__(self): |
|
167 | 181 | return len(self.db_repo_group_list) |
@@ -173,7 +187,7 b' class GroupList(object):' | |||
|
173 | 187 | for dbgr in self.db_repo_group_list: |
|
174 | 188 | # check permission at this level |
|
175 | 189 | if not HasReposGroupPermissionAny( |
|
176 | 'group.read', 'group.write', 'group.admin' | |
|
190 | *self.perm_set | |
|
177 | 191 | )(dbgr.group_name, 'get group repo check'): |
|
178 | 192 | continue |
|
179 | 193 |
@@ -475,11 +475,19 b' def CanWriteGroup():' | |||
|
475 | 475 | "to create repository in this group") |
|
476 | 476 | } |
|
477 | 477 | |
|
478 | def to_python(self, value, state): | |
|
479 | #root location | |
|
480 | if value in [-1, "-1"]: | |
|
481 | return None | |
|
482 | return value | |
|
483 | ||
|
478 | 484 | def validate_python(self, value, state): |
|
479 | 485 | gr = RepoGroup.get(value) |
|
480 | if not HasReposGroupPermissionAny( | |
|
481 |
|
|
|
482 | )(gr.group_name, 'get group of repo form'): | |
|
486 | gr_name = gr.group_name if gr else None # None means ROOT location | |
|
487 | val = HasReposGroupPermissionAny('group.write', 'group.admin') | |
|
488 | forbidden = not val(gr_name, 'can write into group validator') | |
|
489 | #parent group need to be existing | |
|
490 | if gr and forbidden: | |
|
483 | 491 | msg = M(self, 'permission_denied', state) |
|
484 | 492 | raise formencode.Invalid(msg, value, state, |
|
485 | 493 | error_dict=dict(repo_type=msg) |
@@ -487,6 +495,46 b' def CanWriteGroup():' | |||
|
487 | 495 | return _validator |
|
488 | 496 | |
|
489 | 497 | |
|
498 | def CanCreateGroup(can_create_in_root=False): | |
|
499 | class _validator(formencode.validators.FancyValidator): | |
|
500 | messages = { | |
|
501 | 'permission_denied': _(u"You don't have permissions " | |
|
502 | "to create a group in this location") | |
|
503 | } | |
|
504 | ||
|
505 | def to_python(self, value, state): | |
|
506 | #root location | |
|
507 | if value in [-1, "-1"]: | |
|
508 | return None | |
|
509 | return value | |
|
510 | ||
|
511 | def validate_python(self, value, state): | |
|
512 | #TODO: REMOVE THIS !! | |
|
513 | ################################ | |
|
514 | import ipdb;ipdb.set_trace() | |
|
515 | print 'setting ipdb debuggin for rhodecode.model.validators._validator.validate_python' | |
|
516 | ################################ | |
|
517 | ||
|
518 | ||
|
519 | gr = RepoGroup.get(value) | |
|
520 | gr_name = gr.group_name if gr else None # None means ROOT location | |
|
521 | ||
|
522 | if can_create_in_root and gr is None: | |
|
523 | #we can create in root, we're fine no validations required | |
|
524 | return | |
|
525 | ||
|
526 | forbidden_in_root = gr is None and can_create_in_root is False | |
|
527 | val = HasReposGroupPermissionAny('group.admin') | |
|
528 | forbidden = not val(gr_name, 'can create group validator') | |
|
529 | if forbidden_in_root or forbidden: | |
|
530 | msg = M(self, 'permission_denied', state) | |
|
531 | raise formencode.Invalid(msg, value, state, | |
|
532 | error_dict=dict(group_parent_id=msg) | |
|
533 | ) | |
|
534 | ||
|
535 | return _validator | |
|
536 | ||
|
537 | ||
|
490 | 538 | def ValidPerms(type_='repo'): |
|
491 | 539 | if type_ == 'group': |
|
492 | 540 | EMPTY_PERM = 'group.none' |
@@ -4631,7 +4631,7 b' PULL REQUESTS' | |||
|
4631 | 4631 | } |
|
4632 | 4632 | |
|
4633 | 4633 | #perms .perm_tag.write{ |
|
4634 |
background-color: # |
|
|
4634 | background-color: #DB7525; | |
|
4635 | 4635 | color: #ffffff; |
|
4636 | 4636 | } |
|
4637 | 4637 |
@@ -148,7 +148,7 b'' | |||
|
148 | 148 | %if section == 'repositories': |
|
149 | 149 | <a href="${h.url('edit_repo',repo_name=k,anchor='permissions_manage')}">${_('edit')}</a> |
|
150 | 150 | %elif section == 'repositories_groups': |
|
151 |
<a href="${h.url('edit_repos_group', |
|
|
151 | <a href="${h.url('edit_repos_group',group_name=k,anchor='permissions_manage')}">${_('edit')}</a> | |
|
152 | 152 | %else: |
|
153 | 153 | -- |
|
154 | 154 | %endif |
@@ -28,7 +28,7 b'' | |||
|
28 | 28 | </ul> |
|
29 | 29 | </div> |
|
30 | 30 | <!-- end box / title --> |
|
31 |
${h.form(url('repos_group', |
|
|
31 | ${h.form(url('repos_group',group_name=c.repos_group.group_name),method='put')} | |
|
32 | 32 | <div class="form"> |
|
33 | 33 | <!-- fields --> |
|
34 | 34 | <div class="fields"> |
@@ -51,12 +51,12 b'' | |||
|
51 | 51 | <td>${gr.group_description}</td> |
|
52 | 52 | <td><b>${gr_cn}</b></td> |
|
53 | 53 | <td> |
|
54 |
<a href="${h.url('edit_repos_group', |
|
|
54 | <a href="${h.url('edit_repos_group',group_name=gr.group_name)}" title="${_('edit')}"> | |
|
55 | 55 | ${h.submit('edit_%s' % gr.group_name,_('edit'),class_="edit_icon action_button")} |
|
56 | 56 | </a> |
|
57 | 57 | </td> |
|
58 | 58 | <td> |
|
59 |
${h.form(url('repos_group', |
|
|
59 | ${h.form(url('repos_group', group_name=gr.group_name),method='delete')} | |
|
60 | 60 | ${h.submit('remove_%s' % gr.name,_('delete'),class_="delete_icon action_button",onclick="return confirm('"+ungettext('Confirm to delete this group: %s with %s repository','Confirm to delete this group: %s with %s repositories',gr_cn) % (gr.name,gr_cn)+"');")} |
|
61 | 61 | ${h.end_form()} |
|
62 | 62 | </td> |
@@ -231,7 +231,7 b'' | |||
|
231 | 231 | %if section == 'repositories': |
|
232 | 232 | <a href="${h.url('edit_repo',repo_name=k,anchor='permissions_manage')}">${_('edit')}</a> |
|
233 | 233 | %elif section == 'repositories_groups': |
|
234 |
<a href="${h.url('edit_repos_group', |
|
|
234 | <a href="${h.url('edit_repos_group',group_name=k,anchor='permissions_manage')}">${_('edit')}</a> | |
|
235 | 235 | %else: |
|
236 | 236 | -- |
|
237 | 237 | %endif |
@@ -206,7 +206,7 b'' | |||
|
206 | 206 | %if section == 'repositories': |
|
207 | 207 | <a href="${h.url('edit_repo',repo_name=k,anchor='permissions_manage')}">${_('edit')}</a> |
|
208 | 208 | %elif section == 'repositories_groups': |
|
209 |
<a href="${h.url('edit_repos_group', |
|
|
209 | <a href="${h.url('edit_repos_group',group_name=k,anchor='permissions_manage')}">${_('edit')}</a> | |
|
210 | 210 | %else: |
|
211 | 211 | -- |
|
212 | 212 | %endif |
@@ -6,17 +6,22 b'' | |||
|
6 | 6 | <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" value="${_('quick filter...')}"/> ${parent.breadcrumbs()} <span id="repo_count">0</span> ${_('repositories')} |
|
7 | 7 | </h5> |
|
8 | 8 | %if c.rhodecode_user.username != 'default': |
|
9 | <ul class="links"> | |
|
9 | 10 | %if h.HasPermissionAny('hg.admin','hg.create.repository')(): |
|
10 | <ul class="links"> | |
|
11 | 11 | <li> |
|
12 | 12 | %if c.group: |
|
13 | 13 | <span>${h.link_to(_('Add repository'),h.url('admin_settings_create_repository',parent_group=c.group.group_id))}</span> |
|
14 | 14 | %else: |
|
15 | <span>${h.link_to(_('Add repository'),h.url('admin_settings_create_repository'))}</span> | |
|
15 | <span>${h.link_to(_('Add repository'),h.url('admin_settings_create_repository'))}</span> | |
|
16 | 16 | %endif |
|
17 | 17 | </li> |
|
18 | </ul> | |
|
19 | 18 | %endif |
|
19 | %if c.group and h.HasReposGroupPermissionAny('group.admin')(c.group.group_name): | |
|
20 | <li> | |
|
21 | <span>${h.link_to(_('Edit group'),h.url('edit_repos_group',group_name=c.group.group_name), title=_('You have admin right to this group, and can edit it'))}</span> | |
|
22 | </li> | |
|
23 | %endif | |
|
24 | </ul> | |
|
20 | 25 | %endif |
|
21 | 26 | </div> |
|
22 | 27 | <!-- end box / title --> |
@@ -90,7 +90,8 b' class TestAdminReposController(TestContr' | |||
|
90 | 90 | ## create GROUP |
|
91 | 91 | group_name = 'sometest' |
|
92 | 92 | gr = ReposGroupModel().create(group_name=group_name, |
|
93 |
group_description='test', |
|
|
93 | group_description='test', | |
|
94 | owner=TEST_USER_ADMIN_LOGIN) | |
|
94 | 95 | self.Session().commit() |
|
95 | 96 | |
|
96 | 97 | repo_name = 'ingroup' |
@@ -1,43 +1,51 b'' | |||
|
1 | 1 | from rhodecode.tests import * |
|
2 | 2 | |
|
3 | ||
|
3 | 4 | class TestReposGroupsController(TestController): |
|
4 | 5 | |
|
5 | 6 | def test_index(self): |
|
7 | self.log_user() | |
|
6 | 8 | response = self.app.get(url('repos_groups')) |
|
7 | # Test response... | |
|
9 | response.mustcontain('There are no repositories groups yet') | |
|
8 | 10 | |
|
9 | def test_index_as_xml(self): | |
|
10 | response = self.app.get(url('formatted_repos_groups', format='xml')) | |
|
11 | ||
|
12 | def test_create(self): | |
|
13 | response = self.app.post(url('repos_groups')) | |
|
11 | # def test_index_as_xml(self): | |
|
12 | # response = self.app.get(url('formatted_repos_groups', format='xml')) | |
|
13 | # | |
|
14 | # def test_create(self): | |
|
15 | # response = self.app.post(url('repos_groups')) | |
|
14 | 16 | |
|
15 | 17 | def test_new(self): |
|
18 | self.log_user() | |
|
16 | 19 | response = self.app.get(url('new_repos_group')) |
|
17 | 20 | |
|
18 |
def test_new_ |
|
|
19 | response = self.app.get(url('formatted_new_repos_group', format='xml')) | |
|
20 | ||
|
21 | def test_update(self): | |
|
22 | response = self.app.put(url('repos_group', id=1)) | |
|
23 | ||
|
24 | def test_update_browser_fakeout(self): | |
|
25 | response = self.app.post(url('repos_group', id=1), params=dict(_method='put')) | |
|
26 | ||
|
27 | def test_delete(self): | |
|
28 | response = self.app.delete(url('repos_group', id=1)) | |
|
29 | ||
|
30 | def test_delete_browser_fakeout(self): | |
|
31 | response = self.app.post(url('repos_group', id=1), params=dict(_method='delete')) | |
|
32 | ||
|
33 | def test_show(self): | |
|
34 | response = self.app.get(url('repos_group', id=1)) | |
|
35 | ||
|
36 | def test_show_as_xml(self): | |
|
37 | response = self.app.get(url('formatted_repos_group', id=1, format='xml')) | |
|
38 | ||
|
39 | def test_edit(self): | |
|
40 | response = self.app.get(url('edit_repos_group', id=1)) | |
|
41 | ||
|
42 | def test_edit_as_xml(self): | |
|
43 | response = self.app.get(url('formatted_edit_repos_group', id=1, format='xml')) | |
|
21 | def test_new_by_regular_user(self): | |
|
22 | self.log_user(TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS) | |
|
23 | response = self.app.get(url('new_repos_group'), status=403) | |
|
24 | # | |
|
25 | # def test_new_as_xml(self): | |
|
26 | # response = self.app.get(url('formatted_new_repos_group', format='xml')) | |
|
27 | # | |
|
28 | # def test_update(self): | |
|
29 | # response = self.app.put(url('repos_group', group_name=1)) | |
|
30 | # | |
|
31 | # def test_update_browser_fakeout(self): | |
|
32 | # response = self.app.post(url('repos_group', group_name=1), params=dict(_method='put')) | |
|
33 | # | |
|
34 | # def test_delete(self): | |
|
35 | # self.log_user() | |
|
36 | # response = self.app.delete(url('repos_group', group_name=1)) | |
|
37 | # | |
|
38 | # def test_delete_browser_fakeout(self): | |
|
39 | # response = self.app.post(url('repos_group', group_name=1), params=dict(_method='delete')) | |
|
40 | # | |
|
41 | # def test_show(self): | |
|
42 | # response = self.app.get(url('repos_group', group_name=1)) | |
|
43 | # | |
|
44 | # def test_show_as_xml(self): | |
|
45 | # response = self.app.get(url('formatted_repos_group', group_name=1, format='xml')) | |
|
46 | # | |
|
47 | # def test_edit(self): | |
|
48 | # response = self.app.get(url('edit_repos_group', group_name=1)) | |
|
49 | # | |
|
50 | # def test_edit_as_xml(self): | |
|
51 | # response = self.app.get(url('formatted_edit_repos_group', group_name=1, format='xml')) |
@@ -21,7 +21,7 b" def _make_group(path, desc='desc', paren" | |||
|
21 | 21 | return gr |
|
22 | 22 | if isinstance(parent_id, RepoGroup): |
|
23 | 23 | parent_id = parent_id.group_id |
|
24 | gr = ReposGroupModel().create(path, desc, parent_id) | |
|
24 | gr = ReposGroupModel().create(path, desc, TEST_USER_ADMIN_LOGIN, parent_id) | |
|
25 | 25 | return gr |
|
26 | 26 | |
|
27 | 27 |
@@ -17,7 +17,7 b" def _make_group(path, desc='desc', paren" | |||
|
17 | 17 | return gr |
|
18 | 18 | if isinstance(parent_id, RepoGroup): |
|
19 | 19 | parent_id = parent_id.group_id |
|
20 | gr = ReposGroupModel().create(path, desc, parent_id) | |
|
20 | gr = ReposGroupModel().create(path, desc, TEST_USER_ADMIN_LOGIN, parent_id) | |
|
21 | 21 | return gr |
|
22 | 22 | |
|
23 | 23 |
@@ -79,7 +79,8 b' class TestReposGroups(unittest.TestCase)' | |||
|
79 | 79 | {'group_name': HG_REPO, }) |
|
80 | 80 | gr = model.create(group_name='test_gr', group_description='desc', |
|
81 | 81 | parent=None, |
|
82 |
just_db=True |
|
|
82 | just_db=True, | |
|
83 | owner=TEST_USER_ADMIN_LOGIN) | |
|
83 | 84 | self.assertRaises(formencode.Invalid, |
|
84 | 85 | validator.to_python, {'group_name': gr.group_name, }) |
|
85 | 86 | |
@@ -150,7 +151,8 b' class TestReposGroups(unittest.TestCase)' | |||
|
150 | 151 | |
|
151 | 152 | gr = ReposGroupModel().create(group_name='group_test', |
|
152 | 153 | group_description='desc', |
|
153 |
parent=None, |
|
|
154 | parent=None, | |
|
155 | owner=TEST_USER_ADMIN_LOGIN) | |
|
154 | 156 | self.assertRaises(formencode.Invalid, |
|
155 | 157 | validator.to_python, {'repo_name': gr.group_name}) |
|
156 | 158 |
General Comments 0
You need to be logged in to leave comments.
Login now