@@ -102,31 +102,58 @@ def make_map(config):
#ADMIN REPOS GROUP REST ROUTES
rmap.resource('repos_group', 'repos_groups',
controller='admin/repos_groups', path_prefix='/_admin')
#ADMIN USER REST ROUTES
rmap.resource('user', 'users', controller='admin/users',
path_prefix='/_admin')
with rmap.submapper(path_prefix='/_admin', controller='admin/users') as m:
m.connect("users", "/users",
action="create", conditions=dict(method=["POST"]))
action="index", conditions=dict(method=["GET"]))
m.connect("formatted_users", "/users.{format}",
m.connect("new_user", "/users/new",
action="new", conditions=dict(method=["GET"]))
m.connect("formatted_new_user", "/users/new.{format}",
m.connect("update_user", "/users/{id}",
action="update", conditions=dict(method=["PUT"]))
m.connect("delete_user", "/users/{id}",
action="delete", conditions=dict(method=["DELETE"]))
m.connect("edit_user", "/users/{id}/edit",
action="edit", conditions=dict(method=["GET"]))
m.connect("formatted_edit_user",
"/users/{id}.{format}/edit",
m.connect("user", "/users/{id}",
action="show", conditions=dict(method=["GET"]))
m.connect("formatted_user", "/users/{id}.{format}",
#EXTRAS USER ROUTES
m.connect("user_perm", "/users_perm/{id}",
action="update_perm", conditions=dict(method=["PUT"]))
#ADMIN USERS REST ROUTES
rmap.resource('users_group', 'users_groups',
controller='admin/users_groups', path_prefix='/_admin')
#ADMIN GROUP REST ROUTES
rmap.resource('group', 'groups', controller='admin/groups',
rmap.resource('group', 'groups',
controller='admin/groups', path_prefix='/_admin')
#ADMIN PERMISSIONS REST ROUTES
rmap.resource('permission', 'permissions',
controller='admin/permissions', path_prefix='/_admin')
##ADMIN LDAP SETTINGS
rmap.connect('ldap_settings', '/_admin/ldap',
controller='admin/ldap_settings', action='ldap_settings',
conditions=dict(method=["POST"]))
rmap.connect('ldap_home', '/_admin/ldap',
controller='admin/ldap_settings')
#ADMIN SETTINGS REST ROUTES
with rmap.submapper(path_prefix='/_admin',
controller='admin/settings') as m:
@@ -30,13 +30,12 @@ from pylons.i18n.translation import _
from rhodecode.lib import helpers as h
from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
from rhodecode.lib.auth_ldap import LdapImportError
from rhodecode.lib.base import BaseController, render
from rhodecode.model.forms import LdapSettingsForm, DefaultPermissionsForm
from rhodecode.model.permission import PermissionModel
from rhodecode.model.settings import SettingsModel
from rhodecode.model.user import UserModel
import formencode
import logging
import traceback
log = logging.getLogger(__name__)
@@ -35,13 +35,13 @@ from pylons.i18n.translation import _
from rhodecode.lib.exceptions import DefaultUserException, \
UserOwnsReposException
from rhodecode.model.db import User
from rhodecode.model.db import User, RepoToPerm, UserToPerm, Permission
from rhodecode.model.forms import UserForm
@@ -98,31 +98,34 @@ class UsersController(BaseController):
def update(self, id):
"""PUT /users/id: Update an existing item"""
# Forms posted to this method should contain a hidden field:
# <input type="hidden" name="_method" value="PUT" />
# Or using helpers:
# h.form(url('user', id=ID),
# h.form(url('update_user', id=ID),
# method='put')
# url('user', id=ID)
user_model = UserModel()
c.user = user_model.get(id)
_form = UserForm(edit=True, old_data={'user_id': id,
'email': c.user.email})()
form_result = {}
try:
form_result = _form.to_python(dict(request.POST))
user_model.update(id, form_result)
h.flash(_('User updated succesfully'), category='success')
h.flash(_('User updated successfully'), category='success')
except formencode.Invalid, errors:
e = errors.error_dict or {}
perm = Permission.get_by_key('hg.create.repository')
e.update({'create_repo_perm': UserToPerm.has_perm(id, perm)})
return htmlfill.render(
render('admin/users/user_edit.html'),
defaults=errors.value,
errors=errors.error_dict or {},
errors=e,
prefix_error=False,
encoding="UTF-8")
except Exception:
log.error(traceback.format_exc())
h.flash(_('error occurred during update of user %s') \
% form_result.get('username'), category='error')
@@ -131,13 +134,13 @@ class UsersController(BaseController):
def delete(self, id):
"""DELETE /users/id: Delete an existing item"""
# <input type="hidden" name="_method" value="DELETE" />
# h.form(url('delete_user', id=ID),
# method='delete')
user_model.delete(id)
h.flash(_('successfully deleted user'), category='success')
@@ -164,13 +167,41 @@ class UsersController(BaseController):
return redirect(url('users'))
c.user.permissions = {}
c.granted_permissions = user_model.fill_perms(c.user)\
.permissions['global']
defaults = c.user.get_dict()
defaults.update({'create_repo_perm': UserToPerm.has_perm(id, perm)})
defaults=defaults,
encoding="UTF-8",
force_defaults=False
)
def update_perm(self, id):
"""PUT /users_perm/id: Update an existing item"""
# url('user_perm', id=ID, method='put')
grant_perm = request.POST.get('create_repo_perm', False)
if grant_perm:
perm = Permission.get_by_key('hg.create.none')
UserToPerm.revoke_perm(id, perm)
UserToPerm.grant_perm(id, perm)
h.flash(_("Granted 'repository create' permission to user"),
category='success')
else:
h.flash(_("Revoked 'repository create' permission to user"),
return redirect(url('edit_user', id=id))
@@ -33,19 +33,20 @@ from os.path import dirname as dn, join
from rhodecode import __dbversion__
from rhodecode.model import meta
from rhodecode.lib.auth import get_crypt_password, generate_api_key
from rhodecode.lib.utils import ask_ok
from rhodecode.model import init_model
from rhodecode.model.db import User, Permission, RhodeCodeUi, RhodeCodeSettings, \
UserToPerm, DbMigrateVersion
from rhodecode.model.db import User, Permission, RhodeCodeUi, \
RhodeCodeSettings, UserToPerm, DbMigrateVersion
from sqlalchemy.engine import create_engine
class DbManage(object):
def __init__(self, log_sql, dbconf, root, tests=False):
self.dbname = dbconf.split('/')[-1]
self.tests = tests
self.root = root
self.dburi = dbconf
@@ -73,14 +74,12 @@ class DbManage(object):
meta.Base.metadata.drop_all()
checkfirst = not override
meta.Base.metadata.create_all(checkfirst=checkfirst)
log.info('Created tables for %s', self.dbname)
def set_db_version(self):
ver = DbMigrateVersion()
ver.version = __dbversion__
ver.repository_id = 'rhodecode_db_migrations'
ver.repository_path = 'versions'
@@ -88,13 +87,12 @@ class DbManage(object):
self.sa.commit()
except:
self.sa.rollback()
raise
log.info('db version set to: %s', __dbversion__)
def upgrade(self):
"""Upgrades given database schema to given revision following
all needed steps, to perform the upgrade
"""
@@ -167,14 +165,12 @@ class DbManage(object):
#CALL THE PROPER ORDER OF STEPS TO PERFORM FULL UPGRADE
for step in upgrade_steps:
print ('performing upgrade step %s' % step)
callable = getattr(UpgradeSteps(self), 'step_%s' % step)()
def fix_repo_paths(self):
"""Fixes a old rhodecode version path into new one without a '*'
paths = self.sa.query(RhodeCodeUi)\
.filter(RhodeCodeUi.ui_key == '/')\
@@ -222,15 +218,15 @@ class DbManage(object):
def admin_prompt(self, second=False):
if not self.tests:
import getpass
def get_password():
password = getpass.getpass('Specify admin password (min 6 chars):')
password = getpass.getpass('Specify admin password '
'(min 6 chars):')
confirm = getpass.getpass('Confirm password:')
if password != confirm:
log.error('passwords mismatch')
return False
if len(password) < 6:
@@ -249,15 +245,18 @@ class DbManage(object):
sys.exit()
email = raw_input('Specify admin email:')
self.create_user(username, password, email, True)
log.info('creating admin and regular test users')
self.create_user('test_admin', 'test12', 'test_admin@mail.com', True)
self.create_user('test_regular', 'test12', 'test_regular@mail.com', False)
self.create_user('test_regular2', 'test12', 'test_regular2@mail.com', False)
self.create_user('test_admin', 'test12',
'test_admin@mail.com', True)
self.create_user('test_regular', 'test12',
'test_regular@mail.com', False)
self.create_user('test_regular2', 'test12',
'test_regular2@mail.com', False)
def create_ui_settings(self):
"""Creates ui settings, fills out hooks
and disables dotencode
@@ -305,26 +304,24 @@ class DbManage(object):
self.sa.add(dotencode_disable)
def create_ldap_options(self):
"""Creates ldap settings"""
for k, v in [('ldap_active', 'false'), ('ldap_host', ''),
('ldap_port', '389'), ('ldap_ldaps', 'false'),
('ldap_tls_reqcert', ''), ('ldap_dn_user', ''),
('ldap_dn_pass', ''), ('ldap_base_dn', ''),
('ldap_filter', ''), ('ldap_search_scope', ''),
('ldap_attr_login', ''), ('ldap_attr_firstname', ''),
('ldap_attr_lastname', ''), ('ldap_attr_email', '')]:
setting = RhodeCodeSettings(k, v)
self.sa.add(setting)
@@ -350,20 +347,18 @@ class DbManage(object):
if not os.access(path, os.W_OK):
path_ok = False
log.error('No write permission to given path: %s [%s/3]',
path, retries)
if retries == 0:
if path_ok is False:
retries -= 1
return self.config_prompt(test_repo_path, retries)
return path
def create_settings(self, path):
self.create_ui_settings()
@@ -390,18 +385,16 @@ class DbManage(object):
paths = RhodeCodeUi()
paths.ui_section = 'paths'
paths.ui_key = '/'
paths.ui_value = path
hgsettings1 = RhodeCodeSettings('realm', 'RhodeCode authentication')
hgsettings2 = RhodeCodeSettings('title', 'RhodeCode')
hgsettings3 = RhodeCodeSettings('ga_code', '')
self.sa.add(web1)
self.sa.add(web2)
self.sa.add(web3)
self.sa.add(web4)
self.sa.add(paths)
@@ -464,14 +457,19 @@ class DbManage(object):
('repository.write', 'Repository write access'),
('repository.admin', 'Repository admin access'),
('hg.admin', 'Hg Administrator'),
('hg.create.repository', 'Repository create'),
('hg.create.none', 'Repository creation disabled'),
('hg.register.none', 'Register disabled'),
('hg.register.manual_activate', 'Register new user with RhodeCode without manual activation'),
('hg.register.auto_activate', 'Register new user with RhodeCode without auto activation'),
('hg.register.manual_activate', 'Register new user with '
'RhodeCode without manual'
'activation'),
('hg.register.auto_activate', 'Register new user with '
'RhodeCode without auto '
]
for p in perms:
new_perm = Permission()
new_perm.permission_name = p[0]
new_perm.permission_longname = p[1]
@@ -30,13 +30,15 @@ from datetime import date
from sqlalchemy import *
from sqlalchemy.exc import DatabaseError
from sqlalchemy.orm import relationship, backref
from sqlalchemy.orm.interfaces import MapperExtension
from rhodecode.lib import str2bool
from rhodecode.model.meta import Base, Session
from rhodecode.model.caching_query import FromCache
#==============================================================================
# MAPPER EXTENSIONS
@@ -58,12 +60,41 @@ class RhodeCodeSettings(Base):
self.app_settings_value = v
def __repr__(self):
return "<%s('%s:%s')>" % (self.__class__.__name__,
self.app_settings_name, self.app_settings_value)
@classmethod
def get_app_settings(cls, cache=False):
ret = Session.query(cls)
if cache:
ret = ret.options(FromCache("sql_cache_short", "get_hg_settings"))
if not ret:
raise Exception('Could not get application settings !')
settings = {}
for each in ret:
settings['rhodecode_' + each.app_settings_name] = \
each.app_settings_value
return settings
def get_ldap_settings(cls, cache=False):
ret = Session.query(cls)\
.filter(cls.app_settings_name.startswith('ldap_'))\
.all()
fd = {}
for row in ret:
fd.update({row.app_settings_name:str2bool(row.app_settings_value)})
return fd
class RhodeCodeUi(Base):
__tablename__ = 'rhodecode_ui'
__table_args__ = {'useexisting':True}
ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
ui_section = Column("ui_section", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
ui_key = Column("ui_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
@@ -282,12 +313,16 @@ class Permission(Base):
permission_longname = Column("permission_longname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
self.permission_id, self.permission_name)
def get_by_key(cls, key):
return Session.query(cls).filter(cls.permission_name == key).scalar()
class RepoToPerm(Base):
__tablename__ = 'repo_to_perm'
__table_args__ = (UniqueConstraint('user_id', 'repository_id'), {'useexisting':True})
repo_to_perm_id = Column("repo_to_perm_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)
permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
@@ -304,12 +339,46 @@ class UserToPerm(Base):
user = relationship('User')
permission = relationship('Permission')
def has_perm(cls, user_id, perm):
if not isinstance(perm, Permission):
raise Exception('perm needs to be an instance of Permission class')
return Session.query(cls).filter(cls.user_id == user_id)\
.filter(cls.permission == perm).scalar() is not None
def grant_perm(cls, user_id, perm):
new = cls()
new.user_id = user_id
new.permission = perm
Session.add(new)
Session.commit()
Session.rollback()
def revoke_perm(cls, user_id, perm):
Session.query(cls).filter(cls.user_id == user_id)\
.filter(cls.permission == perm).delete()
class UsersGroupToPerm(Base):
__tablename__ = 'users_group_to_perm'
__table_args__ = (UniqueConstraint('users_group_id', 'permission_id'), {'useexisting':True})
users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
@@ -21,13 +21,13 @@
<div class="box box-left">
<!-- box / title -->
<div class="title">
${self.breadcrumbs()}
</div>
<!-- end box / title -->
${h.form(url('user', id=c.user.user_id),method='put')}
${h.form(url('update_user', id=c.user.user_id),method='put')}
<div class="form">
<div class="field">
<div class="gravatar_box">
<div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(c.user.email)}"/></div>
<p>
<strong>Change your avatar at <a href="http://gravatar.com">gravatar.com</a></strong><br/>
@@ -123,22 +123,22 @@
<div class="box box-right">
<h5>${_('Permissions')}</h5>
${h.form(url('user_perm', id=c.user.user_id),method='put')}
<!-- fields -->
<div class="fields">
<div class="label label-checkbox">
<label for="">${_('Create repositories')}:</label>
<div class="checkboxes">
${h.checkbox('create',value=True)}
${h.checkbox('create_repo_perm',value=True)}
<div class="buttons">
${h.submit('save','Save',class_="ui-button")}
${h.reset('reset','Reset',class_="ui-button")}
@@ -48,13 +48,13 @@
<td>${user.lastname}</td>
<td>${user.last_login}</td>
<td>${h.bool2icon(user.active)}</td>
<td>${h.bool2icon(user.admin)}</td>
<td>${h.bool2icon(bool(user.ldap_dn))}</td>
<td>
${h.form(url('user', id=user.user_id),method='delete')}
${h.form(url('delete_user', id=user.user_id),method='delete')}
${h.submit('remove_','delete',id="remove_user_%s" % user.user_id,
class_="delete_icon action_button",onclick="return confirm('Confirm to delete this user');")}
${h.end_form()}
</td>
</tr>
%endif
@@ -244,13 +244,13 @@ ${h.end_form()}
</script>
${h.form(url('user', id=''),method='put')}
${h.form(url('xxx', id=''),method='put')}
Status change: