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