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 | 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 | 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 |
|
|
8 | the ability to authenticate via LDAP or ActiveDirectory. RhodeCode also provides | |
|
9 | 9 | simple API so it's easy integrable with existing external systems. |
|
10 | 10 | |
|
11 | 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 | 91 | This command can be executed only using api_key belonging to user with admin |
|
92 | 92 | rights. |
|
93 | 93 | |
|
94 | ||
|
94 | 95 | INPUT:: |
|
95 | 96 | |
|
96 | 97 | api_key : "<api_key>" |
@@ -122,6 +123,7 b' get_users' | |||
|
122 | 123 | Lists all existing users. This command can be executed only using api_key |
|
123 | 124 | belonging to user with admin rights. |
|
124 | 125 | |
|
126 | ||
|
125 | 127 | INPUT:: |
|
126 | 128 | |
|
127 | 129 | api_key : "<api_key>" |
@@ -145,12 +147,14 b' OUTPUT::' | |||
|
145 | 147 | ] |
|
146 | 148 | error: null |
|
147 | 149 | |
|
150 | ||
|
148 | 151 | create_user |
|
149 | 152 | ----------- |
|
150 | 153 | |
|
151 | 154 | Creates new user or updates current one if such user exists. This command can |
|
152 | 155 | be executed only using api_key belonging to user with admin rights. |
|
153 | 156 | |
|
157 | ||
|
154 | 158 | INPUT:: |
|
155 | 159 | |
|
156 | 160 | api_key : "<api_key>" |
@@ -174,12 +178,14 b' OUTPUT::' | |||
|
174 | 178 | } |
|
175 | 179 | error: null |
|
176 | 180 | |
|
181 | ||
|
177 | 182 | get_users_group |
|
178 | 183 | --------------- |
|
179 | 184 | |
|
180 | 185 | Gets an existing users group. This command can be executed only using api_key |
|
181 | 186 | belonging to user with admin rights. |
|
182 | 187 | |
|
188 | ||
|
183 | 189 | INPUT:: |
|
184 | 190 | |
|
185 | 191 | api_key : "<api_key>" |
@@ -210,12 +216,14 b' OUTPUT::' | |||
|
210 | 216 | } |
|
211 | 217 | error : null |
|
212 | 218 | |
|
219 | ||
|
213 | 220 | get_users_groups |
|
214 | 221 | ---------------- |
|
215 | 222 | |
|
216 | 223 | Lists all existing users groups. This command can be executed only using |
|
217 | 224 | api_key belonging to user with admin rights. |
|
218 | 225 | |
|
226 | ||
|
219 | 227 | INPUT:: |
|
220 | 228 | |
|
221 | 229 | api_key : "<api_key>" |
@@ -253,6 +261,7 b' create_users_group' | |||
|
253 | 261 | Creates new users group. This command can be executed only using api_key |
|
254 | 262 | belonging to user with admin rights |
|
255 | 263 | |
|
264 | ||
|
256 | 265 | INPUT:: |
|
257 | 266 | |
|
258 | 267 | api_key : "<api_key>" |
@@ -270,12 +279,14 b' OUTPUT::' | |||
|
270 | 279 | } |
|
271 | 280 | error: null |
|
272 | 281 | |
|
282 | ||
|
273 | 283 | add_user_to_users_group |
|
274 | 284 | ----------------------- |
|
275 | 285 | |
|
276 | 286 | Adds a user to a users group. This command can be executed only using api_key |
|
277 | 287 | belonging to user with admin rights |
|
278 | 288 | |
|
289 | ||
|
279 | 290 | INPUT:: |
|
280 | 291 | |
|
281 | 292 | api_key : "<api_key>" |
@@ -293,12 +304,14 b' OUTPUT::' | |||
|
293 | 304 | } |
|
294 | 305 | error: null |
|
295 | 306 | |
|
307 | ||
|
296 | 308 | get_repo |
|
297 | 309 | -------- |
|
298 | 310 | |
|
299 | 311 | Gets an existing repository. This command can be executed only using api_key |
|
300 | 312 | belonging to user with admin rights |
|
301 | 313 | |
|
314 | ||
|
302 | 315 | INPUT:: |
|
303 | 316 | |
|
304 | 317 | api_key : "<api_key>" |
@@ -338,12 +351,14 b' OUTPUT::' | |||
|
338 | 351 | } |
|
339 | 352 | error: null |
|
340 | 353 | |
|
354 | ||
|
341 | 355 | get_repos |
|
342 | 356 | --------- |
|
343 | 357 | |
|
344 | 358 | Lists all existing repositories. This command can be executed only using api_key |
|
345 | 359 | belonging to user with admin rights |
|
346 | 360 | |
|
361 | ||
|
347 | 362 | INPUT:: |
|
348 | 363 | |
|
349 | 364 | api_key : "<api_key>" |
@@ -372,6 +387,7 b" at given revision. It's possible to spec" | |||
|
372 | 387 | `dirs`. This command can be executed only using api_key belonging to user |
|
373 | 388 | with admin rights |
|
374 | 389 | |
|
390 | ||
|
375 | 391 | INPUT:: |
|
376 | 392 | |
|
377 | 393 | api_key : "<api_key>" |
@@ -395,7 +411,6 b' OUTPUT::' | |||
|
395 | 411 | error: null |
|
396 | 412 | |
|
397 | 413 | |
|
398 | ||
|
399 | 414 | create_repo |
|
400 | 415 | ----------- |
|
401 | 416 | |
@@ -405,6 +420,7 b' If repository name contains "/", all nee' | |||
|
405 | 420 | For example "foo/bar/baz" will create groups "foo", "bar" (with "foo" as parent), |
|
406 | 421 | and create "baz" repository with "bar" as group. |
|
407 | 422 | |
|
423 | ||
|
408 | 424 | INPUT:: |
|
409 | 425 | |
|
410 | 426 | api_key : "<api_key>" |
@@ -420,54 +436,106 b' INPUT::' | |||
|
420 | 436 | OUTPUT:: |
|
421 | 437 | |
|
422 | 438 | result: { |
|
423 |
|
|
|
424 |
|
|
|
439 | "id": "<newrepoid>", | |
|
440 | "msg": "Created new repository <reponame>", | |
|
425 | 441 | } |
|
426 | 442 | error: null |
|
427 | 443 | |
|
428 | add_user_to_repo | |
|
429 | ---------------- | |
|
444 | ||
|
445 | grant_user_permission | |
|
446 | --------------------- | |
|
430 | 447 | |
|
431 | Add a user to a repository. This command can be executed only using api_key | |
|
432 | belonging to user with admin rights. | |
|
433 | If "perm" is None, user will be removed from the repository. | |
|
448 | Grant permission for user on given repository, or update existing one | |
|
449 | if found. This command can be executed only using api_key belonging to user | |
|
450 | with admin rights. | |
|
451 | ||
|
434 | 452 | |
|
435 | 453 | INPUT:: |
|
436 | 454 | |
|
437 | 455 | api_key : "<api_key>" |
|
438 |
method : " |
|
|
456 | method : "grant_user_permission" | |
|
439 | 457 | args: { |
|
440 | 458 | "repo_name" : "<reponame>", |
|
441 | 459 | "username" : "<username>", |
|
442 |
"perm" : "( |
|
|
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 | 487 | OUTPUT:: |
|
446 | 488 | |
|
447 | 489 | result: { |
|
448 |
|
|
|
490 | "msg" : "Revoked perm for user: <suername> in repo: <reponame>" | |
|
449 | 491 | } |
|
450 | 492 | error: null |
|
451 | 493 | |
|
452 | add_users_group_to_repo | |
|
453 | ----------------------- | |
|
494 | ||
|
495 | grant_users_group_permission | |
|
496 | ---------------------------- | |
|
454 | 497 | |
|
455 | Add a users group to a repository. This command can be executed only using | |
|
456 | api_key belonging to user with admin rights. If "perm" is None, group will | |
|
457 | be removed from the repository. | |
|
498 | Grant permission for users group on given repository, or update | |
|
499 | existing one if found. This command can be executed only using | |
|
500 | api_key belonging to user with admin rights. | |
|
501 | ||
|
458 | 502 | |
|
459 | 503 | INPUT:: |
|
460 | 504 | |
|
461 | 505 | api_key : "<api_key>" |
|
462 |
method : " |
|
|
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 | 531 | args: { |
|
464 | 532 | "repo_name" : "<reponame>", |
|
465 |
"group |
|
|
466 | "perm" : "(None|repository.(read|write|admin))", | |
|
533 | "users_group" : "<usersgroupname>", | |
|
467 | 534 | } |
|
535 | ||
|
468 | 536 | OUTPUT:: |
|
469 | ||
|
537 | ||
|
470 | 538 | result: { |
|
471 |
|
|
|
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 | 51 | from rhodecode.lib.profiler import ProfilingMiddleware |
|
52 | 52 | app = ProfilingMiddleware(app) |
|
53 | 53 | |
|
54 | if asbool(full_stack): | |
|
54 | 55 | |
|
55 | if asbool(full_stack): | |
|
56 | 56 | # Handle Python exceptions |
|
57 | 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 | 80 | app = Cascade([static_app, app]) |
|
81 | 81 | app = make_gzip_middleware(app, global_conf, compress_level=1) |
|
82 | 82 | |
|
83 | ||
|
84 | 83 | app.config = config |
|
85 | 84 | |
|
86 | 85 | return app |
@@ -113,8 +113,9 b' def make_map(config):' | |||
|
113 | 113 | function=check_repo)) |
|
114 | 114 | #ajax delete repo perm user |
|
115 | 115 | m.connect('delete_repo_user', "/repos_delete_user/{repo_name:.*}", |
|
116 |
action="delete_perm_user", |
|
|
117 | function=check_repo)) | |
|
116 | action="delete_perm_user", | |
|
117 | conditions=dict(method=["DELETE"], function=check_repo)) | |
|
118 | ||
|
118 | 119 | #ajax delete repo perm users_group |
|
119 | 120 | m.connect('delete_repo_users_group', |
|
120 | 121 | "/repos_delete_users_group/{repo_name:.*}", |
@@ -128,7 +129,7 b' def make_map(config):' | |||
|
128 | 129 | m.connect('repo_cache', "/repos_cache/{repo_name:.*}", |
|
129 | 130 | action="repo_cache", conditions=dict(method=["DELETE"], |
|
130 | 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 | 133 | action="repo_public_journal", conditions=dict(method=["PUT"], |
|
133 | 134 | function=check_repo)) |
|
134 | 135 | m.connect('repo_pull', "/repo_pull/{repo_name:.*}", |
@@ -169,6 +170,17 b' def make_map(config):' | |||
|
169 | 170 | m.connect("formatted_repos_group", "/repos_groups/{id}.{format}", |
|
170 | 171 | action="show", conditions=dict(method=["GET"], |
|
171 | 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 | 185 | #ADMIN USER REST ROUTES |
|
174 | 186 | with rmap.submapper(path_prefix=ADMIN_PREFIX, |
@@ -310,8 +322,6 b' def make_map(config):' | |||
|
310 | 322 | m.connect("formatted_notification", "/notifications/{notification_id}.{format}", |
|
311 | 323 | action="show", conditions=dict(method=["GET"])) |
|
312 | 324 | |
|
313 | ||
|
314 | ||
|
315 | 325 | #ADMIN MAIN PAGES |
|
316 | 326 | with rmap.submapper(path_prefix=ADMIN_PREFIX, |
|
317 | 327 | controller='admin/admin') as m: |
@@ -320,13 +330,12 b' def make_map(config):' | |||
|
320 | 330 | action='add_repo') |
|
321 | 331 | |
|
322 | 332 | #========================================================================== |
|
323 |
# API V |
|
|
333 | # API V2 | |
|
324 | 334 | #========================================================================== |
|
325 | 335 | with rmap.submapper(path_prefix=ADMIN_PREFIX, |
|
326 | 336 | controller='api/api') as m: |
|
327 | 337 | m.connect('api', '/api') |
|
328 | 338 | |
|
329 | ||
|
330 | 339 | #USER JOURNAL |
|
331 | 340 | rmap.connect('journal', '%s/journal' % ADMIN_PREFIX, controller='journal') |
|
332 | 341 | |
@@ -388,11 +397,13 b' def make_map(config):' | |||
|
388 | 397 | controller='changeset', revision='tip', |
|
389 | 398 | conditions=dict(function=check_repo)) |
|
390 | 399 | |
|
391 |
rmap.connect('changeset_comment', |
|
|
400 | rmap.connect('changeset_comment', | |
|
401 | '/{repo_name:.*}/changeset/{revision}/comment', | |
|
392 | 402 | controller='changeset', revision='tip', action='comment', |
|
393 | 403 | conditions=dict(function=check_repo)) |
|
394 | 404 | |
|
395 |
rmap.connect('changeset_comment_delete', |
|
|
405 | rmap.connect('changeset_comment_delete', | |
|
406 | '/{repo_name:.*}/changeset/comment/{comment_id}/delete', | |
|
396 | 407 | controller='changeset', action='delete_comment', |
|
397 | 408 | conditions=dict(function=check_repo, method=["DELETE"])) |
|
398 | 409 | |
@@ -493,5 +504,4 b' def make_map(config):' | |||
|
493 | 504 | controller='followers', action='followers', |
|
494 | 505 | conditions=dict(function=check_repo)) |
|
495 | 506 | |
|
496 | ||
|
497 | 507 | return rmap |
@@ -3,7 +3,7 b'' | |||
|
3 | 3 | rhodecode.controllers.admin.repos |
|
4 | 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
5 | 5 | |
|
6 |
|
|
|
6 | Repositories controller for RhodeCode | |
|
7 | 7 | |
|
8 | 8 | :created_on: Apr 7, 2010 |
|
9 | 9 | :author: marcink |
@@ -277,7 +277,6 b' class ReposController(BaseController):' | |||
|
277 | 277 | |
|
278 | 278 | return redirect(url('repos')) |
|
279 | 279 | |
|
280 | ||
|
281 | 280 | @HasRepoPermissionAllDecorator('repository.admin') |
|
282 | 281 | def delete_perm_user(self, repo_name): |
|
283 | 282 | """ |
@@ -287,10 +286,11 b' class ReposController(BaseController):' | |||
|
287 | 286 | """ |
|
288 | 287 | |
|
289 | 288 | try: |
|
290 | repo_model = RepoModel() | |
|
291 | repo_model.delete_perm_user(request.POST, repo_name) | |
|
289 | RepoModel().revoke_user_permission(repo=repo_name, | |
|
290 | user=request.POST['user_id']) | |
|
292 | 291 | Session.commit() |
|
293 |
except Exception |
|
|
292 | except Exception: | |
|
293 | log.error(traceback.format_exc()) | |
|
294 | 294 | h.flash(_('An error occurred during deletion of repository user'), |
|
295 | 295 | category='error') |
|
296 | 296 | raise HTTPInternalServerError() |
@@ -302,11 +302,14 b' class ReposController(BaseController):' | |||
|
302 | 302 | |
|
303 | 303 | :param repo_name: |
|
304 | 304 | """ |
|
305 | ||
|
305 | 306 | try: |
|
306 | repo_model = RepoModel() | |
|
307 | repo_model.delete_perm_users_group(request.POST, repo_name) | |
|
307 | RepoModel().revoke_users_group_permission( | |
|
308 | repo=repo_name, group_name=request.POST['users_group_id'] | |
|
309 | ) | |
|
308 | 310 | Session.commit() |
|
309 |
except Exception |
|
|
311 | except Exception: | |
|
312 | log.error(traceback.format_exc()) | |
|
310 | 313 | h.flash(_('An error occurred during deletion of repository' |
|
311 | 314 | ' users groups'), |
|
312 | 315 | category='error') |
@@ -321,8 +324,7 b' class ReposController(BaseController):' | |||
|
321 | 324 | """ |
|
322 | 325 | |
|
323 | 326 | try: |
|
324 | repo_model = RepoModel() | |
|
325 | repo_model.delete_stats(repo_name) | |
|
327 | RepoModel().delete_stats(repo_name) | |
|
326 | 328 | Session.commit() |
|
327 | 329 | except Exception, e: |
|
328 | 330 | h.flash(_('An error occurred during deletion of repository stats'), |
@@ -3,7 +3,7 b'' | |||
|
3 | 3 | rhodecode.controllers.admin.repos_groups |
|
4 | 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
5 | 5 | |
|
6 |
|
|
|
6 | Repositories groups controller for RhodeCode | |
|
7 | 7 | |
|
8 | 8 | :created_on: Mar 23, 2010 |
|
9 | 9 | :author: marcink |
@@ -29,19 +29,22 b' import formencode' | |||
|
29 | 29 | |
|
30 | 30 | from formencode import htmlfill |
|
31 | 31 | |
|
32 |
from pylons import request |
|
|
33 |
from pylons.controllers.util import |
|
|
32 | from pylons import request, tmpl_context as c, url | |
|
33 | from pylons.controllers.util import redirect | |
|
34 | 34 | from pylons.i18n.translation import _ |
|
35 | 35 | |
|
36 | 36 | from sqlalchemy.exc import IntegrityError |
|
37 | 37 | |
|
38 | 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 | 41 | from rhodecode.lib.base import BaseController, render |
|
41 | 42 | from rhodecode.model.db import RepoGroup |
|
42 | 43 | from rhodecode.model.repos_group import ReposGroupModel |
|
43 | 44 | from rhodecode.model.forms import ReposGroupForm |
|
44 | 45 | from rhodecode.model.meta import Session |
|
46 | from rhodecode.model.repo import RepoModel | |
|
47 | from webob.exc import HTTPInternalServerError | |
|
45 | 48 | |
|
46 | 49 | log = logging.getLogger(__name__) |
|
47 | 50 | |
@@ -60,6 +63,10 b' class ReposGroupsController(BaseControll' | |||
|
60 | 63 | c.repo_groups = RepoGroup.groups_choices() |
|
61 | 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 | 70 | def __load_data(self, group_id): |
|
64 | 71 | """ |
|
65 | 72 | Load defaults settings for edit, and update |
@@ -74,13 +81,22 b' class ReposGroupsController(BaseControll' | |||
|
74 | 81 | |
|
75 | 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 | 94 | return data |
|
78 | 95 | |
|
79 | 96 | @HasPermissionAnyDecorator('hg.admin') |
|
80 | 97 | def index(self, format='html'): |
|
81 | 98 | """GET /repos_groups: All items in the collection""" |
|
82 | 99 | # url('repos_groups') |
|
83 | ||
|
84 | 100 | sk = lambda g: g.parents[0].group_name if g.parents else g.group_name |
|
85 | 101 | c.groups = sorted(RepoGroup.query().all(), key=sk) |
|
86 | 102 | return render('admin/repos_groups/repos_groups_show.html') |
@@ -94,7 +110,11 b' class ReposGroupsController(BaseControll' | |||
|
94 | 110 | c.repo_groups_choices)() |
|
95 | 111 | try: |
|
96 | 112 | form_result = repos_group_form.to_python(dict(request.POST)) |
|
97 |
ReposGroupModel().create( |
|
|
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 | 118 | Session.commit() |
|
99 | 119 | h.flash(_('created repos group %s') \ |
|
100 | 120 | % form_result['group_name'], category='success') |
@@ -134,10 +154,11 b' class ReposGroupsController(BaseControll' | |||
|
134 | 154 | self.__load_defaults() |
|
135 | 155 | c.repos_group = RepoGroup.get(id) |
|
136 | 156 | |
|
137 |
repos_group_form = ReposGroupForm( |
|
|
138 | old_data=c.repos_group.get_dict(), | |
|
139 | available_groups= | |
|
140 | c.repo_groups_choices)() | |
|
157 | repos_group_form = ReposGroupForm( | |
|
158 | edit=True, | |
|
159 | old_data=c.repos_group.get_dict(), | |
|
160 | available_groups=c.repo_groups_choices | |
|
161 | )() | |
|
141 | 162 | try: |
|
142 | 163 | form_result = repos_group_form.to_python(dict(request.POST)) |
|
143 | 164 | ReposGroupModel().update(id, form_result) |
@@ -201,10 +222,52 b' class ReposGroupsController(BaseControll' | |||
|
201 | 222 | |
|
202 | 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 | 265 | def show_by_name(self, group_name): |
|
205 | 266 | id_ = RepoGroup.get_by_group_name(group_name).group_id |
|
206 | 267 | return self.show(id_) |
|
207 | 268 | |
|
269 | @HasReposGroupPermissionAnyDecorator('group.read', 'group.write', | |
|
270 | 'group.admin') | |
|
208 | 271 | def show(self, id, format='html'): |
|
209 | 272 | """GET /repos_groups/id: Show a specific item""" |
|
210 | 273 | # url('repos_group', id=ID) |
@@ -240,7 +303,7 b' class ReposGroupsController(BaseControll' | |||
|
240 | 303 | defaults = self.__load_data(id_) |
|
241 | 304 | |
|
242 | 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 | 308 | return htmlfill.render( |
|
246 | 309 | render('admin/repos_groups/repos_groups_edit.html'), |
@@ -401,13 +401,7 b' class ApiController(JSONRPCController):' | |||
|
401 | 401 | for g in groups: |
|
402 | 402 | group = RepoGroup.get_by_group_name(g) |
|
403 | 403 | if not group: |
|
404 | group = ReposGroupModel().create( | |
|
405 | dict( | |
|
406 | group_name=g, | |
|
407 | group_description='', | |
|
408 | group_parent_id=parent_id | |
|
409 | ) | |
|
410 | ) | |
|
404 | group = ReposGroupModel().create(g, '', parent_id) | |
|
411 | 405 | parent_id = group.group_id |
|
412 | 406 | |
|
413 | 407 | repo = RepoModel().create( |
@@ -434,11 +428,11 b' class ApiController(JSONRPCController):' | |||
|
434 | 428 | raise JSONRPCError('failed to create repository %s' % repo_name) |
|
435 | 429 | |
|
436 | 430 | @HasPermissionAnyDecorator('hg.admin') |
|
437 |
def |
|
|
431 | def grant_user_permission(self, repo_name, username, perm): | |
|
438 | 432 | """ |
|
439 |
|
|
|
433 | Grant permission for user on given repository, or update existing one | |
|
434 | if found | |
|
440 | 435 | |
|
441 | :param apiuser: | |
|
442 | 436 | :param repo_name: |
|
443 | 437 | :param username: |
|
444 | 438 | :param perm: |
@@ -449,17 +443,15 b' class ApiController(JSONRPCController):' | |||
|
449 | 443 | if repo is None: |
|
450 | 444 | raise JSONRPCError('unknown repository %s' % repo) |
|
451 | 445 | |
|
452 | try: | |
|
453 | user = User.get_by_username(username) | |
|
454 | except NoResultFound: | |
|
455 | raise JSONRPCError('unknown user %s' % user) | |
|
446 | user = User.get_by_username(username) | |
|
447 | if user is None: | |
|
448 | raise JSONRPCError('unknown user %s' % username) | |
|
456 | 449 | |
|
457 | RepositoryPermissionModel()\ | |
|
458 | .update_or_delete_user_permission(repo, user, perm) | |
|
450 | RepoModel().grant_user_permission(repo=repo, user=user, perm=perm) | |
|
451 | ||
|
459 | 452 | Session.commit() |
|
460 | ||
|
461 | 453 | return dict( |
|
462 |
msg=' |
|
|
454 | msg='Granted perm: %s for user: %s in repo: %s' % ( | |
|
463 | 455 | perm, username, repo_name |
|
464 | 456 | ) |
|
465 | 457 | ) |
@@ -472,11 +464,45 b' class ApiController(JSONRPCController):' | |||
|
472 | 464 | ) |
|
473 | 465 | |
|
474 | 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 | 506 | :param repo_name: |
|
481 | 507 | :param group_name: |
|
482 | 508 | :param perm: |
@@ -487,24 +513,59 b' class ApiController(JSONRPCController):' | |||
|
487 | 513 | if repo is None: |
|
488 | 514 | raise JSONRPCError('unknown repository %s' % repo) |
|
489 | 515 | |
|
490 | try: | |
|
491 | user_group = UsersGroup.get_by_group_name(group_name) | |
|
492 | except NoResultFound: | |
|
516 | user_group = UsersGroup.get_by_group_name(group_name) | |
|
517 | if user_group is None: | |
|
493 | 518 | raise JSONRPCError('unknown users group %s' % user_group) |
|
494 | 519 | |
|
495 | RepositoryPermissionModel()\ | |
|
496 | .update_or_delete_users_group_permission(repo, user_group, | |
|
497 |
|
|
|
520 | RepoModel().grant_users_group_permission(repo=repo_name, | |
|
521 | group_name=group_name, | |
|
522 | perm=perm) | |
|
523 | ||
|
498 | 524 | Session.commit() |
|
499 | 525 | return dict( |
|
500 |
msg=' |
|
|
526 | msg='Granted perm: %s for group: %s in repo: %s' % ( | |
|
501 | 527 | perm, group_name, repo_name |
|
502 | 528 | ) |
|
503 | 529 | ) |
|
504 | 530 | except Exception: |
|
505 | 531 | log.error(traceback.format_exc()) |
|
506 | 532 | raise JSONRPCError( |
|
507 | 'failed to edit permission %(repo)s for %(usergr)s' % dict( | |
|
508 | usergr=group_name, repo=repo_name | |
|
533 | 'failed to edit permission %(repo)s for %(usersgr)s' % dict( | |
|
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 | 31 | from rhodecode.lib.auth import LoginRequired |
|
32 | 32 | from rhodecode.lib.base import BaseController, render |
|
33 |
from rhodecode.model.db import |
|
|
33 | from rhodecode.model.db import Repository | |
|
34 | 34 | |
|
35 | 35 | log = logging.getLogger(__name__) |
|
36 | 36 | |
@@ -42,11 +42,8 b' class HomeController(BaseController):' | |||
|
42 | 42 | super(HomeController, self).__before__() |
|
43 | 43 | |
|
44 | 44 | def index(self): |
|
45 | ||
|
46 | 45 | c.repos_list = self.scm_model.get_repos() |
|
47 | ||
|
48 | c.groups = RepoGroup.query()\ | |
|
49 | .filter(RepoGroup.group_parent_id == None).all() | |
|
46 | c.groups = self.scm_model.get_repos_groups() | |
|
50 | 47 | |
|
51 | 48 | return render('/index.html') |
|
52 | 49 |
@@ -25,6 +25,8 b'' | |||
|
25 | 25 | |
|
26 | 26 | import os |
|
27 | 27 | import re |
|
28 | from vcs.utils.lazy import LazyProperty | |
|
29 | ||
|
28 | 30 | |
|
29 | 31 | def __get_lem(): |
|
30 | 32 | from pygments import lexers |
@@ -213,6 +215,7 b" def safe_unicode(str_, from_encoding='ut" | |||
|
213 | 215 | except (ImportError, UnicodeDecodeError, Exception): |
|
214 | 216 | return unicode(str_, from_encoding, 'replace') |
|
215 | 217 | |
|
218 | ||
|
216 | 219 | def safe_str(unicode_, to_encoding='utf8'): |
|
217 | 220 | """ |
|
218 | 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 | 253 | return safe_str |
|
251 | 254 | |
|
252 | 255 | |
|
253 | ||
|
254 | 256 | def engine_from_config(configuration, prefix='sqlalchemy.', **kwargs): |
|
255 | 257 | """ |
|
256 | 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 | 396 | return ''.join(uri) |
|
395 | 397 | |
|
398 | ||
|
396 | 399 | def get_changeset_safe(repo, rev): |
|
397 | 400 | """ |
|
398 | 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 | 440 | "was: %s" % err) |
|
438 | 441 | return None |
|
439 | 442 | |
|
443 | ||
|
440 | 444 | def extract_mentioned_users(s): |
|
441 | 445 | """ |
|
442 | 446 | Returns unique usernames from given string s that have @mention |
@@ -31,7 +31,7 b' import hashlib' | |||
|
31 | 31 | from tempfile import _RandomNameSequence |
|
32 | 32 | from decorator import decorator |
|
33 | 33 | |
|
34 |
from pylons import config, |
|
|
34 | from pylons import config, url, request | |
|
35 | 35 | from pylons.controllers.util import abort, redirect |
|
36 | 36 | from pylons.i18n.translation import _ |
|
37 | 37 | |
@@ -45,7 +45,7 b' if __platform__ in PLATFORM_OTHERS:' | |||
|
45 | 45 | |
|
46 | 46 | from rhodecode.lib import str2bool, safe_unicode |
|
47 | 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 | 49 | from rhodecode.lib.auth_ldap import AuthLdap |
|
50 | 50 | |
|
51 | 51 | from rhodecode.model import meta |
@@ -80,8 +80,8 b' class PasswordGenerator(object):' | |||
|
80 | 80 | def __init__(self, passwd=''): |
|
81 | 81 | self.passwd = passwd |
|
82 | 82 | |
|
83 | def gen_password(self, len, type): | |
|
84 | self.passwd = ''.join([random.choice(type) for _ in xrange(len)]) | |
|
83 | def gen_password(self, length, type_): | |
|
84 | self.passwd = ''.join([random.choice(type_) for _ in xrange(length)]) | |
|
85 | 85 | return self.passwd |
|
86 | 86 | |
|
87 | 87 | |
@@ -575,6 +575,41 b' class HasRepoPermissionAnyDecorator(Perm' | |||
|
575 | 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 | 614 | # CHECK FUNCTIONS |
|
580 | 615 | #============================================================================== |
@@ -641,8 +676,9 b' class HasRepoPermissionAll(PermsFunction' | |||
|
641 | 676 | self.repo_name = get_repo_slug(request) |
|
642 | 677 | |
|
643 | 678 | try: |
|
644 |
self.user_perms = set( |
|
|
645 | 'ories'][self.repo_name]]) | |
|
679 | self.user_perms = set( | |
|
680 | [self.user_perms['repositories'][self.repo_name]] | |
|
681 | ) | |
|
646 | 682 | except KeyError: |
|
647 | 683 | return False |
|
648 | 684 | self.granted_for = self.repo_name |
@@ -662,8 +698,9 b' class HasRepoPermissionAny(PermsFunction' | |||
|
662 | 698 | self.repo_name = get_repo_slug(request) |
|
663 | 699 | |
|
664 | 700 | try: |
|
665 |
self.user_perms = set( |
|
|
666 | 'tories'][self.repo_name]]) | |
|
701 | self.user_perms = set( | |
|
702 | [self.user_perms['repositories'][self.repo_name]] | |
|
703 | ) | |
|
667 | 704 | except KeyError: |
|
668 | 705 | return False |
|
669 | 706 | self.granted_for = self.repo_name |
@@ -672,6 +709,42 b' class HasRepoPermissionAny(PermsFunction' | |||
|
672 | 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 | 749 | # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH |
|
677 | 750 | #============================================================================== |
@@ -442,23 +442,28 b' class DbManage(object):' | |||
|
442 | 442 | |
|
443 | 443 | def create_permissions(self): |
|
444 | 444 | # module.(access|create|change|delete)_[name] |
|
445 |
# module.(read|write| |
|
|
446 | perms = [('repository.none', 'Repository no access'), | |
|
447 |
|
|
|
448 |
|
|
|
449 |
|
|
|
450 | ('hg.admin', 'Hg Administrator'), | |
|
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'), | |
|
445 | # module.(none|read|write|admin) | |
|
446 | perms = [ | |
|
447 | ('repository.none', 'Repository no access'), | |
|
448 | ('repository.read', 'Repository read access'), | |
|
449 | ('repository.write', 'Repository write access'), | |
|
450 | ('repository.admin', 'Repository admin access'), | |
|
457 | 451 | |
|
458 | ('hg.register.auto_activate', 'Register new user with ' | |
|
459 | 'RhodeCode without auto ' | |
|
460 | 'activation'), | |
|
461 | ] | |
|
452 | ('group.none', 'Repositories Group no access'), | |
|
453 | ('group.read', 'Repositories Group read access'), | |
|
454 | ('group.write', 'Repositories Group write access'), | |
|
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 | 468 | for p in perms: |
|
464 | 469 | new_perm = Permission() |
@@ -130,7 +130,7 b' def log_create_repository(repository_dic' | |||
|
130 | 130 | Post create repository Hook. This is a dummy function for admins to re-use |
|
131 | 131 | if needed |
|
132 | 132 | |
|
133 |
:param repository: dict dump of repository object |
|
|
133 | :param repository: dict dump of repository object | |
|
134 | 134 | :param created_by: username who created repository |
|
135 | 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 | 52 | from rhodecode.model.db import Repository, User, RhodeCodeUi, \ |
|
53 | 53 | UserLog, RepoGroup, RhodeCodeSetting |
|
54 | 54 | from rhodecode.model.meta import Session |
|
55 | from rhodecode.model.repos_group import ReposGroupModel | |
|
55 | 56 | |
|
56 | 57 | log = logging.getLogger(__name__) |
|
57 | 58 | |
@@ -94,6 +95,10 b' def get_repo_slug(request):' | |||
|
94 | 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 | 102 | def action_logger(user, action, repo, ipaddr='', sa=None, commit=False): |
|
98 | 103 | """ |
|
99 | 104 | Action logger for various actions made by users |
@@ -197,6 +202,7 b' def is_valid_repo(repo_name, base_path):' | |||
|
197 | 202 | except VCSError: |
|
198 | 203 | return False |
|
199 | 204 | |
|
205 | ||
|
200 | 206 | def is_valid_repos_group(repos_group_name, base_path): |
|
201 | 207 | """ |
|
202 | 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 | 223 | return False |
|
218 | 224 | |
|
225 | ||
|
219 | 226 | def ask_ok(prompt, retries=4, complaint='Yes or no, please!'): |
|
220 | 227 | while True: |
|
221 | 228 | ok = raw_input(prompt) |
@@ -317,7 +324,8 b' class EmptyChangeset(BaseChangeset):' | |||
|
317 | 324 | an EmptyChangeset |
|
318 | 325 | """ |
|
319 | 326 | |
|
320 |
def __init__(self, cs='0' * 40, repo=None, requested_revision=None, |
|
|
327 | def __init__(self, cs='0' * 40, repo=None, requested_revision=None, | |
|
328 | alias=None): | |
|
321 | 329 | self._empty_cs = cs |
|
322 | 330 | self.revision = -1 |
|
323 | 331 | self.message = '' |
@@ -368,14 +376,23 b' def map_groups(groups):' | |||
|
368 | 376 | |
|
369 | 377 | # last element is repo in nested groups structure |
|
370 | 378 | groups = groups[:-1] |
|
371 | ||
|
379 | rgm = ReposGroupModel(sa) | |
|
372 | 380 | for lvl, group_name in enumerate(groups): |
|
381 | log.debug('creating group level: %s group_name: %s' % (lvl, group_name)) | |
|
373 | 382 | group_name = '/'.join(groups[:lvl] + [group_name]) |
|
374 |
group = |
|
|
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 | 391 | if group is None: |
|
377 | 392 | group = RepoGroup(group_name, parent) |
|
393 | group.group_description = desc | |
|
378 | 394 | sa.add(group) |
|
395 | rgm._create_default_perms(group) | |
|
379 | 396 | sa.commit() |
|
380 | 397 | parent = group |
|
381 | 398 | return group |
@@ -404,15 +421,14 b' def repo2db_mapper(initial_repo_list, re' | |||
|
404 | 421 | log.info('repository %s not found creating default' % name) |
|
405 | 422 | added.append(name) |
|
406 | 423 | form_data = { |
|
407 |
|
|
|
408 |
|
|
|
409 |
|
|
|
410 |
|
|
|
411 |
|
|
|
412 | '%s repository' % name, | |
|
413 | 'private': False, | |
|
414 | 'group_id': getattr(group, 'group_id', None) | |
|
415 | } | |
|
424 | 'repo_name': name, | |
|
425 | 'repo_name_full': name, | |
|
426 | 'repo_type': repo.alias, | |
|
427 | 'description': repo.description \ | |
|
428 | if repo.description != 'unknown' else '%s repository' % name, | |
|
429 | 'private': False, | |
|
430 | 'group_id': getattr(group, 'group_id', None) | |
|
431 | } | |
|
416 | 432 | rm.create(form_data, user, just_db=True) |
|
417 | 433 | sa.commit() |
|
418 | 434 | removed = [] |
@@ -426,6 +442,7 b' def repo2db_mapper(initial_repo_list, re' | |||
|
426 | 442 | |
|
427 | 443 | return added, removed |
|
428 | 444 | |
|
445 | ||
|
429 | 446 | # set cache regions for beaker so celery can utilise it |
|
430 | 447 | def add_cache(settings): |
|
431 | 448 | cache_settings = {'regions': None} |
@@ -74,12 +74,13 b' class BaseModel(object):' | |||
|
74 | 74 | else: |
|
75 | 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 | 81 | :param cls: class to fetch |
|
82 | 82 | :param instance: int or Instance |
|
83 | :param callback: callback to call if all lookups failed | |
|
83 | 84 | """ |
|
84 | 85 | |
|
85 | 86 | if isinstance(instance, cls): |
@@ -88,5 +89,10 b' class BaseModel(object):' | |||
|
88 | 89 | return cls.get(instance) |
|
89 | 90 | else: |
|
90 | 91 | if instance: |
|
91 | raise Exception('given object must be int or Instance' | |
|
92 | ' of %s got %s' % (type(cls), type(instance))) | |
|
92 | if callback is None: | |
|
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 | 717 | group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None) |
|
718 | 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 | 723 | parent_group = relationship('RepoGroup', remote_side=group_id) |
|
721 | 724 | |
|
722 | 725 | def __init__(self, group_name='', parent_group=None): |
@@ -833,8 +836,9 b' class Permission(Base, BaseModel):' | |||
|
833 | 836 | permission_longname = Column("permission_longname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) |
|
834 | 837 | |
|
835 | 838 | def __repr__(self): |
|
836 |
return "<%s('%s:%s')>" % ( |
|
|
837 |
|
|
|
839 | return "<%s('%s:%s')>" % ( | |
|
840 | self.__class__.__name__, self.permission_id, self.permission_name | |
|
841 | ) | |
|
838 | 842 | |
|
839 | 843 | @classmethod |
|
840 | 844 | def get_by_key(cls, key): |
@@ -843,9 +847,18 b' class Permission(Base, BaseModel):' | |||
|
843 | 847 | @classmethod |
|
844 | 848 | def get_default_perms(cls, default_user_id): |
|
845 | 849 | q = Session.query(UserRepoToPerm, Repository, cls)\ |
|
846 |
|
|
|
847 |
|
|
|
848 |
|
|
|
850 | .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\ | |
|
851 | .join((cls, UserRepoToPerm.permission_id == cls.permission_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 | 863 | return q.all() |
|
851 | 864 |
@@ -388,57 +388,66 b' def ValidForkType(old_data):' | |||
|
388 | 388 | return _ValidForkType |
|
389 | 389 | |
|
390 | 390 | |
|
391 | class ValidPerms(formencode.validators.FancyValidator): | |
|
392 | messages = {'perm_new_member_name': _('This username or users group name' | |
|
393 | ' is not valid')} | |
|
391 | def ValidPerms(type_='repo'): | |
|
392 | if type_ == 'group': | |
|
393 | EMPTY_PERM = 'group.none' | |
|
394 | elif type_ == 'repo': | |
|
395 | EMPTY_PERM = 'repository.none' | |
|
394 | 396 | |
|
395 | def to_python(self, value, state): | |
|
396 |
|
|
|
397 | perms_new = [] | |
|
398 | #build a list of permission to update and new permission to create | |
|
399 | for k, v in value.items(): | |
|
400 | #means new added member to permissions | |
|
401 | if k.startswith('perm_new_member'): | |
|
402 | new_perm = value.get('perm_new_member', False) | |
|
403 | new_member = value.get('perm_new_member_name', False) | |
|
404 | new_type = value.get('perm_new_member_type') | |
|
397 | class _ValidPerms(formencode.validators.FancyValidator): | |
|
398 | messages = { | |
|
399 | 'perm_new_member_name': | |
|
400 | _('This username or users group name is not valid') | |
|
401 | } | |
|
402 | ||
|
403 | def to_python(self, value, state): | |
|
404 | perms_update = [] | |
|
405 | perms_new = [] | |
|
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: | |
|
407 | if (new_member, new_perm, new_type) not in perms_new: | |
|
408 | perms_new.append((new_member, new_perm, new_type)) | |
|
409 | elif k.startswith('u_perm_') or k.startswith('g_perm_'): | |
|
410 | member = k[7:] | |
|
411 | t = {'u': 'user', | |
|
412 | 'g': 'users_group' | |
|
413 | }[k[0]] | |
|
414 | if member == 'default': | |
|
415 |
if value |
|
|
416 | #set none for default when updating to private repo | |
|
417 |
v = |
|
|
418 | perms_update.append((member, v, t)) | |
|
414 | if new_member and new_perm: | |
|
415 | if (new_member, new_perm, new_type) not in perms_new: | |
|
416 | perms_new.append((new_member, new_perm, new_type)) | |
|
417 | elif k.startswith('u_perm_') or k.startswith('g_perm_'): | |
|
418 | member = k[7:] | |
|
419 | t = {'u': 'user', | |
|
420 | 'g': 'users_group' | |
|
421 | }[k[0]] | |
|
422 | if member == 'default': | |
|
423 | if value.get('private'): | |
|
424 | # set none for default when updating to private repo | |
|
425 | v = EMPTY_PERM | |
|
426 | perms_update.append((member, v, t)) | |
|
419 | 427 | |
|
420 | value['perms_updates'] = perms_update | |
|
421 | value['perms_new'] = perms_new | |
|
428 | value['perms_updates'] = perms_update | |
|
429 | value['perms_new'] = perms_new | |
|
422 | 430 | |
|
423 | #update permissions | |
|
424 | for k, v, t in perms_new: | |
|
425 | try: | |
|
426 | if t is 'user': | |
|
427 | self.user_db = User.query()\ | |
|
428 | .filter(User.active == True)\ | |
|
429 | .filter(User.username == k).one() | |
|
430 | if t is 'users_group': | |
|
431 | self.user_db = UsersGroup.query()\ | |
|
432 | .filter(UsersGroup.users_group_active == True)\ | |
|
433 | .filter(UsersGroup.users_group_name == k).one() | |
|
431 | # update permissions | |
|
432 | for k, v, t in perms_new: | |
|
433 | try: | |
|
434 | if t is 'user': | |
|
435 | self.user_db = User.query()\ | |
|
436 | .filter(User.active == True)\ | |
|
437 | .filter(User.username == k).one() | |
|
438 | if t is 'users_group': | |
|
439 | self.user_db = UsersGroup.query()\ | |
|
440 | .filter(UsersGroup.users_group_active == True)\ | |
|
441 | .filter(UsersGroup.users_group_name == k).one() | |
|
434 | 442 | |
|
435 | except Exception: | |
|
436 | msg = self.message('perm_new_member_name', | |
|
437 | state=State_obj) | |
|
438 | raise formencode.Invalid( | |
|
439 | msg, value, state, error_dict={'perm_new_member_name': msg} | |
|
440 | ) | |
|
441 | return value | |
|
443 | except Exception: | |
|
444 | msg = self.message('perm_new_member_name', | |
|
445 | state=State_obj) | |
|
446 | raise formencode.Invalid( | |
|
447 | msg, value, state, error_dict={'perm_new_member_name': msg} | |
|
448 | ) | |
|
449 | return value | |
|
450 | return _ValidPerms | |
|
442 | 451 | |
|
443 | 452 | |
|
444 | 453 | class ValidSettings(formencode.validators.FancyValidator): |
@@ -588,7 +597,7 b' def UsersGroupForm(edit=False, old_data=' | |||
|
588 | 597 | def ReposGroupForm(edit=False, old_data={}, available_groups=[]): |
|
589 | 598 | class _ReposGroupForm(formencode.Schema): |
|
590 | 599 | allow_extra_fields = True |
|
591 |
filter_extra_fields = |
|
|
600 | filter_extra_fields = False | |
|
592 | 601 | |
|
593 | 602 | group_name = All(UnicodeString(strip=True, min=1, not_empty=True), |
|
594 | 603 | SlugifyName()) |
@@ -598,7 +607,7 b' def ReposGroupForm(edit=False, old_data=' | |||
|
598 | 607 | testValueList=True, |
|
599 | 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 | 612 | return _ReposGroupForm |
|
604 | 613 | |
@@ -649,7 +658,7 b' def RepoForm(edit=False, old_data={}, su' | |||
|
649 | 658 | #this is repo owner |
|
650 | 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 | 662 | return _RepoForm |
|
654 | 663 | |
|
655 | 664 | |
@@ -683,7 +692,7 b' def RepoSettingsForm(edit=False, old_dat' | |||
|
683 | 692 | repo_group = OneOf(repo_groups, hideList=True) |
|
684 | 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 | 696 | ValidSettings] |
|
688 | 697 | return _RepoForm |
|
689 | 698 |
@@ -42,10 +42,7 b' log = logging.getLogger(__name__)' | |||
|
42 | 42 | class NotificationModel(BaseModel): |
|
43 | 43 | |
|
44 | 44 | def __get_user(self, user): |
|
45 | if isinstance(user, basestring): | |
|
46 | return User.get_by_username(username=user) | |
|
47 | else: | |
|
48 | return self._get_instance(User, user) | |
|
45 | return self._get_instance(User, user, callback=User.get_by_username) | |
|
49 | 46 | |
|
50 | 47 | def __get_notification(self, notification): |
|
51 | 48 | if isinstance(notification, Notification): |
@@ -28,9 +28,9 b' import logging' | |||
|
28 | 28 | import traceback |
|
29 | 29 | from datetime import datetime |
|
30 | 30 | |
|
31 | from vcs.utils.lazy import LazyProperty | |
|
32 | 31 | from vcs.backends import get_backend |
|
33 | 32 | |
|
33 | from rhodecode.lib import LazyProperty | |
|
34 | 34 | from rhodecode.lib import safe_str, safe_unicode |
|
35 | 35 | from rhodecode.lib.caching_query import FromCache |
|
36 | 36 | from rhodecode.lib.hooks import log_create_repository |
@@ -39,11 +39,31 b' from rhodecode.model import BaseModel' | |||
|
39 | 39 | from rhodecode.model.db import Repository, UserRepoToPerm, User, Permission, \ |
|
40 | 40 | Statistics, UsersGroup, UsersGroupRepoToPerm, RhodeCodeUi, RepoGroup |
|
41 | 41 | |
|
42 | ||
|
42 | 43 | log = logging.getLogger(__name__) |
|
43 | 44 | |
|
44 | 45 | |
|
45 | 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 | 67 | @LazyProperty |
|
48 | 68 | def repos_path(self): |
|
49 | 69 | """ |
@@ -138,49 +158,24 b' class RepoModel(BaseModel):' | |||
|
138 | 158 | # update permissions |
|
139 | 159 | for member, perm, member_type in form_data['perms_updates']: |
|
140 | 160 | if member_type == 'user': |
|
141 | _member = User.get_by_username(member) | |
|
142 | r2p = self.sa.query(UserRepoToPerm)\ | |
|
143 |
|
|
|
144 | .filter(UserRepoToPerm.repository == cur_repo)\ | |
|
145 | .one() | |
|
146 | ||
|
147 | r2p.permission = self.sa.query(Permission)\ | |
|
148 | .filter(Permission.permission_name == | |
|
149 | perm).scalar() | |
|
150 | self.sa.add(r2p) | |
|
161 | # this updates existing one | |
|
162 | RepoModel().grant_user_permission( | |
|
163 | repo=cur_repo, user=member, perm=perm | |
|
164 | ) | |
|
151 | 165 | else: |
|
152 |
|
|
|
153 | .filter(UsersGroupRepoToPerm.users_group == | |
|
154 | UsersGroup.get_by_group_name(member))\ | |
|
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 | ||
|
166 | RepoModel().grant_users_group_permission( | |
|
167 | repo=cur_repo, group_name=member, perm=perm | |
|
168 | ) | |
|
163 | 169 | # set new permissions |
|
164 | 170 | for member, perm, member_type in form_data['perms_new']: |
|
165 | 171 | if member_type == 'user': |
|
166 |
|
|
|
167 |
|
|
|
168 | r2p.user = User.get_by_username(member) | |
|
169 | ||
|
170 | r2p.permission = self.sa.query(Permission)\ | |
|
171 | .filter(Permission. | |
|
172 | permission_name == perm)\ | |
|
173 | .scalar() | |
|
174 | self.sa.add(r2p) | |
|
172 | RepoModel().grant_user_permission( | |
|
173 | repo=cur_repo, user=member, perm=perm | |
|
174 | ) | |
|
175 | 175 | else: |
|
176 |
|
|
|
177 | g2p.repository = cur_repo | |
|
178 | g2p.users_group = UsersGroup.get_by_group_name(member) | |
|
179 | g2p.permission = self.sa.query(Permission)\ | |
|
180 | .filter(Permission. | |
|
181 | permission_name == perm)\ | |
|
182 | .scalar() | |
|
183 | self.sa.add(g2p) | |
|
176 | RepoModel().grant_users_group_permission( | |
|
177 | repo=cur_repo, group_name=member, perm=perm | |
|
178 | ) | |
|
184 | 179 | |
|
185 | 180 | # update current repo |
|
186 | 181 | for k, v in form_data.items(): |
@@ -314,28 +309,93 b' class RepoModel(BaseModel):' | |||
|
314 | 309 | log.error(traceback.format_exc()) |
|
315 | 310 | raise |
|
316 | 311 | |
|
317 | def delete_perm_user(self, form_data, repo_name): | |
|
318 |
|
|
|
319 | obj = self.sa.query(UserRepoToPerm)\ | |
|
320 | .filter(UserRepoToPerm.repository \ | |
|
321 | == self.get_by_repo_name(repo_name))\ | |
|
322 | .filter(UserRepoToPerm.user_id == form_data['user_id']).one() | |
|
323 | self.sa.delete(obj) | |
|
324 | except: | |
|
325 | log.error(traceback.format_exc()) | |
|
326 | raise | |
|
312 | def grant_user_permission(self, repo, user, perm): | |
|
313 | """ | |
|
314 | Grant permission for user on given repository, or update existing one | |
|
315 | if found | |
|
316 | ||
|
317 | :param repo: Instance of Repository, repository_id, or repository name | |
|
318 | :param user: Instance of User, user_id or username | |
|
319 | :param perm: Instance of Permission, or permission_name | |
|
320 | """ | |
|
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 |
|
|
329 |
|
|
|
330 | obj = self.sa.query(UsersGroupRepoToPerm)\ | |
|
331 | .filter(UsersGroupRepoToPerm.repository \ | |
|
332 | == self.get_by_repo_name(repo_name))\ | |
|
333 | .filter(UsersGroupRepoToPerm.users_group_id | |
|
334 | == form_data['users_group_id']).one() | |
|
335 | self.sa.delete(obj) | |
|
336 | except: | |
|
337 | log.error(traceback.format_exc()) | |
|
338 | raise | |
|
354 | def grant_users_group_permission(self, repo, group_name, perm): | |
|
355 | """ | |
|
356 | Grant permission for users group on given repository, or update | |
|
357 | existing one if found | |
|
358 | ||
|
359 | :param repo: Instance of Repository, repository_id, or repository name | |
|
360 | :param group_name: Instance of UserGroup, users_group_id, | |
|
361 | or users group name | |
|
362 | :param perm: Instance of Permission, or permission_name | |
|
363 | """ | |
|
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 | 400 | def delete_stats(self, repo_name): |
|
341 | 401 | """ |
@@ -345,8 +405,9 b' class RepoModel(BaseModel):' | |||
|
345 | 405 | """ |
|
346 | 406 | try: |
|
347 | 407 | obj = self.sa.query(Statistics)\ |
|
348 |
.filter(Statistics.repository == |
|
|
349 |
self.get_by_repo_name(repo_name)) |
|
|
408 | .filter(Statistics.repository == | |
|
409 | self.get_by_repo_name(repo_name))\ | |
|
410 | .one() | |
|
350 | 411 | self.sa.delete(obj) |
|
351 | 412 | except: |
|
352 | 413 | log.error(traceback.format_exc()) |
@@ -373,10 +434,9 b' class RepoModel(BaseModel):' | |||
|
373 | 434 | new_parent_path = '' |
|
374 | 435 | |
|
375 | 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 | 438 | [self.repos_path, new_parent_path, repo_name])) |
|
378 | 439 | |
|
379 | ||
|
380 | 440 | # check if this path is not a repository |
|
381 | 441 | if is_valid_repo(repo_path, self.repos_path): |
|
382 | 442 | raise Exception('This path %s is a valid repository' % repo_path) |
@@ -393,7 +453,6 b' class RepoModel(BaseModel):' | |||
|
393 | 453 | |
|
394 | 454 | backend(repo_path, create=True, src_url=clone_uri) |
|
395 | 455 | |
|
396 | ||
|
397 | 456 | def __rename_repo(self, old, new): |
|
398 | 457 | """ |
|
399 | 458 | renames repository on filesystem |
@@ -406,8 +465,9 b' class RepoModel(BaseModel):' | |||
|
406 | 465 | old_path = os.path.join(self.repos_path, old) |
|
407 | 466 | new_path = os.path.join(self.repos_path, new) |
|
408 | 467 | if os.path.isdir(new_path): |
|
409 | raise Exception('Was trying to rename to already existing dir %s' \ | |
|
410 | % new_path) | |
|
468 | raise Exception( | |
|
469 | 'Was trying to rename to already existing dir %s' % new_path | |
|
470 | ) | |
|
411 | 471 | shutil.move(old_path, new_path) |
|
412 | 472 | |
|
413 | 473 | def __delete_repo(self, repo): |
@@ -426,7 +486,6 b' class RepoModel(BaseModel):' | |||
|
426 | 486 | shutil.move(os.path.join(rm_path, '.%s' % alias), |
|
427 | 487 | os.path.join(rm_path, 'rm__.%s' % alias)) |
|
428 | 488 | # disable repo |
|
429 | shutil.move(rm_path, os.path.join(self.repos_path, 'rm__%s__%s' \ | |
|
430 |
|
|
|
431 | .strftime('%Y%m%d_%H%M%S_%f'), | |
|
432 | repo.repo_name))) | |
|
489 | _d = 'rm__%s__%s' % (datetime.now().strftime('%Y%m%d_%H%M%S_%f'), | |
|
490 | repo.repo_name) | |
|
491 | shutil.move(rm_path, os.path.join(self.repos_path, _d)) |
@@ -26,14 +26,29 b'' | |||
|
26 | 26 | |
|
27 | 27 | import logging |
|
28 | 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 | 32 | log = logging.getLogger(__name__) |
|
32 | 33 | |
|
33 | 34 | |
|
34 | 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 | 48 | def get_user_permission(self, repository, user): |
|
49 | repository = self.__get_repo(repository) | |
|
50 | user = self.__get_user(user) | |
|
51 | ||
|
37 | 52 | return UserRepoToPerm.query() \ |
|
38 | 53 | .filter(UserRepoToPerm.user == user) \ |
|
39 | 54 | .filter(UserRepoToPerm.repository == repository) \ |
@@ -28,18 +28,32 b' import logging' | |||
|
28 | 28 | import traceback |
|
29 | 29 | import shutil |
|
30 | 30 | |
|
31 | from pylons.i18n.translation import _ | |
|
32 | ||
|
33 | from vcs.utils.lazy import LazyProperty | |
|
31 | from rhodecode.lib import LazyProperty | |
|
34 | 32 | |
|
35 | 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 | 37 | log = logging.getLogger(__name__) |
|
39 | 38 | |
|
40 | 39 | |
|
41 | 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 | 57 | @LazyProperty |
|
44 | 58 | def repos_path(self): |
|
45 | 59 | """ |
@@ -49,6 +63,24 b' class ReposGroupModel(BaseModel):' | |||
|
49 | 63 | q = RhodeCodeUi.get_by_key('/').one() |
|
50 | 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 | 84 | def __create_group(self, group_name): |
|
53 | 85 | """ |
|
54 | 86 | makes repositories group on filesystem |
@@ -102,16 +134,21 b' class ReposGroupModel(BaseModel):' | |||
|
102 | 134 | # delete only if that path really exists |
|
103 | 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 | 138 | try: |
|
107 | 139 | new_repos_group = RepoGroup() |
|
108 |
new_repos_group.group_description = |
|
|
109 |
new_repos_group.parent_group = |
|
|
110 |
new_repos_group.group_name = new_repos_group.get_new_name( |
|
|
140 | new_repos_group.group_description = group_description | |
|
141 | new_repos_group.parent_group = self.__get_repos_group(parent) | |
|
142 | new_repos_group.group_name = new_repos_group.get_new_name(group_name) | |
|
111 | 143 | |
|
112 | 144 | self.sa.add(new_repos_group) |
|
113 | self.sa.flush() | |
|
114 | self.__create_group(new_repos_group.group_name) | |
|
145 | self._create_default_perms(new_repos_group) | |
|
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 | 153 | return new_repos_group |
|
117 | 154 | except: |
@@ -122,6 +159,29 b' class ReposGroupModel(BaseModel):' | |||
|
122 | 159 | |
|
123 | 160 | try: |
|
124 | 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 | 185 | old_path = repos_group.full_path |
|
126 | 186 | |
|
127 | 187 | # change properties |
@@ -154,3 +214,97 b' class ReposGroupModel(BaseModel):' | |||
|
154 | 214 | except: |
|
155 | 215 | log.error(traceback.format_exc()) |
|
156 | 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 | 36 | from rhodecode import BACKENDS |
|
37 | 37 | from rhodecode.lib import helpers as h |
|
38 | 38 | from rhodecode.lib import safe_str |
|
39 | from rhodecode.lib.auth import HasRepoPermissionAny | |
|
39 | from rhodecode.lib.auth import HasRepoPermissionAny, HasReposGroupPermissionAny | |
|
40 | 40 | from rhodecode.lib.utils import get_repos as get_filesystem_repos, make_ui, \ |
|
41 | 41 | action_logger, EmptyChangeset |
|
42 | 42 | from rhodecode.model import BaseModel |
|
43 | 43 | from rhodecode.model.db import Repository, RhodeCodeUi, CacheInvalidation, \ |
|
44 | UserFollowing, UserLog, User | |
|
44 | UserFollowing, UserLog, User, RepoGroup | |
|
45 | 45 | |
|
46 | 46 | log = logging.getLogger(__name__) |
|
47 | 47 | |
@@ -80,15 +80,16 b' class CachedRepoList(object):' | |||
|
80 | 80 | for dbr in self.db_repo_list: |
|
81 | 81 | scmr = dbr.scm_instance_cached |
|
82 | 82 | # check permission at this level |
|
83 |
if not HasRepoPermissionAny( |
|
|
84 | 'repository.admin')(dbr.repo_name, | |
|
85 | 'get repo check'): | |
|
83 | if not HasRepoPermissionAny( | |
|
84 | 'repository.read', 'repository.write', 'repository.admin' | |
|
85 | )(dbr.repo_name, 'get repo check'): | |
|
86 | 86 | continue |
|
87 | 87 | |
|
88 | 88 | if scmr is None: |
|
89 | log.error('%s this repository is present in database but it ' | |
|
90 | 'cannot be created as an scm instance', | |
|
91 |
dbr.repo_name |
|
|
89 | log.error( | |
|
90 | '%s this repository is present in database but it ' | |
|
91 | 'cannot be created as an scm instance' % dbr.repo_name | |
|
92 | ) | |
|
92 | 93 | continue |
|
93 | 94 | |
|
94 | 95 | last_change = scmr.last_change |
@@ -115,6 +116,28 b' class CachedRepoList(object):' | |||
|
115 | 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 | 141 | class ScmModel(BaseModel): |
|
119 | 142 | """ |
|
120 | 143 | Generic Scm Model |
@@ -200,6 +223,14 b' class ScmModel(BaseModel):' | |||
|
200 | 223 | |
|
201 | 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 | 234 | def mark_for_invalidation(self, repo_name): |
|
204 | 235 | """Puts cache invalidation task into db for |
|
205 | 236 | further global cache invalidation |
@@ -35,7 +35,7 b' from rhodecode.lib.caching_query import ' | |||
|
35 | 35 | from rhodecode.model import BaseModel |
|
36 | 36 | from rhodecode.model.db import User, UserRepoToPerm, Repository, Permission, \ |
|
37 | 37 | UserToPerm, UsersGroupRepoToPerm, UsersGroupToPerm, UsersGroupMember, \ |
|
38 | Notification | |
|
38 | Notification, RepoGroup, UserRepoGroupToPerm, UsersGroup | |
|
39 | 39 | from rhodecode.lib.exceptions import DefaultUserException, \ |
|
40 | 40 | UserOwnsReposException |
|
41 | 41 | |
@@ -46,16 +46,26 b' from sqlalchemy.orm import joinedload' | |||
|
46 | 46 | log = logging.getLogger(__name__) |
|
47 | 47 | |
|
48 | 48 | |
|
49 |
PERM_WEIGHTS = { |
|
|
50 |
|
|
|
51 |
|
|
|
52 |
|
|
|
49 | PERM_WEIGHTS = { | |
|
50 | 'repository.none': 0, | |
|
51 | 'repository.read': 1, | |
|
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 | 61 | class UserModel(BaseModel): |
|
56 | 62 | |
|
57 | 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 | 70 | def get(self, user_id, cache=False): |
|
61 | 71 | user = self.sa.query(User) |
@@ -348,9 +358,12 b' class UserModel(BaseModel):' | |||
|
348 | 358 | |
|
349 | 359 | :param user: user instance to fill his perms |
|
350 | 360 | """ |
|
351 | ||
|
352 | user.permissions['repositories'] = {} | |
|
353 | user.permissions['global'] = set() | |
|
361 | RK = 'repositories' | |
|
362 | GK = 'repositories_groups' | |
|
363 | GLOBAL = 'global' | |
|
364 | user.permissions[RK] = {} | |
|
365 | user.permissions[GK] = {} | |
|
366 | user.permissions[GLOBAL] = set() | |
|
354 | 367 | |
|
355 | 368 | #====================================================================== |
|
356 | 369 | # fetch default permissions |
@@ -358,36 +371,45 b' class UserModel(BaseModel):' | |||
|
358 | 371 | default_user = User.get_by_username('default', cache=True) |
|
359 | 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 | 377 | if user.is_admin: |
|
364 | 378 | #================================================================== |
|
365 |
# |
|
|
379 | # admin user have all default rights for repositories | |
|
380 | # and groups set to admin | |
|
366 | 381 | #================================================================== |
|
367 |
user.permissions[ |
|
|
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 | 387 | p = 'repository.admin' |
|
371 |
user.permissions[ |
|
|
372 | repository.repo_name] = p | |
|
388 | user.permissions[RK][r_k] = 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 | 396 | else: |
|
375 | 397 | #================================================================== |
|
376 | # set default permissions | |
|
398 | # set default permissions first for repositories and groups | |
|
377 | 399 | #================================================================== |
|
378 | 400 | uid = user.user_id |
|
379 | 401 | |
|
380 | # default global | |
|
402 | # default global permissions | |
|
381 | 403 | default_global_perms = self.sa.query(UserToPerm)\ |
|
382 | 404 | .filter(UserToPerm.user_id == default_user_id) |
|
383 | 405 | |
|
384 | 406 | for perm in default_global_perms: |
|
385 |
user.permissions[ |
|
|
407 | user.permissions[GLOBAL].add(perm.permission.permission_name) | |
|
386 | 408 | |
|
387 | 409 | # default for repositories |
|
388 | for perm in default_perms: | |
|
389 | if perm.Repository.private and not (perm.Repository.user_id == | |
|
390 | uid): | |
|
410 | for perm in default_repo_perms: | |
|
411 | r_k = perm.UserRepoToPerm.repository.repo_name | |
|
412 | if perm.Repository.private and not (perm.Repository.user_id == uid): | |
|
391 | 413 | # disable defaults for private repos, |
|
392 | 414 | p = 'repository.none' |
|
393 | 415 | elif perm.Repository.user_id == uid: |
@@ -396,8 +418,13 b' class UserModel(BaseModel):' | |||
|
396 | 418 | else: |
|
397 | 419 | p = perm.Permission.permission_name |
|
398 | 420 | |
|
399 |
user.permissions[ |
|
|
400 | repository.repo_name] = p | |
|
421 | user.permissions[RK][r_k] = 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 | 430 | # overwrite default with user permissions if any |
@@ -409,25 +436,24 b' class UserModel(BaseModel):' | |||
|
409 | 436 | .filter(UserToPerm.user_id == uid).all() |
|
410 | 437 | |
|
411 | 438 | for perm in user_perms: |
|
412 |
user.permissions[ |
|
|
439 | user.permissions[GLOBAL].add(perm.permission.permission_name) | |
|
413 | 440 | |
|
414 | 441 | # user repositories |
|
415 | user_repo_perms = self.sa.query(UserRepoToPerm, Permission, | |
|
416 | Repository)\ | |
|
417 |
|
|
|
418 | Repository.repo_id))\ | |
|
419 |
|
|
|
420 | Permission.permission_id))\ | |
|
421 | .filter(UserRepoToPerm.user_id == uid).all() | |
|
442 | user_repo_perms = \ | |
|
443 | self.sa.query(UserRepoToPerm, Permission, Repository)\ | |
|
444 | .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\ | |
|
445 | .join((Permission, UserRepoToPerm.permission_id == Permission.permission_id))\ | |
|
446 | .filter(UserRepoToPerm.user_id == uid)\ | |
|
447 | .all() | |
|
422 | 448 | |
|
423 | 449 | for perm in user_repo_perms: |
|
424 | 450 | # set admin if owner |
|
451 | r_k = perm.UserRepoToPerm.repository.repo_name | |
|
425 | 452 | if perm.Repository.user_id == uid: |
|
426 | 453 | p = 'repository.admin' |
|
427 | 454 | else: |
|
428 | 455 | p = perm.Permission.permission_name |
|
429 |
user.permissions[ |
|
|
430 | repository.repo_name] = p | |
|
456 | user.permissions[RK][r_k] = p | |
|
431 | 457 | |
|
432 | 458 | #================================================================== |
|
433 | 459 | # check if user is part of groups for this repository and fill in |
@@ -442,30 +468,44 b' class UserModel(BaseModel):' | |||
|
442 | 468 | .filter(UsersGroupMember.user_id == uid).all() |
|
443 | 469 | |
|
444 | 470 | for perm in user_perms_from_users_groups: |
|
445 |
user.permissions[ |
|
|
471 | user.permissions[GLOBAL].add(perm.permission.permission_name) | |
|
446 | 472 | |
|
447 | 473 | # users group repositories |
|
448 |
user_repo_perms_from_users_groups = |
|
|
449 | UsersGroupRepoToPerm, | |
|
450 | Permission, Repository,)\ | |
|
451 |
|
|
|
452 | Repository.repo_id))\ | |
|
453 |
|
|
|
454 | Permission.permission_id))\ | |
|
455 | .join((UsersGroupMember, UsersGroupRepoToPerm.users_group_id == | |
|
456 | UsersGroupMember.users_group_id))\ | |
|
457 | .filter(UsersGroupMember.user_id == uid).all() | |
|
474 | user_repo_perms_from_users_groups = \ | |
|
475 | self.sa.query(UsersGroupRepoToPerm, Permission, Repository,)\ | |
|
476 | .join((Repository, UsersGroupRepoToPerm.repository_id == Repository.repo_id))\ | |
|
477 | .join((Permission, UsersGroupRepoToPerm.permission_id == Permission.permission_id))\ | |
|
478 | .join((UsersGroupMember, UsersGroupRepoToPerm.users_group_id == UsersGroupMember.users_group_id))\ | |
|
479 | .filter(UsersGroupMember.user_id == uid)\ | |
|
480 | .all() | |
|
458 | 481 | |
|
459 | 482 | for perm in user_repo_perms_from_users_groups: |
|
483 | r_k = perm.UsersGroupRepoToPerm.repository.repo_name | |
|
460 | 484 | p = perm.Permission.permission_name |
|
461 |
cur_perm = user.permissions[ |
|
|
462 | UsersGroupRepoToPerm. | |
|
463 | repository.repo_name] | |
|
485 | cur_perm = user.permissions[RK][r_k] | |
|
464 | 486 | # overwrite permission only if it's greater than permission |
|
465 | 487 | # given from other sources |
|
466 | 488 | if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm]: |
|
467 |
user.permissions[ |
|
|
468 | repository.repo_name] = p | |
|
489 | user.permissions[RK][r_k] = 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 | 510 | return user |
|
471 | 511 | |
@@ -480,23 +520,28 b' class UserModel(BaseModel):' | |||
|
480 | 520 | .filter(UserToPerm.permission == perm).scalar() is not None |
|
481 | 521 | |
|
482 | 522 | def grant_perm(self, user, perm): |
|
483 | if not isinstance(perm, Permission): | |
|
484 | raise Exception('perm needs to be an instance of Permission class ' | |
|
485 | 'got %s instead' % type(perm)) | |
|
523 | """ | |
|
524 | Grant user global permissions | |
|
486 | 525 |
|
|
526 | :param user: | |
|
527 | :param perm: | |
|
528 | """ | |
|
487 | 529 | user = self.__get_user(user) |
|
488 | ||
|
530 | perm = self.__get_perm(perm) | |
|
489 | 531 | new = UserToPerm() |
|
490 | 532 | new.user = user |
|
491 | 533 | new.permission = perm |
|
492 | 534 | self.sa.add(new) |
|
493 | 535 | |
|
494 | 536 | def revoke_perm(self, user, perm): |
|
495 | if not isinstance(perm, Permission): | |
|
496 | raise Exception('perm needs to be an instance of Permission class ' | |
|
497 | 'got %s instead' % type(perm)) | |
|
537 | """ | |
|
538 | Revoke users global permissions | |
|
498 | 539 |
|
|
540 | :param user: | |
|
541 | :param perm: | |
|
542 | """ | |
|
499 | 543 | user = self.__get_user(user) |
|
544 | perm = self.__get_perm(perm) | |
|
500 | 545 | |
|
501 | 546 | obj = UserToPerm.query().filter(UserToPerm.user == user)\ |
|
502 | 547 | .filter(UserToPerm.permission == perm).scalar() |
@@ -38,7 +38,12 b' log = logging.getLogger(__name__)' | |||
|
38 | 38 | class UsersGroupModel(BaseModel): |
|
39 | 39 | |
|
40 | 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 | 48 | def get(self, users_group_id, cache=False): |
|
44 | 49 | return UsersGroup.get(users_group_id) |
@@ -80,7 +85,15 b' class UsersGroupModel(BaseModel):' | |||
|
80 | 85 | log.error(traceback.format_exc()) |
|
81 | 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 | 97 | try: |
|
85 | 98 | users_group = self.__get_users_group(users_group) |
|
86 | 99 | |
@@ -88,7 +101,7 b' class UsersGroupModel(BaseModel):' | |||
|
88 | 101 | assigned_groups = UsersGroupRepoToPerm.query()\ |
|
89 | 102 | .filter(UsersGroupRepoToPerm.users_group == users_group).all() |
|
90 | 103 | |
|
91 | if assigned_groups: | |
|
104 | if assigned_groups and force is False: | |
|
92 | 105 | raise UsersGroupsAssignedException('RepoGroup assigned to %s' % |
|
93 | 106 | assigned_groups) |
|
94 | 107 | |
@@ -118,10 +131,8 b' class UsersGroupModel(BaseModel):' | |||
|
118 | 131 | raise |
|
119 | 132 | |
|
120 | 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 | 134 | users_group = self.__get_users_group(users_group) |
|
135 | perm = self.__get_perm(perm) | |
|
125 | 136 | |
|
126 | 137 | return UsersGroupToPerm.query()\ |
|
127 | 138 | .filter(UsersGroupToPerm.users_group == users_group)\ |
@@ -139,10 +150,8 b' class UsersGroupModel(BaseModel):' | |||
|
139 | 150 | self.sa.add(new) |
|
140 | 151 | |
|
141 | 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 | 153 | users_group = self.__get_users_group(users_group) |
|
154 | perm = self.__get_perm(perm) | |
|
146 | 155 | |
|
147 | 156 | obj = UsersGroupToPerm.query()\ |
|
148 | 157 | .filter(UsersGroupToPerm.users_group == users_group)\ |
@@ -53,9 +53,18 b'' | |||
|
53 | 53 | ${h.select('group_parent_id','',c.repo_groups,class_="medium")} |
|
54 | 54 | </div> |
|
55 | 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 | 65 | <div class="buttons"> |
|
58 |
${h.submit('save',_(' |
|
|
66 | ${h.submit('save',_('Save'),class_="ui-button")} | |
|
67 | ${h.reset('reset',_('Reset'),class_="ui-button")} | |
|
59 | 68 | </div> |
|
60 | 69 | </div> |
|
61 | 70 | </div> |
@@ -38,7 +38,9 b'' | |||
|
38 | 38 | </div> |
|
39 | 39 | </td> |
|
40 | 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 | 44 | </tr> |
|
43 | 45 | % endfor |
|
44 | 46 |
@@ -12,13 +12,27 b' from rhodecode.model.user import UserMod' | |||
|
12 | 12 | from rhodecode.model.meta import Session |
|
13 | 13 | from rhodecode.model.notification import NotificationModel |
|
14 | 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 | 30 | class TestReposGroups(unittest.TestCase): |
|
17 | 31 | |
|
18 | 32 | def setUp(self): |
|
19 |
self.g1 = |
|
|
20 |
self.g2 = |
|
|
21 |
self.g3 = |
|
|
33 | self.g1 = _make_group('test1', skip_if_exists=True) | |
|
34 | self.g2 = _make_group('test2', skip_if_exists=True) | |
|
35 | self.g3 = _make_group('test3', skip_if_exists=True) | |
|
22 | 36 | |
|
23 | 37 | def tearDown(self): |
|
24 | 38 | print 'out' |
@@ -31,102 +45,81 b' class TestReposGroups(unittest.TestCase)' | |||
|
31 | 45 | def _check_folders(self): |
|
32 | 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 | 48 | def __delete_group(self, id_): |
|
49 | 49 | ReposGroupModel().delete(id_) |
|
50 | 50 | |
|
51 | ||
|
52 | 51 | def __update_group(self, id_, path, desc='desc', parent_id=None): |
|
53 | 52 | form_data = dict(group_name=path, |
|
54 | 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 | 58 | gr = ReposGroupModel().update(id_, form_data) |
|
58 | 59 | return gr |
|
59 | 60 | |
|
60 | 61 | def test_create_group(self): |
|
61 |
g = |
|
|
62 | g = _make_group('newGroup') | |
|
62 | 63 | self.assertEqual(g.full_path, 'newGroup') |
|
63 | 64 | |
|
64 | 65 | self.assertTrue(self.__check_path('newGroup')) |
|
65 | 66 | |
|
66 | ||
|
67 | 67 | def test_create_same_name_group(self): |
|
68 |
self.assertRaises(IntegrityError, lambda: |
|
|
68 | self.assertRaises(IntegrityError, lambda:_make_group('newGroup')) | |
|
69 | 69 | Session.rollback() |
|
70 | 70 | |
|
71 | 71 | def test_same_subgroup(self): |
|
72 |
sg1 = |
|
|
72 | sg1 = _make_group('sub1', parent_id=self.g1.group_id) | |
|
73 | 73 | self.assertEqual(sg1.parent_group, self.g1) |
|
74 | 74 | self.assertEqual(sg1.full_path, 'test1/sub1') |
|
75 | 75 | self.assertTrue(self.__check_path('test1', 'sub1')) |
|
76 | 76 | |
|
77 |
ssg1 = |
|
|
77 | ssg1 = _make_group('subsub1', parent_id=sg1.group_id) | |
|
78 | 78 | self.assertEqual(ssg1.parent_group, sg1) |
|
79 | 79 | self.assertEqual(ssg1.full_path, 'test1/sub1/subsub1') |
|
80 | 80 | self.assertTrue(self.__check_path('test1', 'sub1', 'subsub1')) |
|
81 | 81 | |
|
82 | ||
|
83 | 82 | def test_remove_group(self): |
|
84 |
sg1 = |
|
|
83 | sg1 = _make_group('deleteme') | |
|
85 | 84 | self.__delete_group(sg1.group_id) |
|
86 | 85 | |
|
87 | 86 | self.assertEqual(RepoGroup.get(sg1.group_id), None) |
|
88 | 87 | self.assertFalse(self.__check_path('deteteme')) |
|
89 | 88 | |
|
90 |
sg1 = |
|
|
89 | sg1 = _make_group('deleteme', parent_id=self.g1.group_id) | |
|
91 | 90 | self.__delete_group(sg1.group_id) |
|
92 | 91 | |
|
93 | 92 | self.assertEqual(RepoGroup.get(sg1.group_id), None) |
|
94 | 93 | self.assertFalse(self.__check_path('test1', 'deteteme')) |
|
95 | 94 | |
|
96 | ||
|
97 | 95 | def test_rename_single_group(self): |
|
98 |
sg1 = |
|
|
96 | sg1 = _make_group('initial') | |
|
99 | 97 | |
|
100 | 98 | new_sg1 = self.__update_group(sg1.group_id, 'after') |
|
101 | 99 | self.assertTrue(self.__check_path('after')) |
|
102 | 100 | self.assertEqual(RepoGroup.get_by_group_name('initial'), None) |
|
103 | 101 | |
|
104 | ||
|
105 | 102 | def test_update_group_parent(self): |
|
106 | 103 | |
|
107 |
sg1 = |
|
|
104 | sg1 = _make_group('initial', parent_id=self.g1.group_id) | |
|
108 | 105 | |
|
109 | 106 | new_sg1 = self.__update_group(sg1.group_id, 'after', parent_id=self.g1.group_id) |
|
110 | 107 | self.assertTrue(self.__check_path('test1', 'after')) |
|
111 | 108 | self.assertEqual(RepoGroup.get_by_group_name('test1/initial'), None) |
|
112 | 109 | |
|
113 | ||
|
114 | 110 | new_sg1 = self.__update_group(sg1.group_id, 'after', parent_id=self.g3.group_id) |
|
115 | 111 | self.assertTrue(self.__check_path('test3', 'after')) |
|
116 | 112 | self.assertEqual(RepoGroup.get_by_group_name('test3/initial'), None) |
|
117 | 113 | |
|
118 | ||
|
119 | 114 | new_sg1 = self.__update_group(sg1.group_id, 'hello') |
|
120 | 115 | self.assertTrue(self.__check_path('hello')) |
|
121 | 116 | |
|
122 | 117 | self.assertEqual(RepoGroup.get_by_group_name('hello'), new_sg1) |
|
123 | 118 | |
|
124 | ||
|
125 | ||
|
126 | 119 | def test_subgrouping_with_repo(self): |
|
127 | 120 | |
|
128 |
g1 = |
|
|
129 |
g2 = |
|
|
121 | g1 = _make_group('g1') | |
|
122 | g2 = _make_group('g2') | |
|
130 | 123 | |
|
131 | 124 | # create new repo |
|
132 | 125 | form_data = dict(repo_name='john', |
@@ -150,13 +143,13 b' class TestReposGroups(unittest.TestCase)' | |||
|
150 | 143 | RepoModel().update(r.repo_name, form_data) |
|
151 | 144 | self.assertEqual(r.repo_name, 'g1/john') |
|
152 | 145 | |
|
153 | ||
|
154 | 146 | self.__update_group(g1.group_id, 'g1', parent_id=g2.group_id) |
|
155 | 147 | self.assertTrue(self.__check_path('g2', 'g1')) |
|
156 | 148 | |
|
157 | 149 | # test repo |
|
158 | 150 | self.assertEqual(r.repo_name, os.path.join('g2', 'g1', r.just_name)) |
|
159 | 151 | |
|
152 | ||
|
160 | 153 | class TestUser(unittest.TestCase): |
|
161 | 154 | def __init__(self, methodName='runTest'): |
|
162 | 155 | Session.remove() |
@@ -245,7 +238,6 b' class TestNotifications(unittest.TestCas' | |||
|
245 | 238 | self.assertEqual(len(unotification), len(usrs)) |
|
246 | 239 | self.assertEqual([x.user.user_id for x in unotification], usrs) |
|
247 | 240 | |
|
248 | ||
|
249 | 241 | def test_user_notifications(self): |
|
250 | 242 | self.assertEqual([], Notification.query().all()) |
|
251 | 243 | self.assertEqual([], UserNotification.query().all()) |
@@ -284,7 +276,6 b' class TestNotifications(unittest.TestCas' | |||
|
284 | 276 | == notification).all() |
|
285 | 277 | self.assertEqual(un, []) |
|
286 | 278 | |
|
287 | ||
|
288 | 279 | def test_delete_association(self): |
|
289 | 280 | |
|
290 | 281 | self.assertEqual([], Notification.query().all()) |
@@ -361,6 +352,7 b' class TestNotifications(unittest.TestCas' | |||
|
361 | 352 | self.assertEqual(NotificationModel() |
|
362 | 353 | .get_unread_cnt_for_user(self.u3), 2) |
|
363 | 354 | |
|
355 | ||
|
364 | 356 | class TestUsers(unittest.TestCase): |
|
365 | 357 | |
|
366 | 358 | def __init__(self, methodName='runTest'): |
@@ -401,4 +393,163 b' class TestUsers(unittest.TestCase):' | |||
|
401 | 393 | #revoke |
|
402 | 394 | UserModel().revoke_perm(self.u1, perm) |
|
403 | 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 | 89 | beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long |
|
90 | 90 | |
|
91 | 91 | beaker.cache.super_short_term.type=memory |
|
92 |
beaker.cache.super_short_term.expire=1 |
|
|
92 | beaker.cache.super_short_term.expire=1 | |
|
93 | 93 | beaker.cache.super_short_term.key_length = 256 |
|
94 | 94 | |
|
95 | 95 | beaker.cache.short_term.type=memory |
@@ -101,7 +101,7 b' beaker.cache.long_term.expire=36000' | |||
|
101 | 101 | beaker.cache.long_term.key_length = 256 |
|
102 | 102 | |
|
103 | 103 | beaker.cache.sql_cache_short.type=memory |
|
104 |
beaker.cache.sql_cache_short.expire=1 |
|
|
104 | beaker.cache.sql_cache_short.expire=1 | |
|
105 | 105 | beaker.cache.sql_cache_short.key_length = 256 |
|
106 | 106 | |
|
107 | 107 | beaker.cache.sql_cache_med.type=memory |
General Comments 0
You need to be logged in to leave comments.
Login now