@@ -96,11 +96,13 @@ def make_map(config):
action="repo_pull", conditions=dict(method=["PUT"],
function=check_repo))
#ADMIN REPOS GROUP REST ROUTES
routes_map.resource('repos_group', 'repos_groups', controller='admin/repos_groups', path_prefix='/_admin')
#ADMIN USER REST ROUTES
routes_map.resource('user', 'users', controller='admin/users', path_prefix='/_admin')
#ADMIN USERS REST ROUTES
routes_map.resource('users_group', 'users_groups', controller='admin/users_groups', path_prefix='/_admin')
#ADMIN GROUP REST ROUTES
new file 100644
import logging
from pylons import request, response, session, tmpl_context as c, url
from pylons.controllers.util import abort, redirect
from rhodecode.lib.base import BaseController, render
log = logging.getLogger(__name__)
class ReposGroupsController(BaseController):
"""REST Controller styled on the Atom Publishing Protocol"""
# To properly map this controller, ensure your config/routing.py
# file has a resource setup:
# map.resource('repos_group', 'repos_groups')
def index(self, format='html'):
"""GET /repos_groups: All items in the collection"""
# url('repos_groups')
def create(self):
"""POST /repos_groups: Create a new item"""
def new(self, format='html'):
"""GET /repos_groups/new: Form to create a new item"""
# url('new_repos_group')
def update(self, id):
"""PUT /repos_groups/id: Update an existing item"""
# Forms posted to this method should contain a hidden field:
# <input type="hidden" name="_method" value="PUT" />
# Or using helpers:
# h.form(url('repos_group', id=ID),
# method='put')
# url('repos_group', id=ID)
def delete(self, id):
"""DELETE /repos_groups/id: Delete an existing item"""
# <input type="hidden" name="_method" value="DELETE" />
# method='delete')
def show(self, id, format='html'):
"""GET /repos_groups/id: Show a specific item"""
def edit(self, id, format='html'):
"""GET /repos_groups/id/edit: Form to edit an existing item"""
# url('edit_repos_group', id=ID)
@@ -35,7 +35,8 @@ from vcs.exceptions import ChangesetErro
from pylons import tmpl_context as c, request, url
from pylons.i18n.translation import _
from rhodecode.model.db import Statistics
from rhodecode.model.db import Statistics, Repository
from rhodecode.model.repo import RepoModel
from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
from rhodecode.lib.base import BaseRepoController, render
@@ -60,19 +61,20 @@ class SummaryController(BaseRepoControll
def __before__(self):
super(SummaryController, self).__before__()
def index(self):
c.repo, dbrepo = self.scm_model.get(c.repo_name)
c.dbrepo = dbrepo
def index(self, repo_name):
e = request.environ
c.dbrepo = dbrepo = Repository.by_repo_name(repo_name)
c.following = self.scm_model.is_following_repo(c.repo_name,
self.rhodecode_user.user_id)
c.following = self.scm_model.is_following_repo(repo_name,
def url_generator(**kw):
return url('shortlog_home', repo_name=c.repo_name, **kw)
return url('shortlog_home', repo_name=repo_name, **kw)
c.repo_changesets = RepoPage(c.repo, page=1, items_per_page=10,
c.repo_changesets = RepoPage(c.rhodecode_repo, page=1, items_per_page=10,
url=url_generator)
if self.rhodecode_user.username == 'default':
#for default(anonymous) user we don't need to pass credentials
@@ -88,19 +90,19 @@ class SummaryController(BaseRepoControll
'password':password,
'host':e.get('HTTP_HOST'),
'prefix':e.get('SCRIPT_NAME'),
'repo_name':c.repo_name, }
'repo_name':repo_name, }
c.clone_repo_url = uri
c.repo_tags = OrderedDict()
for name, hash in c.repo.tags.items()[:10]:
for name, hash in c.rhodecode_repo.tags.items()[:10]:
try:
c.repo_tags[name] = c.repo.get_changeset(hash)
c.repo_tags[name] = c.rhodecode_repo.get_changeset(hash)
except ChangesetError:
c.repo_tags[name] = EmptyChangeset(hash)
c.repo_branches = OrderedDict()
for name, hash in c.repo.branches.items()[:10]:
for name, hash in c.rhodecode_repo.branches.items()[:10]:
c.repo_branches[name] = c.repo.get_changeset(hash)
c.repo_branches[name] = c.rhodecode_repo.get_changeset(hash)
c.repo_branches[name] = EmptyChangeset(hash)
@@ -114,7 +116,7 @@ class SummaryController(BaseRepoControll
if dbrepo.enable_statistics:
c.no_data_msg = _('No data loaded yet')
run_task(get_commits_stats, c.repo.name, ts_min_y, ts_max_y)
run_task(get_commits_stats, c.dbrepo.repo_name, ts_min_y, ts_max_y)
else:
c.no_data_msg = _('Statistics are disabled for this repository')
c.ts_min = ts_min_m
@@ -143,7 +145,7 @@ class SummaryController(BaseRepoControll
c.enable_downloads = dbrepo.enable_downloads
if c.enable_downloads:
c.download_options = self._get_download_links(c.repo)
c.download_options = self._get_download_links(c.rhodecode_repo)
return render('summary/summary.html')
@@ -293,7 +293,7 @@ def pygmentize(filenode, **kwargs):
return literal(code_highlight(filenode.content,
filenode.lexer, CodeHtmlFormatter(**kwargs)))
def pygmentize_annotation(filenode, **kwargs):
def pygmentize_annotation(repo_name, filenode, **kwargs):
"""pygmentize function for annotation
:param filenode:
@@ -326,27 +326,30 @@ def pygmentize_annotation(filenode, **kw
col = color_dict[cs] = cgenerator.next()
return "color: rgb(%s)! important;" % (', '.join(col))
def url_func(changeset):
tooltip_html = "<div style='font-size:0.8em'><b>Author:</b>" + \
" %s<br/><b>Date:</b> %s</b><br/><b>Message:</b> %s<br/></div>"
def url_func(repo_name):
def _url_func(changeset):
tooltip_html = tooltip_html % (changeset.author,
changeset.date,
tooltip(changeset.message))
lnk_format = '%5s:%s' % ('r%s' % changeset.revision,
short_id(changeset.raw_id))
uri = link_to(
lnk_format,
url('changeset_home', repo_name=changeset.repository.name,
revision=changeset.raw_id),
style=get_color_string(changeset.raw_id),
class_='tooltip',
title=tooltip_html
)
url('changeset_home', repo_name=repo_name,
uri += '\n'
return uri
return literal(annotate_highlight(filenode, url_func, **kwargs))
return _url_func
return literal(annotate_highlight(filenode, url_func(repo_name), **kwargs))
def get_changeset_safe(repo, rev):
from vcs.backends.base import BaseRepository
@@ -690,7 +693,7 @@ def repo_link(groups_and_repos):
return repo_name
def make_link(group):
return link_to(group.group_name, url('/', group.group_id))
return link_to(group.group_name, url('repos_group', id=group.group_id))
return literal(' » '.join(map(make_link, groups)) + \
" » " + repo_name)
@@ -91,7 +91,7 @@ class WhooshIndexingDaemon(object):
filtered_repo_paths = {}
for repo_name, repo in self.repo_paths.items():
if repo_name in repo_list:
filtered_repo_paths[repo.name] = repo
filtered_repo_paths[repo_name] = repo
self.repo_paths = filtered_repo_paths
@@ -130,7 +130,7 @@ class WhooshIndexingDaemon(object):
def get_node_mtime(self, node):
return mktime(node.last_changeset.date.timetuple())
def add_doc(self, writer, path, repo):
def add_doc(self, writer, path, repo, repo_name):
"""Adding doc to writer this function itself fetches data from
the instance of vcs backend"""
node = self.get_node(repo, path)
@@ -152,7 +152,7 @@ class WhooshIndexingDaemon(object):
u_content = u''
writer.add_document(owner=unicode(repo.contact),
repository=safe_unicode(repo.name),
repository=safe_unicode(repo_name),
path=safe_unicode(path),
content=u_content,
modtime=self.get_node_mtime(node),
@@ -170,11 +170,11 @@ class WhooshIndexingDaemon(object):
idx = create_in(self.index_location, SCHEMA, indexname=IDX_NAME)
writer = idx.writer()
for repo in self.repo_paths.values():
log.debug('building index @ %s' % repo.path)
for idx_path in self.get_paths(repo):
self.add_doc(writer, idx_path, repo)
self.add_doc(writer, idx_path, repo, repo_name)
log.debug('>> COMMITING CHANGES <<')
writer.commit(merge=True)
@@ -221,12 +221,12 @@ class WhooshIndexingDaemon(object):
# Loop over the files in the filesystem
# Assume we have a function that gathers the filenames of the
# documents to be indexed
for path in self.get_paths(repo):
if path in to_index or path not in indexed_paths:
# This is either a file that's changed, or a new file
# that wasn't indexed before. So index it!
self.add_doc(writer, path, repo)
self.add_doc(writer, path, repo, repo_name)
log.debug('re indexing %s' % path)
@@ -136,7 +136,7 @@
<img class="icon" alt="${_('public')}" src="${h.url("/images/icons/lock_open.png")}"/>
%endif
${h.link_to(repo['repo'].name, h.url('summary_home',repo_name=repo['repo'].name),class_="repo_name")}
${h.link_to(repo['name'], h.url('summary_home',repo_name=repo['name']),class_="repo_name")}
%if repo['dbrepo_fork']:
<a href="${h.url('summary_home',repo_name=repo['dbrepo_fork']['repo_name'])}">
<img class="icon" alt="${_('public')}"
@@ -145,10 +145,10 @@
</td>
<td><span class="tooltip" title="${repo['repo'].last_change}">${("r%s:%s") % (h.get_changeset_safe(repo['repo'],'tip').revision,h.short_id(h.get_changeset_safe(repo['repo'],'tip').raw_id))}</span></td>
<td><a href="${h.url('repo_settings_home',repo_name=repo['repo'].name)}" title="${_('edit')}"><img class="icon" alt="${_('private')}" src="${h.url("/images/icons/application_form_edit.png")}"/></a></td>
<td><a href="${h.url('repo_settings_home',repo_name=repo['name'])}" title="${_('edit')}"><img class="icon" alt="${_('private')}" src="${h.url("/images/icons/application_form_edit.png")}"/></a></td>
<td>
${h.form(url('repo_settings_delete', repo_name=repo['repo'].name),method='delete')}
${h.submit('remove_%s' % repo['repo'].name,'',class_="delete_icon action_button",onclick="return confirm('Confirm to delete this repository');")}
${h.form(url('repo_settings_delete', repo_name=repo['name']),method='delete')}
${h.submit('remove_%s' % repo['name'],'',class_="delete_icon action_button",onclick="return confirm('Confirm to delete this repository');")}
${h.end_form()}
</tr>
@@ -67,7 +67,7 @@
${_('Binary file')}
%else:
% if c.file.size < c.cut_off_limit:
${h.pygmentize_annotation(c.file,linenos=True,anchorlinenos=True,lineanchors='S',cssclass="code-highlight")}
${h.pygmentize_annotation(c.repo_name,c.file,linenos=True,anchorlinenos=True,lineanchors='S',cssclass="code-highlight")}
${_('File is to big to display')} ${h.link_to(_('show as raw'),
h.url('files_raw_home',repo_name=c.repo_name,revision=c.cs.revision,f_path=c.f_path))}
@@ -4,7 +4,7 @@
%if repo['dbrepo']['private']:
<li>
<img src="${h.url("/images/icons/lock.png")}" alt="${_('Private repository')}" class="repo_switcher_type"/>
${h.link_to(repo['name'].name,h.url('summary_home',repo_name=repo['name']),class_="%s" % repo['dbrepo']['repo_type'])}
${h.link_to(repo['name'],h.url('summary_home',repo_name=repo['name']),class_="%s" % repo['dbrepo']['repo_type'])}
</li>
@@ -7,7 +7,7 @@
<%def name="breadcrumbs_links()">
${h.link_to(u'Home',h.url('/'))}
»
${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
${h.link_to(c.dbrepo.just_name,h.url('summary_home',repo_name=c.repo_name))}
${_('summary')}
</%def>
@@ -31,6 +31,17 @@
<label>${_('Name')}:</label>
</div>
<div class="input-short">
%if c.rhodecode_user.username != 'default':
%if c.following:
<span id="follow_toggle" class="following" title="${_('Stop following this repository')}"
onclick="javascript:toggleFollowingRepo(this,${c.dbrepo.repo_id},'${str(h.get_token())}')">
</span>
<span id="follow_toggle" class="follow" title="${_('Start following this repository')}"
%endif:
%if c.dbrepo.repo_type =='hg':
<img style="margin-bottom:2px" class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="${h.url("/images/icons/hgicon.png")}"/>
@@ -43,19 +54,8 @@
<img style="margin-bottom:2px" class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="${h.url("/images/icons/lock_open.png")}"/>
<span style="font-size: 1.6em;font-weight: bold;vertical-align: baseline;">${c.repo.name}</span>
<br/>
<span style="font-size: 1.6em;font-weight: bold;vertical-align: baseline;">${h.repo_link(c.dbrepo.groups_and_repo)}</span>
%if c.dbrepo.fork:
<span style="margin-top:5px">
<a href="${h.url('summary_home',repo_name=c.dbrepo.fork.repo_name)}">
@@ -109,8 +109,11 @@
<label>${_('Last change')}:</label>
${h.age(c.repo.last_change)} - ${c.repo.last_change}
${_('by')} ${h.get_changeset_safe(c.repo,'tip').author}
<b>${'r%s:%s' % (h.get_changeset_safe(c.rhodecode_repo,'tip').revision,
h.get_changeset_safe(c.rhodecode_repo,'tip').short_id)}</b> -
<span class="tooltip" title="${c.rhodecode_repo.last_change}">
${h.age(c.rhodecode_repo.last_change)}</span><br/>
${_('by')} ${h.get_changeset_safe(c.rhodecode_repo,'tip').author}
@@ -138,7 +141,7 @@
<label>${_('Download')}:</label>
%if len(c.repo.revisions) == 0:
%if len(c.rhodecode_repo.revisions) == 0:
${_('There are no downloads yet')}
%elif c.enable_downloads is False:
${_('Downloads are disabled for this repository')}
@@ -146,14 +149,14 @@
[${h.link_to(_('enable'),h.url('edit_repo',repo_name=c.repo_name))}]
${h.select('download_options',c.repo.get_changeset().raw_id,c.download_options)}
%for cnt,archive in enumerate(c.repo._get_archives()):
${h.select('download_options',c.rhodecode_repo.get_changeset().raw_id,c.download_options)}
%for cnt,archive in enumerate(c.rhodecode_repo._get_archives()):
%if cnt >=1:
|
<span class="tooltip" title="${_('Download %s as %s') %('tip',archive['type'])}"
id="${archive['type']+'_link'}">${h.link_to(archive['type'],
h.url('files_archive_home',repo_name=c.repo.name,
h.url('files_archive_home',repo_name=c.dbrepo.repo_name,
fname='tip'+archive['extension']),class_="archive_icon")}</span>
%endfor
@@ -166,11 +169,11 @@
${h.link_to(_('RSS'),h.url('rss_feed_home',repo_name=c.repo.name,api_key=c.rhodecode_user.api_key),class_='rss_icon')}
${h.link_to(_('Atom'),h.url('atom_feed_home',repo_name=c.repo.name,api_key=c.rhodecode_user.api_key),class_='atom_icon')}
${h.link_to(_('RSS'),h.url('rss_feed_home',repo_name=c.dbrepo.repo_name,api_key=c.rhodecode_user.api_key),class_='rss_icon')}
${h.link_to(_('Atom'),h.url('atom_feed_home',repo_name=c.dbrepo.repo_name,api_key=c.rhodecode_user.api_key),class_='atom_icon')}
${h.link_to(_('RSS'),h.url('rss_feed_home',repo_name=c.repo.name),class_='rss_icon')}
${h.link_to(_('Atom'),h.url('atom_feed_home',repo_name=c.repo.name),class_='atom_icon')}
${h.link_to(_('RSS'),h.url('rss_feed_home',repo_name=c.dbrepo.repo_name),class_='rss_icon')}
${h.link_to(_('Atom'),h.url('atom_feed_home',repo_name=c.dbrepo.repo_name),class_='atom_icon')}
@@ -265,9 +268,9 @@
YUE.on('download_options','change',function(e){
var new_cs = e.target.options[e.target.selectedIndex];
var tmpl_links = {}
tmpl_links['${archive['type']}'] = '${h.link_to(archive['type'],
fname='__CS__'+archive['extension']),class_="archive_icon")}';
from rhodecode.tests import *
class TestReposGroupsController(TestController):
def test_index(self):
response = self.app.get(url('repos_groups'))
# Test response...
def test_index_as_xml(self):
response = self.app.get(url('formatted_repos_groups', format='xml'))
def test_create(self):
response = self.app.post(url('repos_groups'))
def test_new(self):
response = self.app.get(url('new_repos_group'))
def test_new_as_xml(self):
response = self.app.get(url('formatted_new_repos_group', format='xml'))
def test_update(self):
response = self.app.put(url('repos_group', id=1))
def test_update_browser_fakeout(self):
response = self.app.post(url('repos_group', id=1), params=dict(_method='put'))
def test_delete(self):
response = self.app.delete(url('repos_group', id=1))
def test_delete_browser_fakeout(self):
response = self.app.post(url('repos_group', id=1), params=dict(_method='delete'))
def test_show(self):
response = self.app.get(url('repos_group', id=1))
def test_show_as_xml(self):
response = self.app.get(url('formatted_repos_group', id=1, format='xml'))
def test_edit(self):
response = self.app.get(url('edit_repos_group', id=1))
def test_edit_as_xml(self):
response = self.app.get(url('formatted_edit_repos_group', id=1, format='xml'))
Status change: