diff --git a/rhodecode/controllers/admin/repos.py b/rhodecode/controllers/admin/repos.py --- a/rhodecode/controllers/admin/repos.py +++ b/rhodecode/controllers/admin/repos.py @@ -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)) + .render(name, rtype, private, fork_of, short_name=False, + admin=True, _=_, h=h, c=c)) repo_actions = lambda repo_name: (template.get_def("repo_actions") - .render(repo_name, _=_, h=h)) + .render(repo_name, _=_, h=h, c=c)) 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), diff --git a/rhodecode/controllers/admin/settings.py b/rhodecode/controllers/admin/settings.py --- a/rhodecode/controllers/admin/settings.py +++ b/rhodecode/controllers/admin/settings.py @@ -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()() + try: + 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" + ) + + try: + 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().add(sett1) + Session().add(sett2) + Session().add(sett3) + 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'), + category='error') + if setting_id == 'vcs': application_form = ApplicationUiSettingsForm()() try: diff --git a/rhodecode/controllers/admin/users.py b/rhodecode/controllers/admin/users.py --- a/rhodecode/controllers/admin/users.py +++ b/rhodecode/controllers/admin/users.py @@ -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") - .render(user_id, username, _=_, h=h)) + .render(user_id, username, _=_, h=h, c=c)) for user in c.users_list: users_data.append({ diff --git a/rhodecode/lib/base.py b/rhodecode/lib/base.py --- a/rhodecode/lib/base.py +++ b/rhodecode/lib/base.py @@ -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 + 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()\ diff --git a/rhodecode/lib/helpers.py b/rhodecode/lib/helpers.py --- a/rhodecode/lib/helpers.py +++ b/rhodecode/lib/helpers.py @@ -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\/\=\?\&\ \:\/\.\-]*)\]', + '
see => \\1
', value) + value = re.sub(r'\[license\ \=\>\ *([a-zA-Z0-9\/\=\?\&\ \:\/\.\-]*)\]', + '
\\1
', value) + value = re.sub(r'\[(requires|recommends|conflicts|base)\ \=\>\ *([a-zA-Z\-\/]*)\]', + '
\\1 => \\2
', value) + value = re.sub(r'\[(lang|language)\ \=\>\ *([a-zA-Z\-\/]*)\]', + '
\\2
', value) + value = re.sub(r'\[([a-z]+)\]', + '
\\1
', value) + + return value + + def bool2icon(value): """Returns True/False values represented as small html image of true/false icons diff --git a/rhodecode/lib/utils2.py b/rhodecode/lib/utils2.py --- a/rhodecode/lib/utils2.py +++ b/rhodecode/lib/utils2.py @@ -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__ diff --git a/rhodecode/model/db.py b/rhodecode/model/db.py --- a/rhodecode/model/db.py +++ b/rhodecode/model/db.py @@ -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() + + @classmethod + def get_by_name_or_create(cls, key): + res = cls.get_by_name(key) + if not res: + res = cls(key) + return res @classmethod 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', + 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', + 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') diff --git a/rhodecode/model/forms.py b/rhodecode/model/forms.py --- a/rhodecode/model/forms.py +++ b/rhodecode/model/forms.py @@ -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): allow_extra_fields = True filter_extra_fields = False - 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'], - if_missing=False) - hooks_changegroup_push_logger = v.OneOf(['True', 'False'], - if_missing=False) - hooks_preoutgoing_pull_logger = v.OneOf(['True', 'False'], - if_missing=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 allow_extra_fields = True 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) diff --git a/rhodecode/public/css/style.css b/rhodecode/public/css/style.css --- a/rhodecode/public/css/style.css +++ b/rhodecode/public/css/style.css @@ -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 { + display: inline-block; + margin-right: 1px; + -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"] { + border: solid 1px #9CF; + background-color: #DEF; + 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%; diff --git a/rhodecode/templates/admin/settings/settings.html b/rhodecode/templates/admin/settings/settings.html --- a/rhodecode/templates/admin/settings/settings.html +++ b/rhodecode/templates/admin/settings/settings.html @@ -116,6 +116,63 @@ ${h.end_form()} +

${_('Visualisation settings')}

+ ${h.form(url('admin_setting', setting_id='visual'),method='put')} +
+ + +
+ +
+
+ +
+
+
+ ${h.checkbox('rhodecode_show_public_icon','True')} + +
+
+ ${h.checkbox('rhodecode_show_private_icon','True')} + +
+
+
+ +
+
+ +
+
+
+ ${h.checkbox('rhodecode_stylify_metatags','True')} + +
+
+
    +
  • [featured] featured
  • +
  • [stale] stale
  • +
  • [dead] dead
  • +
  • [lang => lang] lang
  • +
  • [license => License] License
  • +
  • [requires => Repo] requires => Repo
  • +
  • [recommends => Repo] recommends => Repo
  • +
  • [see => URI] see => URI
  • +
+
+
+
+ +
+ ${h.submit('save',_('Save settings'),class_="ui-btn large")} + ${h.reset('reset',_('Reset'),class_="ui-btn large")} +
+ +
+
+ ${h.end_form()} + +

${_('VCS settings')}

${h.form(url('admin_setting', setting_id='vcs'),method='put')}
diff --git a/rhodecode/templates/data_table/_dt_elements.html b/rhodecode/templates/data_table/_dt_elements.html --- a/rhodecode/templates/data_table/_dt_elements.html +++ b/rhodecode/templates/data_table/_dt_elements.html @@ -63,10 +63,10 @@ %endif ##PRIVATE/PUBLIC - %if private: - ${_('private repository')} - %else: - ${_('public repository')} + %if private and c.visual.show_private_icon: + ${_('private repository')} + %elif not private and c.visual.show_public_icon: + ${_('public repository')} %endif ##NAME @@ -108,4 +108,3 @@ <%def name="user_name(user_id, username)"> ${h.link_to(username,h.url('edit_user', id=user_id))} - diff --git a/rhodecode/templates/index_base.html b/rhodecode/templates/index_base.html --- a/rhodecode/templates/index_base.html +++ b/rhodecode/templates/index_base.html @@ -41,7 +41,11 @@ ${h.link_to(gr.name,url('repos_group_home',group_name=gr.group_name))}
- ${gr.group_description} + %if c.visual.stylify_metatags: + ${h.desc_stylize(gr.group_description)} + %else: + ${gr.group_description} + %endif ## this is commented out since for multi nested repos can be HEAVY! ## in number of executed queries during traversing uncomment at will ##${gr.repositories_recursive_count} @@ -85,7 +89,11 @@ ##DESCRIPTION + %if c.visual.stylify_metatags: + ${h.urlify_text(h.desc_stylize(h.truncate(repo['description'],60)))} + %else: ${h.truncate(repo['description'],60)} + %endif ##LAST CHANGE DATE diff --git a/rhodecode/templates/journal/journal.html b/rhodecode/templates/journal/journal.html --- a/rhodecode/templates/journal/journal.html +++ b/rhodecode/templates/journal/journal.html @@ -128,9 +128,9 @@ ${_('Git repository')} %endif - %if entry.follows_repository.private: + %if entry.follows_repository.private and c.visual.show_private_icon: ${_('private repository')} - %else: + %elif not entry.follows_repository.private and c.visual.show_public_icon: ${_('public repository')} %endif diff --git a/rhodecode/templates/repo_switcher_list.html b/rhodecode/templates/repo_switcher_list.html --- a/rhodecode/templates/repo_switcher_list.html +++ b/rhodecode/templates/repo_switcher_list.html @@ -6,12 +6,12 @@ %for repo in c.repos_list: - %if repo['dbrepo']['private']: + %if repo['dbrepo']['private'] and c.visual.show_private_icon:
  • ${_('Private repository')} ${h.link_to(repo['name'],h.url('summary_home',repo_name=repo['name']),class_="repo_name %s" % repo['dbrepo']['repo_type'])}
  • - %else: + %elif not repo['dbrepo']['private'] and c.visual.show_public_icon:
  • ${_('Public repository')} ${h.link_to(repo['name'],h.url('summary_home',repo_name=repo['name']),class_="repo_name %s" % repo['dbrepo']['repo_type'])} diff --git a/rhodecode/templates/summary/summary.html b/rhodecode/templates/summary/summary.html --- a/rhodecode/templates/summary/summary.html +++ b/rhodecode/templates/summary/summary.html @@ -104,7 +104,11 @@
    -
    ${h.urlify_text(c.dbrepo.description)}
    + %if c.visual.stylify_metatags: +
    ${h.urlify_text(h.desc_stylize(c.dbrepo.description))}
    + %else: +
    ${h.urlify_text(c.dbrepo.description)}
    + %endif
    diff --git a/rhodecode/tests/test_libs.py b/rhodecode/tests/test_libs.py --- a/rhodecode/tests/test_libs.py +++ b/rhodecode/tests/test_libs.py @@ -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('
    tag
    ' in res) + self.assertTrue('
    obsolete
    ' in res) + self.assertTrue('
    stale
    ' in res) + self.assertTrue('
    python
    ' in res) + self.assertTrue('
    requires => url
    ' in res) + self.assertTrue('
    tag
    ' in res)