@@ -44,192 +44,195 @@ import traceback
log = logging.getLogger(__name__)
class ReposController(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('repo', 'repos')
@LoginRequired()
@HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
def __before__(self):
c.admin_user = session.get('admin_user')
c.admin_username = session.get('admin_username')
super(ReposController, self).__before__()
@HasPermissionAllDecorator('hg.admin')
def index(self, format='html'):
"""GET /repos: All items in the collection"""
# url('repos')
cached_repo_list = HgModel().get_repos()
c.repos_list = sorted(cached_repo_list, key=itemgetter('name_sort'))
return render('admin/repos/repos.html')
def create(self):
"""POST /repos: Create a new item"""
repo_model = RepoModel()
_form = RepoForm()()
form_result = {}
try:
form_result = _form.to_python(dict(request.POST))
repo_model.create(form_result, c.rhodecode_user)
invalidate_cache('cached_repo_list')
h.flash(_('created repository %s') % form_result['repo_name'],
category='success')
if request.POST.get('user_created'):
action_logger(self.rhodecode_user, 'user_created_repo',
form_result['repo_name'], '', self.sa)
else:
action_logger(self.rhodecode_user, 'admin_created_repo',
except formencode.Invalid, errors:
c.new_repo = errors.value['repo_name']
r = render('admin/repos/repo_add_create_repository.html')
r = render('admin/repos/repo_add.html')
return htmlfill.render(
r,
defaults=errors.value,
errors=errors.error_dict or {},
prefix_error=False,
encoding="UTF-8")
except Exception:
log.error(traceback.format_exc())
msg = _('error occured during creation of repository %s') \
% form_result.get('repo_name')
h.flash(msg, category='error')
return redirect(url('home'))
return redirect(url('repos'))
def new(self, format='html'):
"""GET /repos/new: Form to create a new item"""
new_repo = request.GET.get('repo', '')
c.new_repo = h.repo_name_slug(new_repo)
return render('admin/repos/repo_add.html')
def update(self, repo_name):
"""PUT /repos/repo_name: 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('repo', repo_name=ID),
# method='put')
# url('repo', repo_name=ID)
changed_name = repo_name
_form = RepoForm(edit=True, old_data={'repo_name':repo_name})()
repo_model.update(repo_name, form_result)
h.flash(_('Repository %s updated succesfully' % repo_name),
changed_name = form_result['repo_name']
action_logger(self.rhodecode_user, 'admin_updated_repo',
changed_name, '', self.sa)
c.repo_info = repo_model.get(repo_name)
c.users_array = repo_model.get_users_js()
errors.value.update({'user':c.repo_info.user.username})
render('admin/repos/repo_edit.html'),
h.flash(_('error occured during update of repository %s') \
% repo_name, category='error')
return redirect(url('edit_repo', repo_name=changed_name))
def delete(self, repo_name):
"""DELETE /repos/repo_name: Delete an existing item"""
# <input type="hidden" name="_method" value="DELETE" />
# method='delete')
repo = repo_model.get(repo_name)
if not repo:
h.flash(_('%s repository is not mapped to db perhaps'
' it was moved or renamed from the filesystem'
' please run the application again'
' in order to rescan repositories') % repo_name,
category='error')
action_logger(self.rhodecode_user, 'admin_deleted_repo',
repo_name, '', self.sa)
repo_model.delete(repo)
h.flash(_('deleted repository %s') % repo_name, category='success')
except Exception, e:
h.flash(_('An error occured during deletion of %s') % repo_name,
def delete_perm_user(self, repo_name):
"""
DELETE an existing repository permission user
:param repo_name:
repo_model.delete_perm_user(request.POST, repo_name)
h.flash(_('An error occured during deletion of repository user'),
raise HTTPInternalServerError()
def show(self, repo_name, format='html'):
"""GET /repos/repo_name: Show a specific item"""
def edit(self, repo_name, format='html'):
"""GET /repos/repo_name/edit: Form to edit an existing item"""
# url('edit_repo', repo_name=ID)
c.repo_info = repo = repo_model.get(repo_name)
' it was created or renamed from the filesystem'
defaults = c.repo_info.__dict__
if c.repo_info.user:
defaults.update({'user':c.repo_info.user.username})
replacement_user = self.sa.query(User)\
.filter(User.admin == True).first().username
defaults.update({'user':replacement_user})
#!/usr/bin/env python
# encoding: utf-8
# settings controller for pylons
# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; version 2
# of the License or (at your opinion) any later version of the license.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA.
Created on June 30, 2010
settings controller for pylons
@author: marcink
from formencode import htmlfill
from pylons import tmpl_context as c, request, url
from pylons.controllers.util import redirect
from pylons.i18n.translation import _
from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAllDecorator
from rhodecode.lib.base import BaseController, render
from rhodecode.lib.utils import invalidate_cache, action_logger
from rhodecode.model.forms import RepoSettingsForm, RepoForkForm
from rhodecode.model.repo import RepoModel
import formencode
import logging
import rhodecode.lib.helpers as h
import traceback
class SettingsController(BaseController):
@HasRepoPermissionAllDecorator('repository.admin')
super(SettingsController, self).__before__()
def index(self, repo_name):
for p in c.repo_info.repo_to_perm:
defaults.update({'perm_%s' % p.user.username:
p.permission.permission_name})
render('settings/repo_settings.html'),
defaults=defaults,
encoding="UTF-8",
force_defaults=False
)
_form = RepoSettingsForm(edit=True, old_data={'repo_name':repo_name})()
h.flash(_('Repository %s updated successfully' % repo_name),
action_logger(self.rhodecode_user, 'user_updated_repo',
return redirect(url('repo_settings_home', repo_name=changed_name))
# h.form(url('repo_settings_delete', repo_name=ID),
# url('repo_settings_delete', repo_name=ID)
action_logger(self.rhodecode_user, 'user_deleted_repo',
h.flash(_('An error occurred during deletion of %s') % repo_name,
def fork(self, repo_name):
return render('settings/repo_fork.html')
def fork_create(self, repo_name):
_form = RepoForkForm(old_data={'repo_type':c.repo_info.repo_type})()
form_result.update({'repo_name':repo_name})
repo_model.create_fork(form_result, c.rhodecode_user)
h.flash(_('fork %s repository as %s task added') \
% (repo_name, form_result['fork_name']),
action_logger(self.rhodecode_user, 'user_forked_repo',
c.new_repo = errors.value['fork_name']
r = render('settings/repo_fork.html')
@@ -235,167 +235,211 @@ def pygmentize(filenode, **kwargs):
def pygmentize_annotation(filenode, **kwargs):
pygmentize function for annotation
:param filenode:
color_dict = {}
def gen_color():
"""generator for getting 10k of evenly distibuted colors using hsv color
and golden ratio.
import colorsys
n = 10000
golden_ratio = 0.618033988749895
h = 0.22717784590367374
#generate 10k nice web friendly colors in the same order
for c in xrange(n):
h += golden_ratio
h %= 1
HSV_tuple = [h, 0.95, 0.95]
RGB_tuple = colorsys.hsv_to_rgb(*HSV_tuple)
yield map(lambda x:str(int(x * 256)), RGB_tuple)
cgenerator = gen_color()
def get_color_string(cs):
if color_dict.has_key(cs):
col = color_dict[cs]
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>"
tooltip_html = tooltip_html % (changeset.author,
changeset.date,
tooltip(changeset.message))
lnk_format = 'r%-5s:%s' % (changeset.revision,
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',
tooltip_title=tooltip_html
uri += '\n'
return uri
return literal(annotate_highlight(filenode, url_func, **kwargs))
def repo_name_slug(value):
"""Return slug of name of repository
This function is called on each creation/modification
of repository to prevent bad names in repo
slug = remove_formatting(value)
slug = strip_tags(slug)
for c in """=[]\;'"<>,/~!@#$%^&*()+{}|: """:
slug = slug.replace(c, '-')
slug = recursive_replace(slug, '-')
slug = collapse(slug, '-')
return slug
def get_changeset_safe(repo, rev):
from vcs.backends.base import BaseRepository
from vcs.exceptions import RepositoryError
if not isinstance(repo, BaseRepository):
raise Exception('You must pass an Repository '
'object as first argument got %s', type(repo))
cs = repo.get_changeset(rev)
except RepositoryError:
from rhodecode.lib.utils import EmptyChangeset
cs = EmptyChangeset()
return cs
flash = _Flash()
#==============================================================================
# MERCURIAL FILTERS available via h.
from mercurial import util
from mercurial.templatefilters import person as _person
def _age(curdate):
"""turns a datetime into an age string."""
if not curdate:
return ''
from datetime import timedelta, datetime
agescales = [("year", 3600 * 24 * 365),
("month", 3600 * 24 * 30),
("day", 3600 * 24),
("hour", 3600),
("minute", 60),
("second", 1), ]
age = datetime.now() - curdate
age_seconds = (age.days * agescales[2][1]) + age.seconds
pos = 1
for scale in agescales:
if scale[1] <= age_seconds:
if pos == 6:pos = 5
return time_ago_in_words(curdate, agescales[pos][0])
pos += 1
age = lambda x:_age(x)
capitalize = lambda x: x.capitalize()
email = util.email
email_or_none = lambda x: util.email(x) if util.email(x) != x else None
person = lambda x: _person(x)
short_id = lambda x: x[:12]
def action_parser(user_log):
This helper will map the specified string action into translated
fancy names with icons and links
@param action:
action = user_log.action
action_params = None
cs_links = ''
x = action.split(':')
if len(x) > 1:
action, action_params = x
if action == 'push':
revs_limit = 5
revs = action_params.split(',')
cs_links = " " + ', '.join ([link(rev,
url('changeset_home',
repo_name=user_log.repository.repo_name,
revision=rev)) for rev in revs[:revs_limit] ])
if len(revs) > revs_limit:
html_tmpl = '<span title="%s"> %s </span>'
cs_links += html_tmpl % (', '.join(r for r in revs[revs_limit:]),
_('and %s more revisions') % (len(revs) - revs_limit))
map = {'user_deleted_repo':_('User deleted repository'),
'user_created_repo':_('User created repository'),
'user_forked_repo':_('User forked repository'),
'user_updated_repo':_('User updated repository'),
'admin_deleted_repo':_('Admin delete repository'),
'admin_created_repo':_('Admin created repository'),
'admin_forked_repo':_('Admin forked repository'),
'admin_updated_repo':_('Admin updated repository'),
'push':_('Pushed') + literal(cs_links),
'pull':_('Pulled'), }
print action, action_params
return map.get(action, action)
# PERMS
from rhodecode.lib.auth import HasPermissionAny, HasPermissionAll, \
HasRepoPermissionAny, HasRepoPermissionAll
# GRAVATAR URL
import hashlib
import urllib
from pylons import request
def gravatar_url(email_address, size=30):
ssl_enabled = 'https' == request.environ.get('HTTP_X_URL_SCHEME')
default = 'identicon'
baseurl_nossl = "http://www.gravatar.com/avatar/"
baseurl_ssl = "https://secure.gravatar.com/avatar/"
baseurl = baseurl_ssl if ssl_enabled else baseurl_nossl
# construct the url
gravatar_url = baseurl + hashlib.md5(email_address.lower()).hexdigest() + "?"
gravatar_url += urllib.urlencode({'d':default, 's':str(size)})
return gravatar_url
def safe_unicode(str):
"""safe unicode function. In case of UnicodeDecode error we try to return
unicode with errors replace, if this failes we return unicode with
string_escape decoding """
u_str = unicode(str)
except UnicodeDecodeError:
u_str = unicode(str, 'utf-8', 'replace')
#incase we have a decode error just represent as byte string
u_str = unicode(str(str).encode('string_escape'))
return u_str
## -*- coding: utf-8 -*-
%if c.users_log:
<table>
<tr>
<th class="left">${_('Username')}</th>
<th class="left">${_('Action')}</th>
<th class="left">${_('Repository')}</th>
<th class="left">${_('Date')}</th>
<th class="left">${_('From IP')}</th>
</tr>
%for cnt,l in enumerate(c.users_log):
<tr class="parity${cnt%2}">
<td>${h.link_to(l.user.username,h.url('edit_user', id=l.user.user_id))}</td>
<td>${h.action_parser(l)}</td>
<td>
%if l.repository:
${h.link_to(l.repository.repo_name,h.url('summary_home',repo_name=l.repository.repo_name))}
%else:
${l.repository_name}
%endif
</td>
% if l.action == 'push' and l.revision:
${h.link_to('%s - %s' % (l.action,l.revision),
h.url('changeset_home',repo_name=l.repository.repo_name,revision=l.revision))}
${l.action}
<td>${l.action_date}</td>
<td>${l.user_ip}</td>
%endfor
</table>
<script type="text/javascript">
var data_div = 'user_log';
YAHOO.util.Event.onDOMReady(function(){
YAHOO.util.Event.addListener(YAHOO.util.Dom.getElementsByClassName('pager_link'),"click",function(){
YAHOO.util.Dom.setStyle('shortlog_data','opacity','0.3');});});
</script>
<div class="pagination-wh pagination-left">
${c.users_log.pager('$link_previous ~2~ $link_next',
onclick="""YAHOO.util.Connect.asyncRequest('GET','$partial_url',{
success:function(o){YAHOO.util.Dom.get(data_div).innerHTML=o.responseText;
YAHOO.util.Dom.setStyle(data_div,'opacity','0.3');});
YAHOO.util.Dom.setStyle(data_div,'opacity','1');}},null); return false;""")}
</div>
${_('No actions yet')}
Status change: