@@ -58,294 +58,294 @@ def ValidUsername(edit, old_data):
class _ValidUsername(formencode.validators.FancyValidator):
def validate_python(self, value, state):
if value in ['default', 'new_user']:
raise formencode.Invalid(_('Invalid username'), value, state)
#check if user is uniq
sa = meta.Session
old_un = None
if edit:
old_un = sa.query(User).get(old_data.get('user_id')).username
if old_un != value or not edit:
if sa.query(User).filter(User.username == value).scalar():
raise formencode.Invalid(_('This username already exists') ,
value, state)
meta.Session.remove()
return _ValidUsername
class ValidPassword(formencode.validators.FancyValidator):
def to_python(self, value, state):
if value:
return get_crypt_password(value)
class ValidAuth(formencode.validators.FancyValidator):
messages = {
'invalid_password':_('invalid password'),
'invalid_login':_('invalid user name'),
'disabled_account':_('Your acccount is disabled')
}
#error mapping
e_dict = {'username':messages['invalid_login'],
'password':messages['invalid_password']}
e_dict_disable = {'username':messages['disabled_account']}
password = value['password']
username = value['username']
user = UserModel().get_user_by_name(username)
if user is None:
raise formencode.Invalid(self.message('invalid_password',
state=State_obj), value, state,
error_dict=self.e_dict)
if user:
if user.active:
if user.username == username and check_password(password,
user.password):
return value
else:
log.warning('user %s not authenticated', username)
log.warning('user %s is disabled', username)
raise formencode.Invalid(self.message('disabled_account',
state=State_obj),
value, state,
error_dict=self.e_dict_disable)
class ValidRepoUser(formencode.validators.FancyValidator):
try:
self.user_db = meta.Session.query(User)\
.filter(User.active == True)\
.filter(User.username == value).one()
except Exception:
raise formencode.Invalid(_('This username is not valid'),
finally:
return self.user_db.user_id
def ValidRepoName(edit, old_data):
class _ValidRepoName(formencode.validators.FancyValidator):
slug = h.repo_name_slug(value)
if slug in ['_admin']:
raise formencode.Invalid(_('This repository name is disallowed'),
if old_data.get('repo_name') != value or not edit:
if sa.query(Repository).filter(Repository.repo_name == slug).scalar():
raise formencode.Invalid(_('This repository already exists') ,
return slug
return _ValidRepoName
class ValidPerms(formencode.validators.FancyValidator):
messages = {'perm_new_user_name':_('This username is not valid')}
perms_update = []
perms_new = []
#build a list of permission to update and new permission to create
for k, v in value.items():
if k.startswith('perm_'):
if k.startswith('perm_new_user'):
new_perm = value.get('perm_new_user', False)
new_user = value.get('perm_new_user_name', False)
if new_user and new_perm:
if (new_user, new_perm) not in perms_new:
perms_new.append((new_user, new_perm))
usr = k[5:]
if usr == 'default':
if value['private']:
#set none for default when updating to private repo
v = 'repository.none'
perms_update.append((usr, v))
value['perms_updates'] = perms_update
value['perms_new'] = perms_new
for k, v in perms_new:
self.user_db = sa.query(User)\
.filter(User.username == k).one()
msg = self.message('perm_new_user_name',
state=State_obj)
raise formencode.Invalid(msg, value, state, error_dict={'perm_new_user_name':msg})
class ValidSettings(formencode.validators.FancyValidator):
#settings form can't edit user
if value.has_key('user'):
del['value']['user']
class ValidPath(formencode.validators.FancyValidator):
isdir = os.path.isdir(value.replace('*', ''))
if (value.endswith('/*') or value.endswith('/**')) and isdir:
elif not isdir:
msg = _('This is not a valid path')
msg = _('You need to specify * or ** at the end of path (ie. /tmp/*)')
raise formencode.Invalid(msg, value, state,
error_dict={'paths_root_path':msg})
def UniqSystemEmail(old_data):
class _UniqSystemEmail(formencode.validators.FancyValidator):
if old_data.get('email') != value:
user = sa.query(User).filter(User.email == value).scalar()
raise formencode.Invalid(_("That e-mail address is already taken") ,
return _UniqSystemEmail
class ValidSystemEmail(formencode.validators.FancyValidator):
raise formencode.Invalid(_("That e-mail address doesn't exist.") ,
#===============================================================================
# FORMS
class LoginForm(formencode.Schema):
allow_extra_fields = True
filter_extra_fields = True
username = UnicodeString(
strip=True,
min=3,
min=1,
not_empty=True,
messages={
'empty':_('Please enter a login'),
'tooShort':_('Enter a value %(min)i characters long or more')}
)
password = UnicodeString(
min=8,
'empty':_('Please enter a password'),
#chained validators have access to all data
chained_validators = [ValidAuth]
def UserForm(edit=False, old_data={}):
class _UserForm(formencode.Schema):
username = All(UnicodeString(strip=True, min=3, not_empty=True), ValidUsername(edit, old_data))
username = All(UnicodeString(strip=True, min=1, not_empty=True), ValidUsername(edit, old_data))
new_password = All(UnicodeString(strip=True, min=3, not_empty=False), ValidPassword)
new_password = All(UnicodeString(strip=True, min=8, not_empty=False), ValidPassword)
admin = StringBoolean(if_missing=False)
password = All(UnicodeString(strip=True, min=8, not_empty=True), ValidPassword)
active = StringBoolean(if_missing=False)
name = UnicodeString(strip=True, min=3, not_empty=True)
lastname = UnicodeString(strip=True, min=3, not_empty=True)
name = UnicodeString(strip=True, min=1, not_empty=True)
lastname = UnicodeString(strip=True, min=1, not_empty=True)
email = All(Email(not_empty=True), UniqSystemEmail(old_data))
return _UserForm
RegisterForm = UserForm
def PasswordResetForm():
class _PasswordResetForm(formencode.Schema):
email = All(ValidSystemEmail(), Email(not_empty=True))
return _PasswordResetForm
def RepoForm(edit=False, old_data={}):
class _RepoForm(formencode.Schema):
filter_extra_fields = False
repo_name = All(UnicodeString(strip=True, min=1, not_empty=True), ValidRepoName(edit, old_data))
description = UnicodeString(strip=True, min=3, not_empty=True)
description = UnicodeString(strip=True, min=1, not_empty=True)
private = StringBoolean(if_missing=False)
user = All(Int(not_empty=True), ValidRepoUser)
chained_validators = [ValidPerms]
return _RepoForm
def RepoSettingsForm(edit=False, old_data={}):
chained_validators = [ValidPerms, ValidSettings]
def ApplicationSettingsForm():
class _ApplicationSettingsForm(formencode.Schema):
hg_app_title = UnicodeString(strip=True, min=3, not_empty=True)
hg_app_realm = UnicodeString(strip=True, min=3, not_empty=True)
hg_app_title = UnicodeString(strip=True, min=1, not_empty=True)
hg_app_realm = UnicodeString(strip=True, min=1, not_empty=True)
return _ApplicationSettingsForm
def ApplicationUiSettingsForm():
class _ApplicationUiSettingsForm(formencode.Schema):
web_push_ssl = OneOf(['true', 'false'], if_missing='false')
paths_root_path = All(ValidPath(), UnicodeString(strip=True, min=3, not_empty=True))
paths_root_path = All(ValidPath(), UnicodeString(strip=True, min=1, not_empty=True))
hooks_changegroup_update = OneOf(['True', 'False'], if_missing=False)
hooks_changegroup_repo_size = OneOf(['True', 'False'], if_missing=False)
return _ApplicationUiSettingsForm
def DefaultPermissionsForm(perms_choices, register_choices, create_choices):
class _DefaultPermissionsForm(formencode.Schema):
overwrite_default = OneOf(['true', 'false'], if_missing='false')
default_perm = OneOf(perms_choices)
default_register = OneOf(register_choices)
default_create = OneOf(create_choices)
return _DefaultPermissionsForm
@@ -2963,463 +2963,463 @@ div.form div.fields div.buttons input
#register div.form div.fields div.buttons div.highlight input.ui-state-default
{
background:url("../images/colors/blue/button_highlight.png") repeat-x scroll 0 0 #4E85BB;
border-color:#5C91A4 #2B7089 #1A6480 #2A6F89;
border-style:solid;
border-width:1px;
color:#FFFFFF;
#register div.form div.fields div.buttons input.ui-state-hover
margin: 0;
padding: 6px 12px 6px 12px;
background: #b4b4b4 url("../images/button_selected.png") repeat-x;
border-top: 1px solid #cccccc;
border-left: 1px solid #bebebe;
border-right: 1px solid #b1b1b1;
border-bottom: 1px solid #afafaf;
color: #515151;
#register div.form div.activation_msg {
padding-top:4px;
padding-bottom:4px;
/* -----------------------------------------------------------
SUMMARY
----------------------------------------------------------- */
.trending_language_tbl, .trending_language_tbl td {
margin: 0px !important;
padding: 0px !important;
border: 0 !important;
.trending_language{
-moz-border-radius-bottomright:4px;
-moz-border-radius-topright:4px;
border-bottom-right-radius: 4px 4px;
border-top-right-radius: 4px 4px;
background-color:#336699;
display:block;
min-width:20px;
max-width:400px;
padding:3px;
text-decoration:none;
height: 10px;
margin-bottom: 4px;
margin-left: 5px;
#clone_url{
border: none;
FILES
h3.files_location{
font-size: 1.8em;
font-weight: bold;
margin: 10px 0 !important;
border-bottom: none !important;
#files_data.dl{
#files_data dl dt{
float:left;
margin:0 !important;
padding:5px;
width:115px;
#files_data dl dd{
padding: 5px !important;
CHANGESETS
#changeset_content {
border:1px solid #CCCCCC;
#changeset_content .container .wrapper {
width: 600px;
#changeset_content .container {
height: 120px;
#changeset_content .container .left {
float: left;
width: 70%;
padding-left: 5px;
#changeset_content .container .right {
float: right;
width: 25%;
text-align: right;
#changeset_content .container .left .date {
#changeset_content .container .left .author {
#changeset_content .container .left .message {
font-style: italic;
color: #556CB5;
.cs_files {
.cs_files .cs_added {
background: url("/images/icons/page_white_add.png") no-repeat scroll 3px;
/*background-color:#BBFFBB;*/
height: 16px;
padding-left: 20px;
margin-top: 7px;
text-align: left;
.cs_files .cs_changed {
background: url("/images/icons/page_white_edit.png") no-repeat scroll
3px;
/*background-color: #FFDD88;*/
.cs_files .cs_removed {
background: url("/images/icons/page_white_delete.png") no-repeat scroll
/*background-color: #FF8888;*/
CHANGESETS - CANVAS
#graph {
overflow: hidden;
#graph_nodes {
width: 160px;
margin-left:-50px;
margin-top: 5px;
#graph_content {
width: 800px;
#graph_content .container_header {
border: 1px solid #CCCCCC;
padding:10px;
#graph_content .container .wrapper {
#graph_content .container {
border-bottom: 1px solid #CCCCCC;
border-left: 1px solid #CCCCCC;
border-right: 1px solid #CCCCCC;
min-height: 90px;
min-height: 80px;
font-size:1.2em;
#graph_content .container .left {
#graph_content .container .right {
#graph_content .container .left .date {
#graph_content .container .left .author {
#graph_content .container .left .message {
font-size: 100%;
padding-top: 3px;
.right div {
clear: both;
.right .changes .added,.changed,.removed {
border: 1px solid #DDDDDD;
display: block;
font-size: 0.75em;
text-align: center;
min-width: 15px;
.right .changes .added {
background: #BBFFBB;
.right .changes .changed {
background: #FFDD88;
.right .changes .removed {
background: #FF8888;
.right .merge {
vertical-align: top;
font-size: 60%;
.right .merge img {
vertical-align: bottom;
.right .parent {
font-size: 90%;
font-family: monospace;
.right .logtags .branchtag{
background: #FFFFFF url("../images/icons/arrow_branch.png") no-repeat 130px 9px;
background: #FFFFFF url("../images/icons/arrow_branch.png") no-repeat right 9px;
padding:12px 2px 2px 24px;
padding:12px 16px 0px 0px
.right .logtags .tagtag{
background: #FFFFFF url("../images/icons/tag_blue.png") no-repeat 130px 9px;
background: #FFFFFF url("../images/icons/tag_blue.png") no-repeat right 9px;
padding:12px 18px 0px 0px
FILE BROWSER
div.browserblock {
padding: 0px;
border: 1px solid #ccc;
background: #f8f8f8;
line-height: 100%;
/* new */
line-height: 125%;
div.browserblock .browser-header {
background: #FFFFFF;
color: blue;
padding: 10px 0 10px 0;
div.browserblock .browser-header span {
margin-left: 25px;
div.browserblock .browser-body {
background: #EEEEEE;
table.code-browser {
border-collapse: collapse;
width: 100%;
table.code-browser tr {
margin: 3px;
table.code-browser thead th {
background-color: #EEEEEE;
height: 20px;
font-size: 1.1em;
padding-left: 10px;
table.code-browser tbody tr {
table.code-browser tbody td {
table.code-browser .browser-file {
background: url("/images/icons/document_16.png") no-repeat scroll 3px;
table.code-browser .browser-dir {
background: url("/images/icons/folder_16.png") no-repeat scroll 3px;
ADMIN - SETTINGS
#path_unlock{
color: red;
font-size: 1.2em;
padding-left: 4px;
INFOBOX
.info_box *{
background:url("../../images/pager.png") repeat-x scroll 0 0 #EBEBEB;
border-color:#DEDEDE #C4C4C4 #C4C4C4 #CFCFCF;
color:#4A4A4A;
font-weight:bold;
height:1%;
padding:4px 6px;
display: inline;
.info_box span{
margin-left:3px;
margin-right:3px;
.info_box input#at_rev {
padding:1px 3px 3px 2px;
text-align:center;
.info_box input#view {
padding:0px 3px 2px 2px;
YUI TOOLTIP
.yui-overlay,.yui-panel-container {
visibility: hidden;
position: absolute;
z-index: 2;
.yui-tt {
color: #666666;
background-color: #FFFFFF;
font-family: arial, helvetica, verdana, sans-serif;
padding: 8px;
border: 2px solid #556CB5;
font: 100% sans-serif;
width: auto;
opacity: 1.0;
.yui-tt-shadow {
display: none;
YUI AUTOCOMPLETE
.ac{
.ac .match {
.ac .yui-ac {
position: relative;
font-family: arial;
.ac .perm_ac{
width:15em;
/* styles for input field */
.ac .yui-ac-input {
/* styles for results container */
.ac .yui-ac-container {
top: 1.6em;
/* styles for header/body/footer wrapper within container */
.ac .yui-ac-content {
border: 1px solid #808080;
background: #fff;
z-index: 9050;
/* styles for container shadow */
.ac .yui-ac-shadow {
margin: .3em;
background: #000;
-moz-opacity: 0.10;
opacity: .10;
filter: alpha(opacity = 10);
z-index: 9049;
/* styles for results list */
.ac .yui-ac-content ul {
## -*- coding: utf-8 -*-
<%inherit file="/base/base.html"/>
<%def name="title()">
${_('Changelog - %s') % c.repo_name}
</%def>
<%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))}
${_('Changelog')} - ${_('showing ')} ${c.size if c.size <= c.total_cs else c.total_cs} ${_('out of')} ${c.total_cs} ${_('revisions')}
<%def name="page_nav()">
${self.menu('changelog')}
<%def name="main()">
<div class="box">
<!-- box / title -->
<div class="title">
${self.breadcrumbs()}
</div>
<div class="table">
% if c.pagination:
<div id="graph">
<div id="graph_nodes">
<canvas id="graph_canvas"></canvas>
<div id="graph_content">
<div class="container_header">
${h.form(h.url.current(),method='get')}
<div class="info_box">
<span>${_('Show')}:</span>
${h.text('size',size=1,value=c.size)}
<span>${_('revisions')}</span>
${h.submit('set',_('set'))}
${h.end_form()}
%for cnt,cs in enumerate(c.pagination):
<div id="chg_${cnt+1}" class="container">
<div class="left">
<div class="date">${_('commit')} ${cs.revision}: ${cs.short_id}@${cs.date}</div>
<div class="author">
<div class="gravatar">
<img alt="gravatar" src="${h.gravatar_url(h.email(cs.author),20)}"/>
<span>${h.person(cs.author)}</span><br/>
<span><a href="mailto:${h.email_or_none(cs.author)}">${h.email_or_none(cs.author)}</a></span><br/>
<div class="message">
${h.link_to(h.wrap_paragraphs(cs.message),
h.url('changeset_home',repo_name=c.repo_name,revision=cs.short_id))}
<div class="right">
<div class="changes">
<span class="removed" title="${_('removed')}">${len(cs.removed)}</span>
<span class="changed" title="${_('changed')}">${len(cs.changed)}</span>
<span class="added" title="${_('added')}">${len(cs.added)}</span>
%if len(cs.parents)>1:
<div class="merge">
${_('merge')}<img alt="merge" src="/images/icons/arrow_join.png"/>
%endif
%for p_cs in reversed(cs.parents):
<div class="parent">${_('Parent')} ${p_cs.revision}: ${h.link_to(p_cs.short_id,
h.url('changeset_home',repo_name=c.repo_name,revision=p_cs.short_id),title=p_cs.message)}
%endfor
<span class="logtags">
<span class="branchtag">${cs.branch}</span>
<span class="branchtag" title="${'%s %s' % (_('branch'),cs.branch)}">
${h.link_to(cs.branch,h.url('files_home',repo_name=c.repo_name,revision=cs.short_id))}</span>
%for tag in cs.tags:
<span class="tagtag">${tag}</span>
<span class="tagtag" title="${'%s %s' % (_('tag'),tag)}">
${h.link_to(tag,h.url('files_home',repo_name=c.repo_name,revision=cs.short_id))}</span>
</span>
<div class="pagination-wh pagination-left">
${c.pagination.pager('$link_previous ~2~ $link_next')}
<script type="text/javascript" src="/js/graph.js"></script>
<script type="text/javascript">
YAHOO.util.Event.onDOMReady(function(){
function set_canvas() {
var c = document.getElementById('graph_nodes');
var t = document.getElementById('graph_content');
canvas = document.getElementById('graph_canvas');
var div_h = t.clientHeight;
c.style.height=div_h+'px';
canvas.setAttribute('height',div_h);
canvas.setAttribute('width',160);
};
set_canvas();
var jsdata = ${c.jsdata|n};
var r = new BranchRenderer();
r.render(jsdata);
});
</script>
%else:
${_('There are no changes yet')}
\ No newline at end of file
Status change: