@@ -149,27 +149,27 @@ create_user
-----------
Creates new user or updates current one if such user exists. This command can
be executed only using api_key belonging to user with admin rights.
INPUT::
api_key : "<api_key>"
method : "create_user"
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"
}
OUTPUT::
result: {
"id" : "<new_user_id>",
"msg" : "created new user <username>"
error: null
@@ -26,24 +26,25 @@ news
- #239 option to manually mark repository as fork
- #320 mapping of commit authors to RhodeCode users
- #304 hashes are displayed using monospace font
- diff configuration, toggle white lines and context lines
- #307 configurable diffs, whitespace toggle, increasing context lines
- sorting on branches, tags and bookmarks using YUI datatable
- improved file filter on files page
- implements #330 api method for listing nodes ar particular revision
- #73 added linking issues in commit messages to chosen issue tracker url
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
-----
- rewrote dbsession management for atomic operations, and better error handling
- fixed sorting of repo tables
- #326 escape of special html entities in diffs
- normalized user_name => username in api attributes
- fixes #298 ldap created users with mixed case emails created conflicts
on saving a form
- fixes issue when owner of a repo couldn't revoke permissions for users
and groups
@@ -122,35 +122,35 @@ class ApiController(JSONRPCController):
username=user.username,
firstname=user.name,
lastname=user.lastname,
email=user.email,
active=user.active,
admin=user.admin,
ldap=user.ldap_dn
)
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:
if User.get_by_username(username):
raise JSONRPCError("user %s already exist" % username)
try:
usr = UserModel().create_or_update(
username, password, email, firstname,
lastname, active, admin, ldap_dn
@@ -120,24 +120,25 @@ class RhodeCodeCrypto(object):
else:
raise Exception('Unknown or unsupported platform %s' \
% __platform__)
def get_crypt_password(password):
return RhodeCodeCrypto.hash_string(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
:param str_:
:param salt:
if salt is None:
salt = _RandomNameSequence().next()
return hashlib.sha1(str_ + salt).hexdigest()
@@ -228,89 +229,93 @@ def authenticate(username, password):
user_attrs):
log.info('created new ldap user %s', username)
Session.commit()
return True
except (LdapUsernameError, LdapPasswordError,):
pass
except (Exception,):
log.error(traceback.format_exc())
return False
def login_container_auth(username):
user = User.get_by_username(username)
if user is None:
user_attrs = {
'name': username,
'lastname': None,
'email': None,
user = UserModel().create_for_container_auth(username, user_attrs)
if not user:
return None
log.info('User %s was created by container authentication', username)
if not user.active:
user.update_lastlogin()
log.debug('User %s is now logged in by container authentication',
user.username)
return user
def get_container_username(environ, config):
username = None
if str2bool(config.get('container_auth_enabled', False)):
from paste.httpheaders import REMOTE_USER
username = REMOTE_USER(environ)
if not username and str2bool(config.get('proxypass_auth_enabled', False)):
username = environ.get('HTTP_X_FORWARDED_USER')
if username:
# Removing realm and domain from username
username = username.partition('@')[0]
username = username.rpartition('\\')[2]
log.debug('Received username %s from container', username)
return username
class AuthUser(object):
A simple object that handles all attributes of user in RhodeCode
It does lookup based on API key,given user, or user present in session
Then it fills all required information for such user. It also checks if
anonymous access is enabled and if so, it returns default user as logged
in
def __init__(self, user_id=None, api_key=None, username=None):
self.user_id = user_id
self.api_key = None
self.username = username
self.name = ''
self.lastname = ''
self.email = ''
self.is_authenticated = False
self.admin = False
self.permissions = {}
self._api_key = api_key
self.propagate_data()
self._instance = None
def propagate_data(self):
user_model = UserModel()
self.anonymous_user = User.get_by_username('default', cache=True)
is_user_loaded = False
# try go get user by api key
if self._api_key and self._api_key != self.anonymous_user.api_key:
log.debug('Auth User lookup by API KEY %s', self._api_key)
is_user_loaded = user_model.fill_data(self, api_key=self._api_key)
# lookup by userid
elif (self.user_id is not None and
@@ -341,63 +346,60 @@ class AuthUser(object):
if not self.username:
self.username = 'None'
log.debug('Auth User is now %s', self)
user_model.fill_perms(self)
@property
def is_admin(self):
return self.admin
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)
def set_authenticated(self, authenticated=True):
if self.user_id != self.anonymous_user.user_id:
self.is_authenticated = authenticated
def get_cookie_store(self):
return {'username':self.username,
return {'username': self.username,
'user_id': self.user_id,
'is_authenticated':self.is_authenticated}
'is_authenticated': self.is_authenticated}
@classmethod
def from_cookie_store(cls, cookie_store):
user_id = cookie_store.get('user_id')
username = cookie_store.get('username')
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
permission given in db. We don't want to check each time from db for new
permissions since adding a new permission also requires application restart
ie. to decorate new views with the newly created permission
:param config: current pylons config instance
log.info('getting information about all available permissions')
sa = meta.Session
all_perms = sa.query(Permission).all()
except:
except Exception:
finally:
meta.Session.remove()
config['available_permissions'] = [x.permission_name for x in all_perms]
#==============================================================================
# CHECK DECORATORS
class LoginRequired(object):
@@ -290,24 +290,29 @@ class User(Base, BaseModel):
def email(self):
return self._email
@email.setter
def email(self, val):
self._email = val.lower() if val else None
def full_name(self):
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)
def short_contact(self):
@@ -345,26 +350,31 @@ class User(Base, BaseModel):
if cache:
q = q.options(FromCache("sql_cache_short",
"get_api_key_%s" % email))
return q.scalar()
def update_lastlogin(self):
"""Update user lastlogin"""
self.last_login = datetime.datetime.now()
Session.add(self)
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):
__tablename__ = 'user_logs'
__table_args__ = {'extend_existing': True}
user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
repository_name = Column("repository_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
user_ip = Column("user_ip", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
action = Column("action", UnicodeText(length=1200000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
@@ -42,85 +42,93 @@ from rhodecode import BACKENDS
log = logging.getLogger(__name__)
#this is needed to translate the messages using _() in validators
class State_obj(object):
_ = staticmethod(_)
# VALIDATORS
class ValidAuthToken(formencode.validators.FancyValidator):
messages = {'invalid_token':_('Token mismatch')}
messages = {'invalid_token': _('Token mismatch')}
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):
class _ValidUsername(formencode.validators.FancyValidator):
if value in ['default', 'new_user']:
raise formencode.Invalid(_('Invalid username'), value, state)
#check if user is unique
old_un = None
if edit:
old_un = User.get(old_data.get('user_id')).username
if old_un != value or not edit:
if User.get_by_username(value, case_insensitive=True):
raise formencode.Invalid(_('This username already '
'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
def ValidUsersGroup(edit, old_data):
class _ValidUsersGroup(formencode.validators.FancyValidator):
if value in ['default']:
raise formencode.Invalid(_('Invalid group name'), value, state)
#check if group is unique
old_ugname = None
old_ugname = UsersGroup.get(
old_data.get('users_group_id')).users_group_name
if old_ugname != value or not edit:
if UsersGroup.get_by_group_name(value, cache=False,
case_insensitive=True):
raise formencode.Invalid(_('This users group '
'already exists') , value,
'already exists'), value,
state)
raise formencode.Invalid(_('RepoGroup name may only contain '
_('RepoGroup name may only contain alphanumeric characters '
return _ValidUsersGroup
def ValidReposGroup(edit, old_data):
class _ValidReposGroup(formencode.validators.FancyValidator):
# TODO WRITE VALIDATIONS
group_name = value.get('group_name')
group_parent_id = value.get('group_parent_id')
@@ -168,94 +176,101 @@ def ValidReposGroup(edit, old_data):
'group_name': _('Repository with this name already exists')
raise formencode.Invalid('', value, state,
error_dict=e_dict)
return _ValidReposGroup
class ValidPassword(formencode.validators.FancyValidator):
def to_python(self, value, state):
if value:
if not value:
return
if value.get('password'):
value['password'] = get_crypt_password(value['password'])
except UnicodeEncodeError:
e_dict = {'password':_('Invalid characters in password')}
raise formencode.Invalid('', value, state, error_dict=e_dict)
e_dict = {'password': _('Invalid characters in password')}
if value.get('password_confirmation'):
value['password_confirmation'] = \
get_crypt_password(value['password_confirmation'])
e_dict = {'password_confirmation':_('Invalid characters in password')}
e_dict = {
'password_confirmation': _('Invalid characters in password')
if value.get('new_password'):
value['new_password'] = \
get_crypt_password(value['new_password'])
e_dict = {'new_password':_('Invalid characters in password')}
e_dict = {'new_password': _('Invalid characters in password')}
return value
class ValidPasswordsMatch(formencode.validators.FancyValidator):
pass_val = value.get('password') or value.get('new_password')
if pass_val != value['password_confirmation']:
e_dict = {'password_confirmation':
_('Passwords do not match')}
class ValidAuth(formencode.validators.FancyValidator):
messages = {
'invalid_password':_('invalid password'),
'invalid_login':_('invalid user name'),
'disabled_account':_('Your account is disabled')
# error mapping
e_dict = {'username':messages['invalid_login'],
'password':messages['invalid_password']}
e_dict_disable = {'username':messages['disabled_account']}
e_dict = {'username': messages['invalid_login'],
'password': messages['invalid_password']}
e_dict_disable = {'username': messages['disabled_account']}
password = value['password']
username = value['username']
if authenticate(username, password):
if user and user.active is False:
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)
self.message('disabled_account',
error_dict=self.e_dict_disable
log.warning('user %s not authenticated', username)
raise formencode.Invalid(self.message('invalid_password',
state=State_obj), value, state,
error_dict=self.e_dict)
self.message('invalid_password',
error_dict=self.e_dict
class ValidRepoUser(formencode.validators.FancyValidator):
User.query().filter(User.active == True)\
.filter(User.username == value).one()
raise formencode.Invalid(_('This username is not valid'),
value, state)
@@ -263,59 +278,59 @@ class ValidRepoUser(formencode.validator
def ValidRepoName(edit, old_data):
class _ValidRepoName(formencode.validators.FancyValidator):
repo_name = value.get('repo_name')
slug = repo_name_slug(repo_name)
if slug in [ADMIN_PREFIX, '']:
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
# value needs to be aware of group name in order to check
# db key This is an actual just the name to store in the
# database
repo_name_full = group_path + RepoGroup.url_sep() + repo_name
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
if rename or create:
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
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
elif Repository.get_by_repo_name(repo_name_full):
e_dict = {'repo_name':_('This repository '
e_dict = {'repo_name': _('This repository '
'already exists')}
return _ValidRepoName
def ValidForkName(*args, **kwargs):
return ValidRepoName(*args, **kwargs)
@@ -332,32 +347,32 @@ def SlugifyName():
def ValidCloneUri():
from mercurial.httprepo import httprepository, httpsrepository
from rhodecode.lib.utils import make_ui
class _ValidCloneUri(formencode.validators.FancyValidator):
elif value.startswith('https'):
httpsrepository(make_ui('db'), value).capabilities
except Exception, e:
raise formencode.Invalid(_('invalid clone url'), value,
elif value.startswith('http'):
httprepository(make_ui('db'), value).capabilities
raise formencode.Invalid(_('Invalid clone url, provide a '
'valid clone http\s url'), value,
return _ValidCloneUri
@@ -365,190 +380,195 @@ def ValidForkType(old_data):
class _ValidForkType(formencode.validators.FancyValidator):
if old_data['repo_type'] != value:
raise formencode.Invalid(_('Fork have to be the same '
'type as original'), value, state)
return _ValidForkType
class ValidPerms(formencode.validators.FancyValidator):
messages = {'perm_new_member_name':_('This username or users group name'
messages = {'perm_new_member_name': _('This username or users group name'
' 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():
#means new added member to permissions
if k.startswith('perm_new_member'):
new_perm = value.get('perm_new_member', False)
new_member = value.get('perm_new_member_name', False)
new_type = value.get('perm_new_member_type')
if new_member and new_perm:
if (new_member, new_perm, new_type) not in perms_new:
perms_new.append((new_member, new_perm, new_type))
elif k.startswith('u_perm_') or k.startswith('g_perm_'):
member = k[7:]
t = {'u':'user',
'g':'users_group'}[k[0]]
t = {'u': 'user',
'g': 'users_group'
}[k[0]]
if member == 'default':
if value['private']:
#set none for default when updating to private repo
v = 'repository.none'
perms_update.append((member, v, t))
value['perms_updates'] = perms_update
value['perms_new'] = perms_new
#update permissions
for k, v, t in perms_new:
if t is 'user':
self.user_db = User.query()\
.filter(User.active == True)\
.filter(User.username == k).one()
if t is 'users_group':
self.user_db = UsersGroup.query()\
.filter(UsersGroup.users_group_active == True)\
.filter(UsersGroup.users_group_name == k).one()
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}
class ValidSettings(formencode.validators.FancyValidator):
# settings form can't edit user
if value.has_key('user'):
if 'user' in value:
del['value']['user']
class ValidPath(formencode.validators.FancyValidator):
if not os.path.isdir(value):
msg = _('This is not a valid path')
error_dict={'paths_root_path':msg})
error_dict={'paths_root_path': msg})
def UniqSystemEmail(old_data):
class _UniqSystemEmail(formencode.validators.FancyValidator):
value = value.lower()
if old_data.get('email','').lower() != value:
if old_data.get('email', '').lower() != value:
user = User.get_by_email(value, case_insensitive=True)
if user:
_("This e-mail address is already taken"),
_("This e-mail address is already taken"), value, state
return _UniqSystemEmail
class ValidSystemEmail(formencode.validators.FancyValidator):
raise formencode.Invalid(_("This e-mail address doesn't exist.") ,
_("This e-mail address doesn't exist."), value, state
class LdapLibValidator(formencode.validators.FancyValidator):
import ldap
except ImportError:
raise LdapImportError
class AttrLoginValidator(formencode.validators.FancyValidator):
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
class LoginForm(formencode.Schema):
allow_extra_fields = True
filter_extra_fields = True
username = UnicodeString(
strip=True,
min=1,
not_empty=True,
messages={
'empty':_('Please enter a login'),
'tooShort':_('Enter a value %(min)i characters long or more')}
'empty': _('Please enter a login'),
'tooShort': _('Enter a value %(min)i characters long or more')}
password = UnicodeString(
min=3,
'empty':_('Please enter a password'),
'tooShort':_('Enter %(min)i characters or more')}
'empty': _('Please enter a password'),
'tooShort': _('Enter %(min)i characters or more')}
remember = StringBoolean(if_missing=False)
chained_validators = [ValidAuth]
def UserForm(edit=False, old_data={}):
class _UserForm(formencode.Schema):
username = All(UnicodeString(strip=True, min=1, not_empty=True),
ValidUsername(edit, old_data))
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]
return _UserForm
def UsersGroupForm(edit=False, old_data={}, available_members=[]):
class _UsersGroupForm(formencode.Schema):
@@ -583,80 +603,84 @@ def ReposGroupForm(edit=False, old_data=
return _ReposGroupForm
def RegisterForm(edit=False, old_data={}):
class _RegisterForm(formencode.Schema):
username = All(ValidUsername(edit, old_data),
UnicodeString(strip=True, min=1, not_empty=True))
password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=True))
return _RegisterForm
def PasswordResetForm():
class _PasswordResetForm(formencode.Schema):
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):
filter_extra_fields = False
repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
SlugifyName())
clone_uri = All(UnicodeString(strip=True, min=1, not_empty=False),
ValidCloneUri()())
repo_group = OneOf(repo_groups, hideList=True)
repo_type = OneOf(supported_backends)
description = UnicodeString(strip=True, min=1, not_empty=True)
private = StringBoolean(if_missing=False)
enable_statistics = StringBoolean(if_missing=False)
enable_downloads = StringBoolean(if_missing=False)
#this is repo owner
user = All(UnicodeString(not_empty=True), ValidRepoUser)
chained_validators = [ValidRepoName(edit, old_data), ValidPerms]
return _RepoForm
def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
class _RepoForkForm(formencode.Schema):
repo_type = All(ValidForkType(old_data), OneOf(supported_backends))
copy_permissions = StringBoolean(if_missing=False)
update_after_clone = StringBoolean(if_missing=False)
fork_parent_id = UnicodeString()
chained_validators = [ValidForkName(edit, old_data)]
return _RepoForkForm
def RepoSettingsForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
chained_validators = [ValidRepoName(edit, old_data), ValidPerms,
@@ -665,37 +689,39 @@ def RepoSettingsForm(edit=False, old_dat
def ApplicationSettingsForm():
class _ApplicationSettingsForm(formencode.Schema):
rhodecode_title = UnicodeString(strip=True, min=1, not_empty=True)
rhodecode_realm = UnicodeString(strip=True, min=1, not_empty=True)
rhodecode_ga_code = UnicodeString(strip=True, min=1, not_empty=False)
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=1, not_empty=True))
hooks_changegroup_update = OneOf(['True', 'False'], if_missing=False)
hooks_changegroup_repo_size = OneOf(['True', 'False'], if_missing=False)
hooks_pretxnchangegroup_push_logger = OneOf(['True', 'False'], if_missing=False)
hooks_preoutgoing_pull_logger = OneOf(['True', 'False'], if_missing=False)
return _ApplicationUiSettingsForm
def DefaultPermissionsForm(perms_choices, register_choices, create_choices):
class _DefaultPermissionsForm(formencode.Schema):
overwrite_default = StringBoolean(if_missing=False)
anonymous = OneOf(['True', 'False'], if_missing=False)
default_perm = OneOf(perms_choices)
default_register = OneOf(register_choices)
default_create = OneOf(create_choices)
return _DefaultPermissionsForm
@@ -83,25 +83,24 @@ class UserModel(BaseModel):
new_user = User()
for k, v in form_data.items():
setattr(new_user, k, v)
new_user.api_key = generate_api_key(form_data['username'])
self.sa.add(new_user)
return new_user
raise
def create_or_update(self, username, password, email, name, lastname,
active=True, admin=False, ldap_dn=None):
Creates a new instance if not found, or updates current one
@@ -127,25 +126,24 @@ class UserModel(BaseModel):
new_user.api_key = generate_api_key(username)
new_user.email = email
new_user.active = active
new_user.ldap_dn = safe_unicode(ldap_dn) if ldap_dn else None
new_user.name = name
new_user.lastname = lastname
except (DatabaseError,):
def create_for_container_auth(self, username, attrs):
Creates the given user if it's not already in the database
:param attrs:
if self.get_by_username(username, case_insensitive=True) is None:
# autogenerate email for container account without one
generate_email = lambda usr: '%s@container_auth.account' % usr
@@ -222,25 +220,25 @@ class UserModel(BaseModel):
self.sa.flush()
# notification to admins
subject = _('new user registration')
body = ('New user registration\n'
'---------------------\n'
'- Username: %s\n'
'- Full Name: %s\n'
'- Email: %s\n')
body = body % (new_user.username, new_user.full_name,
new_user.email)
edit_url = url('edit_user', id=new_user.user_id, qualified=True)
kw = {'registered_user_url':edit_url}
kw = {'registered_user_url': edit_url}
NotificationModel().create(created_by=new_user, subject=subject,
body=body, recipients=None,
type_=Notification.TYPE_REGISTRATION,
email_kwargs=kw)
def update(self, user_id, form_data):
user = self.get(user_id, cache=False)
@@ -484,24 +482,23 @@ class UserModel(BaseModel):
def grant_perm(self, user, perm):
if not isinstance(perm, Permission):
raise Exception('perm needs to be an instance of Permission class '
'got %s instead' % type(perm))
user = self.__get_user(user)
new = UserToPerm()
new.user = user
new.permission = perm
self.sa.add(new)
def revoke_perm(self, user, perm):
obj = UserToPerm.query().filter(UserToPerm.user == user)\
.filter(UserToPerm.permission == perm).scalar()
if obj:
self.sa.delete(obj)
@@ -77,24 +77,24 @@
<label for="email">${_('Email')}:</label>
</div>
<div class="input">
${h.text('email',class_='small')}
<div class="field">
<div class="label label-checkbox">
<label for="active">${_('Active')}:</label>
<div class="checkboxes">
${h.checkbox('active',value=True)}
${h.checkbox('active',value=True,checked='checked')}
<div class="buttons">
${h.submit('save',_('save'),class_="ui-button")}
${h.end_form()}
</%def>
@@ -103,25 +103,25 @@
${h.link_to(_("Don't have an account ?"),h.url('register'))}
%endif
<div class="submit">
${h.submit('sign_in',_('Log In'),class_="ui-btn xsmall")}
%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>
<div class="links_right">
<ol class="links">
<li>${h.link_to(_(u'Home'),h.url('home'))}</li>
<li>${h.link_to(_(u'My account'),h.url('admin_settings_my_account'))}</li>
<li class="logout">${h.link_to(_(u'Log Out'),h.url('logout_home'))}</li>
</ol>
Status change: