@@ -158,9 +158,9 @@ INPUT::
args : {
"username" : "<username>",
"password" : "<password>",
"firstname" : "<firstname>",
"lastname" : "<lastname>",
"email" : "<useremail>"
"email" : "<useremail>",
"firstname" : "<firstname> = None",
"lastname" : "<lastname> = None",
"active" : "<bool> = True",
"admin" : "<bool> = False",
"ldap_dn" : "<ldap_dn> = None"
@@ -35,6 +35,7 @@ news
based on user defined regular expression
- added linking of changesets in commit messages
- new compact changelog with expandable commit messages
- firstname and lastname are optional in user creation
fixes
-----
@@ -131,17 +131,17 @@ class ApiController(JSONRPCController):
return result
@HasPermissionAllDecorator('hg.admin')
def create_user(self, apiuser, username, password, firstname,
lastname, email, active=True, admin=False, ldap_dn=None):
def create_user(self, apiuser, username, password, email, firstname=None,
lastname=None, active=True, admin=False, ldap_dn=None):
"""
Create new user or updates current one
:param apiuser:
:param username:
:param password:
:param email:
:param name:
:param lastname:
:param active:
:param admin:
:param ldap_dn:
@@ -129,6 +129,7 @@ def get_crypt_password(password):
def check_password(password, hashed):
return RhodeCodeCrypto.hash_check(password, hashed)
def generate_api_key(str_, salt=None):
Generates API KEY from given string
@@ -237,6 +238,7 @@ def authenticate(username, password):
pass
return False
def login_container_auth(username):
user = User.get_by_username(username)
if user is None:
@@ -260,6 +262,7 @@ def login_container_auth(username):
user.username)
return user
def get_container_username(environ, config):
username = None
@@ -278,6 +281,7 @@ def get_container_username(environ, conf
return username
class AuthUser(object):
A simple object that handles all attributes of user in RhodeCode
@@ -302,6 +306,7 @@ class AuthUser(object):
self.permissions = {}
self._api_key = api_key
self.propagate_data()
self._instance = None
def propagate_data(self):
user_model = UserModel()
@@ -350,10 +355,6 @@ class AuthUser(object):
def is_admin(self):
return self.admin
@property
def full_contact(self):
return '%s %s <%s>' % (self.name, self.lastname, self.email)
def __repr__(self):
return "<AuthUser('id:%s:%s|%s')>" % (self.user_id, self.username,
self.is_authenticated)
@@ -374,6 +375,7 @@ class AuthUser(object):
api_key = cookie_store.get('api_key')
return AuthUser(user_id, api_key, username)
def set_available_permissions(config):
This function will propagate pylons globals with all available defined
@@ -388,7 +390,7 @@ def set_available_permissions(config):
try:
sa = meta.Session
all_perms = sa.query(Permission).all()
except:
except Exception:
finally:
meta.Session.remove()
@@ -299,6 +299,11 @@ class User(Base, BaseModel):
return '%s %s' % (self.name, self.lastname)
def full_name_or_username(self):
return ('%s %s' % (self.name, self.lastname)
if (self.name and self.lastname) else self.username)
@@ -354,8 +359,13 @@ class User(Base, BaseModel):
log.debug('updated user %s lastlogin', self.username)
def __json__(self):
return dict(email=self.email,
full_name=self.full_name)
return dict(
email=self.email,
full_name=self.full_name,
full_name_or_username=self.full_name_or_username,
short_contact=self.short_contact,
full_contact=self.full_contact
)
class UserLog(Base, BaseModel):
@@ -56,8 +56,12 @@ class ValidAuthToken(formencode.validato
def validate_python(self, value, state):
if value != authentication_token():
raise formencode.Invalid(self.message('invalid_token', state,
search_number=value), value, state)
raise formencode.Invalid(
self.message('invalid_token',
state, search_number=value),
value,
state
def ValidUsername(edit, old_data):
@@ -77,11 +81,13 @@ def ValidUsername(edit, old_data):
'exists') , value, state)
if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
raise formencode.Invalid(_('Username may only contain '
'alphanumeric characters '
'underscores, periods or dashes '
'and must begin with alphanumeric '
'character'), value, state)
_('Username may only contain alphanumeric characters '
'underscores, periods or dashes and must begin with '
'alphanumeric character'),
return _ValidUsername
@@ -107,11 +113,13 @@ def ValidUsersGroup(edit, old_data):
state)
raise formencode.Invalid(_('RepoGroup name may only contain '
_('RepoGroup name may only contain alphanumeric characters '
return _ValidUsersGroup
@@ -177,7 +185,8 @@ class ValidPassword(formencode.validator
def to_python(self, value, state):
if value:
if not value:
return
if value.get('password'):
@@ -191,7 +200,9 @@ class ValidPassword(formencode.validator
value['password_confirmation'] = \
get_crypt_password(value['password_confirmation'])
except UnicodeEncodeError:
e_dict = {'password_confirmation':_('Invalid characters in password')}
e_dict = {
'password_confirmation': _('Invalid characters in password')
}
raise formencode.Invalid('', value, state, error_dict=e_dict)
if value.get('new_password'):
@@ -238,15 +249,19 @@ class ValidAuth(formencode.validators.Fa
else:
if user and user.active is False:
log.warning('user %s is disabled', username)
raise formencode.Invalid(self.message('disabled_account',
self.message('disabled_account',
state=State_obj),
value, state,
error_dict=self.e_dict_disable)
error_dict=self.e_dict_disable
log.warning('user %s not authenticated', username)
raise formencode.Invalid(self.message('invalid_password',
self.message('invalid_password',
state=State_obj), value, state,
error_dict=self.e_dict)
error_dict=self.e_dict
class ValidRepoUser(formencode.validators.FancyValidator):
@@ -272,7 +287,6 @@ def ValidRepoName(edit, old_data):
e_dict = {'repo_name': _('This repository name is disallowed')}
if value.get('repo_group'):
gr = RepoGroup.get(value.get('repo_group'))
group_path = gr.full_path
@@ -285,7 +299,6 @@ def ValidRepoName(edit, old_data):
group_path = ''
repo_name_full = repo_name
value['repo_name_full'] = repo_name_full
rename = old_data.get('repo_name') != repo_name_full
create = not edit
@@ -293,15 +306,17 @@ def ValidRepoName(edit, old_data):
if group_path != '':
if Repository.get_by_repo_name(repo_name_full):
e_dict = {'repo_name':_('This repository already '
'exists in a group "%s"') %
gr.group_name}
'repo_name': _('This repository already exists in '
'a group "%s"') % gr.group_name
raise formencode.Invalid('', value, state,
error_dict=e_dict)
elif RepoGroup.get_by_group_name(repo_name_full):
e_dict = {'repo_name':_('There is a group with this'
' name already "%s"') %
repo_name_full}
'repo_name': _('There is a group with this name '
'already "%s"') % repo_name_full
@@ -341,14 +356,14 @@ def ValidCloneUri():
elif value.startswith('https'):
httpsrepository(make_ui('db'), value).capabilities
except Exception, e:
log.error(traceback.format_exc())
raise formencode.Invalid(_('invalid clone url'), value,
elif value.startswith('http'):
httprepository(make_ui('db'), value).capabilities
@@ -394,7 +409,8 @@ class ValidPerms(formencode.validators.F
elif k.startswith('u_perm_') or k.startswith('g_perm_'):
member = k[7:]
t = {'u':'user',
'g':'users_group'}[k[0]]
'g': 'users_group'
}[k[0]]
if member == 'default':
if value['private']:
#set none for default when updating to private repo
@@ -419,8 +435,9 @@ class ValidPerms(formencode.validators.F
msg = self.message('perm_new_member_name',
state=State_obj)
raise formencode.Invalid(msg, value, state,
error_dict={'perm_new_member_name':msg})
msg, value, state, error_dict={'perm_new_member_name': msg}
return value
@@ -428,9 +445,8 @@ class ValidSettings(formencode.validator
# settings form can't edit user
if value.has_key('user'):
if 'user' in value:
del['value']['user']
@@ -452,8 +468,8 @@ def UniqSystemEmail(old_data):
user = User.get_by_email(value, case_insensitive=True)
if user:
_("This e-mail address is already taken"),
value, state)
_("This e-mail address is already taken"), value, state
return _UniqSystemEmail
@@ -464,8 +480,9 @@ class ValidSystemEmail(formencode.valida
value = value.lower()
raise formencode.Invalid(_("This e-mail address doesn't exist.") ,
_("This e-mail address doesn't exist."), value, state
@@ -486,14 +503,15 @@ class AttrLoginValidator(formencode.vali
if not value or not isinstance(value, (str, unicode)):
raise formencode.Invalid(_("The LDAP Login attribute of the CN "
"must be specified - this is the name "
"of the attribute that is equivalent "
"to 'username'"),
_("The LDAP Login attribute of the CN must be specified - "
"this is the name of the attribute that is equivalent "
"to 'username'"), value, state
#==============================================================================
# FORMS
@@ -531,15 +549,17 @@ def UserForm(edit=False, old_data={}):
ValidUsername(edit, old_data))
if edit:
new_password = All(UnicodeString(strip=True, min=6, not_empty=False))
password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=False))
password_confirmation = All(UnicodeString(strip=True, min=6,
not_empty=False))
admin = StringBoolean(if_missing=False)
password = All(UnicodeString(strip=True, min=6, not_empty=True))
active = StringBoolean(if_missing=False)
name = UnicodeString(strip=True, min=1, not_empty=True)
lastname = UnicodeString(strip=True, min=1, not_empty=True)
name = UnicodeString(strip=True, min=1, not_empty=False)
lastname = UnicodeString(strip=True, min=1, not_empty=False)
email = All(Email(not_empty=True), UniqSystemEmail(old_data))
chained_validators = [ValidPasswordsMatch, ValidPassword]
@@ -592,14 +612,15 @@ def RegisterForm(edit=False, old_data={}
password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=True))
return _RegisterForm
def PasswordResetForm():
class _PasswordResetForm(formencode.Schema):
allow_extra_fields = True
@@ -607,6 +628,7 @@ def PasswordResetForm():
email = All(ValidSystemEmail(), Email(not_empty=True))
return _PasswordResetForm
def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
repo_groups=[]):
class _RepoForm(formencode.Schema):
@@ -630,6 +652,7 @@ def RepoForm(edit=False, old_data={}, su
chained_validators = [ValidRepoName(edit, old_data), ValidPerms]
return _RepoForm
def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
class _RepoForkForm(formencode.Schema):
@@ -648,6 +671,7 @@ def RepoForkForm(edit=False, old_data={}
return _RepoForkForm
def RepoSettingsForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
@@ -674,6 +698,7 @@ def ApplicationSettingsForm():
return _ApplicationSettingsForm
def ApplicationUiSettingsForm():
class _ApplicationUiSettingsForm(formencode.Schema):
@@ -687,6 +712,7 @@ def ApplicationUiSettingsForm():
return _ApplicationUiSettingsForm
def DefaultPermissionsForm(perms_choices, register_choices, create_choices):
class _DefaultPermissionsForm(formencode.Schema):
@@ -92,7 +92,6 @@ class UserModel(BaseModel):
raise
def create_or_update(self, username, password, email, name, lastname,
active=True, admin=False, ldap_dn=None):
@@ -136,7 +135,6 @@ class UserModel(BaseModel):
def create_for_container_auth(self, username, attrs):
Creates the given user if it's not already in the database
@@ -493,7 +491,6 @@ class UserModel(BaseModel):
new.permission = perm
self.sa.add(new)
def revoke_perm(self, user, perm):
if not isinstance(perm, Permission):
raise Exception('perm needs to be an instance of Permission class '
@@ -86,7 +86,7 @@
<label for="active">${_('Active')}:</label>
</div>
<div class="checkboxes">
${h.checkbox('active',value=True)}
${h.checkbox('active',value=True,checked='checked')}
@@ -112,7 +112,7 @@
${h.end_form()}
%else:
<div class="links_left">
<div class="full_name">${c.rhodecode_user.full_name}</div>
<div class="full_name">${c.rhodecode_user.full_name_or_username}</div>
<div class="email">${c.rhodecode_user.email}</div>
<div class="big_gravatar"><img alt="gravatar" src="${h.gravatar_url(c.rhodecode_user.email,48)}" /></div>
Status change: