##// END OF EJS Templates
implements #330 api method for listing nodes at particular revision...
marcink -
r1810:203af055 beta
parent child Browse files
Show More
@@ -235,7 +235,7 b' INPUT::'
235 method : "add_user_users_group"
235 method : "add_user_users_group"
236 args: {
236 args: {
237 "group_name" : "<groupname>",
237 "group_name" : "<groupname>",
238 "user_name" : "<username>"
238 "username" : "<username>"
239 }
239 }
240
240
241 OUTPUT::
241 OUTPUT::
@@ -316,6 +316,38 b' OUTPUT::'
316 }
316 }
317 error: null
317 error: null
318
318
319 get_repo_nodes
320 --------------
321
322 returns a list of nodes and it's children in a flat list for a given path
323 at given revision. It's possible to specify ret_type to show only files or
324 dirs. This command can be executed only using api_key belonging to user
325 with admin rights
326
327 INPUT::
328
329 api_key : "<api_key>"
330 method : "get_repo_nodes"
331 args: {
332 "repo_name" : "<name>",
333 "revision" : "<revision>",
334 "root_path" : "<root_path>",
335 "ret_type" : "<ret_type>" = 'all'
336 }
337
338 OUTPUT::
339
340 result: [
341 {
342 "name" : "<name>"
343 "type" : "<type>",
344 },
345
346 ]
347 error: null
348
349
350
319 create_repo
351 create_repo
320 -----------
352 -----------
321
353
@@ -355,7 +387,7 b' INPUT::'
355 method : "add_user_to_repo"
387 method : "add_user_to_repo"
356 args: {
388 args: {
357 "repo_name" : "<reponame>",
389 "repo_name" : "<reponame>",
358 "user_name" : "<username>",
390 "username" : "<username>",
359 "perm" : "(None|repository.(read|write|admin))",
391 "perm" : "(None|repository.(read|write|admin))",
360 }
392 }
361
393
@@ -29,6 +29,8 b' news'
29 - diff configuration, toggle white lines and context lines
29 - diff configuration, toggle white lines and context lines
30 - #307 configurable diffs, whitespace toggle, increasing context lines
30 - #307 configurable diffs, whitespace toggle, increasing context lines
31 - sorting on branches, tags and bookmarks using YUI datatable
31 - sorting on branches, tags and bookmarks using YUI datatable
32 - improved file filter on files page
33 - implements #330 api method for listing nodes ar particular revision
32
34
33 fixes
35 fixes
34 -----
36 -----
@@ -36,6 +38,7 b' fixes'
36 - rewrote dbsession management for atomic operations, and better error handling
38 - rewrote dbsession management for atomic operations, and better error handling
37 - fixed sorting of repo tables
39 - fixed sorting of repo tables
38 - #326 escape of special html entities in diffs
40 - #326 escape of special html entities in diffs
41 - normalized user_name => username in api attributes
39
42
40 1.2.3 (**2011-11-02**)
43 1.2.3 (**2011-11-02**)
41 ======================
44 ======================
@@ -212,13 +212,13 b' class ApiController(JSONRPCController):'
212 raise JSONRPCError('failed to create group %s' % name)
212 raise JSONRPCError('failed to create group %s' % name)
213
213
214 @HasPermissionAllDecorator('hg.admin')
214 @HasPermissionAllDecorator('hg.admin')
215 def add_user_to_users_group(self, apiuser, group_name, user_name):
215 def add_user_to_users_group(self, apiuser, group_name, username):
216 """"
216 """"
217 Add a user to a group
217 Add a user to a group
218
218
219 :param apiuser:
219 :param apiuser:
220 :param group_name:
220 :param group_name:
221 :param user_name:
221 :param username:
222 """
222 """
223
223
224 try:
224 try:
@@ -227,9 +227,9 b' class ApiController(JSONRPCController):'
227 raise JSONRPCError('unknown users group %s' % group_name)
227 raise JSONRPCError('unknown users group %s' % group_name)
228
228
229 try:
229 try:
230 user = User.get_by_username(user_name)
230 user = User.get_by_username(username)
231 except NoResultFound:
231 except NoResultFound:
232 raise JSONRPCError('unknown user %s' % user_name)
232 raise JSONRPCError('unknown user %s' % username)
233
233
234 ugm = UsersGroupModel().add_user_to_group(users_group, user)
234 ugm = UsersGroupModel().add_user_to_group(users_group, user)
235 Session.commit()
235 Session.commit()
@@ -311,6 +311,34 b' class ApiController(JSONRPCController):'
311 )
311 )
312 return result
312 return result
313
313
314 @HasPermissionAnyDecorator('hg.admin')
315 def get_repo_nodes(self, apiuser, repo_name, revision, root_path,
316 ret_type='all'):
317 """
318 returns a list of nodes and it's children
319 for a given path at given revision. It's possible to specify ret_type
320 to show only files or dirs
321
322 :param apiuser:
323 :param repo_name: name of repository
324 :param revision: revision for which listing should be done
325 :param root_path: path from which start displaying
326 :param ret_type: return type 'all|files|dirs' nodes
327 """
328 try:
329 _d, _f = ScmModel().get_nodes(repo_name, revision, root_path,
330 flat=False)
331 _map = {
332 'all': _d + _f,
333 'files': _f,
334 'dirs': _d,
335 }
336 return _map[ret_type]
337 except KeyError:
338 raise JSONRPCError('ret_type must be one of %s' % _map.keys())
339 except Exception, e:
340 raise JSONRPCError(e)
341
314 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
342 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
315 def create_repo(self, apiuser, name, owner_name, description='',
343 def create_repo(self, apiuser, name, owner_name, description='',
316 repo_type='hg', private=False):
344 repo_type='hg', private=False):
@@ -368,13 +396,13 b' class ApiController(JSONRPCController):'
368 raise JSONRPCError('failed to create repository %s' % name)
396 raise JSONRPCError('failed to create repository %s' % name)
369
397
370 @HasPermissionAnyDecorator('hg.admin')
398 @HasPermissionAnyDecorator('hg.admin')
371 def add_user_to_repo(self, apiuser, repo_name, user_name, perm):
399 def add_user_to_repo(self, apiuser, repo_name, username, perm):
372 """
400 """
373 Add permission for a user to a repository
401 Add permission for a user to a repository
374
402
375 :param apiuser:
403 :param apiuser:
376 :param repo_name:
404 :param repo_name:
377 :param user_name:
405 :param username:
378 :param perm:
406 :param perm:
379 """
407 """
380
408
@@ -384,7 +412,7 b' class ApiController(JSONRPCController):'
384 raise JSONRPCError('unknown repository %s' % repo)
412 raise JSONRPCError('unknown repository %s' % repo)
385
413
386 try:
414 try:
387 user = User.get_by_username(user_name)
415 user = User.get_by_username(username)
388 except NoResultFound:
416 except NoResultFound:
389 raise JSONRPCError('unknown user %s' % user)
417 raise JSONRPCError('unknown user %s' % user)
390
418
@@ -394,14 +422,14 b' class ApiController(JSONRPCController):'
394
422
395 return dict(
423 return dict(
396 msg='Added perm: %s for %s in repo: %s' % (
424 msg='Added perm: %s for %s in repo: %s' % (
397 perm, user_name, repo_name
425 perm, username, repo_name
398 )
426 )
399 )
427 )
400 except Exception:
428 except Exception:
401 log.error(traceback.format_exc())
429 log.error(traceback.format_exc())
402 raise JSONRPCError(
430 raise JSONRPCError(
403 'failed to edit permission %(repo)s for %(user)s' % dict(
431 'failed to edit permission %(repo)s for %(user)s' % dict(
404 user=user_name, repo=repo_name
432 user=username, repo=repo_name
405 )
433 )
406 )
434 )
407
435
@@ -49,6 +49,7 b' from rhodecode.model.repo import RepoMod'
49 from rhodecode.controllers.changeset import anchor_url, _ignorews_url,\
49 from rhodecode.controllers.changeset import anchor_url, _ignorews_url,\
50 _context_url, get_line_ctx, get_ignore_ws
50 _context_url, get_line_ctx, get_ignore_ws
51 from rhodecode.lib.diffs import wrapped_diff
51 from rhodecode.lib.diffs import wrapped_diff
52 from rhodecode.model.scm import ScmModel
52
53
53 log = logging.getLogger(__name__)
54 log = logging.getLogger(__name__)
54
55
@@ -107,25 +108,6 b' class FilesController(BaseRepoController'
107
108
108 return file_node
109 return file_node
109
110
110 def __get_paths(self, changeset, starting_path):
111 """recursive walk in root dir and return a set of all path in that dir
112 based on repository walk function
113 """
114 _files = list()
115 _dirs = list()
116
117 try:
118 tip = changeset
119 for topnode, dirs, files in tip.walk(starting_path):
120 for f in files:
121 _files.append(f.path)
122 for d in dirs:
123 _dirs.append(d.path)
124 except RepositoryError, e:
125 log.debug(traceback.format_exc())
126 pass
127 return _dirs, _files
128
129 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
111 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
130 'repository.admin')
112 'repository.admin')
131 def index(self, repo_name, revision, f_path):
113 def index(self, repo_name, revision, f_path):
@@ -505,6 +487,7 b' class FilesController(BaseRepoController'
505 def nodelist(self, repo_name, revision, f_path):
487 def nodelist(self, repo_name, revision, f_path):
506 if request.environ.get('HTTP_X_PARTIAL_XHR'):
488 if request.environ.get('HTTP_X_PARTIAL_XHR'):
507 cs = self.__get_cs_or_redirect(revision, repo_name)
489 cs = self.__get_cs_or_redirect(revision, repo_name)
508 _d, _f = self.__get_paths(cs, f_path)
490 _d, _f = ScmModel().get_nodes(repo_name, cs.raw_id, f_path,
491 flat=False)
509 return _d + _f
492 return _d + _f
510
493
@@ -129,6 +129,7 b' class MakeIndex(BasePasterCommand):'
129 " destroy old and build from scratch",
129 " destroy old and build from scratch",
130 default=False)
130 default=False)
131
131
132
132 class ResultWrapper(object):
133 class ResultWrapper(object):
133 def __init__(self, search_type, searcher, matcher, highlight_items):
134 def __init__(self, search_type, searcher, matcher, highlight_items):
134 self.search_type = search_type
135 self.search_type = search_type
@@ -176,7 +177,6 b' class ResultWrapper(object):'
176 slice.append(self.get_full_content(docid))
177 slice.append(self.get_full_content(docid))
177 return slice
178 return slice
178
179
179
180 def get_full_content(self, docid):
180 def get_full_content(self, docid):
181 res = self.searcher.stored_fields(docid[0])
181 res = self.searcher.stored_fields(docid[0])
182 f_path = res['path'][res['path'].find(res['repository']) \
182 f_path = res['path'][res['path'].find(res['repository']) \
@@ -198,7 +198,7 b' class ResultWrapper(object):'
198 Smart function that implements chunking the content
198 Smart function that implements chunking the content
199 but not overlap chunks so it doesn't highlight the same
199 but not overlap chunks so it doesn't highlight the same
200 close occurrences twice.
200 close occurrences twice.
201
201
202 :param matcher:
202 :param matcher:
203 :param size:
203 :param size:
204 """
204 """
@@ -391,5 +391,35 b' class ScmModel(BaseModel):'
391
391
392 self.mark_for_invalidation(repo_name)
392 self.mark_for_invalidation(repo_name)
393
393
394 def get_nodes(self, repo_name, revision, root_path='/', flat=True):
395 """
396 recursive walk in root dir and return a set of all path in that dir
397 based on repository walk function
398
399 :param repo_name: name of repository
400 :param revision: revision for which to list nodes
401 :param root_path: root path to list
402 :param flat: return as a list, if False returns a dict with decription
403
404 """
405 _files = list()
406 _dirs = list()
407 try:
408 _repo = self.__get_repo(repo_name)
409 changeset = _repo.scm_instance.get_changeset(revision)
410 root_path = root_path.lstrip('/')
411 for topnode, dirs, files in changeset.walk(root_path):
412 for f in files:
413 _files.append(f.path if flat else {"name": f.path,
414 "type": "file"})
415 for d in dirs:
416 _dirs.append(d.path if flat else {"name": d.path,
417 "type": "dir"})
418 except RepositoryError:
419 log.debug(traceback.format_exc())
420 raise
421
422 return _dirs, _files
423
394 def get_unread_journal(self):
424 def get_unread_journal(self):
395 return self.sa.query(UserLog).count()
425 return self.sa.query(UserLog).count()
@@ -418,6 +418,11 b' var fileBrowserListeners = function(curr'
418 nodes = JSON.parse(o.responseText);
418 nodes = JSON.parse(o.responseText);
419 YUD.setStyle('node_filter_box_loading','display','none');
419 YUD.setStyle('node_filter_box_loading','display','none');
420 YUD.setStyle('node_filter_box','display','');
420 YUD.setStyle('node_filter_box','display','');
421 n_filter.focus();
422 if(YUD.hasClass(n_filter,'init')){
423 n_filter.value = '';
424 YUD.removeClass(n_filter,'init');
425 }
421 },
426 },
422 failure:function(o){
427 failure:function(o){
423 console.log('failed to load');
428 console.log('failed to load');
@@ -430,13 +435,14 b' var fileBrowserListeners = function(curr'
430 return function(){
435 return function(){
431 // Reset timeout
436 // Reset timeout
432 F.filterTimeout = null;
437 F.filterTimeout = null;
433 var query = e.target.value;
438 var query = e.target.value.toLowerCase();
434 var match = [];
439 var match = [];
435 var matches = 0;
440 var matches = 0;
436 var matches_max = 20;
441 var matches_max = 20;
437 if (query != ""){
442 if (query != ""){
438 for(var i=0;i<nodes.length;i++){
443 for(var i=0;i<nodes.length;i++){
439 var pos = nodes[i].toLowerCase().indexOf(query)
444
445 var pos = nodes[i].name.toLowerCase().indexOf(query)
440 if(query && pos != -1){
446 if(query && pos != -1){
441
447
442 matches++
448 matches++
@@ -445,11 +451,12 b' var fileBrowserListeners = function(curr'
445 break;
451 break;
446 }
452 }
447
453
448 var n = nodes[i];
454 var n = nodes[i].name;
455 var t = nodes[i].type;
449 var n_hl = n.substring(0,pos)
456 var n_hl = n.substring(0,pos)
450 +"<b>{0}</b>".format(n.substring(pos,pos+query.length))
457 +"<b>{0}</b>".format(n.substring(pos,pos+query.length))
451 +n.substring(pos+query.length)
458 +n.substring(pos+query.length)
452 match.push('<tr><td><a class="browser-file" href="{0}">{1}</a></td><td colspan="5"></td></tr>'.format(node_url.replace('__FPATH__',n),n_hl));
459 match.push('<tr><td><a class="browser-{0}" href="{1}">{2}</a></td><td colspan="5"></td></tr>'.format(t,node_url.replace('__FPATH__',n),n_hl));
453 }
460 }
454 if(match.length >= matches_max){
461 if(match.length >= matches_max){
455 match.push('<tr><td>{0}</td><td colspan="5"></td></tr>'.format(truncated_lbl));
462 match.push('<tr><td>{0}</td><td colspan="5"></td></tr>'.format(truncated_lbl));
@@ -479,7 +486,10 b' var fileBrowserListeners = function(curr'
479 F.initFilter();
486 F.initFilter();
480 })
487 })
481 YUE.on(n_filter,'click',function(){
488 YUE.on(n_filter,'click',function(){
482 n_filter.value = '';
489 if(YUD.hasClass(n_filter,'init')){
490 n_filter.value = '';
491 YUD.removeClass(n_filter,'init');
492 }
483 });
493 });
484 YUE.on(n_filter,'keyup',function(e){
494 YUE.on(n_filter,'keyup',function(e){
485 clearTimeout(F.filterTimeout);
495 clearTimeout(F.filterTimeout);
@@ -34,7 +34,7 b''
34 <div>
34 <div>
35 <div id="node_filter_box_loading" style="display:none">${_('Loading file list...')}</div>
35 <div id="node_filter_box_loading" style="display:none">${_('Loading file list...')}</div>
36 <div id="node_filter_box" style="display:none">
36 <div id="node_filter_box" style="display:none">
37 ${h.files_breadcrumbs(c.repo_name,c.changeset.raw_id,c.file.path)}/<input type="text" value="type to search..." name="filter" size="25" id="node_filter" autocomplete="off">
37 ${h.files_breadcrumbs(c.repo_name,c.changeset.raw_id,c.file.path)}/<input class="init" type="text" value="type to search..." name="filter" size="25" id="node_filter" autocomplete="off">
38 </div>
38 </div>
39 </div>
39 </div>
40 </div>
40 </div>
General Comments 0
You need to be logged in to leave comments. Login now