@@ -60,115 +60,142 @@ def make_map(config):
m.connect("/repos/{repo_name:.*}",
action="update", conditions=dict(method=["PUT"],
function=check_repo))
action="delete", conditions=dict(method=["DELETE"],
m.connect("edit_repo", "/repos/{repo_name:.*}/edit",
action="edit", conditions=dict(method=["GET"],
m.connect("formatted_edit_repo", "/repos/{repo_name:.*}.{format}/edit",
m.connect("repo", "/repos/{repo_name:.*}",
action="show", conditions=dict(method=["GET"],
m.connect("formatted_repo", "/repos/{repo_name:.*}.{format}",
#ajax delete repo perm user
m.connect('delete_repo_user', "/repos_delete_user/{repo_name:.*}",
action="delete_perm_user", conditions=dict(method=["DELETE"],
#ajax delete repo perm users_group
m.connect('delete_repo_users_group',
"/repos_delete_users_group/{repo_name:.*}",
action="delete_perm_users_group",
conditions=dict(method=["DELETE"], function=check_repo))
#settings actions
m.connect('repo_stats', "/repos_stats/{repo_name:.*}",
action="repo_stats", conditions=dict(method=["DELETE"],
m.connect('repo_cache', "/repos_cache/{repo_name:.*}",
action="repo_cache", conditions=dict(method=["DELETE"],
m.connect('repo_public_journal',
"/repos_public_journal/{repo_name:.*}",
action="repo_public_journal", conditions=dict(method=["PUT"],
m.connect('repo_pull', "/repo_pull/{repo_name:.*}",
action="repo_pull", conditions=dict(method=["PUT"],
#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:
m.connect("admin_settings", "/settings",
m.connect("formatted_admin_settings", "/settings.{format}",
m.connect("admin_new_setting", "/settings/new",
m.connect("formatted_admin_new_setting", "/settings/new.{format}",
m.connect("/settings/{setting_id}",
m.connect("admin_edit_setting", "/settings/{setting_id}/edit",
m.connect("formatted_admin_edit_setting",
"/settings/{setting_id}.{format}/edit",
m.connect("admin_setting", "/settings/{setting_id}",
m.connect("formatted_admin_setting", "/settings/{setting_id}.{format}",
m.connect("admin_settings_my_account", "/my_account",
action="my_account", conditions=dict(method=["GET"]))
m.connect("admin_settings_my_account_update", "/my_account_update",
action="my_account_update", conditions=dict(method=["PUT"]))
m.connect("admin_settings_create_repository", "/create_repository",
action="create_repository", conditions=dict(method=["GET"]))
#ADMIN MAIN PAGES
with rmap.submapper(path_prefix='/_admin', controller='admin/admin') as m:
m.connect('admin_home', '', action='index')
m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
action='add_repo')
#USER JOURNAL
rmap.connect('journal', '/_admin/journal', controller='journal')
rmap.connect('public_journal', '/_admin/public_journal',
controller='journal', action="public_journal")
# -*- coding: utf-8 -*-
"""
rhodecode.controllers.admin.permissions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
permissions controller for Rhodecode
:created_on: Apr 27, 2010
:author: marcink
:copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
:license: GPLv3, see COPYING for more details.
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from formencode import htmlfill
from pylons import request, session, tmpl_context as c, url
from pylons.controllers.util import abort, redirect
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__)
class PermissionsController(BaseController):
"""REST Controller styled on the Atom Publishing Protocol"""
# To properly map this controller, ensure your config/routing.py
# file has a resource setup:
# map.resource('permission', 'permissions')
@LoginRequired()
@HasPermissionAllDecorator('hg.admin')
def __before__(self):
c.admin_user = session.get('admin_user')
c.admin_username = session.get('admin_username')
super(PermissionsController, self).__before__()
self.perms_choices = [('repository.none', _('None'),),
('repository.read', _('Read'),),
('repository.write', _('Write'),),
('repository.admin', _('Admin'),)]
self.register_choices = [
('hg.register.none',
_('disabled')),
('hg.register.manual_activate',
_('allowed with manual account activation')),
('hg.register.auto_activate',
_('allowed with automatic account activation')), ]
self.create_choices = [('hg.create.none', _('Disabled')),
('hg.create.repository', _('Enabled'))]
def index(self, format='html'):
"""GET /permissions: All items in the collection"""
# url('permissions')
def create(self):
"""POST /permissions: Create a new item"""
def new(self, format='html'):
"""GET /permissions/new: Form to create a new item"""
# url('new_permission')
rhodecode.controllers.admin.users
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Users crud controller for pylons
:created_on: Apr 4, 2010
from pylons import request, session, tmpl_context as c, url, config
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
class UsersController(BaseController):
# map.resource('user', 'users')
super(UsersController, self).__before__()
c.available_permissions = config['available_permissions']
"""GET /users: All items in the collection"""
# url('users')
c.users_list = self.sa.query(User).all()
return render('admin/users/users.html')
"""POST /users: Create a new item"""
user_model = UserModel()
login_form = UserForm()()
try:
form_result = login_form.to_python(dict(request.POST))
user_model.create(form_result)
h.flash(_('created user %s') % form_result['username'],
category='success')
#action_logger(self.rhodecode_user, 'new_user', '', '', self.sa)
except formencode.Invalid, errors:
return htmlfill.render(
render('admin/users/user_add.html'),
defaults=errors.value,
errors=errors.error_dict or {},
prefix_error=False,
encoding="UTF-8")
except Exception:
log.error(traceback.format_exc())
h.flash(_('error occurred during creation of user %s') \
% request.POST.get('username'), category='error')
return redirect(url('users'))
"""GET /users/new: Form to create a new item"""
# url('new_user')
return render('admin/users/user_add.html')
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)
c.user = user_model.get(id)
_form = UserForm(edit=True, old_data={'user_id': id,
'email': c.user.email})()
form_result = {}
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')
e = errors.error_dict or {}
perm = Permission.get_by_key('hg.create.repository')
e.update({'create_repo_perm': UserToPerm.has_perm(id, perm)})
render('admin/users/user_edit.html'),
errors=e,
h.flash(_('error occurred during update of user %s') \
% form_result.get('username'), category='error')
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')
except (UserOwnsReposException, DefaultUserException), e:
h.flash(str(e), category='warning')
h.flash(_('An error occurred during deletion of user'),
category='error')
def show(self, id, format='html'):
"""GET /users/id: Show a specific item"""
def edit(self, id, format='html'):
"""GET /users/id/edit: Form to edit an existing item"""
# url('edit_user', id=ID)
if not c.user:
if c.user.username == 'default':
h.flash(_("You can't edit this user"), category='warning')
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"),
else:
h.flash(_("Revoked 'repository create' permission to user"),
return redirect(url('edit_user', id=id))
rhodecode.lib.db_manage
~~~~~~~~~~~~~~~~~~~~~~~
Database creation, and setup module for RhodeCode. Used for creation
of database as well as for migration operations
:created_on: Apr 10, 2010
import os
import sys
import uuid
from os.path import dirname as dn, join as jn
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
self.log_sql = log_sql
self.db_exists = False
self.init_db()
def init_db(self):
engine = create_engine(self.dburi, echo=self.log_sql)
init_model(engine)
self.sa = meta.Session()
def create_tables(self, override=False):
"""Create a auth database
log.info("Any existing database is going to be destroyed")
if self.tests:
destroy = True
destroy = ask_ok('Are you sure to destroy old database ? [y/n]')
if not destroy:
sys.exit()
if destroy:
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'
self.sa.add(ver)
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
from rhodecode.lib.dbmigrate.migrate.versioning import api
from rhodecode.lib.dbmigrate.migrate.exceptions import \
DatabaseNotControlledError
upgrade = ask_ok('You are about to perform database upgrade, make '
'sure You backed up your database before. '
'Continue ? [y/n]')
if not upgrade:
sys.exit('Nothing done')
repository_path = jn(dn(dn(dn(os.path.realpath(__file__)))),
'rhodecode/lib/dbmigrate')
db_uri = self.dburi
curr_version = api.db_version(db_uri, repository_path)
msg = ('Found current database under version'
' control with version %s' % curr_version)
except (RuntimeError, DatabaseNotControlledError), e:
curr_version = 1
msg = ('Current database is not under version control. Setting'
' as version %s' % curr_version)
api.version_control(db_uri, repository_path, curr_version)
print (msg)
if curr_version == __dbversion__:
sys.exit('This database is already at the newest version')
#======================================================================
# UPGRADE STEPS
class UpgradeSteps(object):
"""Those steps follow schema versions so for example schema
for example schema with seq 002 == step_2 and so on.
def __init__(self, klass):
self.klass = klass
def step_0(self):
#step 0 is the schema upgrade, and than follow proper upgrades
print ('attempting to do database upgrade to version %s' \
% __dbversion__)
api.upgrade(db_uri, repository_path, __dbversion__)
print ('Schema upgrade completed')
def step_1(self):
pass
def step_2(self):
print ('Patching repo paths for newer version of RhodeCode')
self.klass.fix_repo_paths()
print ('Patching default user of RhodeCode')
self.klass.fix_default_user()
log.info('Changing ui settings')
self.klass.create_ui_settings()
def step_3(self):
print ('Adding additional settings into RhodeCode db')
self.klass.fix_settings()
upgrade_steps = [0] + range(curr_version + 1, __dbversion__ + 1)
#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 == '/')\
.scalar()
paths.ui_value = paths.ui_value.replace('*', '')
self.sa.add(paths)
def fix_default_user(self):
"""Fixes a old default user with some 'nicer' default values,
used mostly for anonymous access
def_user = self.sa.query(User)\
.filter(User.username == 'default')\
.one()
def_user.name = 'Anonymous'
def_user.lastname = 'User'
def_user.email = 'anonymous@rhodecode.org'
self.sa.add(def_user)
def fix_settings(self):
"""Fixes rhodecode settings adds ga_code key for google analytics
hgsettings3 = RhodeCodeSettings('ga_code', '')
self.sa.add(hgsettings3)
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:
log.error('password is to short use at least 6 characters')
return password
username = raw_input('Specify admin username:')
password = get_password()
if not password:
#second try
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
#HOOKS
hooks1_key = 'changegroup.update'
hooks1_ = self.sa.query(RhodeCodeUi)\
.filter(RhodeCodeUi.ui_key == hooks1_key).scalar()
hooks1 = RhodeCodeUi() if hooks1_ is None else hooks1_
hooks1.ui_section = 'hooks'
hooks1.ui_key = hooks1_key
hooks1.ui_value = 'hg update >&2'
hooks1.ui_active = False
hooks2_key = 'changegroup.repo_size'
hooks2_ = self.sa.query(RhodeCodeUi)\
.filter(RhodeCodeUi.ui_key == hooks2_key).scalar()
hooks2 = RhodeCodeUi() if hooks2_ is None else hooks2_
hooks2.ui_section = 'hooks'
hooks2.ui_key = hooks2_key
hooks2.ui_value = 'python:rhodecode.lib.hooks.repo_size'
hooks3 = RhodeCodeUi()
hooks3.ui_section = 'hooks'
hooks3.ui_key = 'pretxnchangegroup.push_logger'
hooks3.ui_value = 'python:rhodecode.lib.hooks.log_push_action'
hooks4 = RhodeCodeUi()
hooks4.ui_section = 'hooks'
hooks4.ui_key = 'preoutgoing.pull_logger'
hooks4.ui_value = 'python:rhodecode.lib.hooks.log_pull_action'
#For mercurial 1.7 set backward comapatibility with format
dotencode_disable = RhodeCodeUi()
dotencode_disable.ui_section = 'format'
dotencode_disable.ui_key = 'dotencode'
dotencode_disable.ui_value = 'false'
self.sa.add(hooks1)
self.sa.add(hooks2)
self.sa.add(hooks3)
self.sa.add(hooks4)
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)
def config_prompt(self, test_repo_path='', retries=3):
if retries == 3:
log.info('Setting up repositories config')
if not self.tests and not test_repo_path:
path = raw_input('Specify valid full path to your repositories'
' you can change this later in application settings:')
path = test_repo_path
path_ok = True
#check proper dir
if not os.path.isdir(path):
path_ok = False
log.error('Entered path is not a valid directory: %s [%s/3]',
path, retries)
#check write access
if not os.access(path, os.W_OK):
log.error('No write permission to given path: %s [%s/3]',
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()
#HG UI OPTIONS
web1 = RhodeCodeUi()
web1.ui_section = 'web'
web1.ui_key = 'push_ssl'
web1.ui_value = 'false'
web2 = RhodeCodeUi()
web2.ui_section = 'web'
web2.ui_key = 'allow_archive'
web2.ui_value = 'gz zip bz2'
web3 = RhodeCodeUi()
web3.ui_section = 'web'
web3.ui_key = 'allow_push'
web3.ui_value = '*'
web4 = RhodeCodeUi()
web4.ui_section = 'web'
web4.ui_key = 'baseurl'
web4.ui_value = '/'
paths = RhodeCodeUi()
paths.ui_section = 'paths'
paths.ui_key = '/'
paths.ui_value = path
hgsettings1 = RhodeCodeSettings('realm', 'RhodeCode authentication')
hgsettings2 = RhodeCodeSettings('title', 'RhodeCode')
self.sa.add(web1)
self.sa.add(web2)
self.sa.add(web3)
self.sa.add(web4)
self.sa.add(hgsettings1)
self.sa.add(hgsettings2)
self.create_ldap_options()
log.info('created ui config')
def create_user(self, username, password, email='', admin=False):
log.info('creating administrator user %s', username)
new_user = User()
new_user.username = username
new_user.password = get_crypt_password(password)
new_user.api_key = generate_api_key(username)
new_user.name = 'RhodeCode'
new_user.lastname = 'Admin'
new_user.email = email
new_user.admin = admin
new_user.active = True
self.sa.add(new_user)
def create_default_user(self):
log.info('creating default user')
#create default user for handling default permissions.
def_user = User()
def_user.username = 'default'
def_user.password = get_crypt_password(str(uuid.uuid1())[:8])
def_user.api_key = generate_api_key('default')
def_user.admin = False
def_user.active = False
def create_permissions(self):
#module.(access|create|change|delete)_[name]
#module.(read|write|owner)
perms = [('repository.none', 'Repository no access'),
('repository.read', 'Repository read access'),
('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]
self.sa.add(new_perm)
def populate_default_permissions(self):
log.info('creating default user permissions')
default_user = self.sa.query(User)\
.filter(User.username == 'default').scalar()
reg_perm = UserToPerm()
reg_perm.user = default_user
reg_perm.permission = self.sa.query(Permission)\
.filter(Permission.permission_name == 'hg.register.manual_activate')\
create_repo_perm = UserToPerm()
create_repo_perm.user = default_user
create_repo_perm.permission = self.sa.query(Permission)\
.filter(Permission.permission_name == 'hg.create.repository')\
default_repo_perm = UserToPerm()
default_repo_perm.user = default_user
default_repo_perm.permission = self.sa.query(Permission)\
.filter(Permission.permission_name == 'repository.read')\
self.sa.add(reg_perm)
self.sa.add(create_repo_perm)
self.sa.add(default_repo_perm)
rhodecode.model.db
~~~~~~~~~~~~~~~~~~
Database Models for RhodeCode
:created_on: Apr 08, 2010
import datetime
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
class RepositoryMapper(MapperExtension):
def after_update(self, mapper, connection, instance):
class RhodeCodeSettings(Base):
__tablename__ = 'rhodecode_settings'
__table_args__ = (UniqueConstraint('app_settings_name'), {'useexisting':True})
app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
app_settings_name = Column("app_settings_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
app_settings_value = Column("app_settings_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
def __init__(self, k='', v=''):
self.app_settings_name = k
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)
ui_value = Column("ui_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
class User(Base):
__tablename__ = 'users'
__table_args__ = (UniqueConstraint('username'), UniqueConstraint('email'), {'useexisting':True})
user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
username = Column("username", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
password = Column("password", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
active = Column("active", Boolean(), nullable=True, unique=None, default=None)
admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
name = Column("name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
lastname = Column("lastname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
email = Column("email", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
ldap_dn = Column("ldap_dn", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
api_key = Column("api_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
user_log = relationship('UserLog', cascade='all')
user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
repositories = relationship('Repository')
user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
group_member = relationship('UsersGroupMember', cascade='all')
@property
def full_contact(self):
return '%s %s <%s>' % (self.name, self.lastname, self.email)
def short_contact(self):
return '%s %s' % (self.name, self.lastname)
def is_admin(self):
return self.admin
return "<%s('id:%s:%s')>" % (self.__class__.__name__,
@@ -240,118 +271,156 @@ class Group(Base):
__tablename__ = 'groups'
__table_args__ = (UniqueConstraint('group_name'), {'useexisting':True},)
group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
group_name = Column("group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
parent_group = relationship('Group', remote_side=group_id)
def __init__(self, group_name='', parent_group=None):
self.group_name = group_name
self.parent_group = parent_group
return "<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
self.group_name)
def parents(self):
groups = []
if self.parent_group is None:
return groups
cur_gr = self.parent_group
groups.insert(0, cur_gr)
while 1:
gr = getattr(cur_gr, 'parent_group', None)
cur_gr = cur_gr.parent_group
if gr is None:
break
groups.insert(0, gr)
def repositories(self):
return Session.query(Repository).filter(Repository.group == self).all()
class Permission(Base):
__tablename__ = 'permissions'
permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
permission_name = Column("permission_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
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)
repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
user = relationship('User')
permission = relationship('Permission')
repository = relationship('Repository')
class UserToPerm(Base):
__tablename__ = 'user_to_perm'
__table_args__ = (UniqueConstraint('user_id', 'permission_id'), {'useexisting':True})
user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
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)
users_group = relationship('UsersGroup')
class GroupToPerm(Base):
__tablename__ = 'group_to_perm'
__table_args__ = (UniqueConstraint('group_id', 'permission_id'), {'useexisting':True})
group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
group = relationship('Group')
class Statistics(Base):
__tablename__ = 'statistics'
__table_args__ = (UniqueConstraint('repository_id'), {'useexisting':True})
stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
repository = relationship('Repository', single_parent=True)
class UserFollowing(Base):
__tablename__ = 'user_followings'
__table_args__ = (UniqueConstraint('user_id', 'follows_repository_id'),
UniqueConstraint('user_id', 'follows_user_id')
, {'useexisting':True})
user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
## -*- coding: utf-8 -*-
<%inherit file="/base/base.html"/>
<%def name="title()">
${_('Edit user')} ${c.user.username} - ${c.rhodecode_name}
</%def>
<%def name="breadcrumbs_links()">
${h.link_to(_('Admin'),h.url('admin_home'))}
»
${h.link_to(_('Users'),h.url('users'))}
${_('edit')} "${c.user.username}"
<%def name="page_nav()">
${self.menu('admin')}
<%def name="main()">
<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/>
${_('Using')} ${c.user.email}
</p>
<div class="label">
<label>${_('API key')}</label> ${c.user.api_key}
<div class="fields">
<label for="username">${_('Username')}:</label>
<div class="input">
${h.text('username',class_='medium')}
<label for="ldap_dn">${_('LDAP DN')}:</label>
${h.text('ldap_dn',class_='medium')}
<label for="new_password">${_('New password')}:</label>
${h.password('new_password',class_='medium')}
<label for="name">${_('First Name')}:</label>
@@ -81,69 +81,69 @@
<label for="lastname">${_('Last Name')}:</label>
${h.text('lastname',class_='medium')}
<label for="email">${_('Email')}:</label>
${h.text('email',class_='medium')}
<div class="label label-checkbox">
<label for="active">${_('Active')}:</label>
<div class="checkboxes">
${h.checkbox('active',value=True)}
<label for="admin">${_('Admin')}:</label>
${h.checkbox('admin',value=True)}
<div class="buttons">
${h.submit('save','Save',class_="ui-button")}
${h.reset('reset','Reset',class_="ui-button")}
${h.end_form()}
<div class="box box-right">
<h5>${_('Permissions')}</h5>
${h.form(url('user_perm', id=c.user.user_id),method='put')}
<!-- fields -->
<label for="">${_('Create repositories')}:</label>
${h.checkbox('create',value=True)}
${h.checkbox('create_repo_perm',value=True)}
@@ -6,60 +6,60 @@
${h.link_to(_('Admin'),h.url('admin_home'))} » ${_('Users')}
<div class="box">
<ul class="links">
<li>
<span>${h.link_to(u'ADD NEW USER',h.url('new_user'))}</span>
</li>
</ul>
<div class="table">
<table class="table_disp">
<tr class="header">
<th></th>
<th class="left">${_('username')}</th>
<th class="left">${_('name')}</th>
<th class="left">${_('lastname')}</th>
<th class="left">${_('last login')}</th>
<th class="left">${_('active')}</th>
<th class="left">${_('admin')}</th>
<th class="left">${_('ldap')}</th>
<th class="left">${_('action')}</th>
</tr>
%for cnt,user in enumerate(c.users_list):
%if user.name !='default':
<tr class="parity${cnt%2}">
<td><div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(user.email,24)}"/> </div></td>
<td>${h.link_to(user.username,h.url('edit_user', id=user.user_id))}</td>
<td>${user.name}</td>
<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');")}
</td>
%endif
%endfor
</table>
@@ -202,69 +202,69 @@ ${h.end_form()}
if (this.id=='add_element'){
var c = get_checked(available);
add_to(choosen,c[0]);
fill_with(available,c[1]);
}
// remove action
if (this.id=='remove_element'){
var c = get_checked(choosen);
add_to(available,c[0]);
fill_with(choosen,c[1]);
// add all elements
if(this.id=='add_all_elements'){
for(var i=0; node = available.options[i];i++){
choosen.appendChild(new Option(node.text,
node.value, false, false));
available.options.length = 0;
//remove all elements
if(this.id=='remove_all_elements'){
for(var i=0; node = choosen.options[i];i++){
available.appendChild(new Option(node.text,
choosen.options.length = 0;
E.addListener(['add_element','remove_element',
'add_all_elements','remove_all_elements'],'click',
prompts_action_callback)
E.addListener(form_id,'submit',function(){
var choosen = D.get(selected_container);
for (var i = 0; i < choosen.options.length; i++) {
choosen.options[i].selected = 'selected';
})
});
</script>
${h.form(url('user', id=''),method='put')}
${h.form(url('xxx', id=''),method='put')}
\ No newline at end of file
Status change: