@@ -232,13 +232,13 @@ belonging to user with admin rights
INPUT::
api_key : "<api_key>"
method : "add_user_users_group"
args: {
"group_name" : "<groupname>",
"user_name" : "<username>"
"username" : "<username>"
}
OUTPUT::
result: {
"id": "<newusersgroupmemberid>",
@@ -313,12 +313,44 @@ OUTPUT::
},
…
]
error: null
get_repo_nodes
--------------
returns a list of nodes and it's children in a flat list for a given path
at given revision. It's possible to specify ret_type to show only files or
dirs. This command can be executed only using api_key belonging to user
with admin rights
method : "get_repo_nodes"
"repo_name" : "<name>",
"revision" : "<revision>",
"root_path" : "<root_path>",
"ret_type" : "<ret_type>" = 'all'
result: [
{
"name" : "<name>"
"type" : "<type>",
create_repo
-----------
Creates a repository. This command can be executed only using api_key
belonging to user with admin rights.
If repository name contains "/", all needed repository groups will be created.
@@ -352,13 +384,13 @@ If "perm" is None, user will be removed
method : "add_user_to_repo"
"repo_name" : "<reponame>",
"user_name" : "<username>",
"username" : "<username>",
"perm" : "(None|repository.(read|write|admin))",
result: None
@@ -26,19 +26,22 @@ news
- #239 option to manually mark repository as fork
- #320 mapping of commit authors to RhodeCode users
- #304 hashes are displayed using monospace font
- diff configuration, toggle white lines and context lines
- #307 configurable diffs, whitespace toggle, increasing context lines
- sorting on branches, tags and bookmarks using YUI datatable
- improved file filter on files page
- implements #330 api method for listing nodes ar particular revision
fixes
-----
- rewrote dbsession management for atomic operations, and better error handling
- fixed sorting of repo tables
- #326 escape of special html entities in diffs
- normalized user_name => username in api attributes
1.2.3 (**2011-11-02**)
======================
news
----
@@ -209,30 +209,30 @@ class ApiController(JSONRPCController):
msg='created new users group %s' % name)
except Exception:
log.error(traceback.format_exc())
raise JSONRPCError('failed to create group %s' % name)
@HasPermissionAllDecorator('hg.admin')
def add_user_to_users_group(self, apiuser, group_name, user_name):
def add_user_to_users_group(self, apiuser, group_name, username):
""""
Add a user to a group
:param apiuser:
:param group_name:
:param user_name:
:param username:
"""
try:
users_group = UsersGroup.get_by_group_name(group_name)
if not users_group:
raise JSONRPCError('unknown users group %s' % group_name)
user = User.get_by_username(user_name)
user = User.get_by_username(username)
except NoResultFound:
raise JSONRPCError('unknown user %s' % user_name)
raise JSONRPCError('unknown user %s' % username)
ugm = UsersGroupModel().add_user_to_group(users_group, user)
Session.commit()
return dict(id=ugm.users_group_member_id,
msg='created new users group member')
@@ -308,12 +308,40 @@ class ApiController(JSONRPCController):
type=repository.repo_type,
description=repository.description
)
return result
@HasPermissionAnyDecorator('hg.admin')
def get_repo_nodes(self, apiuser, repo_name, revision, root_path,
ret_type='all'):
returns a list of nodes and it's children
for a given path at given revision. It's possible to specify ret_type
to show only files or dirs
:param repo_name: name of repository
:param revision: revision for which listing should be done
:param root_path: path from which start displaying
:param ret_type: return type 'all|files|dirs' nodes
_d, _f = ScmModel().get_nodes(repo_name, revision, root_path,
flat=False)
_map = {
'all': _d + _f,
'files': _f,
'dirs': _d,
return _map[ret_type]
except KeyError:
raise JSONRPCError('ret_type must be one of %s' % _map.keys())
except Exception, e:
raise JSONRPCError(e)
@HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
def create_repo(self, apiuser, name, owner_name, description='',
repo_type='hg', private=False):
Create a repository
@@ -365,46 +393,46 @@ class ApiController(JSONRPCController):
raise JSONRPCError('failed to create repository %s' % name)
def add_user_to_repo(self, apiuser, repo_name, user_name, perm):
def add_user_to_repo(self, apiuser, repo_name, username, perm):
Add permission for a user to a repository
:param repo_name:
:param perm:
repo = Repository.get_by_repo_name(repo_name)
if repo is None:
raise JSONRPCError('unknown repository %s' % repo)
raise JSONRPCError('unknown user %s' % user)
RepositoryPermissionModel()\
.update_or_delete_user_permission(repo, user, perm)
return dict(
msg='Added perm: %s for %s in repo: %s' % (
perm, user_name, repo_name
perm, username, repo_name
raise JSONRPCError(
'failed to edit permission %(repo)s for %(user)s' % dict(
user=user_name, repo=repo_name
user=username, repo=repo_name
def add_users_group_to_repo(self, apiuser, repo_name, group_name, perm):
@@ -46,12 +46,13 @@ from rhodecode.lib.utils import EmptyCha
from rhodecode.lib import diffs
import rhodecode.lib.helpers as h
from rhodecode.model.repo import RepoModel
from rhodecode.controllers.changeset import anchor_url, _ignorews_url,\
_context_url, get_line_ctx, get_ignore_ws
from rhodecode.lib.diffs import wrapped_diff
from rhodecode.model.scm import ScmModel
log = logging.getLogger(__name__)
class FilesController(BaseRepoController):
@@ -104,31 +105,12 @@ class FilesController(BaseRepoController
h.flash(str(e), category='warning')
redirect(h.url('files_home', repo_name=repo_name,
revision=cs.raw_id))
return file_node
def __get_paths(self, changeset, starting_path):
"""recursive walk in root dir and return a set of all path in that dir
based on repository walk function
_files = list()
_dirs = list()
tip = changeset
for topnode, dirs, files in tip.walk(starting_path):
for f in files:
_files.append(f.path)
for d in dirs:
_dirs.append(d.path)
except RepositoryError, e:
log.debug(traceback.format_exc())
pass
return _dirs, _files
@HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
'repository.admin')
def index(self, repo_name, revision, f_path):
# redirect to given revision from form if given
post_revision = request.POST.get('at_rev', None)
if post_revision:
@@ -502,9 +484,10 @@ class FilesController(BaseRepoController
@jsonify
def nodelist(self, repo_name, revision, f_path):
if request.environ.get('HTTP_X_PARTIAL_XHR'):
cs = self.__get_cs_or_redirect(revision, repo_name)
_d, _f = self.__get_paths(cs, f_path)
_d, _f = ScmModel().get_nodes(repo_name, cs.raw_id, f_path,
return _d + _f
@@ -126,12 +126,13 @@ class MakeIndex(BasePasterCommand):
action='store_true',
dest='full_index',
help="Specifies that index should be made full i.e"
" destroy old and build from scratch",
default=False)
class ResultWrapper(object):
def __init__(self, search_type, searcher, matcher, highlight_items):
self.search_type = search_type
self.searcher = searcher
self.matcher = matcher
self.highlight_items = highlight_items
@@ -173,13 +174,12 @@ class ResultWrapper(object):
slice = []
for docid in self.doc_ids[i:j]:
slice.append(self.get_full_content(docid))
return slice
def get_full_content(self, docid):
res = self.searcher.stored_fields(docid[0])
f_path = res['path'][res['path'].find(res['repository']) \
+ len(res['repository']):].lstrip('/')
content_short = self.get_short_content(res, docid[1])
@@ -195,13 +195,13 @@ class ResultWrapper(object):
def get_chunks(self):
Smart function that implements chunking the content
but not overlap chunks so it doesn't highlight the same
close occurrences twice.
:param matcher:
:param size:
memory = [(0, 0)]
for span in self.matcher.spans():
start = span.startchar or 0
@@ -388,8 +388,38 @@ class ScmModel(BaseModel):
action = 'push_local:%s' % new_cs
action_logger(user, action, repo_name)
self.mark_for_invalidation(repo_name)
def get_nodes(self, repo_name, revision, root_path='/', flat=True):
recursive walk in root dir and return a set of all path in that dir
:param revision: revision for which to list nodes
:param root_path: root path to list
:param flat: return as a list, if False returns a dict with decription
_repo = self.__get_repo(repo_name)
changeset = _repo.scm_instance.get_changeset(revision)
root_path = root_path.lstrip('/')
for topnode, dirs, files in changeset.walk(root_path):
_files.append(f.path if flat else {"name": f.path,
"type": "file"})
_dirs.append(d.path if flat else {"name": d.path,
"type": "dir"})
except RepositoryError:
raise
def get_unread_journal(self):
return self.sa.query(UserLog).count()
@@ -415,44 +415,51 @@ var fileBrowserListeners = function(curr
YUC.initHeader('X-PARTIAL-XHR',true);
YUC.asyncRequest('GET',url,{
success:function(o){
nodes = JSON.parse(o.responseText);
YUD.setStyle('node_filter_box_loading','display','none');
YUD.setStyle('node_filter_box','display','');
n_filter.focus();
if(YUD.hasClass(n_filter,'init')){
n_filter.value = '';
YUD.removeClass(n_filter,'init');
failure:function(o){
console.log('failed to load');
},null);
F.updateFilter = function(e) {
return function(){
// Reset timeout
F.filterTimeout = null;
var query = e.target.value;
var query = e.target.value.toLowerCase();
var match = [];
var matches = 0;
var matches_max = 20;
if (query != ""){
for(var i=0;i<nodes.length;i++){
var pos = nodes[i].toLowerCase().indexOf(query)
var pos = nodes[i].name.toLowerCase().indexOf(query)
if(query && pos != -1){
matches++
//show only certain amount to not kill browser
if (matches > matches_max){
break;
var n = nodes[i];
var n = nodes[i].name;
var t = nodes[i].type;
var n_hl = n.substring(0,pos)
+"<b>{0}</b>".format(n.substring(pos,pos+query.length))
+n.substring(pos+query.length)
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));
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));
if(match.length >= matches_max){
match.push('<tr><td>{0}</td><td colspan="5"></td></tr>'.format(truncated_lbl));
@@ -476,13 +483,16 @@ var fileBrowserListeners = function(curr
};
YUE.on(YUD.get('filter_activate'),'click',function(){
F.initFilter();
})
YUE.on(n_filter,'click',function(){
});
YUE.on(n_filter,'keyup',function(e){
clearTimeout(F.filterTimeout);
F.filterTimeout = setTimeout(F.updateFilter(e),600);
@@ -31,13 +31,13 @@
<a class="ui-btn" href="${h.url('files_add_home',repo_name=c.repo_name,revision=c.changeset.raw_id,f_path=c.f_path)}">${_('add new file')}</a>
</div>
% endif
<div>
<div id="node_filter_box_loading" style="display:none">${_('Loading file list...')}</div>
<div id="node_filter_box" style="display:none">
${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">
${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">
<div class="browser-body">
Status change: