##// END OF EJS Templates
merged + fixed pull request #62: Implemented metatags and visualisation options....
marcink -
r2674:a221706d beta
parent child Browse files
Show More
@@ -144,20 +144,21 b' class ReposController(BaseController):'
144 144 template = _tmpl_lookup.get_template('data_table/_dt_elements.html')
145 145
146 146 quick_menu = lambda repo_name: (template.get_def("quick_menu")
147 .render(repo_name, _=_, h=h))
147 .render(repo_name, _=_, h=h, c=c))
148 148 repo_lnk = lambda name, rtype, private, fork_of: (
149 149 template.get_def("repo_name")
150 .render(name, rtype, private, fork_of, short_name=False,
151 admin=True, _=_, h=h))
150 .render(name, rtype, private, fork_of, short_name=False,
151 admin=True, _=_, h=h, c=c))
152 152
153 153 repo_actions = lambda repo_name: (template.get_def("repo_actions")
154 .render(repo_name, _=_, h=h))
154 .render(repo_name, _=_, h=h, c=c))
155 155
156 156 for repo in c.repos_list:
157 157 repos_data.append({
158 158 "menu": quick_menu(repo.repo_name),
159 159 "raw_name": repo.repo_name,
160 "name": repo_lnk(repo.repo_name, repo.repo_type, repo.private, repo.fork),
160 "name": repo_lnk(repo.repo_name, repo.repo_type,
161 repo.private, repo.fork),
161 162 "desc": repo.description,
162 163 "owner": repo.user.username,
163 164 "action": repo_actions(repo.repo_name),
@@ -45,7 +45,7 b' from rhodecode.lib.utils import repo2db_'
45 45 from rhodecode.model.db import RhodeCodeUi, Repository, RepoGroup, \
46 46 RhodeCodeSetting, PullRequest, PullRequestReviewers
47 47 from rhodecode.model.forms import UserForm, ApplicationSettingsForm, \
48 ApplicationUiSettingsForm
48 ApplicationUiSettingsForm, ApplicationVisualisationForm
49 49 from rhodecode.model.scm import ScmModel
50 50 from rhodecode.model.user import UserModel
51 51 from rhodecode.model.db import User
@@ -143,15 +143,15 b' class SettingsController(BaseController)'
143 143 )
144 144
145 145 try:
146 sett1 = RhodeCodeSetting.get_by_name('title')
146 sett1 = RhodeCodeSetting.get_by_name_or_create('title')
147 147 sett1.app_settings_value = form_result['rhodecode_title']
148 148 Session().add(sett1)
149 149
150 sett2 = RhodeCodeSetting.get_by_name('realm')
150 sett2 = RhodeCodeSetting.get_by_name_or_create('realm')
151 151 sett2.app_settings_value = form_result['rhodecode_realm']
152 152 Session().add(sett2)
153 153
154 sett3 = RhodeCodeSetting.get_by_name('ga_code')
154 sett3 = RhodeCodeSetting.get_by_name_or_create('ga_code')
155 155 sett3.app_settings_value = form_result['rhodecode_ga_code']
156 156 Session().add(sett3)
157 157
@@ -165,6 +165,47 b' class SettingsController(BaseController)'
165 165 'application settings'),
166 166 category='error')
167 167
168 if setting_id == 'visual':
169
170 application_form = ApplicationVisualisationForm()()
171 try:
172 form_result = application_form.to_python(dict(request.POST))
173 except formencode.Invalid, errors:
174 return htmlfill.render(
175 render('admin/settings/settings.html'),
176 defaults=errors.value,
177 errors=errors.error_dict or {},
178 prefix_error=False,
179 encoding="UTF-8"
180 )
181
182 try:
183 sett1 = RhodeCodeSetting.get_by_name_or_create('show_public_icon')
184 sett1.app_settings_value = \
185 form_result['rhodecode_show_public_icon']
186
187 sett2 = RhodeCodeSetting.get_by_name_or_create('show_private_icon')
188 sett2.app_settings_value = \
189 form_result['rhodecode_show_private_icon']
190
191 sett3 = RhodeCodeSetting.get_by_name_or_create('stylify_metatags')
192 sett3.app_settings_value = \
193 form_result['rhodecode_stylify_metatags']
194
195 Session().add(sett1)
196 Session().add(sett2)
197 Session().add(sett3)
198 Session().commit()
199 set_rhodecode_config(config)
200 h.flash(_('Updated visualisation settings'),
201 category='success')
202
203 except Exception:
204 log.error(traceback.format_exc())
205 h.flash(_('error occurred during updating '
206 'visualisation settings'),
207 category='error')
208
168 209 if setting_id == 'vcs':
169 210 application_form = ApplicationUiSettingsForm()()
170 211 try:
@@ -78,15 +78,15 b' class UsersController(BaseController):'
78 78
79 79 grav_tmpl = lambda user_email, size: (
80 80 template.get_def("user_gravatar")
81 .render(user_email, size, _=_, h=h))
81 .render(user_email, size, _=_, h=h, c=c))
82 82
83 83 user_lnk = lambda user_id, username: (
84 84 template.get_def("user_name")
85 .render(user_id, username, _=_, h=h))
85 .render(user_id, username, _=_, h=h, c=c))
86 86
87 87 user_actions = lambda user_id, username: (
88 88 template.get_def("user_actions")
89 .render(user_id, username, _=_, h=h))
89 .render(user_id, username, _=_, h=h, c=c))
90 90
91 91 for user in c.users_list:
92 92 users_data.append({
@@ -17,7 +17,7 b' from pylons.templating import render_mak'
17 17
18 18 from rhodecode import __version__, BACKENDS
19 19
20 from rhodecode.lib.utils2 import str2bool, safe_unicode
20 from rhodecode.lib.utils2 import str2bool, safe_unicode, AttributeDict
21 21 from rhodecode.lib.auth import AuthUser, get_container_username, authfunc,\
22 22 HasPermissionAnyMiddleware, CookieStoreWrapper
23 23 from rhodecode.lib.utils import get_repo_slug, invalidate_cache
@@ -158,7 +158,7 b' class BaseVCSController(object):'
158 158 log.debug('proto is %s and SSL is required BAD REQUEST !'
159 159 % org_proto)
160 160 return False
161 return True
161 return True
162 162
163 163 def __call__(self, environ, start_response):
164 164 start = time.time()
@@ -178,6 +178,12 b' class BaseController(WSGIController):'
178 178 c.rhodecode_name = config.get('rhodecode_title')
179 179 c.use_gravatar = str2bool(config.get('use_gravatar'))
180 180 c.ga_code = config.get('rhodecode_ga_code')
181 # Visual options
182 c.visual = AttributeDict({})
183 c.visual.show_public_icon = str2bool(config.get('rhodecode_show_public_icon'))
184 c.visual.show_private_icon = str2bool(config.get('rhodecode_show_private_icon'))
185 c.visual.stylify_metatags = str2bool(config.get('rhodecode_stylify_metatags'))
186
181 187 c.repo_name = get_repo_slug(request)
182 188 c.backends = BACKENDS.keys()
183 189 c.unread_notifications = NotificationModel()\
@@ -9,6 +9,7 b' import StringIO'
9 9 import urllib
10 10 import math
11 11 import logging
12 import re
12 13
13 14 from datetime import datetime
14 15 from pygments.formatters.html import HtmlFormatter
@@ -430,6 +431,26 b' def person(author):'
430 431 return _author
431 432
432 433
434 def desc_stylize(value):
435 """
436 converts tags from value into html equivalent
437
438 :param value:
439 """
440 value = re.sub(r'\[see\ \=\>\ *([a-zA-Z0-9\/\=\?\&\ \:\/\.\-]*)\]',
441 '<div class="metatag" tag="see">see =&gt; \\1 </div>', value)
442 value = re.sub(r'\[license\ \=\>\ *([a-zA-Z0-9\/\=\?\&\ \:\/\.\-]*)\]',
443 '<div class="metatag" tag="license"><a href="http:\/\/www.opensource.org/licenses/\\1">\\1</a></div>', value)
444 value = re.sub(r'\[(requires|recommends|conflicts|base)\ \=\>\ *([a-zA-Z\-\/]*)\]',
445 '<div class="metatag" tag="\\1">\\1 =&gt; <a href="/\\2">\\2</a></div>', value)
446 value = re.sub(r'\[(lang|language)\ \=\>\ *([a-zA-Z\-\/]*)\]',
447 '<div class="metatag" tag="lang">\\2</div>', value)
448 value = re.sub(r'\[([a-z]+)\]',
449 '<div class="metatag" tag="\\1">\\1</div>', value)
450
451 return value
452
453
433 454 def bool2icon(value):
434 455 """Returns True/False values represented as small html image of true/false
435 456 icons
@@ -443,3 +443,9 b' def extract_mentioned_users(s):'
443 443 usrs.add(username)
444 444
445 445 return sorted(list(usrs), key=lambda k: k.lower())
446
447 class AttributeDict(dict):
448 def __getattr__(self, attr):
449 return self.get(attr, None)
450 __setattr__ = dict.__setitem__
451 __delattr__ = dict.__delitem__
@@ -182,9 +182,16 b' class RhodeCodeSetting(Base, BaseModel):'
182 182 )
183 183
184 184 @classmethod
185 def get_by_name(cls, ldap_key):
185 def get_by_name(cls, key):
186 186 return cls.query()\
187 .filter(cls.app_settings_name == ldap_key).scalar()
187 .filter(cls.app_settings_name == key).scalar()
188
189 @classmethod
190 def get_by_name_or_create(cls, key):
191 res = cls.get_by_name(key)
192 if not res:
193 res = cls(key)
194 return res
188 195
189 196 @classmethod
190 197 def get_app_settings(cls, cache=False):
@@ -589,8 +596,8 b' class Repository(Base, BaseModel):'
589 596 users_group_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
590 597 stats = relationship('Statistics', cascade='all', uselist=False)
591 598
592 followers = relationship('UserFollowing',
593 primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id',
599 followers = relationship('UserFollowing',
600 primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id',
594 601 cascade='all')
595 602
596 603 logs = relationship('UserLog')
@@ -1547,7 +1554,7 b' class PullRequest(Base, BaseModel):'
1547 1554 self._revisions = ':'.join(val)
1548 1555
1549 1556 author = relationship('User', lazy='joined')
1550 reviewers = relationship('PullRequestReviewers',
1557 reviewers = relationship('PullRequestReviewers',
1551 1558 cascade="all, delete, delete-orphan")
1552 1559 org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id')
1553 1560 other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id')
@@ -242,23 +242,30 b' def ApplicationSettingsForm():'
242 242 return _ApplicationSettingsForm
243 243
244 244
245 def ApplicationVisualisationForm():
246 class _ApplicationVisualisationForm(formencode.Schema):
247 allow_extra_fields = True
248 filter_extra_fields = False
249 rhodecode_show_public_icon = v.StringBoolean(if_missing=False)
250 rhodecode_show_private_icon = v.StringBoolean(if_missing=False)
251 rhodecode_stylify_metatags = v.StringBoolean(if_missing=False)
252
253 return _ApplicationVisualisationForm
254
255
245 256 def ApplicationUiSettingsForm():
246 257 class _ApplicationUiSettingsForm(formencode.Schema):
247 258 allow_extra_fields = True
248 259 filter_extra_fields = False
249 web_push_ssl = v.OneOf(['true', 'false'], if_missing='false')
260 web_push_ssl = v.StringBoolean(if_missing=False)
250 261 paths_root_path = All(
251 262 v.ValidPath(),
252 263 v.UnicodeString(strip=True, min=1, not_empty=True)
253 264 )
254 hooks_changegroup_update = v.OneOf(['True', 'False'],
255 if_missing=False)
256 hooks_changegroup_repo_size = v.OneOf(['True', 'False'],
257 if_missing=False)
258 hooks_changegroup_push_logger = v.OneOf(['True', 'False'],
259 if_missing=False)
260 hooks_preoutgoing_pull_logger = v.OneOf(['True', 'False'],
261 if_missing=False)
265 hooks_changegroup_update = v.StringBoolean(if_missing=False)
266 hooks_changegroup_repo_size = v.StringBoolean(if_missing=False)
267 hooks_changegroup_push_logger = v.StringBoolean(if_missing=False)
268 hooks_preoutgoing_pull_logger = v.StringBoolean(if_missing=False)
262 269
263 270 return _ApplicationUiSettingsForm
264 271
@@ -268,7 +275,7 b' def DefaultPermissionsForm(perms_choices'
268 275 allow_extra_fields = True
269 276 filter_extra_fields = True
270 277 overwrite_default = v.StringBoolean(if_missing=False)
271 anonymous = v.OneOf(['True', 'False'], if_missing=False)
278 anonymous = v.StringBoolean(if_missing=False)
272 279 default_perm = v.OneOf(perms_choices)
273 280 default_register = v.OneOf(register_choices)
274 281 default_create = v.OneOf(create_choices)
@@ -1827,6 +1827,81 b' div.form div.fields div.field div.button'
1827 1827
1828 1828 }
1829 1829
1830 #summary .metatag {
1831 display: inline-block;
1832 padding: 3px 5px;
1833 margin-bottom: 3px;
1834 margin-right: 1px;
1835 border-radius: 5px;
1836 }
1837
1838 #content div.box #summary p {
1839 margin-bottom: -5px;
1840 width: 600px;
1841 white-space: pre-wrap;
1842 }
1843
1844 #content div.box #summary p:last-child {
1845 margin-bottom: 9px;
1846 }
1847
1848 #content div.box #summary p:first-of-type {
1849 margin-top: 9px;
1850 }
1851
1852 .metatag {
1853 display: inline-block;
1854 margin-right: 1px;
1855 -webkit-border-radius: 4px 4px 4px 4px;
1856 -khtml-border-radius: 4px 4px 4px 4px;
1857 -moz-border-radius: 4px 4px 4px 4px;
1858 border-radius: 4px 4px 4px 4px;
1859
1860 border: solid 1px #9CF;
1861 padding: 2px 3px 2px 3px !important;
1862 background-color: #DEF;
1863 }
1864
1865 .metatag[tag="dead"] {
1866 background-color: #E44;
1867 }
1868
1869 .metatag[tag="stale"] {
1870 background-color: #EA4;
1871 }
1872
1873 .metatag[tag="featured"] {
1874 background-color: #AEA;
1875 }
1876
1877 .metatag[tag="requires"] {
1878 background-color: #9CF;
1879 }
1880
1881 .metatag[tag="recommends"] {
1882 background-color: #BDF;
1883 }
1884
1885 .metatag[tag="lang"] {
1886 background-color: #FAF474;
1887 }
1888
1889 .metatag[tag="license"] {
1890 border: solid 1px #9CF;
1891 background-color: #DEF;
1892 target-new: tab !important;
1893 }
1894 .metatag[tag="see"] {
1895 border: solid 1px #CBD;
1896 background-color: #EDF;
1897 }
1898
1899 a.metatag[tag="license"]:hover {
1900 background-color: #003367;
1901 color: #FFF;
1902 text-decoration: none;
1903 }
1904
1830 1905 #summary .desc {
1831 1906 white-space: pre;
1832 1907 width: 100%;
@@ -116,6 +116,63 b''
116 116 </div>
117 117 ${h.end_form()}
118 118
119 <h3>${_('Visualisation settings')}</h3>
120 ${h.form(url('admin_setting', setting_id='visual'),method='put')}
121 <div class="form">
122 <!-- fields -->
123
124 <div class="fields">
125
126 <div class="field">
127 <div class="label label-checkbox">
128 <label>${_('Icons')}:</label>
129 </div>
130 <div class="checkboxes">
131 <div class="checkbox">
132 ${h.checkbox('rhodecode_show_public_icon','True')}
133 <label for="rhodecode_show_public_icon">${_('Show public repo icon on repositories')}</label>
134 </div>
135 <div class="checkbox">
136 ${h.checkbox('rhodecode_show_private_icon','True')}
137 <label for="rhodecode_show_private_icon">${_('Show private repo icon on repositories')}</label>
138 </div>
139 </div>
140 </div>
141
142 <div class="field">
143 <div class="label label-checkbox">
144 <label>${_('Meta-Tagging')}:</label>
145 </div>
146 <div class="checkboxes">
147 <div class="checkbox">
148 ${h.checkbox('rhodecode_stylify_metatags','True')}
149 <label for="rhodecode_stylify_metatags">${_('Stylify recognised metatags:')}</label>
150 </div>
151 <div style="padding-left: 20px;">
152 <ul> <!-- Fix style here -->
153 <li>[featured] <span class="metatag" tag="featured">featured</span></li>
154 <li>[stale] <span class="metatag" tag="stale">stale</span></li>
155 <li>[dead] <span class="metatag" tag="dead">dead</span></li>
156 <li>[lang =&gt; lang] <span class="metatag" tag="lang" >lang</span></li>
157 <li>[license =&gt; License] <span class="metatag" tag="license"><a href="http://www.opensource.org/licenses/License" >License</a></span></li>
158 <li>[requires =&gt; Repo] <span class="metatag" tag="requires" >requires =&gt; <a href="#" >Repo</a></span></li>
159 <li>[recommends =&gt; Repo] <span class="metatag" tag="recommends" >recommends =&gt; <a href="#" >Repo</a></span></li>
160 <li>[see =&gt; URI] <span class="metatag" tag="see">see =&gt; <a href="#">URI</a> </span></li>
161 </ul>
162 </div>
163 </div>
164 </div>
165
166 <div class="buttons">
167 ${h.submit('save',_('Save settings'),class_="ui-btn large")}
168 ${h.reset('reset',_('Reset'),class_="ui-btn large")}
169 </div>
170
171 </div>
172 </div>
173 ${h.end_form()}
174
175
119 176 <h3>${_('VCS settings')}</h3>
120 177 ${h.form(url('admin_setting', setting_id='vcs'),method='put')}
121 178 <div class="form">
@@ -63,10 +63,10 b''
63 63 %endif
64 64
65 65 ##PRIVATE/PUBLIC
66 %if private:
67 <img class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="${h.url('/images/icons/lock.png')}"/>
68 %else:
69 <img class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="${h.url('/images/icons/lock_open.png')}"/>
66 %if private and c.visual.show_private_icon:
67 <img class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="${h.url('/images/icons/lock.png')}"/>
68 %elif not private and c.visual.show_public_icon:
69 <img class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="${h.url('/images/icons/lock_open.png')}"/>
70 70 %endif
71 71
72 72 ##NAME
@@ -108,4 +108,3 b''
108 108 <%def name="user_name(user_id, username)">
109 109 ${h.link_to(username,h.url('edit_user', id=user_id))}
110 110 </%def>
111
@@ -41,7 +41,11 b''
41 41 ${h.link_to(gr.name,url('repos_group_home',group_name=gr.group_name))}
42 42 </div>
43 43 </td>
44 <td>${gr.group_description}</td>
44 %if c.visual.stylify_metatags:
45 <td>${h.desc_stylize(gr.group_description)}</td>
46 %else:
47 <td>${gr.group_description}</td>
48 %endif
45 49 ## this is commented out since for multi nested repos can be HEAVY!
46 50 ## in number of executed queries during traversing uncomment at will
47 51 ##<td><b>${gr.repositories_recursive_count}</b></td>
@@ -85,7 +89,11 b''
85 89 </td>
86 90 ##DESCRIPTION
87 91 <td><span class="tooltip" title="${h.tooltip(repo['description'])}">
92 %if c.visual.stylify_metatags:
93 ${h.urlify_text(h.desc_stylize(h.truncate(repo['description'],60)))}</span>
94 %else:
88 95 ${h.truncate(repo['description'],60)}</span>
96 %endif
89 97 </td>
90 98 ##LAST CHANGE DATE
91 99 <td>
@@ -128,9 +128,9 b''
128 128 <img class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="${h.url('/images/icons/giticon.png')}"/>
129 129 %endif
130 130
131 %if entry.follows_repository.private:
131 %if entry.follows_repository.private and c.visual.show_private_icon:
132 132 <img class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="${h.url('/images/icons/lock.png')}"/>
133 %else:
133 %elif not entry.follows_repository.private and c.visual.show_public_icon:
134 134 <img class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="${h.url('/images/icons/lock_open.png')}"/>
135 135 %endif
136 136 <span class="watched_repo">
@@ -6,12 +6,12 b''
6 6
7 7 %for repo in c.repos_list:
8 8
9 %if repo['dbrepo']['private']:
9 %if repo['dbrepo']['private'] and c.visual.show_private_icon:
10 10 <li>
11 11 <img src="${h.url('/images/icons/lock.png')}" alt="${_('Private repository')}" class="repo_switcher_type"/>
12 12 ${h.link_to(repo['name'],h.url('summary_home',repo_name=repo['name']),class_="repo_name %s" % repo['dbrepo']['repo_type'])}
13 13 </li>
14 %else:
14 %elif not repo['dbrepo']['private'] and c.visual.show_public_icon:
15 15 <li>
16 16 <img src="${h.url('/images/icons/lock_open.png')}" alt="${_('Public repository')}" class="repo_switcher_type" />
17 17 ${h.link_to(repo['name'],h.url('summary_home',repo_name=repo['name']),class_="repo_name %s" % repo['dbrepo']['repo_type'])}
@@ -104,7 +104,11 b''
104 104 <div class="label-summary">
105 105 <label>${_('Description')}:</label>
106 106 </div>
107 <div class="input ${summary(c.show_stats)} desc">${h.urlify_text(c.dbrepo.description)}</div>
107 %if c.visual.stylify_metatags:
108 <div class="input ${summary(c.show_stats)} desc">${h.urlify_text(h.desc_stylize(c.dbrepo.description))}</div>
109 %else:
110 <div class="input ${summary(c.show_stats)} desc">${h.urlify_text(c.dbrepo.description)}</div>
111 %endif
108 112 </div>
109 113
110 114 <div class="field">
@@ -131,3 +131,19 b' class TestLibs(unittest.TestCase):'
131 131 self.assertEqual(age(n - delt(hours=24 * (calendar.mdays[n.month-1] + 2))),
132 132 u'1 month and 2 days ago')
133 133 self.assertEqual(age(n - delt(hours=24 * 400)), u'1 year and 1 month ago')
134
135 def test_tag_exctrator(self):
136 sample = (
137 "hello pta[tag] gog [[]] [[] sda ero[or]d [me =>>< sa]"
138 "[requires] [stale] [see<>=>] [see => http://url.com]"
139 "[requires => url] [lang => python] [just a tag]"
140 "[,d] [ => ULR ] [obsolete] [desc]]"
141 )
142 from rhodecode.lib.helpers import desc_stylize
143 res = desc_stylize(sample)
144 self.assertTrue('<div class="metatag" tag="tag">tag</div>' in res)
145 self.assertTrue('<div class="metatag" tag="obsolete">obsolete</div>' in res)
146 self.assertTrue('<div class="metatag" tag="stale">stale</div>' in res)
147 self.assertTrue('<div class="metatag" tag="lang">python</div>' in res)
148 self.assertTrue('<div class="metatag" tag="requires">requires =&gt; <a href="/url">url</a></div>' in res)
149 self.assertTrue('<div class="metatag" tag="tag">tag</div>' in res)
General Comments 0
You need to be logged in to leave comments. Login now