@@ -144,20 +144,21 @@ class ReposController(BaseController):
template = _tmpl_lookup.get_template('data_table/_dt_elements.html')
quick_menu = lambda repo_name: (template.get_def("quick_menu")
.render(repo_name, _=_, h=h))
.render(repo_name, _=_, h=h, c=c))
repo_lnk = lambda name, rtype, private, fork_of: (
template.get_def("repo_name")
.render(name, rtype, private, fork_of, short_name=False,
admin=True, _=_, h=h))
admin=True, _=_, h=h, c=c))
repo_actions = lambda repo_name: (template.get_def("repo_actions")
for repo in c.repos_list:
repos_data.append({
"menu": quick_menu(repo.repo_name),
"raw_name": repo.repo_name,
"name": repo_lnk(repo.repo_name, repo.repo_type, repo.private, repo.fork),
"name": repo_lnk(repo.repo_name, repo.repo_type,
repo.private, repo.fork),
"desc": repo.description,
"owner": repo.user.username,
"action": repo_actions(repo.repo_name),
@@ -45,7 +45,7 @@ from rhodecode.lib.utils import repo2db_
from rhodecode.model.db import RhodeCodeUi, Repository, RepoGroup, \
RhodeCodeSetting, PullRequest, PullRequestReviewers
from rhodecode.model.forms import UserForm, ApplicationSettingsForm, \
ApplicationUiSettingsForm
ApplicationUiSettingsForm, ApplicationVisualisationForm
from rhodecode.model.scm import ScmModel
from rhodecode.model.user import UserModel
from rhodecode.model.db import User
@@ -143,15 +143,15 @@ class SettingsController(BaseController)
)
try:
sett1 = RhodeCodeSetting.get_by_name('title')
sett1 = RhodeCodeSetting.get_by_name_or_create('title')
sett1.app_settings_value = form_result['rhodecode_title']
Session().add(sett1)
sett2 = RhodeCodeSetting.get_by_name('realm')
sett2 = RhodeCodeSetting.get_by_name_or_create('realm')
sett2.app_settings_value = form_result['rhodecode_realm']
Session().add(sett2)
sett3 = RhodeCodeSetting.get_by_name('ga_code')
sett3 = RhodeCodeSetting.get_by_name_or_create('ga_code')
sett3.app_settings_value = form_result['rhodecode_ga_code']
Session().add(sett3)
@@ -165,6 +165,47 @@ class SettingsController(BaseController)
'application settings'),
category='error')
if setting_id == 'visual':
application_form = ApplicationVisualisationForm()()
form_result = application_form.to_python(dict(request.POST))
except formencode.Invalid, errors:
return htmlfill.render(
render('admin/settings/settings.html'),
defaults=errors.value,
errors=errors.error_dict or {},
prefix_error=False,
encoding="UTF-8"
sett1 = RhodeCodeSetting.get_by_name_or_create('show_public_icon')
sett1.app_settings_value = \
form_result['rhodecode_show_public_icon']
sett2 = RhodeCodeSetting.get_by_name_or_create('show_private_icon')
sett2.app_settings_value = \
form_result['rhodecode_show_private_icon']
sett3 = RhodeCodeSetting.get_by_name_or_create('stylify_metatags')
sett3.app_settings_value = \
form_result['rhodecode_stylify_metatags']
Session().commit()
set_rhodecode_config(config)
h.flash(_('Updated visualisation settings'),
category='success')
except Exception:
log.error(traceback.format_exc())
h.flash(_('error occurred during updating '
'visualisation settings'),
if setting_id == 'vcs':
application_form = ApplicationUiSettingsForm()()
@@ -78,15 +78,15 @@ class UsersController(BaseController):
grav_tmpl = lambda user_email, size: (
template.get_def("user_gravatar")
.render(user_email, size, _=_, h=h))
.render(user_email, size, _=_, h=h, c=c))
user_lnk = lambda user_id, username: (
template.get_def("user_name")
.render(user_id, username, _=_, h=h))
.render(user_id, username, _=_, h=h, c=c))
user_actions = lambda user_id, username: (
template.get_def("user_actions")
for user in c.users_list:
users_data.append({
@@ -17,7 +17,7 @@ from pylons.templating import render_mak
from rhodecode import __version__, BACKENDS
from rhodecode.lib.utils2 import str2bool, safe_unicode
from rhodecode.lib.utils2 import str2bool, safe_unicode, AttributeDict
from rhodecode.lib.auth import AuthUser, get_container_username, authfunc,\
HasPermissionAnyMiddleware, CookieStoreWrapper
from rhodecode.lib.utils import get_repo_slug, invalidate_cache
@@ -158,7 +158,7 @@ class BaseVCSController(object):
log.debug('proto is %s and SSL is required BAD REQUEST !'
% org_proto)
return False
return True
def __call__(self, environ, start_response):
start = time.time()
@@ -178,6 +178,12 @@ class BaseController(WSGIController):
c.rhodecode_name = config.get('rhodecode_title')
c.use_gravatar = str2bool(config.get('use_gravatar'))
c.ga_code = config.get('rhodecode_ga_code')
# Visual options
c.visual = AttributeDict({})
c.visual.show_public_icon = str2bool(config.get('rhodecode_show_public_icon'))
c.visual.show_private_icon = str2bool(config.get('rhodecode_show_private_icon'))
c.visual.stylify_metatags = str2bool(config.get('rhodecode_stylify_metatags'))
c.repo_name = get_repo_slug(request)
c.backends = BACKENDS.keys()
c.unread_notifications = NotificationModel()\
@@ -9,6 +9,7 @@ import StringIO
import urllib
import math
import logging
import re
from datetime import datetime
from pygments.formatters.html import HtmlFormatter
@@ -430,6 +431,26 @@ def person(author):
return _author
def desc_stylize(value):
"""
converts tags from value into html equivalent
:param value:
value = re.sub(r'\[see\ \=\>\ *([a-zA-Z0-9\/\=\?\&\ \:\/\.\-]*)\]',
'<div class="metatag" tag="see">see => \\1 </div>', value)
value = re.sub(r'\[license\ \=\>\ *([a-zA-Z0-9\/\=\?\&\ \:\/\.\-]*)\]',
'<div class="metatag" tag="license"><a href="http:\/\/www.opensource.org/licenses/\\1">\\1</a></div>', value)
value = re.sub(r'\[(requires|recommends|conflicts|base)\ \=\>\ *([a-zA-Z\-\/]*)\]',
'<div class="metatag" tag="\\1">\\1 => <a href="/\\2">\\2</a></div>', value)
value = re.sub(r'\[(lang|language)\ \=\>\ *([a-zA-Z\-\/]*)\]',
'<div class="metatag" tag="lang">\\2</div>', value)
value = re.sub(r'\[([a-z]+)\]',
'<div class="metatag" tag="\\1">\\1</div>', value)
return value
def bool2icon(value):
"""Returns True/False values represented as small html image of true/false
icons
@@ -443,3 +443,9 @@ def extract_mentioned_users(s):
usrs.add(username)
return sorted(list(usrs), key=lambda k: k.lower())
class AttributeDict(dict):
def __getattr__(self, attr):
return self.get(attr, None)
__setattr__ = dict.__setitem__
__delattr__ = dict.__delitem__
@@ -182,9 +182,16 @@ class RhodeCodeSetting(Base, BaseModel):
@classmethod
def get_by_name(cls, ldap_key):
def get_by_name(cls, key):
return cls.query()\
.filter(cls.app_settings_name == ldap_key).scalar()
.filter(cls.app_settings_name == key).scalar()
def get_by_name_or_create(cls, key):
res = cls.get_by_name(key)
if not res:
res = cls(key)
return res
def get_app_settings(cls, cache=False):
@@ -589,8 +596,8 @@ class Repository(Base, BaseModel):
users_group_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
stats = relationship('Statistics', cascade='all', uselist=False)
followers = relationship('UserFollowing',
primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id',
cascade='all')
logs = relationship('UserLog')
@@ -1547,7 +1554,7 @@ class PullRequest(Base, BaseModel):
self._revisions = ':'.join(val)
author = relationship('User', lazy='joined')
reviewers = relationship('PullRequestReviewers',
cascade="all, delete, delete-orphan")
org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id')
other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id')
@@ -242,23 +242,30 @@ def ApplicationSettingsForm():
return _ApplicationSettingsForm
def ApplicationVisualisationForm():
class _ApplicationVisualisationForm(formencode.Schema):
allow_extra_fields = True
filter_extra_fields = False
rhodecode_show_public_icon = v.StringBoolean(if_missing=False)
rhodecode_show_private_icon = v.StringBoolean(if_missing=False)
rhodecode_stylify_metatags = v.StringBoolean(if_missing=False)
return _ApplicationVisualisationForm
def ApplicationUiSettingsForm():
class _ApplicationUiSettingsForm(formencode.Schema):
web_push_ssl = v.OneOf(['true', 'false'], if_missing='false')
web_push_ssl = v.StringBoolean(if_missing=False)
paths_root_path = All(
v.ValidPath(),
v.UnicodeString(strip=True, min=1, not_empty=True)
hooks_changegroup_update = v.OneOf(['True', 'False'],
if_missing=False)
hooks_changegroup_repo_size = v.OneOf(['True', 'False'],
hooks_changegroup_push_logger = v.OneOf(['True', 'False'],
hooks_preoutgoing_pull_logger = v.OneOf(['True', 'False'],
hooks_changegroup_update = v.StringBoolean(if_missing=False)
hooks_changegroup_repo_size = v.StringBoolean(if_missing=False)
hooks_changegroup_push_logger = v.StringBoolean(if_missing=False)
hooks_preoutgoing_pull_logger = v.StringBoolean(if_missing=False)
return _ApplicationUiSettingsForm
@@ -268,7 +275,7 @@ def DefaultPermissionsForm(perms_choices
filter_extra_fields = True
overwrite_default = v.StringBoolean(if_missing=False)
anonymous = v.OneOf(['True', 'False'], if_missing=False)
anonymous = v.StringBoolean(if_missing=False)
default_perm = v.OneOf(perms_choices)
default_register = v.OneOf(register_choices)
default_create = v.OneOf(create_choices)
@@ -1827,6 +1827,81 @@ div.form div.fields div.field div.button
}
#summary .metatag {
display: inline-block;
padding: 3px 5px;
margin-bottom: 3px;
margin-right: 1px;
border-radius: 5px;
#content div.box #summary p {
margin-bottom: -5px;
width: 600px;
white-space: pre-wrap;
#content div.box #summary p:last-child {
margin-bottom: 9px;
#content div.box #summary p:first-of-type {
margin-top: 9px;
.metatag {
-webkit-border-radius: 4px 4px 4px 4px;
-khtml-border-radius: 4px 4px 4px 4px;
-moz-border-radius: 4px 4px 4px 4px;
border-radius: 4px 4px 4px 4px;
border: solid 1px #9CF;
padding: 2px 3px 2px 3px !important;
background-color: #DEF;
.metatag[tag="dead"] {
background-color: #E44;
.metatag[tag="stale"] {
background-color: #EA4;
.metatag[tag="featured"] {
background-color: #AEA;
.metatag[tag="requires"] {
background-color: #9CF;
.metatag[tag="recommends"] {
background-color: #BDF;
.metatag[tag="lang"] {
background-color: #FAF474;
.metatag[tag="license"] {
target-new: tab !important;
.metatag[tag="see"] {
border: solid 1px #CBD;
background-color: #EDF;
a.metatag[tag="license"]:hover {
background-color: #003367;
color: #FFF;
text-decoration: none;
#summary .desc {
white-space: pre;
width: 100%;
@@ -116,6 +116,63 @@
</div>
${h.end_form()}
<h3>${_('Visualisation settings')}</h3>
${h.form(url('admin_setting', setting_id='visual'),method='put')}
<div class="form">
<!-- fields -->
<div class="fields">
<div class="field">
<div class="label label-checkbox">
<label>${_('Icons')}:</label>
<div class="checkboxes">
<div class="checkbox">
${h.checkbox('rhodecode_show_public_icon','True')}
<label for="rhodecode_show_public_icon">${_('Show public repo icon on repositories')}</label>
${h.checkbox('rhodecode_show_private_icon','True')}
<label for="rhodecode_show_private_icon">${_('Show private repo icon on repositories')}</label>
<label>${_('Meta-Tagging')}:</label>
${h.checkbox('rhodecode_stylify_metatags','True')}
<label for="rhodecode_stylify_metatags">${_('Stylify recognised metatags:')}</label>
<div style="padding-left: 20px;">
<ul> <!-- Fix style here -->
<li>[featured] <span class="metatag" tag="featured">featured</span></li>
<li>[stale] <span class="metatag" tag="stale">stale</span></li>
<li>[dead] <span class="metatag" tag="dead">dead</span></li>
<li>[lang => lang] <span class="metatag" tag="lang" >lang</span></li>
<li>[license => License] <span class="metatag" tag="license"><a href="http://www.opensource.org/licenses/License" >License</a></span></li>
<li>[requires => Repo] <span class="metatag" tag="requires" >requires => <a href="#" >Repo</a></span></li>
<li>[recommends => Repo] <span class="metatag" tag="recommends" >recommends => <a href="#" >Repo</a></span></li>
<li>[see => URI] <span class="metatag" tag="see">see => <a href="#">URI</a> </span></li>
</ul>
<div class="buttons">
${h.submit('save',_('Save settings'),class_="ui-btn large")}
${h.reset('reset',_('Reset'),class_="ui-btn large")}
<h3>${_('VCS settings')}</h3>
${h.form(url('admin_setting', setting_id='vcs'),method='put')}
@@ -63,10 +63,10 @@
%endif
##PRIVATE/PUBLIC
%if private:
<img class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="${h.url('/images/icons/lock.png')}"/>
%else:
<img class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="${h.url('/images/icons/lock_open.png')}"/>
%if private and c.visual.show_private_icon:
%elif not private and c.visual.show_public_icon:
##NAME
@@ -108,4 +108,3 @@
<%def name="user_name(user_id, username)">
${h.link_to(username,h.url('edit_user', id=user_id))}
</%def>
@@ -41,7 +41,11 @@
${h.link_to(gr.name,url('repos_group_home',group_name=gr.group_name))}
</td>
<td>${gr.group_description}</td>
%if c.visual.stylify_metatags:
<td>${h.desc_stylize(gr.group_description)}</td>
## this is commented out since for multi nested repos can be HEAVY!
## in number of executed queries during traversing uncomment at will
##<td><b>${gr.repositories_recursive_count}</b></td>
@@ -85,7 +89,11 @@
##DESCRIPTION
<td><span class="tooltip" title="${h.tooltip(repo['description'])}">
${h.urlify_text(h.desc_stylize(h.truncate(repo['description'],60)))}</span>
${h.truncate(repo['description'],60)}</span>
##LAST CHANGE DATE
<td>
@@ -128,9 +128,9 @@
<img class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="${h.url('/images/icons/giticon.png')}"/>
%if entry.follows_repository.private:
%if entry.follows_repository.private and c.visual.show_private_icon:
%elif not entry.follows_repository.private and c.visual.show_public_icon:
<span class="watched_repo">
@@ -6,12 +6,12 @@
%for repo in c.repos_list:
%if repo['dbrepo']['private']:
%if repo['dbrepo']['private'] and c.visual.show_private_icon:
<li>
<img src="${h.url('/images/icons/lock.png')}" alt="${_('Private repository')}" class="repo_switcher_type"/>
${h.link_to(repo['name'],h.url('summary_home',repo_name=repo['name']),class_="repo_name %s" % repo['dbrepo']['repo_type'])}
</li>
%elif not repo['dbrepo']['private'] and c.visual.show_public_icon:
<img src="${h.url('/images/icons/lock_open.png')}" alt="${_('Public repository')}" class="repo_switcher_type" />
@@ -104,7 +104,11 @@
<div class="label-summary">
<label>${_('Description')}:</label>
<div class="input ${summary(c.show_stats)} desc">${h.urlify_text(c.dbrepo.description)}</div>
<div class="input ${summary(c.show_stats)} desc">${h.urlify_text(h.desc_stylize(c.dbrepo.description))}</div>
@@ -131,3 +131,19 @@ class TestLibs(unittest.TestCase):
self.assertEqual(age(n - delt(hours=24 * (calendar.mdays[n.month-1] + 2))),
u'1 month and 2 days ago')
self.assertEqual(age(n - delt(hours=24 * 400)), u'1 year and 1 month ago')
def test_tag_exctrator(self):
sample = (
"hello pta[tag] gog [[]] [[] sda ero[or]d [me =>>< sa]"
"[requires] [stale] [see<>=>] [see => http://url.com]"
"[requires => url] [lang => python] [just a tag]"
"[,d] [ => ULR ] [obsolete] [desc]]"
from rhodecode.lib.helpers import desc_stylize
res = desc_stylize(sample)
self.assertTrue('<div class="metatag" tag="tag">tag</div>' in res)
self.assertTrue('<div class="metatag" tag="obsolete">obsolete</div>' in res)
self.assertTrue('<div class="metatag" tag="stale">stale</div>' in res)
self.assertTrue('<div class="metatag" tag="lang">python</div>' in res)
self.assertTrue('<div class="metatag" tag="requires">requires => <a href="/url">url</a></div>' in res)
Status change: