##// END OF EJS Templates
#227 Initial version of repository groups permissions system...
marcink -
r1982:87f0800a beta
parent child Browse files
Show More
@@ -0,0 +1,270 b''
1 <table id="permissions_manage" class="noborder">
2 <tr>
3 <td>${_('none')}</td>
4 <td>${_('read')}</td>
5 <td>${_('write')}</td>
6 <td>${_('admin')}</td>
7 <td>${_('member')}</td>
8 <td></td>
9 </tr>
10 ## USERS
11 %for r2p in c.repos_group.repo_group_to_perm:
12 <tr id="id${id(r2p.user.username)}">
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>
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>
17 <td style="white-space: nowrap;">
18 <img style="vertical-align:bottom" src="${h.url('/images/icons/user.png')}"/>${r2p.user.username}
19 </td>
20 <td>
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)}')">
23 ${_('revoke')}
24 </span>
25 %endif
26 </td>
27 </tr>
28 %endfor
29
30 ## USERS GROUPS
31 %for g2p in c.repos_group.users_group_to_perm:
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>
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>
36 <td>${h.radio('g_perm_%s' % g2p.users_group.users_group_name,'group.admin')}</td>
37 <td style="white-space: nowrap;">
38 <img style="vertical-align:bottom" src="${h.url('/images/icons/group.png')}"/>${g2p.users_group.users_group_name}
39 </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)}')">
42 ${_('revoke')}
43 </span>
44 </td>
45 </tr>
46 %endfor
47 <tr id="add_perm_input">
48 <td>${h.radio('perm_new_member','group.none')}</td>
49 <td>${h.radio('perm_new_member','group.read')}</td>
50 <td>${h.radio('perm_new_member','group.write')}</td>
51 <td>${h.radio('perm_new_member','group.admin')}</td>
52 <td class='ac'>
53 <div class="perm_ac" id="perm_ac">
54 ${h.text('perm_new_member_name',class_='yui-ac-input')}
55 ${h.hidden('perm_new_member_type')}
56 <div id="perm_container"></div>
57 </div>
58 </td>
59 <td></td>
60 </tr>
61 <tr>
62 <td colspan="6">
63 <span id="add_perm" class="add_icon" style="cursor: pointer;">
64 ${_('Add another member')}
65 </span>
66 </td>
67 </tr>
68 </table>
69 <script type="text/javascript">
70 function ajaxActionUser(user_id, field_id) {
71 var sUrl = "${h.url('delete_repos_group_user_perm',group_name=c.repos_group.name)}";
72 var callback = {
73 success: function (o) {
74 var tr = YUD.get(String(field_id));
75 tr.parentNode.removeChild(tr);
76 },
77 failure: function (o) {
78 alert("${_('Failed to remove user')}");
79 },
80 };
81 var postData = '_method=delete&user_id=' + user_id;
82 var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData);
83 };
84
85 function ajaxActionUsersGroup(users_group_id,field_id){
86 var sUrl = "${h.url('delete_repos_group_users_group_perm',group_name=c.repos_group.name)}";
87 var callback = {
88 success:function(o){
89 var tr = YUD.get(String(field_id));
90 tr.parentNode.removeChild(tr);
91 },
92 failure:function(o){
93 alert("${_('Failed to remove users group')}");
94 },
95 };
96 var postData = '_method=delete&users_group_id='+users_group_id;
97 var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData);
98 };
99
100 YUE.onDOMReady(function () {
101 if (!YUD.hasClass('perm_new_member_name', 'error')) {
102 YUD.setStyle('add_perm_input', 'display', 'none');
103 }
104 YAHOO.util.Event.addListener('add_perm', 'click', function () {
105 YUD.setStyle('add_perm_input', 'display', '');
106 YUD.setStyle('add_perm', 'opacity', '0.6');
107 YUD.setStyle('add_perm', 'cursor', 'default');
108 });
109 });
110
111 YAHOO.example.FnMultipleFields = function () {
112 var myUsers = ${c.users_array|n};
113 var myGroups = ${c.users_groups_array|n};
114
115 // Define a custom search function for the DataSource of users
116 var matchUsers = function (sQuery) {
117 // Case insensitive matching
118 var query = sQuery.toLowerCase();
119 var i = 0;
120 var l = myUsers.length;
121 var matches = [];
122
123 // Match against each name of each contact
124 for (; i < l; i++) {
125 contact = myUsers[i];
126 if ((contact.fname.toLowerCase().indexOf(query) > -1) || (contact.lname.toLowerCase().indexOf(query) > -1) || (contact.nname && (contact.nname.toLowerCase().indexOf(query) > -1))) {
127 matches[matches.length] = contact;
128 }
129 }
130 return matches;
131 };
132
133 // Define a custom search function for the DataSource of usersGroups
134 var matchGroups = function (sQuery) {
135 // Case insensitive matching
136 var query = sQuery.toLowerCase();
137 var i = 0;
138 var l = myGroups.length;
139 var matches = [];
140
141 // Match against each name of each contact
142 for (; i < l; i++) {
143 matched_group = myGroups[i];
144 if (matched_group.grname.toLowerCase().indexOf(query) > -1) {
145 matches[matches.length] = matched_group;
146 }
147 }
148 return matches;
149 };
150
151 //match all
152 var matchAll = function (sQuery) {
153 u = matchUsers(sQuery);
154 g = matchGroups(sQuery);
155 return u.concat(g);
156 };
157
158 // DataScheme for members
159 var memberDS = new YAHOO.util.FunctionDataSource(matchAll);
160 memberDS.responseSchema = {
161 fields: ["id", "fname", "lname", "nname", "grname", "grmembers"]
162 };
163
164 // DataScheme for owner
165 var ownerDS = new YAHOO.util.FunctionDataSource(matchUsers);
166 ownerDS.responseSchema = {
167 fields: ["id", "fname", "lname", "nname"]
168 };
169
170 // Instantiate AutoComplete for perms
171 var membersAC = new YAHOO.widget.AutoComplete("perm_new_member_name", "perm_container", memberDS);
172 membersAC.useShadow = false;
173 membersAC.resultTypeList = false;
174
175 // Instantiate AutoComplete for owner
176 var ownerAC = new YAHOO.widget.AutoComplete("user", "owner_container", ownerDS);
177 ownerAC.useShadow = false;
178 ownerAC.resultTypeList = false;
179
180
181 // Helper highlight function for the formatter
182 var highlightMatch = function (full, snippet, matchindex) {
183 return full.substring(0, matchindex) + "<span class='match'>" + full.substr(matchindex, snippet.length) + "</span>" + full.substring(matchindex + snippet.length);
184 };
185
186 // Custom formatter to highlight the matching letters
187 var custom_formatter = function (oResultData, sQuery, sResultMatch) {
188 var query = sQuery.toLowerCase();
189
190 if (oResultData.grname != undefined) {
191 var grname = oResultData.grname;
192 var grmembers = oResultData.grmembers;
193 var grnameMatchIndex = grname.toLowerCase().indexOf(query);
194 var grprefix = "${_('Group')}: ";
195 var grsuffix = " (" + grmembers + " ${_('members')})";
196
197 if (grnameMatchIndex > -1) {
198 return grprefix + highlightMatch(grname, query, grnameMatchIndex) + grsuffix;
199 }
200
201 return grprefix + oResultData.grname + grsuffix;
202 } else if (oResultData.fname != undefined) {
203
204 var fname = oResultData.fname,
205 lname = oResultData.lname,
206 nname = oResultData.nname || "",
207 // Guard against null value
208 fnameMatchIndex = fname.toLowerCase().indexOf(query),
209 lnameMatchIndex = lname.toLowerCase().indexOf(query),
210 nnameMatchIndex = nname.toLowerCase().indexOf(query),
211 displayfname, displaylname, displaynname;
212
213 if (fnameMatchIndex > -1) {
214 displayfname = highlightMatch(fname, query, fnameMatchIndex);
215 } else {
216 displayfname = fname;
217 }
218
219 if (lnameMatchIndex > -1) {
220 displaylname = highlightMatch(lname, query, lnameMatchIndex);
221 } else {
222 displaylname = lname;
223 }
224
225 if (nnameMatchIndex > -1) {
226 displaynname = "(" + highlightMatch(nname, query, nnameMatchIndex) + ")";
227 } else {
228 displaynname = nname ? "(" + nname + ")" : "";
229 }
230
231 return displayfname + " " + displaylname + " " + displaynname;
232 } else {
233 return '';
234 }
235 };
236 membersAC.formatResult = custom_formatter;
237 ownerAC.formatResult = custom_formatter;
238
239 var myHandler = function (sType, aArgs) {
240
241 var myAC = aArgs[0]; // reference back to the AC instance
242 var elLI = aArgs[1]; // reference to the selected LI element
243 var oData = aArgs[2]; // object literal of selected item's result data
244 //fill the autocomplete with value
245 if (oData.nname != undefined) {
246 //users
247 myAC.getInputEl().value = oData.nname;
248 YUD.get('perm_new_member_type').value = 'user';
249 } else {
250 //groups
251 myAC.getInputEl().value = oData.grname;
252 YUD.get('perm_new_member_type').value = 'users_group';
253 }
254
255 };
256
257 membersAC.itemSelectEvent.subscribe(myHandler);
258 if(ownerAC.itemSelectEvent){
259 ownerAC.itemSelectEvent.subscribe(myHandler);
260 }
261
262 return {
263 memberDS: memberDS,
264 ownerDS: ownerDS,
265 membersAC: membersAC,
266 ownerAC: ownerAC,
267 };
268 }();
269
270 </script>
@@ -3,9 +3,9 b' RhodeCode documentation!'
3 ========================
3 ========================
4
4
5 ``RhodeCode`` is a fast and powerful management tool for Mercurial_ and GIT_
5 ``RhodeCode`` is a fast and powerful management tool for Mercurial_ and GIT_
6 with a built in push/pull server and full text search.
6 with a built in push/pull server and full text search and code-review.
7 It works on http/https and has a built in permission/authentication system with
7 It works on http/https and has a built in permission/authentication system with
8 the ability to authenticate via LDAP or ActiveDirectory. RhodeCode also supports
8 the ability to authenticate via LDAP or ActiveDirectory. RhodeCode also provides
9 simple API so it's easy integrable with existing external systems.
9 simple API so it's easy integrable with existing external systems.
10
10
11 RhodeCode is similar in some respects to github or bitbucket_,
11 RhodeCode is similar in some respects to github or bitbucket_,
@@ -91,6 +91,7 b" Get's an user by username, Returns empty"
91 This command can be executed only using api_key belonging to user with admin
91 This command can be executed only using api_key belonging to user with admin
92 rights.
92 rights.
93
93
94
94 INPUT::
95 INPUT::
95
96
96 api_key : "<api_key>"
97 api_key : "<api_key>"
@@ -122,6 +123,7 b' get_users'
122 Lists all existing users. This command can be executed only using api_key
123 Lists all existing users. This command can be executed only using api_key
123 belonging to user with admin rights.
124 belonging to user with admin rights.
124
125
126
125 INPUT::
127 INPUT::
126
128
127 api_key : "<api_key>"
129 api_key : "<api_key>"
@@ -145,12 +147,14 b' OUTPUT::'
145 ]
147 ]
146 error: null
148 error: null
147
149
150
148 create_user
151 create_user
149 -----------
152 -----------
150
153
151 Creates new user or updates current one if such user exists. This command can
154 Creates new user or updates current one if such user exists. This command can
152 be executed only using api_key belonging to user with admin rights.
155 be executed only using api_key belonging to user with admin rights.
153
156
157
154 INPUT::
158 INPUT::
155
159
156 api_key : "<api_key>"
160 api_key : "<api_key>"
@@ -174,12 +178,14 b' OUTPUT::'
174 }
178 }
175 error: null
179 error: null
176
180
181
177 get_users_group
182 get_users_group
178 ---------------
183 ---------------
179
184
180 Gets an existing users group. This command can be executed only using api_key
185 Gets an existing users group. This command can be executed only using api_key
181 belonging to user with admin rights.
186 belonging to user with admin rights.
182
187
188
183 INPUT::
189 INPUT::
184
190
185 api_key : "<api_key>"
191 api_key : "<api_key>"
@@ -210,12 +216,14 b' OUTPUT::'
210 }
216 }
211 error : null
217 error : null
212
218
219
213 get_users_groups
220 get_users_groups
214 ----------------
221 ----------------
215
222
216 Lists all existing users groups. This command can be executed only using
223 Lists all existing users groups. This command can be executed only using
217 api_key belonging to user with admin rights.
224 api_key belonging to user with admin rights.
218
225
226
219 INPUT::
227 INPUT::
220
228
221 api_key : "<api_key>"
229 api_key : "<api_key>"
@@ -253,6 +261,7 b' create_users_group'
253 Creates new users group. This command can be executed only using api_key
261 Creates new users group. This command can be executed only using api_key
254 belonging to user with admin rights
262 belonging to user with admin rights
255
263
264
256 INPUT::
265 INPUT::
257
266
258 api_key : "<api_key>"
267 api_key : "<api_key>"
@@ -270,12 +279,14 b' OUTPUT::'
270 }
279 }
271 error: null
280 error: null
272
281
282
273 add_user_to_users_group
283 add_user_to_users_group
274 -----------------------
284 -----------------------
275
285
276 Adds a user to a users group. This command can be executed only using api_key
286 Adds a user to a users group. This command can be executed only using api_key
277 belonging to user with admin rights
287 belonging to user with admin rights
278
288
289
279 INPUT::
290 INPUT::
280
291
281 api_key : "<api_key>"
292 api_key : "<api_key>"
@@ -293,12 +304,14 b' OUTPUT::'
293 }
304 }
294 error: null
305 error: null
295
306
307
296 get_repo
308 get_repo
297 --------
309 --------
298
310
299 Gets an existing repository. This command can be executed only using api_key
311 Gets an existing repository. This command can be executed only using api_key
300 belonging to user with admin rights
312 belonging to user with admin rights
301
313
314
302 INPUT::
315 INPUT::
303
316
304 api_key : "<api_key>"
317 api_key : "<api_key>"
@@ -338,12 +351,14 b' OUTPUT::'
338 }
351 }
339 error: null
352 error: null
340
353
354
341 get_repos
355 get_repos
342 ---------
356 ---------
343
357
344 Lists all existing repositories. This command can be executed only using api_key
358 Lists all existing repositories. This command can be executed only using api_key
345 belonging to user with admin rights
359 belonging to user with admin rights
346
360
361
347 INPUT::
362 INPUT::
348
363
349 api_key : "<api_key>"
364 api_key : "<api_key>"
@@ -372,6 +387,7 b" at given revision. It's possible to spec"
372 `dirs`. This command can be executed only using api_key belonging to user
387 `dirs`. This command can be executed only using api_key belonging to user
373 with admin rights
388 with admin rights
374
389
390
375 INPUT::
391 INPUT::
376
392
377 api_key : "<api_key>"
393 api_key : "<api_key>"
@@ -395,7 +411,6 b' OUTPUT::'
395 error: null
411 error: null
396
412
397
413
398
399 create_repo
414 create_repo
400 -----------
415 -----------
401
416
@@ -405,6 +420,7 b' If repository name contains "/", all nee'
405 For example "foo/bar/baz" will create groups "foo", "bar" (with "foo" as parent),
420 For example "foo/bar/baz" will create groups "foo", "bar" (with "foo" as parent),
406 and create "baz" repository with "bar" as group.
421 and create "baz" repository with "bar" as group.
407
422
423
408 INPUT::
424 INPUT::
409
425
410 api_key : "<api_key>"
426 api_key : "<api_key>"
@@ -420,54 +436,106 b' INPUT::'
420 OUTPUT::
436 OUTPUT::
421
437
422 result: {
438 result: {
423 "id": "<newrepoid>",
439 "id": "<newrepoid>",
424 "msg": "Created new repository <reponame>",
440 "msg": "Created new repository <reponame>",
425 }
441 }
426 error: null
442 error: null
427
443
428 add_user_to_repo
444
429 ----------------
445 grant_user_permission
446 ---------------------
430
447
431 Add a user to a repository. This command can be executed only using api_key
448 Grant permission for user on given repository, or update existing one
432 belonging to user with admin rights.
449 if found. This command can be executed only using api_key belonging to user
433 If "perm" is None, user will be removed from the repository.
450 with admin rights.
451
434
452
435 INPUT::
453 INPUT::
436
454
437 api_key : "<api_key>"
455 api_key : "<api_key>"
438 method : "add_user_to_repo"
456 method : "grant_user_permission"
439 args: {
457 args: {
440 "repo_name" : "<reponame>",
458 "repo_name" : "<reponame>",
441 "username" : "<username>",
459 "username" : "<username>",
442 "perm" : "(None|repository.(read|write|admin))",
460 "perm" : "(repository.(none|read|write|admin))",
461 }
462
463 OUTPUT::
464
465 result: {
466 "msg" : "Granted perm: <perm> for user: <username> in repo: <reponame>"
467 }
468 error: null
469
470
471 revoke_user_permission
472 ----------------------
473
474 Revoke permission for user on given repository. This command can be executed
475 only using api_key belonging to user with admin rights.
476
477
478 INPUT::
479
480 api_key : "<api_key>"
481 method : "revoke_user_permission"
482 args: {
483 "repo_name" : "<reponame>",
484 "username" : "<username>",
443 }
485 }
444
486
445 OUTPUT::
487 OUTPUT::
446
488
447 result: {
489 result: {
448 "msg" : "Added perm: <perm> for <username> in repo: <reponame>"
490 "msg" : "Revoked perm for user: <suername> in repo: <reponame>"
449 }
491 }
450 error: null
492 error: null
451
493
452 add_users_group_to_repo
494
453 -----------------------
495 grant_users_group_permission
496 ----------------------------
454
497
455 Add a users group to a repository. This command can be executed only using
498 Grant permission for users group on given repository, or update
456 api_key belonging to user with admin rights. If "perm" is None, group will
499 existing one if found. This command can be executed only using
457 be removed from the repository.
500 api_key belonging to user with admin rights.
501
458
502
459 INPUT::
503 INPUT::
460
504
461 api_key : "<api_key>"
505 api_key : "<api_key>"
462 method : "add_users_group_to_repo"
506 method : "grant_users_group_permission"
507 args: {
508 "repo_name" : "<reponame>",
509 "group_name" : "<usersgroupname>",
510 "perm" : "(repository.(none|read|write|admin))",
511 }
512
513 OUTPUT::
514
515 result: {
516 "msg" : "Granted perm: <perm> for group: <usersgroupname> in repo: <reponame>"
517 }
518 error: null
519
520
521 revoke_users_group_permission
522 -----------------------------
523
524 Revoke permission for users group on given repository.This command can be
525 executed only using api_key belonging to user with admin rights.
526
527 INPUT::
528
529 api_key : "<api_key>"
530 method : "revoke_users_group_permission"
463 args: {
531 args: {
464 "repo_name" : "<reponame>",
532 "repo_name" : "<reponame>",
465 "group_name" : "<groupname>",
533 "users_group" : "<usersgroupname>",
466 "perm" : "(None|repository.(read|write|admin))",
467 }
534 }
535
468 OUTPUT::
536 OUTPUT::
469
537
470 result: {
538 result: {
471 "msg" : Added perm: <perm> for <groupname> in repo: <reponame>"
539 "msg" : "Revoked perm for group: <usersgroupname> in repo: <reponame>"
472 }
540 }
473
541 error: null No newline at end of file
@@ -51,8 +51,8 b' def make_app(global_conf, full_stack=Tru'
51 from rhodecode.lib.profiler import ProfilingMiddleware
51 from rhodecode.lib.profiler import ProfilingMiddleware
52 app = ProfilingMiddleware(app)
52 app = ProfilingMiddleware(app)
53
53
54 if asbool(full_stack):
54
55
55 if asbool(full_stack):
56 # Handle Python exceptions
56 # Handle Python exceptions
57 app = ErrorHandler(app, global_conf, **config['pylons.errorware'])
57 app = ErrorHandler(app, global_conf, **config['pylons.errorware'])
58
58
@@ -80,7 +80,6 b' def make_app(global_conf, full_stack=Tru'
80 app = Cascade([static_app, app])
80 app = Cascade([static_app, app])
81 app = make_gzip_middleware(app, global_conf, compress_level=1)
81 app = make_gzip_middleware(app, global_conf, compress_level=1)
82
82
83
84 app.config = config
83 app.config = config
85
84
86 return app
85 return app
@@ -113,8 +113,9 b' def make_map(config):'
113 function=check_repo))
113 function=check_repo))
114 #ajax delete repo perm user
114 #ajax delete repo perm user
115 m.connect('delete_repo_user', "/repos_delete_user/{repo_name:.*}",
115 m.connect('delete_repo_user', "/repos_delete_user/{repo_name:.*}",
116 action="delete_perm_user", conditions=dict(method=["DELETE"],
116 action="delete_perm_user",
117 function=check_repo))
117 conditions=dict(method=["DELETE"], function=check_repo))
118
118 #ajax delete repo perm users_group
119 #ajax delete repo perm users_group
119 m.connect('delete_repo_users_group',
120 m.connect('delete_repo_users_group',
120 "/repos_delete_users_group/{repo_name:.*}",
121 "/repos_delete_users_group/{repo_name:.*}",
@@ -128,7 +129,7 b' def make_map(config):'
128 m.connect('repo_cache', "/repos_cache/{repo_name:.*}",
129 m.connect('repo_cache', "/repos_cache/{repo_name:.*}",
129 action="repo_cache", conditions=dict(method=["DELETE"],
130 action="repo_cache", conditions=dict(method=["DELETE"],
130 function=check_repo))
131 function=check_repo))
131 m.connect('repo_public_journal',"/repos_public_journal/{repo_name:.*}",
132 m.connect('repo_public_journal', "/repos_public_journal/{repo_name:.*}",
132 action="repo_public_journal", conditions=dict(method=["PUT"],
133 action="repo_public_journal", conditions=dict(method=["PUT"],
133 function=check_repo))
134 function=check_repo))
134 m.connect('repo_pull', "/repo_pull/{repo_name:.*}",
135 m.connect('repo_pull', "/repo_pull/{repo_name:.*}",
@@ -169,6 +170,17 b' def make_map(config):'
169 m.connect("formatted_repos_group", "/repos_groups/{id}.{format}",
170 m.connect("formatted_repos_group", "/repos_groups/{id}.{format}",
170 action="show", conditions=dict(method=["GET"],
171 action="show", conditions=dict(method=["GET"],
171 function=check_int))
172 function=check_int))
173 # ajax delete repos group perm user
174 m.connect('delete_repos_group_user_perm',
175 "/delete_repos_group_user_perm/{group_name:.*}",
176 action="delete_repos_group_user_perm",
177 conditions=dict(method=["DELETE"], function=check_group))
178
179 # ajax delete repos group perm users_group
180 m.connect('delete_repos_group_users_group_perm',
181 "/delete_repos_group_users_group_perm/{group_name:.*}",
182 action="delete_repos_group_users_group_perm",
183 conditions=dict(method=["DELETE"], function=check_group))
172
184
173 #ADMIN USER REST ROUTES
185 #ADMIN USER REST ROUTES
174 with rmap.submapper(path_prefix=ADMIN_PREFIX,
186 with rmap.submapper(path_prefix=ADMIN_PREFIX,
@@ -310,8 +322,6 b' def make_map(config):'
310 m.connect("formatted_notification", "/notifications/{notification_id}.{format}",
322 m.connect("formatted_notification", "/notifications/{notification_id}.{format}",
311 action="show", conditions=dict(method=["GET"]))
323 action="show", conditions=dict(method=["GET"]))
312
324
313
314
315 #ADMIN MAIN PAGES
325 #ADMIN MAIN PAGES
316 with rmap.submapper(path_prefix=ADMIN_PREFIX,
326 with rmap.submapper(path_prefix=ADMIN_PREFIX,
317 controller='admin/admin') as m:
327 controller='admin/admin') as m:
@@ -320,13 +330,12 b' def make_map(config):'
320 action='add_repo')
330 action='add_repo')
321
331
322 #==========================================================================
332 #==========================================================================
323 # API V1
333 # API V2
324 #==========================================================================
334 #==========================================================================
325 with rmap.submapper(path_prefix=ADMIN_PREFIX,
335 with rmap.submapper(path_prefix=ADMIN_PREFIX,
326 controller='api/api') as m:
336 controller='api/api') as m:
327 m.connect('api', '/api')
337 m.connect('api', '/api')
328
338
329
330 #USER JOURNAL
339 #USER JOURNAL
331 rmap.connect('journal', '%s/journal' % ADMIN_PREFIX, controller='journal')
340 rmap.connect('journal', '%s/journal' % ADMIN_PREFIX, controller='journal')
332
341
@@ -388,11 +397,13 b' def make_map(config):'
388 controller='changeset', revision='tip',
397 controller='changeset', revision='tip',
389 conditions=dict(function=check_repo))
398 conditions=dict(function=check_repo))
390
399
391 rmap.connect('changeset_comment', '/{repo_name:.*}/changeset/{revision}/comment',
400 rmap.connect('changeset_comment',
401 '/{repo_name:.*}/changeset/{revision}/comment',
392 controller='changeset', revision='tip', action='comment',
402 controller='changeset', revision='tip', action='comment',
393 conditions=dict(function=check_repo))
403 conditions=dict(function=check_repo))
394
404
395 rmap.connect('changeset_comment_delete', '/{repo_name:.*}/changeset/comment/{comment_id}/delete',
405 rmap.connect('changeset_comment_delete',
406 '/{repo_name:.*}/changeset/comment/{comment_id}/delete',
396 controller='changeset', action='delete_comment',
407 controller='changeset', action='delete_comment',
397 conditions=dict(function=check_repo, method=["DELETE"]))
408 conditions=dict(function=check_repo, method=["DELETE"]))
398
409
@@ -493,5 +504,4 b' def make_map(config):'
493 controller='followers', action='followers',
504 controller='followers', action='followers',
494 conditions=dict(function=check_repo))
505 conditions=dict(function=check_repo))
495
506
496
497 return rmap
507 return rmap
@@ -3,7 +3,7 b''
3 rhodecode.controllers.admin.repos
3 rhodecode.controllers.admin.repos
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Admin controller for RhodeCode
6 Repositories controller for RhodeCode
7
7
8 :created_on: Apr 7, 2010
8 :created_on: Apr 7, 2010
9 :author: marcink
9 :author: marcink
@@ -277,7 +277,6 b' class ReposController(BaseController):'
277
277
278 return redirect(url('repos'))
278 return redirect(url('repos'))
279
279
280
281 @HasRepoPermissionAllDecorator('repository.admin')
280 @HasRepoPermissionAllDecorator('repository.admin')
282 def delete_perm_user(self, repo_name):
281 def delete_perm_user(self, repo_name):
283 """
282 """
@@ -287,10 +286,11 b' class ReposController(BaseController):'
287 """
286 """
288
287
289 try:
288 try:
290 repo_model = RepoModel()
289 RepoModel().revoke_user_permission(repo=repo_name,
291 repo_model.delete_perm_user(request.POST, repo_name)
290 user=request.POST['user_id'])
292 Session.commit()
291 Session.commit()
293 except Exception, e:
292 except Exception:
293 log.error(traceback.format_exc())
294 h.flash(_('An error occurred during deletion of repository user'),
294 h.flash(_('An error occurred during deletion of repository user'),
295 category='error')
295 category='error')
296 raise HTTPInternalServerError()
296 raise HTTPInternalServerError()
@@ -302,11 +302,14 b' class ReposController(BaseController):'
302
302
303 :param repo_name:
303 :param repo_name:
304 """
304 """
305
305 try:
306 try:
306 repo_model = RepoModel()
307 RepoModel().revoke_users_group_permission(
307 repo_model.delete_perm_users_group(request.POST, repo_name)
308 repo=repo_name, group_name=request.POST['users_group_id']
309 )
308 Session.commit()
310 Session.commit()
309 except Exception, e:
311 except Exception:
312 log.error(traceback.format_exc())
310 h.flash(_('An error occurred during deletion of repository'
313 h.flash(_('An error occurred during deletion of repository'
311 ' users groups'),
314 ' users groups'),
312 category='error')
315 category='error')
@@ -321,8 +324,7 b' class ReposController(BaseController):'
321 """
324 """
322
325
323 try:
326 try:
324 repo_model = RepoModel()
327 RepoModel().delete_stats(repo_name)
325 repo_model.delete_stats(repo_name)
326 Session.commit()
328 Session.commit()
327 except Exception, e:
329 except Exception, e:
328 h.flash(_('An error occurred during deletion of repository stats'),
330 h.flash(_('An error occurred during deletion of repository stats'),
@@ -3,7 +3,7 b''
3 rhodecode.controllers.admin.repos_groups
3 rhodecode.controllers.admin.repos_groups
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 repos 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
@@ -29,19 +29,22 b' import formencode'
29
29
30 from formencode import htmlfill
30 from formencode import htmlfill
31
31
32 from pylons import request, response, session, tmpl_context as c, url
32 from pylons import request, tmpl_context as c, url
33 from pylons.controllers.util import abort, 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 from rhodecode.lib.base import BaseController, render
41 from rhodecode.lib.base import BaseController, render
41 from rhodecode.model.db import RepoGroup
42 from rhodecode.model.db import RepoGroup
42 from rhodecode.model.repos_group import ReposGroupModel
43 from rhodecode.model.repos_group import ReposGroupModel
43 from rhodecode.model.forms import ReposGroupForm
44 from rhodecode.model.forms import ReposGroupForm
44 from rhodecode.model.meta import Session
45 from rhodecode.model.meta import Session
46 from rhodecode.model.repo import RepoModel
47 from webob.exc import HTTPInternalServerError
45
48
46 log = logging.getLogger(__name__)
49 log = logging.getLogger(__name__)
47
50
@@ -60,6 +63,10 b' class ReposGroupsController(BaseControll'
60 c.repo_groups = RepoGroup.groups_choices()
63 c.repo_groups = RepoGroup.groups_choices()
61 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
64 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
62
65
66 repo_model = RepoModel()
67 c.users_array = repo_model.get_users_js()
68 c.users_groups_array = repo_model.get_users_groups_js()
69
63 def __load_data(self, group_id):
70 def __load_data(self, group_id):
64 """
71 """
65 Load defaults settings for edit, and update
72 Load defaults settings for edit, and update
@@ -74,13 +81,22 b' class ReposGroupsController(BaseControll'
74
81
75 data['group_name'] = repo_group.name
82 data['group_name'] = repo_group.name
76
83
84 # fill repository users
85 for p in repo_group.repo_group_to_perm:
86 data.update({'u_perm_%s' % p.user.username:
87 p.permission.permission_name})
88
89 # fill repository groups
90 for p in repo_group.users_group_to_perm:
91 data.update({'g_perm_%s' % p.users_group.users_group_name:
92 p.permission.permission_name})
93
77 return data
94 return data
78
95
79 @HasPermissionAnyDecorator('hg.admin')
96 @HasPermissionAnyDecorator('hg.admin')
80 def index(self, format='html'):
97 def index(self, format='html'):
81 """GET /repos_groups: All items in the collection"""
98 """GET /repos_groups: All items in the collection"""
82 # url('repos_groups')
99 # url('repos_groups')
83
84 sk = lambda g: g.parents[0].group_name if g.parents else g.group_name
100 sk = lambda g: g.parents[0].group_name if g.parents else g.group_name
85 c.groups = sorted(RepoGroup.query().all(), key=sk)
101 c.groups = sorted(RepoGroup.query().all(), key=sk)
86 return render('admin/repos_groups/repos_groups_show.html')
102 return render('admin/repos_groups/repos_groups_show.html')
@@ -94,7 +110,11 b' class ReposGroupsController(BaseControll'
94 c.repo_groups_choices)()
110 c.repo_groups_choices)()
95 try:
111 try:
96 form_result = repos_group_form.to_python(dict(request.POST))
112 form_result = repos_group_form.to_python(dict(request.POST))
97 ReposGroupModel().create(form_result)
113 ReposGroupModel().create(
114 group_name=form_result['group_name'],
115 group_description=form_result['group_description'],
116 parent=form_result['group_parent_id']
117 )
98 Session.commit()
118 Session.commit()
99 h.flash(_('created repos group %s') \
119 h.flash(_('created repos group %s') \
100 % form_result['group_name'], category='success')
120 % form_result['group_name'], category='success')
@@ -134,10 +154,11 b' class ReposGroupsController(BaseControll'
134 self.__load_defaults()
154 self.__load_defaults()
135 c.repos_group = RepoGroup.get(id)
155 c.repos_group = RepoGroup.get(id)
136
156
137 repos_group_form = ReposGroupForm(edit=True,
157 repos_group_form = ReposGroupForm(
138 old_data=c.repos_group.get_dict(),
158 edit=True,
139 available_groups=
159 old_data=c.repos_group.get_dict(),
140 c.repo_groups_choices)()
160 available_groups=c.repo_groups_choices
161 )()
141 try:
162 try:
142 form_result = repos_group_form.to_python(dict(request.POST))
163 form_result = repos_group_form.to_python(dict(request.POST))
143 ReposGroupModel().update(id, form_result)
164 ReposGroupModel().update(id, form_result)
@@ -201,10 +222,52 b' class ReposGroupsController(BaseControll'
201
222
202 return redirect(url('repos_groups'))
223 return redirect(url('repos_groups'))
203
224
225 @HasReposGroupPermissionAnyDecorator('group.admin')
226 def delete_repos_group_user_perm(self, group_name):
227 """
228 DELETE an existing repositories group permission user
229
230 :param group_name:
231 """
232
233 try:
234 ReposGroupModel().revoke_user_permission(
235 repos_group=group_name, user=request.POST['user_id']
236 )
237 Session.commit()
238 except Exception:
239 log.error(traceback.format_exc())
240 h.flash(_('An error occurred during deletion of group user'),
241 category='error')
242 raise HTTPInternalServerError()
243
244 @HasReposGroupPermissionAnyDecorator('group.admin')
245 def delete_repos_group_users_group_perm(self, group_name):
246 """
247 DELETE an existing repositories group permission users group
248
249 :param group_name:
250 """
251
252 try:
253 ReposGroupModel().revoke_users_group_permission(
254 repos_group=group_name,
255 group_name=request.POST['users_group_id']
256 )
257 Session.commit()
258 except Exception:
259 log.error(traceback.format_exc())
260 h.flash(_('An error occurred during deletion of group'
261 ' users groups'),
262 category='error')
263 raise HTTPInternalServerError()
264
204 def show_by_name(self, group_name):
265 def show_by_name(self, group_name):
205 id_ = RepoGroup.get_by_group_name(group_name).group_id
266 id_ = RepoGroup.get_by_group_name(group_name).group_id
206 return self.show(id_)
267 return self.show(id_)
207
268
269 @HasReposGroupPermissionAnyDecorator('group.read', 'group.write',
270 'group.admin')
208 def show(self, id, format='html'):
271 def show(self, id, format='html'):
209 """GET /repos_groups/id: Show a specific item"""
272 """GET /repos_groups/id: Show a specific item"""
210 # url('repos_group', id=ID)
273 # url('repos_group', id=ID)
@@ -240,7 +303,7 b' class ReposGroupsController(BaseControll'
240 defaults = self.__load_data(id_)
303 defaults = self.__load_data(id_)
241
304
242 # we need to exclude this group from the group list for editing
305 # we need to exclude this group from the group list for editing
243 c.repo_groups = filter(lambda x:x[0] != id_, c.repo_groups)
306 c.repo_groups = filter(lambda x: x[0] != id_, c.repo_groups)
244
307
245 return htmlfill.render(
308 return htmlfill.render(
246 render('admin/repos_groups/repos_groups_edit.html'),
309 render('admin/repos_groups/repos_groups_edit.html'),
@@ -401,13 +401,7 b' class ApiController(JSONRPCController):'
401 for g in groups:
401 for g in groups:
402 group = RepoGroup.get_by_group_name(g)
402 group = RepoGroup.get_by_group_name(g)
403 if not group:
403 if not group:
404 group = ReposGroupModel().create(
404 group = ReposGroupModel().create(g, '', parent_id)
405 dict(
406 group_name=g,
407 group_description='',
408 group_parent_id=parent_id
409 )
410 )
411 parent_id = group.group_id
405 parent_id = group.group_id
412
406
413 repo = RepoModel().create(
407 repo = RepoModel().create(
@@ -434,11 +428,11 b' class ApiController(JSONRPCController):'
434 raise JSONRPCError('failed to create repository %s' % repo_name)
428 raise JSONRPCError('failed to create repository %s' % repo_name)
435
429
436 @HasPermissionAnyDecorator('hg.admin')
430 @HasPermissionAnyDecorator('hg.admin')
437 def add_user_to_repo(self, apiuser, repo_name, username, perm):
431 def grant_user_permission(self, repo_name, username, perm):
438 """
432 """
439 Add permission for a user to a repository
433 Grant permission for user on given repository, or update existing one
434 if found
440
435
441 :param apiuser:
442 :param repo_name:
436 :param repo_name:
443 :param username:
437 :param username:
444 :param perm:
438 :param perm:
@@ -449,17 +443,15 b' class ApiController(JSONRPCController):'
449 if repo is None:
443 if repo is None:
450 raise JSONRPCError('unknown repository %s' % repo)
444 raise JSONRPCError('unknown repository %s' % repo)
451
445
452 try:
446 user = User.get_by_username(username)
453 user = User.get_by_username(username)
447 if user is None:
454 except NoResultFound:
448 raise JSONRPCError('unknown user %s' % username)
455 raise JSONRPCError('unknown user %s' % user)
456
449
457 RepositoryPermissionModel()\
450 RepoModel().grant_user_permission(repo=repo, user=user, perm=perm)
458 .update_or_delete_user_permission(repo, user, perm)
451
459 Session.commit()
452 Session.commit()
460
461 return dict(
453 return dict(
462 msg='Added perm: %s for %s in repo: %s' % (
454 msg='Granted perm: %s for user: %s in repo: %s' % (
463 perm, username, repo_name
455 perm, username, repo_name
464 )
456 )
465 )
457 )
@@ -472,11 +464,45 b' class ApiController(JSONRPCController):'
472 )
464 )
473
465
474 @HasPermissionAnyDecorator('hg.admin')
466 @HasPermissionAnyDecorator('hg.admin')
475 def add_users_group_to_repo(self, apiuser, repo_name, group_name, perm):
467 def revoke_user_permission(self, repo_name, username):
468 """
469 Revoke permission for user on given repository
470
471 :param repo_name:
472 :param username:
476 """
473 """
477 Add permission for a users group to a repository
474
475 try:
476 repo = Repository.get_by_repo_name(repo_name)
477 if repo is None:
478 raise JSONRPCError('unknown repository %s' % repo)
479
480 user = User.get_by_username(username)
481 if user is None:
482 raise JSONRPCError('unknown user %s' % username)
483
484 RepoModel().revoke_user_permission(repo=repo_name, user=username)
478
485
479 :param apiuser:
486 Session.commit()
487 return dict(
488 msg='Revoked perm for user: %s in repo: %s' % (
489 username, repo_name
490 )
491 )
492 except Exception:
493 log.error(traceback.format_exc())
494 raise JSONRPCError(
495 'failed to edit permission %(repo)s for %(user)s' % dict(
496 user=username, repo=repo_name
497 )
498 )
499
500 @HasPermissionAnyDecorator('hg.admin')
501 def grant_users_group_permission(self, repo_name, group_name, perm):
502 """
503 Grant permission for users group on given repository, or update
504 existing one if found
505
480 :param repo_name:
506 :param repo_name:
481 :param group_name:
507 :param group_name:
482 :param perm:
508 :param perm:
@@ -487,24 +513,59 b' class ApiController(JSONRPCController):'
487 if repo is None:
513 if repo is None:
488 raise JSONRPCError('unknown repository %s' % repo)
514 raise JSONRPCError('unknown repository %s' % repo)
489
515
490 try:
516 user_group = UsersGroup.get_by_group_name(group_name)
491 user_group = UsersGroup.get_by_group_name(group_name)
517 if user_group is None:
492 except NoResultFound:
493 raise JSONRPCError('unknown users group %s' % user_group)
518 raise JSONRPCError('unknown users group %s' % user_group)
494
519
495 RepositoryPermissionModel()\
520 RepoModel().grant_users_group_permission(repo=repo_name,
496 .update_or_delete_users_group_permission(repo, user_group,
521 group_name=group_name,
497 perm)
522 perm=perm)
523
498 Session.commit()
524 Session.commit()
499 return dict(
525 return dict(
500 msg='Added perm: %s for %s in repo: %s' % (
526 msg='Granted perm: %s for group: %s in repo: %s' % (
501 perm, group_name, repo_name
527 perm, group_name, repo_name
502 )
528 )
503 )
529 )
504 except Exception:
530 except Exception:
505 log.error(traceback.format_exc())
531 log.error(traceback.format_exc())
506 raise JSONRPCError(
532 raise JSONRPCError(
507 'failed to edit permission %(repo)s for %(usergr)s' % dict(
533 'failed to edit permission %(repo)s for %(usersgr)s' % dict(
508 usergr=group_name, repo=repo_name
534 usersgr=group_name, repo=repo_name
509 )
535 )
510 )
536 )
537
538 @HasPermissionAnyDecorator('hg.admin')
539 def revoke_users_group_permission(self, repo_name, group_name):
540 """
541 Revoke permission for users group on given repository
542
543 :param repo_name:
544 :param group_name:
545 """
546
547 try:
548 repo = Repository.get_by_repo_name(repo_name)
549 if repo is None:
550 raise JSONRPCError('unknown repository %s' % repo)
551
552 user_group = UsersGroup.get_by_group_name(group_name)
553 if user_group is None:
554 raise JSONRPCError('unknown users group %s' % user_group)
555
556 RepoModel().revoke_users_group_permission(repo=repo_name,
557 group_name=group_name)
558
559 Session.commit()
560 return dict(
561 msg='Revoked perm for group: %s in repo: %s' % (
562 group_name, repo_name
563 )
564 )
565 except Exception:
566 log.error(traceback.format_exc())
567 raise JSONRPCError(
568 'failed to edit permission %(repo)s for %(usersgr)s' % dict(
569 usersgr=group_name, repo=repo_name
570 )
571 )
@@ -30,7 +30,7 b' from paste.httpexceptions import HTTPBad'
30
30
31 from rhodecode.lib.auth import LoginRequired
31 from rhodecode.lib.auth import LoginRequired
32 from rhodecode.lib.base import BaseController, render
32 from rhodecode.lib.base import BaseController, render
33 from rhodecode.model.db import RepoGroup, Repository
33 from rhodecode.model.db import Repository
34
34
35 log = logging.getLogger(__name__)
35 log = logging.getLogger(__name__)
36
36
@@ -42,11 +42,8 b' class HomeController(BaseController):'
42 super(HomeController, self).__before__()
42 super(HomeController, self).__before__()
43
43
44 def index(self):
44 def index(self):
45
46 c.repos_list = self.scm_model.get_repos()
45 c.repos_list = self.scm_model.get_repos()
47
46 c.groups = self.scm_model.get_repos_groups()
48 c.groups = RepoGroup.query()\
49 .filter(RepoGroup.group_parent_id == None).all()
50
47
51 return render('/index.html')
48 return render('/index.html')
52
49
@@ -25,6 +25,8 b''
25
25
26 import os
26 import os
27 import re
27 import re
28 from vcs.utils.lazy import LazyProperty
29
28
30
29 def __get_lem():
31 def __get_lem():
30 from pygments import lexers
32 from pygments import lexers
@@ -213,6 +215,7 b" def safe_unicode(str_, from_encoding='ut"
213 except (ImportError, UnicodeDecodeError, Exception):
215 except (ImportError, UnicodeDecodeError, Exception):
214 return unicode(str_, from_encoding, 'replace')
216 return unicode(str_, from_encoding, 'replace')
215
217
218
216 def safe_str(unicode_, to_encoding='utf8'):
219 def safe_str(unicode_, to_encoding='utf8'):
217 """
220 """
218 safe str function. Does few trick to turn unicode_ into string
221 safe str function. Does few trick to turn unicode_ into string
@@ -250,7 +253,6 b" def safe_str(unicode_, to_encoding='utf8"
250 return safe_str
253 return safe_str
251
254
252
255
253
254 def engine_from_config(configuration, prefix='sqlalchemy.', **kwargs):
256 def engine_from_config(configuration, prefix='sqlalchemy.', **kwargs):
255 """
257 """
256 Custom engine_from_config functions that makes sure we use NullPool for
258 Custom engine_from_config functions that makes sure we use NullPool for
@@ -393,6 +395,7 b' def credentials_filter(uri):'
393
395
394 return ''.join(uri)
396 return ''.join(uri)
395
397
398
396 def get_changeset_safe(repo, rev):
399 def get_changeset_safe(repo, rev):
397 """
400 """
398 Safe version of get_changeset if this changeset doesn't exists for a
401 Safe version of get_changeset if this changeset doesn't exists for a
@@ -437,6 +440,7 b' def get_current_revision(quiet=False):'
437 "was: %s" % err)
440 "was: %s" % err)
438 return None
441 return None
439
442
443
440 def extract_mentioned_users(s):
444 def extract_mentioned_users(s):
441 """
445 """
442 Returns unique usernames from given string s that have @mention
446 Returns unique usernames from given string s that have @mention
@@ -31,7 +31,7 b' import hashlib'
31 from tempfile import _RandomNameSequence
31 from tempfile import _RandomNameSequence
32 from decorator import decorator
32 from decorator import decorator
33
33
34 from pylons import config, session, url, request
34 from pylons import config, url, request
35 from pylons.controllers.util import abort, redirect
35 from pylons.controllers.util import abort, redirect
36 from pylons.i18n.translation import _
36 from pylons.i18n.translation import _
37
37
@@ -45,7 +45,7 b' if __platform__ in PLATFORM_OTHERS:'
45
45
46 from rhodecode.lib import str2bool, safe_unicode
46 from rhodecode.lib import str2bool, safe_unicode
47 from rhodecode.lib.exceptions import LdapPasswordError, LdapUsernameError
47 from rhodecode.lib.exceptions import LdapPasswordError, LdapUsernameError
48 from rhodecode.lib.utils import get_repo_slug
48 from rhodecode.lib.utils import get_repo_slug, get_repos_group_slug
49 from rhodecode.lib.auth_ldap import AuthLdap
49 from rhodecode.lib.auth_ldap import AuthLdap
50
50
51 from rhodecode.model import meta
51 from rhodecode.model import meta
@@ -80,8 +80,8 b' class PasswordGenerator(object):'
80 def __init__(self, passwd=''):
80 def __init__(self, passwd=''):
81 self.passwd = passwd
81 self.passwd = passwd
82
82
83 def gen_password(self, len, type):
83 def gen_password(self, length, type_):
84 self.passwd = ''.join([random.choice(type) for _ in xrange(len)])
84 self.passwd = ''.join([random.choice(type_) for _ in xrange(length)])
85 return self.passwd
85 return self.passwd
86
86
87
87
@@ -575,6 +575,41 b' class HasRepoPermissionAnyDecorator(Perm'
575 return False
575 return False
576
576
577
577
578 class HasReposGroupPermissionAllDecorator(PermsDecorator):
579 """
580 Checks for access permission for all given predicates for specific
581 repository. All of them have to be meet in order to fulfill the request
582 """
583
584 def check_permissions(self):
585 group_name = get_repos_group_slug(request)
586 try:
587 user_perms = set([self.user_perms['repositories_groups'][group_name]])
588 except KeyError:
589 return False
590 if self.required_perms.issubset(user_perms):
591 return True
592 return False
593
594
595 class HasReposGroupPermissionAnyDecorator(PermsDecorator):
596 """
597 Checks for access permission for any of given predicates for specific
598 repository. In order to fulfill the request any of predicates must be meet
599 """
600
601 def check_permissions(self):
602 group_name = get_repos_group_slug(request)
603
604 try:
605 user_perms = set([self.user_perms['repositories_groups'][group_name]])
606 except KeyError:
607 return False
608 if self.required_perms.intersection(user_perms):
609 return True
610 return False
611
612
578 #==============================================================================
613 #==============================================================================
579 # CHECK FUNCTIONS
614 # CHECK FUNCTIONS
580 #==============================================================================
615 #==============================================================================
@@ -641,8 +676,9 b' class HasRepoPermissionAll(PermsFunction'
641 self.repo_name = get_repo_slug(request)
676 self.repo_name = get_repo_slug(request)
642
677
643 try:
678 try:
644 self.user_perms = set([self.user_perms['reposit'
679 self.user_perms = set(
645 'ories'][self.repo_name]])
680 [self.user_perms['repositories'][self.repo_name]]
681 )
646 except KeyError:
682 except KeyError:
647 return False
683 return False
648 self.granted_for = self.repo_name
684 self.granted_for = self.repo_name
@@ -662,8 +698,9 b' class HasRepoPermissionAny(PermsFunction'
662 self.repo_name = get_repo_slug(request)
698 self.repo_name = get_repo_slug(request)
663
699
664 try:
700 try:
665 self.user_perms = set([self.user_perms['reposi'
701 self.user_perms = set(
666 'tories'][self.repo_name]])
702 [self.user_perms['repositories'][self.repo_name]]
703 )
667 except KeyError:
704 except KeyError:
668 return False
705 return False
669 self.granted_for = self.repo_name
706 self.granted_for = self.repo_name
@@ -672,6 +709,42 b' class HasRepoPermissionAny(PermsFunction'
672 return False
709 return False
673
710
674
711
712 class HasReposGroupPermissionAny(PermsFunction):
713 def __call__(self, group_name=None, check_Location=''):
714 self.group_name = group_name
715 return super(HasReposGroupPermissionAny, self).__call__(check_Location)
716
717 def check_permissions(self):
718 try:
719 self.user_perms = set(
720 [self.user_perms['repositories_groups'][self.group_name]]
721 )
722 except KeyError:
723 return False
724 self.granted_for = self.repo_name
725 if self.required_perms.intersection(self.user_perms):
726 return True
727 return False
728
729
730 class HasReposGroupPermissionAll(PermsFunction):
731 def __call__(self, group_name=None, check_Location=''):
732 self.group_name = group_name
733 return super(HasReposGroupPermissionAny, self).__call__(check_Location)
734
735 def check_permissions(self):
736 try:
737 self.user_perms = set(
738 [self.user_perms['repositories_groups'][self.group_name]]
739 )
740 except KeyError:
741 return False
742 self.granted_for = self.repo_name
743 if self.required_perms.issubset(self.user_perms):
744 return True
745 return False
746
747
675 #==============================================================================
748 #==============================================================================
676 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
749 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
677 #==============================================================================
750 #==============================================================================
@@ -442,23 +442,28 b' class DbManage(object):'
442
442
443 def create_permissions(self):
443 def create_permissions(self):
444 # module.(access|create|change|delete)_[name]
444 # module.(access|create|change|delete)_[name]
445 # module.(read|write|owner)
445 # module.(none|read|write|admin)
446 perms = [('repository.none', 'Repository no access'),
446 perms = [
447 ('repository.read', 'Repository read access'),
447 ('repository.none', 'Repository no access'),
448 ('repository.write', 'Repository write access'),
448 ('repository.read', 'Repository read access'),
449 ('repository.admin', 'Repository admin access'),
449 ('repository.write', 'Repository write access'),
450 ('hg.admin', 'Hg Administrator'),
450 ('repository.admin', 'Repository admin access'),
451 ('hg.create.repository', 'Repository create'),
452 ('hg.create.none', 'Repository creation disabled'),
453 ('hg.register.none', 'Register disabled'),
454 ('hg.register.manual_activate', 'Register new user with '
455 'RhodeCode without manual'
456 'activation'),
457
451
458 ('hg.register.auto_activate', 'Register new user with '
452 ('group.none', 'Repositories Group no access'),
459 'RhodeCode without auto '
453 ('group.read', 'Repositories Group read access'),
460 'activation'),
454 ('group.write', 'Repositories Group write access'),
461 ]
455 ('group.admin', 'Repositories Group admin access'),
456
457 ('hg.admin', 'Hg Administrator'),
458 ('hg.create.repository', 'Repository create'),
459 ('hg.create.none', 'Repository creation disabled'),
460 ('hg.register.none', 'Register disabled'),
461 ('hg.register.manual_activate', 'Register new user with RhodeCode '
462 'without manual activation'),
463
464 ('hg.register.auto_activate', 'Register new user with RhodeCode '
465 'without auto activation'),
466 ]
462
467
463 for p in perms:
468 for p in perms:
464 new_perm = Permission()
469 new_perm = Permission()
@@ -130,7 +130,7 b' def log_create_repository(repository_dic'
130 Post create repository Hook. This is a dummy function for admins to re-use
130 Post create repository Hook. This is a dummy function for admins to re-use
131 if needed
131 if needed
132
132
133 :param repository: dict dump of repository object
133 :param repository: dict dump of repository object
134 :param created_by: username who created repository
134 :param created_by: username who created repository
135 :param created_date: date of creation
135 :param created_date: date of creation
136
136
@@ -152,4 +152,4 b' def log_create_repository(repository_dic'
152 """
152 """
153
153
154
154
155 return 0 No newline at end of file
155 return 0
@@ -52,6 +52,7 b' from rhodecode.model import meta'
52 from rhodecode.model.db import Repository, User, RhodeCodeUi, \
52 from rhodecode.model.db import Repository, User, RhodeCodeUi, \
53 UserLog, RepoGroup, RhodeCodeSetting
53 UserLog, RepoGroup, RhodeCodeSetting
54 from rhodecode.model.meta import Session
54 from rhodecode.model.meta import Session
55 from rhodecode.model.repos_group import ReposGroupModel
55
56
56 log = logging.getLogger(__name__)
57 log = logging.getLogger(__name__)
57
58
@@ -94,6 +95,10 b' def get_repo_slug(request):'
94 return request.environ['pylons.routes_dict'].get('repo_name')
95 return request.environ['pylons.routes_dict'].get('repo_name')
95
96
96
97
98 def get_repos_group_slug(request):
99 return request.environ['pylons.routes_dict'].get('group_name')
100
101
97 def action_logger(user, action, repo, ipaddr='', sa=None, commit=False):
102 def action_logger(user, action, repo, ipaddr='', sa=None, commit=False):
98 """
103 """
99 Action logger for various actions made by users
104 Action logger for various actions made by users
@@ -197,6 +202,7 b' def is_valid_repo(repo_name, base_path):'
197 except VCSError:
202 except VCSError:
198 return False
203 return False
199
204
205
200 def is_valid_repos_group(repos_group_name, base_path):
206 def is_valid_repos_group(repos_group_name, base_path):
201 """
207 """
202 Returns True if given path is a repos group False otherwise
208 Returns True if given path is a repos group False otherwise
@@ -216,6 +222,7 b' def is_valid_repos_group(repos_group_nam'
216
222
217 return False
223 return False
218
224
225
219 def ask_ok(prompt, retries=4, complaint='Yes or no, please!'):
226 def ask_ok(prompt, retries=4, complaint='Yes or no, please!'):
220 while True:
227 while True:
221 ok = raw_input(prompt)
228 ok = raw_input(prompt)
@@ -317,7 +324,8 b' class EmptyChangeset(BaseChangeset):'
317 an EmptyChangeset
324 an EmptyChangeset
318 """
325 """
319
326
320 def __init__(self, cs='0' * 40, repo=None, requested_revision=None, alias=None):
327 def __init__(self, cs='0' * 40, repo=None, requested_revision=None,
328 alias=None):
321 self._empty_cs = cs
329 self._empty_cs = cs
322 self.revision = -1
330 self.revision = -1
323 self.message = ''
331 self.message = ''
@@ -368,14 +376,23 b' def map_groups(groups):'
368
376
369 # last element is repo in nested groups structure
377 # last element is repo in nested groups structure
370 groups = groups[:-1]
378 groups = groups[:-1]
371
379 rgm = ReposGroupModel(sa)
372 for lvl, group_name in enumerate(groups):
380 for lvl, group_name in enumerate(groups):
381 log.debug('creating group level: %s group_name: %s' % (lvl, group_name))
373 group_name = '/'.join(groups[:lvl] + [group_name])
382 group_name = '/'.join(groups[:lvl] + [group_name])
374 group = sa.query(RepoGroup).filter(RepoGroup.group_name == group_name).scalar()
383 group = RepoGroup.get_by_group_name(group_name)
384 desc = '%s group' % group_name
385
386 # # WTF that doesn't work !?
387 # if group is None:
388 # group = rgm.create(group_name, desc, parent, just_db=True)
389 # sa.commit()
375
390
376 if group is None:
391 if group is None:
377 group = RepoGroup(group_name, parent)
392 group = RepoGroup(group_name, parent)
393 group.group_description = desc
378 sa.add(group)
394 sa.add(group)
395 rgm._create_default_perms(group)
379 sa.commit()
396 sa.commit()
380 parent = group
397 parent = group
381 return group
398 return group
@@ -404,15 +421,14 b' def repo2db_mapper(initial_repo_list, re'
404 log.info('repository %s not found creating default' % name)
421 log.info('repository %s not found creating default' % name)
405 added.append(name)
422 added.append(name)
406 form_data = {
423 form_data = {
407 'repo_name': name,
424 'repo_name': name,
408 'repo_name_full': name,
425 'repo_name_full': name,
409 'repo_type': repo.alias,
426 'repo_type': repo.alias,
410 'description': repo.description \
427 'description': repo.description \
411 if repo.description != 'unknown' else \
428 if repo.description != 'unknown' else '%s repository' % name,
412 '%s repository' % name,
429 'private': False,
413 'private': False,
430 'group_id': getattr(group, 'group_id', None)
414 'group_id': getattr(group, 'group_id', None)
431 }
415 }
416 rm.create(form_data, user, just_db=True)
432 rm.create(form_data, user, just_db=True)
417 sa.commit()
433 sa.commit()
418 removed = []
434 removed = []
@@ -426,6 +442,7 b' def repo2db_mapper(initial_repo_list, re'
426
442
427 return added, removed
443 return added, removed
428
444
445
429 # set cache regions for beaker so celery can utilise it
446 # set cache regions for beaker so celery can utilise it
430 def add_cache(settings):
447 def add_cache(settings):
431 cache_settings = {'regions': None}
448 cache_settings = {'regions': None}
@@ -74,12 +74,13 b' class BaseModel(object):'
74 else:
74 else:
75 self.sa = meta.Session
75 self.sa = meta.Session
76
76
77 def _get_instance(self, cls, instance):
77 def _get_instance(self, cls, instance, callback=None):
78 """
78 """
79 Get's instance of given cls using some simple lookup mechanism
79 Get's instance of given cls using some simple lookup mechanism.
80
80
81 :param cls: class to fetch
81 :param cls: class to fetch
82 :param instance: int or Instance
82 :param instance: int or Instance
83 :param callback: callback to call if all lookups failed
83 """
84 """
84
85
85 if isinstance(instance, cls):
86 if isinstance(instance, cls):
@@ -88,5 +89,10 b' class BaseModel(object):'
88 return cls.get(instance)
89 return cls.get(instance)
89 else:
90 else:
90 if instance:
91 if instance:
91 raise Exception('given object must be int or Instance'
92 if callback is None:
92 ' of %s got %s' % (type(cls), type(instance)))
93 raise Exception(
94 'given object must be int or Instance of %s got %s, '
95 'no callback provided' % (cls, type(instance))
96 )
97 else:
98 return callback(instance)
@@ -717,6 +717,9 b' class RepoGroup(Base, BaseModel):'
717 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
717 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
718 group_description = Column("group_description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
718 group_description = Column("group_description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
719
719
720 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
721 users_group_to_perm = relationship('UsersGroupRepoGroupToPerm', cascade='all')
722
720 parent_group = relationship('RepoGroup', remote_side=group_id)
723 parent_group = relationship('RepoGroup', remote_side=group_id)
721
724
722 def __init__(self, group_name='', parent_group=None):
725 def __init__(self, group_name='', parent_group=None):
@@ -833,8 +836,9 b' class Permission(Base, BaseModel):'
833 permission_longname = Column("permission_longname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
836 permission_longname = Column("permission_longname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
834
837
835 def __repr__(self):
838 def __repr__(self):
836 return "<%s('%s:%s')>" % (self.__class__.__name__,
839 return "<%s('%s:%s')>" % (
837 self.permission_id, self.permission_name)
840 self.__class__.__name__, self.permission_id, self.permission_name
841 )
838
842
839 @classmethod
843 @classmethod
840 def get_by_key(cls, key):
844 def get_by_key(cls, key):
@@ -843,9 +847,18 b' class Permission(Base, BaseModel):'
843 @classmethod
847 @classmethod
844 def get_default_perms(cls, default_user_id):
848 def get_default_perms(cls, default_user_id):
845 q = Session.query(UserRepoToPerm, Repository, cls)\
849 q = Session.query(UserRepoToPerm, Repository, cls)\
846 .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
850 .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
847 .join((cls, UserRepoToPerm.permission_id == cls.permission_id))\
851 .join((cls, UserRepoToPerm.permission_id == cls.permission_id))\
848 .filter(UserRepoToPerm.user_id == default_user_id)
852 .filter(UserRepoToPerm.user_id == default_user_id)
853
854 return q.all()
855
856 @classmethod
857 def get_default_group_perms(cls, default_user_id):
858 q = Session.query(UserRepoGroupToPerm, RepoGroup, cls)\
859 .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
860 .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id))\
861 .filter(UserRepoGroupToPerm.user_id == default_user_id)
849
862
850 return q.all()
863 return q.all()
851
864
@@ -388,57 +388,66 b' def ValidForkType(old_data):'
388 return _ValidForkType
388 return _ValidForkType
389
389
390
390
391 class ValidPerms(formencode.validators.FancyValidator):
391 def ValidPerms(type_='repo'):
392 messages = {'perm_new_member_name': _('This username or users group name'
392 if type_ == 'group':
393 ' is not valid')}
393 EMPTY_PERM = 'group.none'
394 elif type_ == 'repo':
395 EMPTY_PERM = 'repository.none'
394
396
395 def to_python(self, value, state):
397 class _ValidPerms(formencode.validators.FancyValidator):
396 perms_update = []
398 messages = {
397 perms_new = []
399 'perm_new_member_name':
398 #build a list of permission to update and new permission to create
400 _('This username or users group name is not valid')
399 for k, v in value.items():
401 }
400 #means new added member to permissions
402
401 if k.startswith('perm_new_member'):
403 def to_python(self, value, state):
402 new_perm = value.get('perm_new_member', False)
404 perms_update = []
403 new_member = value.get('perm_new_member_name', False)
405 perms_new = []
404 new_type = value.get('perm_new_member_type')
406 # build a list of permission to update and new permission to create
407 for k, v in value.items():
408 # means new added member to permissions
409 if k.startswith('perm_new_member'):
410 new_perm = value.get('perm_new_member', False)
411 new_member = value.get('perm_new_member_name', False)
412 new_type = value.get('perm_new_member_type')
405
413
406 if new_member and new_perm:
414 if new_member and new_perm:
407 if (new_member, new_perm, new_type) not in perms_new:
415 if (new_member, new_perm, new_type) not in perms_new:
408 perms_new.append((new_member, new_perm, new_type))
416 perms_new.append((new_member, new_perm, new_type))
409 elif k.startswith('u_perm_') or k.startswith('g_perm_'):
417 elif k.startswith('u_perm_') or k.startswith('g_perm_'):
410 member = k[7:]
418 member = k[7:]
411 t = {'u': 'user',
419 t = {'u': 'user',
412 'g': 'users_group'
420 'g': 'users_group'
413 }[k[0]]
421 }[k[0]]
414 if member == 'default':
422 if member == 'default':
415 if value['private']:
423 if value.get('private'):
416 #set none for default when updating to private repo
424 # set none for default when updating to private repo
417 v = 'repository.none'
425 v = EMPTY_PERM
418 perms_update.append((member, v, t))
426 perms_update.append((member, v, t))
419
427
420 value['perms_updates'] = perms_update
428 value['perms_updates'] = perms_update
421 value['perms_new'] = perms_new
429 value['perms_new'] = perms_new
422
430
423 #update permissions
431 # update permissions
424 for k, v, t in perms_new:
432 for k, v, t in perms_new:
425 try:
433 try:
426 if t is 'user':
434 if t is 'user':
427 self.user_db = User.query()\
435 self.user_db = User.query()\
428 .filter(User.active == True)\
436 .filter(User.active == True)\
429 .filter(User.username == k).one()
437 .filter(User.username == k).one()
430 if t is 'users_group':
438 if t is 'users_group':
431 self.user_db = UsersGroup.query()\
439 self.user_db = UsersGroup.query()\
432 .filter(UsersGroup.users_group_active == True)\
440 .filter(UsersGroup.users_group_active == True)\
433 .filter(UsersGroup.users_group_name == k).one()
441 .filter(UsersGroup.users_group_name == k).one()
434
442
435 except Exception:
443 except Exception:
436 msg = self.message('perm_new_member_name',
444 msg = self.message('perm_new_member_name',
437 state=State_obj)
445 state=State_obj)
438 raise formencode.Invalid(
446 raise formencode.Invalid(
439 msg, value, state, error_dict={'perm_new_member_name': msg}
447 msg, value, state, error_dict={'perm_new_member_name': msg}
440 )
448 )
441 return value
449 return value
450 return _ValidPerms
442
451
443
452
444 class ValidSettings(formencode.validators.FancyValidator):
453 class ValidSettings(formencode.validators.FancyValidator):
@@ -588,7 +597,7 b' def UsersGroupForm(edit=False, old_data='
588 def ReposGroupForm(edit=False, old_data={}, available_groups=[]):
597 def ReposGroupForm(edit=False, old_data={}, available_groups=[]):
589 class _ReposGroupForm(formencode.Schema):
598 class _ReposGroupForm(formencode.Schema):
590 allow_extra_fields = True
599 allow_extra_fields = True
591 filter_extra_fields = True
600 filter_extra_fields = False
592
601
593 group_name = All(UnicodeString(strip=True, min=1, not_empty=True),
602 group_name = All(UnicodeString(strip=True, min=1, not_empty=True),
594 SlugifyName())
603 SlugifyName())
@@ -598,7 +607,7 b' def ReposGroupForm(edit=False, old_data='
598 testValueList=True,
607 testValueList=True,
599 if_missing=None, not_empty=False)
608 if_missing=None, not_empty=False)
600
609
601 chained_validators = [ValidReposGroup(edit, old_data)]
610 chained_validators = [ValidReposGroup(edit, old_data), ValidPerms('group')]
602
611
603 return _ReposGroupForm
612 return _ReposGroupForm
604
613
@@ -649,7 +658,7 b' def RepoForm(edit=False, old_data={}, su'
649 #this is repo owner
658 #this is repo owner
650 user = All(UnicodeString(not_empty=True), ValidRepoUser)
659 user = All(UnicodeString(not_empty=True), ValidRepoUser)
651
660
652 chained_validators = [ValidRepoName(edit, old_data), ValidPerms]
661 chained_validators = [ValidRepoName(edit, old_data), ValidPerms()]
653 return _RepoForm
662 return _RepoForm
654
663
655
664
@@ -683,7 +692,7 b' def RepoSettingsForm(edit=False, old_dat'
683 repo_group = OneOf(repo_groups, hideList=True)
692 repo_group = OneOf(repo_groups, hideList=True)
684 private = StringBoolean(if_missing=False)
693 private = StringBoolean(if_missing=False)
685
694
686 chained_validators = [ValidRepoName(edit, old_data), ValidPerms,
695 chained_validators = [ValidRepoName(edit, old_data), ValidPerms(),
687 ValidSettings]
696 ValidSettings]
688 return _RepoForm
697 return _RepoForm
689
698
@@ -42,10 +42,7 b' log = logging.getLogger(__name__)'
42 class NotificationModel(BaseModel):
42 class NotificationModel(BaseModel):
43
43
44 def __get_user(self, user):
44 def __get_user(self, user):
45 if isinstance(user, basestring):
45 return self._get_instance(User, user, callback=User.get_by_username)
46 return User.get_by_username(username=user)
47 else:
48 return self._get_instance(User, user)
49
46
50 def __get_notification(self, notification):
47 def __get_notification(self, notification):
51 if isinstance(notification, Notification):
48 if isinstance(notification, Notification):
@@ -28,9 +28,9 b' import logging'
28 import traceback
28 import traceback
29 from datetime import datetime
29 from datetime import datetime
30
30
31 from vcs.utils.lazy import LazyProperty
32 from vcs.backends import get_backend
31 from vcs.backends import get_backend
33
32
33 from rhodecode.lib import LazyProperty
34 from rhodecode.lib import safe_str, safe_unicode
34 from rhodecode.lib import 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
@@ -39,11 +39,31 b' 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
41
42
42 log = logging.getLogger(__name__)
43 log = logging.getLogger(__name__)
43
44
44
45
45 class RepoModel(BaseModel):
46 class RepoModel(BaseModel):
46
47
48 def __get_user(self, user):
49 return self._get_instance(User, user, callback=User.get_by_username)
50
51 def __get_users_group(self, users_group):
52 return self._get_instance(UsersGroup, users_group,
53 callback=UsersGroup.get_by_group_name)
54
55 def __get_repos_group(self, repos_group):
56 return self._get_instance(RepoGroup, repos_group,
57 callback=RepoGroup.get_by_group_name)
58
59 def __get_repo(self, repository):
60 return self._get_instance(Repository, repository,
61 callback=Repository.get_by_repo_name)
62
63 def __get_perm(self, permission):
64 return self._get_instance(Permission, permission,
65 callback=Permission.get_by_key)
66
47 @LazyProperty
67 @LazyProperty
48 def repos_path(self):
68 def repos_path(self):
49 """
69 """
@@ -138,49 +158,24 b' class RepoModel(BaseModel):'
138 # update permissions
158 # update permissions
139 for member, perm, member_type in form_data['perms_updates']:
159 for member, perm, member_type in form_data['perms_updates']:
140 if member_type == 'user':
160 if member_type == 'user':
141 _member = User.get_by_username(member)
161 # this updates existing one
142 r2p = self.sa.query(UserRepoToPerm)\
162 RepoModel().grant_user_permission(
143 .filter(UserRepoToPerm.user == _member)\
163 repo=cur_repo, user=member, perm=perm
144 .filter(UserRepoToPerm.repository == cur_repo)\
164 )
145 .one()
146
147 r2p.permission = self.sa.query(Permission)\
148 .filter(Permission.permission_name ==
149 perm).scalar()
150 self.sa.add(r2p)
151 else:
165 else:
152 g2p = self.sa.query(UsersGroupRepoToPerm)\
166 RepoModel().grant_users_group_permission(
153 .filter(UsersGroupRepoToPerm.users_group ==
167 repo=cur_repo, group_name=member, perm=perm
154 UsersGroup.get_by_group_name(member))\
168 )
155 .filter(UsersGroupRepoToPerm.repository ==
156 cur_repo).one()
157
158 g2p.permission = self.sa.query(Permission)\
159 .filter(Permission.permission_name ==
160 perm).scalar()
161 self.sa.add(g2p)
162
163 # set new permissions
169 # set new permissions
164 for member, perm, member_type in form_data['perms_new']:
170 for member, perm, member_type in form_data['perms_new']:
165 if member_type == 'user':
171 if member_type == 'user':
166 r2p = UserRepoToPerm()
172 RepoModel().grant_user_permission(
167 r2p.repository = cur_repo
173 repo=cur_repo, user=member, perm=perm
168 r2p.user = User.get_by_username(member)
174 )
169
170 r2p.permission = self.sa.query(Permission)\
171 .filter(Permission.
172 permission_name == perm)\
173 .scalar()
174 self.sa.add(r2p)
175 else:
175 else:
176 g2p = UsersGroupRepoToPerm()
176 RepoModel().grant_users_group_permission(
177 g2p.repository = cur_repo
177 repo=cur_repo, group_name=member, perm=perm
178 g2p.users_group = UsersGroup.get_by_group_name(member)
178 )
179 g2p.permission = self.sa.query(Permission)\
180 .filter(Permission.
181 permission_name == perm)\
182 .scalar()
183 self.sa.add(g2p)
184
179
185 # update current repo
180 # update current repo
186 for k, v in form_data.items():
181 for k, v in form_data.items():
@@ -314,28 +309,93 b' class RepoModel(BaseModel):'
314 log.error(traceback.format_exc())
309 log.error(traceback.format_exc())
315 raise
310 raise
316
311
317 def delete_perm_user(self, form_data, repo_name):
312 def grant_user_permission(self, repo, user, perm):
318 try:
313 """
319 obj = self.sa.query(UserRepoToPerm)\
314 Grant permission for user on given repository, or update existing one
320 .filter(UserRepoToPerm.repository \
315 if found
321 == self.get_by_repo_name(repo_name))\
316
322 .filter(UserRepoToPerm.user_id == form_data['user_id']).one()
317 :param repo: Instance of Repository, repository_id, or repository name
323 self.sa.delete(obj)
318 :param user: Instance of User, user_id or username
324 except:
319 :param perm: Instance of Permission, or permission_name
325 log.error(traceback.format_exc())
320 """
326 raise
321 user = self.__get_user(user)
322 repo = self.__get_repo(repo)
323 permission = self.__get_perm(perm)
324
325 # check if we have that permission already
326 obj = self.sa.query(UserRepoToPerm)\
327 .filter(UserRepoToPerm.user == user)\
328 .filter(UserRepoToPerm.repository == repo)\
329 .scalar()
330 if obj is None:
331 # create new !
332 obj = UserRepoToPerm()
333 obj.repository = repo
334 obj.user = user
335 obj.permission = permission
336 self.sa.add(obj)
337
338 def revoke_user_permission(self, repo, user):
339 """
340 Revoke permission for user on given repository
341
342 :param repo: Instance of Repository, repository_id, or repository name
343 :param user: Instance of User, user_id or username
344 """
345 user = self.__get_user(user)
346 repo = self.__get_repo(repo)
347
348 obj = self.sa.query(UserRepoToPerm)\
349 .filter(UserRepoToPerm.repository == repo)\
350 .filter(UserRepoToPerm.user == user)\
351 .one()
352 self.sa.delete(obj)
327
353
328 def delete_perm_users_group(self, form_data, repo_name):
354 def grant_users_group_permission(self, repo, group_name, perm):
329 try:
355 """
330 obj = self.sa.query(UsersGroupRepoToPerm)\
356 Grant permission for users group on given repository, or update
331 .filter(UsersGroupRepoToPerm.repository \
357 existing one if found
332 == self.get_by_repo_name(repo_name))\
358
333 .filter(UsersGroupRepoToPerm.users_group_id
359 :param repo: Instance of Repository, repository_id, or repository name
334 == form_data['users_group_id']).one()
360 :param group_name: Instance of UserGroup, users_group_id,
335 self.sa.delete(obj)
361 or users group name
336 except:
362 :param perm: Instance of Permission, or permission_name
337 log.error(traceback.format_exc())
363 """
338 raise
364 repo = self.__get_repo(repo)
365 group_name = self.__get_users_group(group_name)
366 permission = self.__get_perm(perm)
367
368 # check if we have that permission already
369 obj = self.sa.query(UsersGroupRepoToPerm)\
370 .filter(UsersGroupRepoToPerm.users_group == group_name)\
371 .filter(UsersGroupRepoToPerm.repository == repo)\
372 .scalar()
373
374 if obj is None:
375 # create new
376 obj = UsersGroupRepoToPerm()
377
378 obj.repository = repo
379 obj.users_group = group_name
380 obj.permission = permission
381 self.sa.add(obj)
382
383 def revoke_users_group_permission(self, repo, group_name):
384 """
385 Revoke permission for users group on given repository
386
387 :param repo: Instance of Repository, repository_id, or repository name
388 :param group_name: Instance of UserGroup, users_group_id,
389 or users group name
390 """
391 repo = self.__get_repo(repo)
392 group_name = self.__get_users_group(group_name)
393
394 obj = self.sa.query(UsersGroupRepoToPerm)\
395 .filter(UsersGroupRepoToPerm.repository == repo)\
396 .filter(UsersGroupRepoToPerm.users_group == group_name)\
397 .one()
398 self.sa.delete(obj)
339
399
340 def delete_stats(self, repo_name):
400 def delete_stats(self, repo_name):
341 """
401 """
@@ -345,8 +405,9 b' class RepoModel(BaseModel):'
345 """
405 """
346 try:
406 try:
347 obj = self.sa.query(Statistics)\
407 obj = self.sa.query(Statistics)\
348 .filter(Statistics.repository == \
408 .filter(Statistics.repository ==
349 self.get_by_repo_name(repo_name)).one()
409 self.get_by_repo_name(repo_name))\
410 .one()
350 self.sa.delete(obj)
411 self.sa.delete(obj)
351 except:
412 except:
352 log.error(traceback.format_exc())
413 log.error(traceback.format_exc())
@@ -373,10 +434,9 b' class RepoModel(BaseModel):'
373 new_parent_path = ''
434 new_parent_path = ''
374
435
375 # we need to make it str for mercurial
436 # we need to make it str for mercurial
376 repo_path = os.path.join(*map(lambda x:safe_str(x),
437 repo_path = os.path.join(*map(lambda x: safe_str(x),
377 [self.repos_path, new_parent_path, repo_name]))
438 [self.repos_path, new_parent_path, repo_name]))
378
439
379
380 # check if this path is not a repository
440 # check if this path is not a repository
381 if is_valid_repo(repo_path, self.repos_path):
441 if is_valid_repo(repo_path, self.repos_path):
382 raise Exception('This path %s is a valid repository' % repo_path)
442 raise Exception('This path %s is a valid repository' % repo_path)
@@ -393,7 +453,6 b' class RepoModel(BaseModel):'
393
453
394 backend(repo_path, create=True, src_url=clone_uri)
454 backend(repo_path, create=True, src_url=clone_uri)
395
455
396
397 def __rename_repo(self, old, new):
456 def __rename_repo(self, old, new):
398 """
457 """
399 renames repository on filesystem
458 renames repository on filesystem
@@ -406,8 +465,9 b' class RepoModel(BaseModel):'
406 old_path = os.path.join(self.repos_path, old)
465 old_path = os.path.join(self.repos_path, old)
407 new_path = os.path.join(self.repos_path, new)
466 new_path = os.path.join(self.repos_path, new)
408 if os.path.isdir(new_path):
467 if os.path.isdir(new_path):
409 raise Exception('Was trying to rename to already existing dir %s' \
468 raise Exception(
410 % new_path)
469 'Was trying to rename to already existing dir %s' % new_path
470 )
411 shutil.move(old_path, new_path)
471 shutil.move(old_path, new_path)
412
472
413 def __delete_repo(self, repo):
473 def __delete_repo(self, repo):
@@ -426,7 +486,6 b' class RepoModel(BaseModel):'
426 shutil.move(os.path.join(rm_path, '.%s' % alias),
486 shutil.move(os.path.join(rm_path, '.%s' % alias),
427 os.path.join(rm_path, 'rm__.%s' % alias))
487 os.path.join(rm_path, 'rm__.%s' % alias))
428 # disable repo
488 # disable repo
429 shutil.move(rm_path, os.path.join(self.repos_path, 'rm__%s__%s' \
489 _d = 'rm__%s__%s' % (datetime.now().strftime('%Y%m%d_%H%M%S_%f'),
430 % (datetime.today()\
490 repo.repo_name)
431 .strftime('%Y%m%d_%H%M%S_%f'),
491 shutil.move(rm_path, os.path.join(self.repos_path, _d))
432 repo.repo_name)))
@@ -26,14 +26,29 b''
26
26
27 import logging
27 import logging
28 from rhodecode.model import BaseModel
28 from rhodecode.model import BaseModel
29 from rhodecode.model.db import UserRepoToPerm, UsersGroupRepoToPerm, Permission
29 from rhodecode.model.db import UserRepoToPerm, UsersGroupRepoToPerm, Permission,\
30 User, Repository
30
31
31 log = logging.getLogger(__name__)
32 log = logging.getLogger(__name__)
32
33
33
34
34 class RepositoryPermissionModel(BaseModel):
35 class RepositoryPermissionModel(BaseModel):
35
36
37 def __get_user(self, user):
38 return self._get_instance(User, user, callback=User.get_by_username)
39
40 def __get_repo(self, repository):
41 return self._get_instance(Repository, repository,
42 callback=Repository.get_by_repo_name)
43
44 def __get_perm(self, permission):
45 return self._get_instance(Permission, permission,
46 callback=Permission.get_by_key)
47
36 def get_user_permission(self, repository, user):
48 def get_user_permission(self, repository, user):
49 repository = self.__get_repo(repository)
50 user = self.__get_user(user)
51
37 return UserRepoToPerm.query() \
52 return UserRepoToPerm.query() \
38 .filter(UserRepoToPerm.user == user) \
53 .filter(UserRepoToPerm.user == user) \
39 .filter(UserRepoToPerm.repository == repository) \
54 .filter(UserRepoToPerm.repository == repository) \
@@ -28,18 +28,32 b' import logging'
28 import traceback
28 import traceback
29 import shutil
29 import shutil
30
30
31 from pylons.i18n.translation import _
31 from rhodecode.lib import LazyProperty
32
33 from vcs.utils.lazy import LazyProperty
34
32
35 from rhodecode.model import BaseModel
33 from rhodecode.model import BaseModel
36 from rhodecode.model.db import RepoGroup, RhodeCodeUi
34 from rhodecode.model.db import RepoGroup, RhodeCodeUi, UserRepoGroupToPerm, \
35 User, Permission, UsersGroupRepoGroupToPerm, UsersGroup
37
36
38 log = logging.getLogger(__name__)
37 log = logging.getLogger(__name__)
39
38
40
39
41 class ReposGroupModel(BaseModel):
40 class ReposGroupModel(BaseModel):
42
41
42 def __get_user(self, user):
43 return self._get_instance(User, user, callback=User.get_by_username)
44
45 def __get_users_group(self, users_group):
46 return self._get_instance(UsersGroup, users_group,
47 callback=UsersGroup.get_by_group_name)
48
49 def __get_repos_group(self, repos_group):
50 return self._get_instance(RepoGroup, repos_group,
51 callback=RepoGroup.get_by_group_name)
52
53 def __get_perm(self, permission):
54 return self._get_instance(Permission, permission,
55 callback=Permission.get_by_key)
56
43 @LazyProperty
57 @LazyProperty
44 def repos_path(self):
58 def repos_path(self):
45 """
59 """
@@ -49,6 +63,24 b' class ReposGroupModel(BaseModel):'
49 q = RhodeCodeUi.get_by_key('/').one()
63 q = RhodeCodeUi.get_by_key('/').one()
50 return q.ui_value
64 return q.ui_value
51
65
66 def _create_default_perms(self, new_group):
67 # create default permission
68 repo_group_to_perm = UserRepoGroupToPerm()
69 default_perm = 'group.read'
70 for p in User.get_by_username('default').user_perms:
71 if p.permission.permission_name.startswith('group.'):
72 default_perm = p.permission.permission_name
73 break
74
75 repo_group_to_perm.permission_id = self.sa.query(Permission)\
76 .filter(Permission.permission_name == default_perm)\
77 .one().permission_id
78
79 repo_group_to_perm.group = new_group
80 repo_group_to_perm.user_id = User.get_by_username('default').user_id
81
82 self.sa.add(repo_group_to_perm)
83
52 def __create_group(self, group_name):
84 def __create_group(self, group_name):
53 """
85 """
54 makes repositories group on filesystem
86 makes repositories group on filesystem
@@ -102,16 +134,21 b' class ReposGroupModel(BaseModel):'
102 # delete only if that path really exists
134 # delete only if that path really exists
103 os.rmdir(rm_path)
135 os.rmdir(rm_path)
104
136
105 def create(self, form_data):
137 def create(self, group_name, group_description, parent, just_db=False):
106 try:
138 try:
107 new_repos_group = RepoGroup()
139 new_repos_group = RepoGroup()
108 new_repos_group.group_description = form_data['group_description']
140 new_repos_group.group_description = group_description
109 new_repos_group.parent_group = RepoGroup.get(form_data['group_parent_id'])
141 new_repos_group.parent_group = self.__get_repos_group(parent)
110 new_repos_group.group_name = new_repos_group.get_new_name(form_data['group_name'])
142 new_repos_group.group_name = new_repos_group.get_new_name(group_name)
111
143
112 self.sa.add(new_repos_group)
144 self.sa.add(new_repos_group)
113 self.sa.flush()
145 self._create_default_perms(new_repos_group)
114 self.__create_group(new_repos_group.group_name)
146
147 if not just_db:
148 # we need to flush here, in order to check if database won't
149 # throw any exceptions, create filesystem dirs at the very end
150 self.sa.flush()
151 self.__create_group(new_repos_group.group_name)
115
152
116 return new_repos_group
153 return new_repos_group
117 except:
154 except:
@@ -122,6 +159,29 b' class ReposGroupModel(BaseModel):'
122
159
123 try:
160 try:
124 repos_group = RepoGroup.get(repos_group_id)
161 repos_group = RepoGroup.get(repos_group_id)
162
163 # update permissions
164 for member, perm, member_type in form_data['perms_updates']:
165 if member_type == 'user':
166 # this updates also current one if found
167 ReposGroupModel().grant_user_permission(
168 repos_group=repos_group, user=member, perm=perm
169 )
170 else:
171 ReposGroupModel().grant_users_group_permission(
172 repos_group=repos_group, group_name=member, perm=perm
173 )
174 # set new permissions
175 for member, perm, member_type in form_data['perms_new']:
176 if member_type == 'user':
177 ReposGroupModel().grant_user_permission(
178 repos_group=repos_group, user=member, perm=perm
179 )
180 else:
181 ReposGroupModel().grant_users_group_permission(
182 repos_group=repos_group, group_name=member, perm=perm
183 )
184
125 old_path = repos_group.full_path
185 old_path = repos_group.full_path
126
186
127 # change properties
187 # change properties
@@ -154,3 +214,97 b' class ReposGroupModel(BaseModel):'
154 except:
214 except:
155 log.error(traceback.format_exc())
215 log.error(traceback.format_exc())
156 raise
216 raise
217
218 def grant_user_permission(self, repos_group, user, perm):
219 """
220 Grant permission for user on given repositories group, or update
221 existing one if found
222
223 :param repos_group: Instance of ReposGroup, repositories_group_id,
224 or repositories_group name
225 :param user: Instance of User, user_id or username
226 :param perm: Instance of Permission, or permission_name
227 """
228
229 repos_group = self.__get_repos_group(repos_group)
230 user = self.__get_user(user)
231 permission = self.__get_perm(perm)
232
233 # check if we have that permission already
234 obj = self.sa.query(UserRepoGroupToPerm)\
235 .filter(UserRepoGroupToPerm.user == user)\
236 .filter(UserRepoGroupToPerm.group == repos_group)\
237 .scalar()
238 if obj is None:
239 # create new !
240 obj = UserRepoGroupToPerm()
241 obj.group = repos_group
242 obj.user = user
243 obj.permission = permission
244 self.sa.add(obj)
245
246 def revoke_user_permission(self, repos_group, user):
247 """
248 Revoke permission for user on given repositories group
249
250 :param repos_group: Instance of ReposGroup, repositories_group_id,
251 or repositories_group name
252 :param user: Instance of User, user_id or username
253 """
254
255 repos_group = self.__get_repos_group(repos_group)
256 user = self.__get_user(user)
257
258 obj = self.sa.query(UserRepoGroupToPerm)\
259 .filter(UserRepoGroupToPerm.user == user)\
260 .filter(UserRepoGroupToPerm.group == repos_group)\
261 .one()
262 self.sa.delete(obj)
263
264 def grant_users_group_permission(self, repos_group, group_name, perm):
265 """
266 Grant permission for users group on given repositories group, or update
267 existing one if found
268
269 :param repos_group: Instance of ReposGroup, repositories_group_id,
270 or repositories_group name
271 :param group_name: Instance of UserGroup, users_group_id,
272 or users group name
273 :param perm: Instance of Permission, or permission_name
274 """
275 repos_group = self.__get_repos_group(repos_group)
276 group_name = self.__get_users_group(group_name)
277 permission = self.__get_perm(perm)
278
279 # check if we have that permission already
280 obj = self.sa.query(UsersGroupRepoGroupToPerm)\
281 .filter(UsersGroupRepoGroupToPerm.group == repos_group)\
282 .filter(UsersGroupRepoGroupToPerm.users_group == group_name)\
283 .scalar()
284
285 if obj is None:
286 # create new
287 obj = UsersGroupRepoGroupToPerm()
288
289 obj.group = repos_group
290 obj.users_group = group_name
291 obj.permission = permission
292 self.sa.add(obj)
293
294 def revoke_users_group_permission(self, repos_group, group_name):
295 """
296 Revoke permission for users group on given repositories group
297
298 :param repos_group: Instance of ReposGroup, repositories_group_id,
299 or repositories_group name
300 :param group_name: Instance of UserGroup, users_group_id,
301 or users group name
302 """
303 repos_group = self.__get_repos_group(repos_group)
304 group_name = self.__get_users_group(group_name)
305
306 obj = self.sa.query(UsersGroupRepoGroupToPerm)\
307 .filter(UsersGroupRepoGroupToPerm.group == repos_group)\
308 .filter(UsersGroupRepoGroupToPerm.users_group == group_name)\
309 .one()
310 self.sa.delete(obj)
@@ -36,12 +36,12 b' from vcs.nodes import FileNode'
36 from rhodecode import BACKENDS
36 from rhodecode import BACKENDS
37 from rhodecode.lib import helpers as h
37 from rhodecode.lib import helpers as h
38 from rhodecode.lib import safe_str
38 from rhodecode.lib import safe_str
39 from rhodecode.lib.auth import HasRepoPermissionAny
39 from rhodecode.lib.auth import HasRepoPermissionAny, HasReposGroupPermissionAny
40 from rhodecode.lib.utils import get_repos as get_filesystem_repos, make_ui, \
40 from rhodecode.lib.utils import get_repos as get_filesystem_repos, make_ui, \
41 action_logger, EmptyChangeset
41 action_logger, EmptyChangeset
42 from rhodecode.model import BaseModel
42 from rhodecode.model import BaseModel
43 from rhodecode.model.db import Repository, RhodeCodeUi, CacheInvalidation, \
43 from rhodecode.model.db import Repository, RhodeCodeUi, CacheInvalidation, \
44 UserFollowing, UserLog, User
44 UserFollowing, UserLog, User, RepoGroup
45
45
46 log = logging.getLogger(__name__)
46 log = logging.getLogger(__name__)
47
47
@@ -80,15 +80,16 b' class CachedRepoList(object):'
80 for dbr in self.db_repo_list:
80 for dbr in self.db_repo_list:
81 scmr = dbr.scm_instance_cached
81 scmr = dbr.scm_instance_cached
82 # check permission at this level
82 # check permission at this level
83 if not HasRepoPermissionAny('repository.read', 'repository.write',
83 if not HasRepoPermissionAny(
84 'repository.admin')(dbr.repo_name,
84 'repository.read', 'repository.write', 'repository.admin'
85 'get repo check'):
85 )(dbr.repo_name, 'get repo check'):
86 continue
86 continue
87
87
88 if scmr is None:
88 if scmr is None:
89 log.error('%s this repository is present in database but it '
89 log.error(
90 'cannot be created as an scm instance',
90 '%s this repository is present in database but it '
91 dbr.repo_name)
91 'cannot be created as an scm instance' % dbr.repo_name
92 )
92 continue
93 continue
93
94
94 last_change = scmr.last_change
95 last_change = scmr.last_change
@@ -115,6 +116,28 b' class CachedRepoList(object):'
115 yield tmp_d
116 yield tmp_d
116
117
117
118
119 class GroupList(object):
120
121 def __init__(self, db_repo_group_list):
122 self.db_repo_group_list = db_repo_group_list
123
124 def __len__(self):
125 return len(self.db_repo_group_list)
126
127 def __repr__(self):
128 return '<%s (%s)>' % (self.__class__.__name__, self.__len__())
129
130 def __iter__(self):
131 for dbgr in self.db_repo_group_list:
132 # check permission at this level
133 if not HasReposGroupPermissionAny(
134 'group.read', 'group.write', 'group.admin'
135 )(dbgr.group_name, 'get group repo check'):
136 continue
137
138 yield dbgr
139
140
118 class ScmModel(BaseModel):
141 class ScmModel(BaseModel):
119 """
142 """
120 Generic Scm Model
143 Generic Scm Model
@@ -200,6 +223,14 b' class ScmModel(BaseModel):'
200
223
201 return repo_iter
224 return repo_iter
202
225
226 def get_repos_groups(self, all_groups=None):
227 if all_groups is None:
228 all_groups = RepoGroup.query()\
229 .filter(RepoGroup.group_parent_id == None).all()
230 group_iter = GroupList(all_groups)
231
232 return group_iter
233
203 def mark_for_invalidation(self, repo_name):
234 def mark_for_invalidation(self, repo_name):
204 """Puts cache invalidation task into db for
235 """Puts cache invalidation task into db for
205 further global cache invalidation
236 further global cache invalidation
@@ -35,7 +35,7 b' from rhodecode.lib.caching_query import '
35 from rhodecode.model import BaseModel
35 from rhodecode.model import BaseModel
36 from rhodecode.model.db import User, UserRepoToPerm, Repository, Permission, \
36 from rhodecode.model.db import User, UserRepoToPerm, Repository, Permission, \
37 UserToPerm, UsersGroupRepoToPerm, UsersGroupToPerm, UsersGroupMember, \
37 UserToPerm, UsersGroupRepoToPerm, UsersGroupToPerm, UsersGroupMember, \
38 Notification
38 Notification, RepoGroup, UserRepoGroupToPerm, UsersGroup
39 from rhodecode.lib.exceptions import DefaultUserException, \
39 from rhodecode.lib.exceptions import DefaultUserException, \
40 UserOwnsReposException
40 UserOwnsReposException
41
41
@@ -46,16 +46,26 b' from sqlalchemy.orm import joinedload'
46 log = logging.getLogger(__name__)
46 log = logging.getLogger(__name__)
47
47
48
48
49 PERM_WEIGHTS = {'repository.none': 0,
49 PERM_WEIGHTS = {
50 'repository.read': 1,
50 'repository.none': 0,
51 'repository.write': 3,
51 'repository.read': 1,
52 'repository.admin': 3}
52 'repository.write': 3,
53 'repository.admin': 4,
54 'group.none': 0,
55 'group.read': 1,
56 'group.write': 3,
57 'group.admin': 4,
58 }
53
59
54
60
55 class UserModel(BaseModel):
61 class UserModel(BaseModel):
56
62
57 def __get_user(self, user):
63 def __get_user(self, user):
58 return self._get_instance(User, user)
64 return self._get_instance(User, user, callback=User.get_by_username)
65
66 def __get_perm(self, permission):
67 return self._get_instance(Permission, permission,
68 callback=Permission.get_by_key)
59
69
60 def get(self, user_id, cache=False):
70 def get(self, user_id, cache=False):
61 user = self.sa.query(User)
71 user = self.sa.query(User)
@@ -348,9 +358,12 b' class UserModel(BaseModel):'
348
358
349 :param user: user instance to fill his perms
359 :param user: user instance to fill his perms
350 """
360 """
351
361 RK = 'repositories'
352 user.permissions['repositories'] = {}
362 GK = 'repositories_groups'
353 user.permissions['global'] = set()
363 GLOBAL = 'global'
364 user.permissions[RK] = {}
365 user.permissions[GK] = {}
366 user.permissions[GLOBAL] = set()
354
367
355 #======================================================================
368 #======================================================================
356 # fetch default permissions
369 # fetch default permissions
@@ -358,36 +371,45 b' class UserModel(BaseModel):'
358 default_user = User.get_by_username('default', cache=True)
371 default_user = User.get_by_username('default', cache=True)
359 default_user_id = default_user.user_id
372 default_user_id = default_user.user_id
360
373
361 default_perms = Permission.get_default_perms(default_user_id)
374 default_repo_perms = Permission.get_default_perms(default_user_id)
375 default_repo_groups_perms = Permission.get_default_group_perms(default_user_id)
362
376
363 if user.is_admin:
377 if user.is_admin:
364 #==================================================================
378 #==================================================================
365 # #admin have all default rights set to admin
379 # admin user have all default rights for repositories
380 # and groups set to admin
366 #==================================================================
381 #==================================================================
367 user.permissions['global'].add('hg.admin')
382 user.permissions[GLOBAL].add('hg.admin')
368
383
369 for perm in default_perms:
384 # repositories
385 for perm in default_repo_perms:
386 r_k = perm.UserRepoToPerm.repository.repo_name
370 p = 'repository.admin'
387 p = 'repository.admin'
371 user.permissions['repositories'][perm.UserRepoToPerm.
388 user.permissions[RK][r_k] = p
372 repository.repo_name] = p
389
390 # repositories groups
391 for perm in default_repo_groups_perms:
392 rg_k = perm.UserRepoGroupToPerm.group.group_name
393 p = 'group.admin'
394 user.permissions[GK][rg_k] = p
373
395
374 else:
396 else:
375 #==================================================================
397 #==================================================================
376 # set default permissions
398 # set default permissions first for repositories and groups
377 #==================================================================
399 #==================================================================
378 uid = user.user_id
400 uid = user.user_id
379
401
380 # default global
402 # default global permissions
381 default_global_perms = self.sa.query(UserToPerm)\
403 default_global_perms = self.sa.query(UserToPerm)\
382 .filter(UserToPerm.user_id == default_user_id)
404 .filter(UserToPerm.user_id == default_user_id)
383
405
384 for perm in default_global_perms:
406 for perm in default_global_perms:
385 user.permissions['global'].add(perm.permission.permission_name)
407 user.permissions[GLOBAL].add(perm.permission.permission_name)
386
408
387 # default for repositories
409 # default for repositories
388 for perm in default_perms:
410 for perm in default_repo_perms:
389 if perm.Repository.private and not (perm.Repository.user_id ==
411 r_k = perm.UserRepoToPerm.repository.repo_name
390 uid):
412 if perm.Repository.private and not (perm.Repository.user_id == uid):
391 # disable defaults for private repos,
413 # disable defaults for private repos,
392 p = 'repository.none'
414 p = 'repository.none'
393 elif perm.Repository.user_id == uid:
415 elif perm.Repository.user_id == uid:
@@ -396,8 +418,13 b' class UserModel(BaseModel):'
396 else:
418 else:
397 p = perm.Permission.permission_name
419 p = perm.Permission.permission_name
398
420
399 user.permissions['repositories'][perm.UserRepoToPerm.
421 user.permissions[RK][r_k] = p
400 repository.repo_name] = p
422
423 # default for repositories groups
424 for perm in default_repo_groups_perms:
425 rg_k = perm.UserRepoGroupToPerm.group.group_name
426 p = perm.Permission.permission_name
427 user.permissions[GK][rg_k] = p
401
428
402 #==================================================================
429 #==================================================================
403 # overwrite default with user permissions if any
430 # overwrite default with user permissions if any
@@ -409,25 +436,24 b' class UserModel(BaseModel):'
409 .filter(UserToPerm.user_id == uid).all()
436 .filter(UserToPerm.user_id == uid).all()
410
437
411 for perm in user_perms:
438 for perm in user_perms:
412 user.permissions['global'].add(perm.permission.permission_name)
439 user.permissions[GLOBAL].add(perm.permission.permission_name)
413
440
414 # user repositories
441 # user repositories
415 user_repo_perms = self.sa.query(UserRepoToPerm, Permission,
442 user_repo_perms = \
416 Repository)\
443 self.sa.query(UserRepoToPerm, Permission, Repository)\
417 .join((Repository, UserRepoToPerm.repository_id ==
444 .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
418 Repository.repo_id))\
445 .join((Permission, UserRepoToPerm.permission_id == Permission.permission_id))\
419 .join((Permission, UserRepoToPerm.permission_id ==
446 .filter(UserRepoToPerm.user_id == uid)\
420 Permission.permission_id))\
447 .all()
421 .filter(UserRepoToPerm.user_id == uid).all()
422
448
423 for perm in user_repo_perms:
449 for perm in user_repo_perms:
424 # set admin if owner
450 # set admin if owner
451 r_k = perm.UserRepoToPerm.repository.repo_name
425 if perm.Repository.user_id == uid:
452 if perm.Repository.user_id == uid:
426 p = 'repository.admin'
453 p = 'repository.admin'
427 else:
454 else:
428 p = perm.Permission.permission_name
455 p = perm.Permission.permission_name
429 user.permissions['repositories'][perm.UserRepoToPerm.
456 user.permissions[RK][r_k] = p
430 repository.repo_name] = p
431
457
432 #==================================================================
458 #==================================================================
433 # check if user is part of groups for this repository and fill in
459 # check if user is part of groups for this repository and fill in
@@ -442,30 +468,44 b' class UserModel(BaseModel):'
442 .filter(UsersGroupMember.user_id == uid).all()
468 .filter(UsersGroupMember.user_id == uid).all()
443
469
444 for perm in user_perms_from_users_groups:
470 for perm in user_perms_from_users_groups:
445 user.permissions['global'].add(perm.permission.permission_name)
471 user.permissions[GLOBAL].add(perm.permission.permission_name)
446
472
447 # users group repositories
473 # users group repositories
448 user_repo_perms_from_users_groups = self.sa.query(
474 user_repo_perms_from_users_groups = \
449 UsersGroupRepoToPerm,
475 self.sa.query(UsersGroupRepoToPerm, Permission, Repository,)\
450 Permission, Repository,)\
476 .join((Repository, UsersGroupRepoToPerm.repository_id == Repository.repo_id))\
451 .join((Repository, UsersGroupRepoToPerm.repository_id ==
477 .join((Permission, UsersGroupRepoToPerm.permission_id == Permission.permission_id))\
452 Repository.repo_id))\
478 .join((UsersGroupMember, UsersGroupRepoToPerm.users_group_id == UsersGroupMember.users_group_id))\
453 .join((Permission, UsersGroupRepoToPerm.permission_id ==
479 .filter(UsersGroupMember.user_id == uid)\
454 Permission.permission_id))\
480 .all()
455 .join((UsersGroupMember, UsersGroupRepoToPerm.users_group_id ==
456 UsersGroupMember.users_group_id))\
457 .filter(UsersGroupMember.user_id == uid).all()
458
481
459 for perm in user_repo_perms_from_users_groups:
482 for perm in user_repo_perms_from_users_groups:
483 r_k = perm.UsersGroupRepoToPerm.repository.repo_name
460 p = perm.Permission.permission_name
484 p = perm.Permission.permission_name
461 cur_perm = user.permissions['repositories'][perm.
485 cur_perm = user.permissions[RK][r_k]
462 UsersGroupRepoToPerm.
463 repository.repo_name]
464 # overwrite permission only if it's greater than permission
486 # overwrite permission only if it's greater than permission
465 # given from other sources
487 # given from other sources
466 if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm]:
488 if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm]:
467 user.permissions['repositories'][perm.UsersGroupRepoToPerm.
489 user.permissions[RK][r_k] = p
468 repository.repo_name] = p
490
491 #==================================================================
492 # get access for this user for repos group and override defaults
493 #==================================================================
494
495 # user repositories groups
496 user_repo_groups_perms = \
497 self.sa.query(UserRepoGroupToPerm, Permission, RepoGroup)\
498 .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
499 .join((Permission, UserRepoGroupToPerm.permission_id == Permission.permission_id))\
500 .filter(UserRepoToPerm.user_id == uid)\
501 .all()
502
503 for perm in user_repo_groups_perms:
504 rg_k = perm.UserRepoGroupToPerm.group.group_name
505 p = perm.Permission.permission_name
506 cur_perm = user.permissions[GK][rg_k]
507 if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm]:
508 user.permissions[GK][rg_k] = p
469
509
470 return user
510 return user
471
511
@@ -480,23 +520,28 b' class UserModel(BaseModel):'
480 .filter(UserToPerm.permission == perm).scalar() is not None
520 .filter(UserToPerm.permission == perm).scalar() is not None
481
521
482 def grant_perm(self, user, perm):
522 def grant_perm(self, user, perm):
483 if not isinstance(perm, Permission):
523 """
484 raise Exception('perm needs to be an instance of Permission class '
524 Grant user global permissions
485 'got %s instead' % type(perm))
486
525
526 :param user:
527 :param perm:
528 """
487 user = self.__get_user(user)
529 user = self.__get_user(user)
488
530 perm = self.__get_perm(perm)
489 new = UserToPerm()
531 new = UserToPerm()
490 new.user = user
532 new.user = user
491 new.permission = perm
533 new.permission = perm
492 self.sa.add(new)
534 self.sa.add(new)
493
535
494 def revoke_perm(self, user, perm):
536 def revoke_perm(self, user, perm):
495 if not isinstance(perm, Permission):
537 """
496 raise Exception('perm needs to be an instance of Permission class '
538 Revoke users global permissions
497 'got %s instead' % type(perm))
498
539
540 :param user:
541 :param perm:
542 """
499 user = self.__get_user(user)
543 user = self.__get_user(user)
544 perm = self.__get_perm(perm)
500
545
501 obj = UserToPerm.query().filter(UserToPerm.user == user)\
546 obj = UserToPerm.query().filter(UserToPerm.user == user)\
502 .filter(UserToPerm.permission == perm).scalar()
547 .filter(UserToPerm.permission == perm).scalar()
@@ -38,7 +38,12 b' log = logging.getLogger(__name__)'
38 class UsersGroupModel(BaseModel):
38 class UsersGroupModel(BaseModel):
39
39
40 def __get_users_group(self, users_group):
40 def __get_users_group(self, users_group):
41 return self._get_instance(UsersGroup, users_group)
41 return self._get_instance(UsersGroup, users_group,
42 callback=UsersGroup.get_by_group_name)
43
44 def __get_perm(self, permission):
45 return self._get_instance(Permission, permission,
46 callback=Permission.get_by_key)
42
47
43 def get(self, users_group_id, cache=False):
48 def get(self, users_group_id, cache=False):
44 return UsersGroup.get(users_group_id)
49 return UsersGroup.get(users_group_id)
@@ -80,7 +85,15 b' class UsersGroupModel(BaseModel):'
80 log.error(traceback.format_exc())
85 log.error(traceback.format_exc())
81 raise
86 raise
82
87
83 def delete(self, users_group):
88 def delete(self, users_group, force=False):
89 """
90 Deletes repos group, unless force flag is used
91 raises exception if there are members in that group, else deletes
92 group and users
93
94 :param users_group:
95 :param force:
96 """
84 try:
97 try:
85 users_group = self.__get_users_group(users_group)
98 users_group = self.__get_users_group(users_group)
86
99
@@ -88,7 +101,7 b' class UsersGroupModel(BaseModel):'
88 assigned_groups = UsersGroupRepoToPerm.query()\
101 assigned_groups = UsersGroupRepoToPerm.query()\
89 .filter(UsersGroupRepoToPerm.users_group == users_group).all()
102 .filter(UsersGroupRepoToPerm.users_group == users_group).all()
90
103
91 if assigned_groups:
104 if assigned_groups and force is False:
92 raise UsersGroupsAssignedException('RepoGroup assigned to %s' %
105 raise UsersGroupsAssignedException('RepoGroup assigned to %s' %
93 assigned_groups)
106 assigned_groups)
94
107
@@ -118,10 +131,8 b' class UsersGroupModel(BaseModel):'
118 raise
131 raise
119
132
120 def has_perm(self, users_group, perm):
133 def has_perm(self, users_group, perm):
121 if not isinstance(perm, Permission):
122 raise Exception('perm needs to be an instance of Permission class')
123
124 users_group = self.__get_users_group(users_group)
134 users_group = self.__get_users_group(users_group)
135 perm = self.__get_perm(perm)
125
136
126 return UsersGroupToPerm.query()\
137 return UsersGroupToPerm.query()\
127 .filter(UsersGroupToPerm.users_group == users_group)\
138 .filter(UsersGroupToPerm.users_group == users_group)\
@@ -139,10 +150,8 b' class UsersGroupModel(BaseModel):'
139 self.sa.add(new)
150 self.sa.add(new)
140
151
141 def revoke_perm(self, users_group, perm):
152 def revoke_perm(self, users_group, perm):
142 if not isinstance(perm, Permission):
143 raise Exception('perm needs to be an instance of Permission class')
144
145 users_group = self.__get_users_group(users_group)
153 users_group = self.__get_users_group(users_group)
154 perm = self.__get_perm(perm)
146
155
147 obj = UsersGroupToPerm.query()\
156 obj = UsersGroupToPerm.query()\
148 .filter(UsersGroupToPerm.users_group == users_group)\
157 .filter(UsersGroupToPerm.users_group == users_group)\
@@ -53,9 +53,18 b''
53 ${h.select('group_parent_id','',c.repo_groups,class_="medium")}
53 ${h.select('group_parent_id','',c.repo_groups,class_="medium")}
54 </div>
54 </div>
55 </div>
55 </div>
56 <div class="field">
57 <div class="label">
58 <label for="input">${_('Permissions')}:</label>
59 </div>
60 <div class="input">
61 <%include file="repos_group_edit_perms.html"/>
62 </div>
56
63
64 </div>
57 <div class="buttons">
65 <div class="buttons">
58 ${h.submit('save',_('save'),class_="ui-button")}
66 ${h.submit('save',_('Save'),class_="ui-button")}
67 ${h.reset('reset',_('Reset'),class_="ui-button")}
59 </div>
68 </div>
60 </div>
69 </div>
61 </div>
70 </div>
@@ -38,7 +38,9 b''
38 </div>
38 </div>
39 </td>
39 </td>
40 <td>${gr.group_description}</td>
40 <td>${gr.group_description}</td>
41 ##<td><b>${gr.repositories.count()}</b></td>
41 ## this is commented out since for multi nested repos can be HEAVY!
42 ## in number of executed queries during traversing uncomment at will
43 ##<td><b>${gr.repositories_recursive_count}</b></td>
42 </tr>
44 </tr>
43 % endfor
45 % endfor
44
46
@@ -12,13 +12,27 b' from rhodecode.model.user import UserMod'
12 from rhodecode.model.meta import Session
12 from rhodecode.model.meta import Session
13 from rhodecode.model.notification import NotificationModel
13 from rhodecode.model.notification import NotificationModel
14 from rhodecode.model.users_group import UsersGroupModel
14 from rhodecode.model.users_group import UsersGroupModel
15 from rhodecode.lib.auth import AuthUser
16
17
18 def _make_group(path, desc='desc', parent_id=None,
19 skip_if_exists=False):
20
21 gr = RepoGroup.get_by_group_name(path)
22 if gr and skip_if_exists:
23 return gr
24
25 gr = ReposGroupModel().create(path, desc, parent_id)
26 Session.commit()
27 return gr
28
15
29
16 class TestReposGroups(unittest.TestCase):
30 class TestReposGroups(unittest.TestCase):
17
31
18 def setUp(self):
32 def setUp(self):
19 self.g1 = self.__make_group('test1', skip_if_exists=True)
33 self.g1 = _make_group('test1', skip_if_exists=True)
20 self.g2 = self.__make_group('test2', skip_if_exists=True)
34 self.g2 = _make_group('test2', skip_if_exists=True)
21 self.g3 = self.__make_group('test3', skip_if_exists=True)
35 self.g3 = _make_group('test3', skip_if_exists=True)
22
36
23 def tearDown(self):
37 def tearDown(self):
24 print 'out'
38 print 'out'
@@ -31,102 +45,81 b' class TestReposGroups(unittest.TestCase)'
31 def _check_folders(self):
45 def _check_folders(self):
32 print os.listdir(TESTS_TMP_PATH)
46 print os.listdir(TESTS_TMP_PATH)
33
47
34 def __make_group(self, path, desc='desc', parent_id=None,
35 skip_if_exists=False):
36
37 gr = RepoGroup.get_by_group_name(path)
38 if gr and skip_if_exists:
39 return gr
40
41 form_data = dict(group_name=path,
42 group_description=desc,
43 group_parent_id=parent_id)
44 gr = ReposGroupModel().create(form_data)
45 Session.commit()
46 return gr
47
48 def __delete_group(self, id_):
48 def __delete_group(self, id_):
49 ReposGroupModel().delete(id_)
49 ReposGroupModel().delete(id_)
50
50
51
52 def __update_group(self, id_, path, desc='desc', parent_id=None):
51 def __update_group(self, id_, path, desc='desc', parent_id=None):
53 form_data = dict(group_name=path,
52 form_data = dict(group_name=path,
54 group_description=desc,
53 group_description=desc,
55 group_parent_id=parent_id)
54 group_parent_id=parent_id,
55 perms_updates=[],
56 perms_new=[])
56
57
57 gr = ReposGroupModel().update(id_, form_data)
58 gr = ReposGroupModel().update(id_, form_data)
58 return gr
59 return gr
59
60
60 def test_create_group(self):
61 def test_create_group(self):
61 g = self.__make_group('newGroup')
62 g = _make_group('newGroup')
62 self.assertEqual(g.full_path, 'newGroup')
63 self.assertEqual(g.full_path, 'newGroup')
63
64
64 self.assertTrue(self.__check_path('newGroup'))
65 self.assertTrue(self.__check_path('newGroup'))
65
66
66
67 def test_create_same_name_group(self):
67 def test_create_same_name_group(self):
68 self.assertRaises(IntegrityError, lambda:self.__make_group('newGroup'))
68 self.assertRaises(IntegrityError, lambda:_make_group('newGroup'))
69 Session.rollback()
69 Session.rollback()
70
70
71 def test_same_subgroup(self):
71 def test_same_subgroup(self):
72 sg1 = self.__make_group('sub1', parent_id=self.g1.group_id)
72 sg1 = _make_group('sub1', parent_id=self.g1.group_id)
73 self.assertEqual(sg1.parent_group, self.g1)
73 self.assertEqual(sg1.parent_group, self.g1)
74 self.assertEqual(sg1.full_path, 'test1/sub1')
74 self.assertEqual(sg1.full_path, 'test1/sub1')
75 self.assertTrue(self.__check_path('test1', 'sub1'))
75 self.assertTrue(self.__check_path('test1', 'sub1'))
76
76
77 ssg1 = self.__make_group('subsub1', parent_id=sg1.group_id)
77 ssg1 = _make_group('subsub1', parent_id=sg1.group_id)
78 self.assertEqual(ssg1.parent_group, sg1)
78 self.assertEqual(ssg1.parent_group, sg1)
79 self.assertEqual(ssg1.full_path, 'test1/sub1/subsub1')
79 self.assertEqual(ssg1.full_path, 'test1/sub1/subsub1')
80 self.assertTrue(self.__check_path('test1', 'sub1', 'subsub1'))
80 self.assertTrue(self.__check_path('test1', 'sub1', 'subsub1'))
81
81
82
83 def test_remove_group(self):
82 def test_remove_group(self):
84 sg1 = self.__make_group('deleteme')
83 sg1 = _make_group('deleteme')
85 self.__delete_group(sg1.group_id)
84 self.__delete_group(sg1.group_id)
86
85
87 self.assertEqual(RepoGroup.get(sg1.group_id), None)
86 self.assertEqual(RepoGroup.get(sg1.group_id), None)
88 self.assertFalse(self.__check_path('deteteme'))
87 self.assertFalse(self.__check_path('deteteme'))
89
88
90 sg1 = self.__make_group('deleteme', parent_id=self.g1.group_id)
89 sg1 = _make_group('deleteme', parent_id=self.g1.group_id)
91 self.__delete_group(sg1.group_id)
90 self.__delete_group(sg1.group_id)
92
91
93 self.assertEqual(RepoGroup.get(sg1.group_id), None)
92 self.assertEqual(RepoGroup.get(sg1.group_id), None)
94 self.assertFalse(self.__check_path('test1', 'deteteme'))
93 self.assertFalse(self.__check_path('test1', 'deteteme'))
95
94
96
97 def test_rename_single_group(self):
95 def test_rename_single_group(self):
98 sg1 = self.__make_group('initial')
96 sg1 = _make_group('initial')
99
97
100 new_sg1 = self.__update_group(sg1.group_id, 'after')
98 new_sg1 = self.__update_group(sg1.group_id, 'after')
101 self.assertTrue(self.__check_path('after'))
99 self.assertTrue(self.__check_path('after'))
102 self.assertEqual(RepoGroup.get_by_group_name('initial'), None)
100 self.assertEqual(RepoGroup.get_by_group_name('initial'), None)
103
101
104
105 def test_update_group_parent(self):
102 def test_update_group_parent(self):
106
103
107 sg1 = self.__make_group('initial', parent_id=self.g1.group_id)
104 sg1 = _make_group('initial', parent_id=self.g1.group_id)
108
105
109 new_sg1 = self.__update_group(sg1.group_id, 'after', parent_id=self.g1.group_id)
106 new_sg1 = self.__update_group(sg1.group_id, 'after', parent_id=self.g1.group_id)
110 self.assertTrue(self.__check_path('test1', 'after'))
107 self.assertTrue(self.__check_path('test1', 'after'))
111 self.assertEqual(RepoGroup.get_by_group_name('test1/initial'), None)
108 self.assertEqual(RepoGroup.get_by_group_name('test1/initial'), None)
112
109
113
114 new_sg1 = self.__update_group(sg1.group_id, 'after', parent_id=self.g3.group_id)
110 new_sg1 = self.__update_group(sg1.group_id, 'after', parent_id=self.g3.group_id)
115 self.assertTrue(self.__check_path('test3', 'after'))
111 self.assertTrue(self.__check_path('test3', 'after'))
116 self.assertEqual(RepoGroup.get_by_group_name('test3/initial'), None)
112 self.assertEqual(RepoGroup.get_by_group_name('test3/initial'), None)
117
113
118
119 new_sg1 = self.__update_group(sg1.group_id, 'hello')
114 new_sg1 = self.__update_group(sg1.group_id, 'hello')
120 self.assertTrue(self.__check_path('hello'))
115 self.assertTrue(self.__check_path('hello'))
121
116
122 self.assertEqual(RepoGroup.get_by_group_name('hello'), new_sg1)
117 self.assertEqual(RepoGroup.get_by_group_name('hello'), new_sg1)
123
118
124
125
126 def test_subgrouping_with_repo(self):
119 def test_subgrouping_with_repo(self):
127
120
128 g1 = self.__make_group('g1')
121 g1 = _make_group('g1')
129 g2 = self.__make_group('g2')
122 g2 = _make_group('g2')
130
123
131 # create new repo
124 # create new repo
132 form_data = dict(repo_name='john',
125 form_data = dict(repo_name='john',
@@ -150,13 +143,13 b' class TestReposGroups(unittest.TestCase)'
150 RepoModel().update(r.repo_name, form_data)
143 RepoModel().update(r.repo_name, form_data)
151 self.assertEqual(r.repo_name, 'g1/john')
144 self.assertEqual(r.repo_name, 'g1/john')
152
145
153
154 self.__update_group(g1.group_id, 'g1', parent_id=g2.group_id)
146 self.__update_group(g1.group_id, 'g1', parent_id=g2.group_id)
155 self.assertTrue(self.__check_path('g2', 'g1'))
147 self.assertTrue(self.__check_path('g2', 'g1'))
156
148
157 # test repo
149 # test repo
158 self.assertEqual(r.repo_name, os.path.join('g2', 'g1', r.just_name))
150 self.assertEqual(r.repo_name, os.path.join('g2', 'g1', r.just_name))
159
151
152
160 class TestUser(unittest.TestCase):
153 class TestUser(unittest.TestCase):
161 def __init__(self, methodName='runTest'):
154 def __init__(self, methodName='runTest'):
162 Session.remove()
155 Session.remove()
@@ -245,7 +238,6 b' class TestNotifications(unittest.TestCas'
245 self.assertEqual(len(unotification), len(usrs))
238 self.assertEqual(len(unotification), len(usrs))
246 self.assertEqual([x.user.user_id for x in unotification], usrs)
239 self.assertEqual([x.user.user_id for x in unotification], usrs)
247
240
248
249 def test_user_notifications(self):
241 def test_user_notifications(self):
250 self.assertEqual([], Notification.query().all())
242 self.assertEqual([], Notification.query().all())
251 self.assertEqual([], UserNotification.query().all())
243 self.assertEqual([], UserNotification.query().all())
@@ -284,7 +276,6 b' class TestNotifications(unittest.TestCas'
284 == notification).all()
276 == notification).all()
285 self.assertEqual(un, [])
277 self.assertEqual(un, [])
286
278
287
288 def test_delete_association(self):
279 def test_delete_association(self):
289
280
290 self.assertEqual([], Notification.query().all())
281 self.assertEqual([], Notification.query().all())
@@ -361,6 +352,7 b' class TestNotifications(unittest.TestCas'
361 self.assertEqual(NotificationModel()
352 self.assertEqual(NotificationModel()
362 .get_unread_cnt_for_user(self.u3), 2)
353 .get_unread_cnt_for_user(self.u3), 2)
363
354
355
364 class TestUsers(unittest.TestCase):
356 class TestUsers(unittest.TestCase):
365
357
366 def __init__(self, methodName='runTest'):
358 def __init__(self, methodName='runTest'):
@@ -401,4 +393,163 b' class TestUsers(unittest.TestCase):'
401 #revoke
393 #revoke
402 UserModel().revoke_perm(self.u1, perm)
394 UserModel().revoke_perm(self.u1, perm)
403 Session.commit()
395 Session.commit()
404 self.assertEqual(UserModel().has_perm(self.u1, perm),False)
396 self.assertEqual(UserModel().has_perm(self.u1, perm), False)
397
398
399 class TestPermissions(unittest.TestCase):
400 def __init__(self, methodName='runTest'):
401 super(TestPermissions, self).__init__(methodName=methodName)
402
403 def setUp(self):
404 self.u1 = UserModel().create_or_update(
405 username=u'u1', password=u'qweqwe',
406 email=u'u1@rhodecode.org', name=u'u1', lastname=u'u1'
407 )
408 self.a1 = UserModel().create_or_update(
409 username=u'a1', password=u'qweqwe',
410 email=u'a1@rhodecode.org', name=u'a1', lastname=u'a1', admin=True
411 )
412 Session.commit()
413
414 def tearDown(self):
415 UserModel().delete(self.u1)
416 UserModel().delete(self.a1)
417 if hasattr(self, 'g1'):
418 ReposGroupModel().delete(self.g1.group_id)
419 if hasattr(self, 'g2'):
420 ReposGroupModel().delete(self.g2.group_id)
421
422 if hasattr(self, 'ug1'):
423 UsersGroupModel().delete(self.ug1, force=True)
424
425 Session.commit()
426
427 def test_default_perms_set(self):
428 u1_auth = AuthUser(user_id=self.u1.user_id)
429 perms = {
430 'repositories_groups': {},
431 'global': set([u'hg.create.repository', u'repository.read',
432 u'hg.register.manual_activate']),
433 'repositories': {u'vcs_test_hg': u'repository.read'}
434 }
435 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
436 perms['repositories'][HG_REPO])
437 new_perm = 'repository.write'
438 RepoModel().grant_user_permission(repo=HG_REPO, user=self.u1, perm=new_perm)
439 Session.commit()
440
441 u1_auth = AuthUser(user_id=self.u1.user_id)
442 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO], new_perm)
443
444 def test_default_admin_perms_set(self):
445 a1_auth = AuthUser(user_id=self.a1.user_id)
446 perms = {
447 'repositories_groups': {},
448 'global': set([u'hg.admin']),
449 'repositories': {u'vcs_test_hg': u'repository.admin'}
450 }
451 self.assertEqual(a1_auth.permissions['repositories'][HG_REPO],
452 perms['repositories'][HG_REPO])
453 new_perm = 'repository.write'
454 RepoModel().grant_user_permission(repo=HG_REPO, user=self.a1, perm=new_perm)
455 Session.commit()
456 # cannot really downgrade admins permissions !? they still get's set as
457 # admin !
458 u1_auth = AuthUser(user_id=self.a1.user_id)
459 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
460 perms['repositories'][HG_REPO])
461
462 def test_default_group_perms(self):
463 self.g1 = _make_group('test1', skip_if_exists=True)
464 self.g2 = _make_group('test2', skip_if_exists=True)
465 u1_auth = AuthUser(user_id=self.u1.user_id)
466 perms = {
467 'repositories_groups': {u'test1': 'group.read', u'test2': 'group.read'},
468 'global': set([u'hg.create.repository', u'repository.read', u'hg.register.manual_activate']),
469 'repositories': {u'vcs_test_hg': u'repository.read'}
470 }
471 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
472 perms['repositories'][HG_REPO])
473 self.assertEqual(u1_auth.permissions['repositories_groups'],
474 perms['repositories_groups'])
475
476 def test_default_admin_group_perms(self):
477 self.g1 = _make_group('test1', skip_if_exists=True)
478 self.g2 = _make_group('test2', skip_if_exists=True)
479 a1_auth = AuthUser(user_id=self.a1.user_id)
480 perms = {
481 'repositories_groups': {u'test1': 'group.admin', u'test2': 'group.admin'},
482 'global': set(['hg.admin']),
483 'repositories': {u'vcs_test_hg': 'repository.admin'}
484 }
485
486 self.assertEqual(a1_auth.permissions['repositories'][HG_REPO],
487 perms['repositories'][HG_REPO])
488 self.assertEqual(a1_auth.permissions['repositories_groups'],
489 perms['repositories_groups'])
490
491 def test_propagated_permission_from_users_group(self):
492 # make group
493 self.ug1 = UsersGroupModel().create('G1')
494 # add user to group
495 UsersGroupModel().add_user_to_group(self.ug1, self.u1)
496
497 # set permission to lower
498 new_perm = 'repository.none'
499 RepoModel().grant_user_permission(repo=HG_REPO, user=self.u1, perm=new_perm)
500 Session.commit()
501 u1_auth = AuthUser(user_id=self.u1.user_id)
502 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
503 new_perm)
504
505 # grant perm for group this should override permission from user
506 new_perm = 'repository.write'
507 RepoModel().grant_users_group_permission(repo=HG_REPO,
508 group_name=self.ug1,
509 perm=new_perm)
510 # check perms
511 u1_auth = AuthUser(user_id=self.u1.user_id)
512 perms = {
513 'repositories_groups': {},
514 'global': set([u'hg.create.repository', u'repository.read',
515 u'hg.register.manual_activate']),
516 'repositories': {u'vcs_test_hg': u'repository.read'}
517 }
518 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
519 new_perm)
520 self.assertEqual(u1_auth.permissions['repositories_groups'],
521 perms['repositories_groups'])
522
523 def test_propagated_permission_from_users_group_lower_weight(self):
524 # make group
525 self.ug1 = UsersGroupModel().create('G1')
526 # add user to group
527 UsersGroupModel().add_user_to_group(self.ug1, self.u1)
528
529 # set permission to lower
530 new_perm_h = 'repository.write'
531 RepoModel().grant_user_permission(repo=HG_REPO, user=self.u1,
532 perm=new_perm_h)
533 Session.commit()
534 u1_auth = AuthUser(user_id=self.u1.user_id)
535 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
536 new_perm_h)
537
538 # grant perm for group this should NOT override permission from user
539 # since it's lower than granted
540 new_perm_l = 'repository.read'
541 RepoModel().grant_users_group_permission(repo=HG_REPO,
542 group_name=self.ug1,
543 perm=new_perm_l)
544 # check perms
545 u1_auth = AuthUser(user_id=self.u1.user_id)
546 perms = {
547 'repositories_groups': {},
548 'global': set([u'hg.create.repository', u'repository.read',
549 u'hg.register.manual_activate']),
550 'repositories': {u'vcs_test_hg': u'repository.write'}
551 }
552 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
553 new_perm_h)
554 self.assertEqual(u1_auth.permissions['repositories_groups'],
555 perms['repositories_groups'])
@@ -89,7 +89,7 b' beaker.cache.lock_dir=/tmp/data/cache/lo'
89 beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
89 beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
90
90
91 beaker.cache.super_short_term.type=memory
91 beaker.cache.super_short_term.type=memory
92 beaker.cache.super_short_term.expire=10
92 beaker.cache.super_short_term.expire=1
93 beaker.cache.super_short_term.key_length = 256
93 beaker.cache.super_short_term.key_length = 256
94
94
95 beaker.cache.short_term.type=memory
95 beaker.cache.short_term.type=memory
@@ -101,7 +101,7 b' beaker.cache.long_term.expire=36000'
101 beaker.cache.long_term.key_length = 256
101 beaker.cache.long_term.key_length = 256
102
102
103 beaker.cache.sql_cache_short.type=memory
103 beaker.cache.sql_cache_short.type=memory
104 beaker.cache.sql_cache_short.expire=10
104 beaker.cache.sql_cache_short.expire=1
105 beaker.cache.sql_cache_short.key_length = 256
105 beaker.cache.sql_cache_short.key_length = 256
106
106
107 beaker.cache.sql_cache_med.type=memory
107 beaker.cache.sql_cache_med.type=memory
General Comments 0
You need to be logged in to leave comments. Login now