diff --git a/rhodecode/__init__.py b/rhodecode/__init__.py --- a/rhodecode/__init__.py +++ b/rhodecode/__init__.py @@ -51,7 +51,7 @@ PYRAMID_SETTINGS = {} EXTENSIONS = {} __version__ = ('.'.join((str(each) for each in VERSION[:3]))) -__dbversion__ = 62 # defines current db version for migrations +__dbversion__ = 63 # defines current db version for migrations __platform__ = platform.system() __license__ = 'AGPLv3, and Commercial License' __author__ = 'RhodeCode GmbH' diff --git a/rhodecode/api/views/user_api.py b/rhodecode/api/views/user_api.py --- a/rhodecode/api/views/user_api.py +++ b/rhodecode/api/views/user_api.py @@ -25,7 +25,7 @@ from rhodecode.api.utils import ( Optional, OAttr, has_superadmin_permission, get_user_or_error, store_update) from rhodecode.lib.auth import AuthUser, PasswordGenerator from rhodecode.lib.exceptions import DefaultUserException -from rhodecode.lib.utils2 import safe_int +from rhodecode.lib.utils2 import safe_int, str2bool from rhodecode.model.db import Session, User, Repository from rhodecode.model.user import UserModel @@ -155,7 +155,8 @@ def create_user(request, apiuser, userna active=Optional(True), admin=Optional(False), extern_name=Optional('rhodecode'), extern_type=Optional('rhodecode'), - force_password_change=Optional(False)): + force_password_change=Optional(False), + create_personal_repo_group=Optional(None)): """ Creates a new user and returns the new user object. @@ -188,7 +189,8 @@ def create_user(request, apiuser, userna :param force_password_change: Force the new user to change password on next login. :type force_password_change: Optional(``True`` | ``False``) - + :param create_personal_repo_group: Create personal repo group for this user + :type create_personal_repo_group: Optional(``True`` | ``False``) Example output: .. code-block:: bash @@ -230,6 +232,9 @@ def create_user(request, apiuser, userna Optional.extract(extern_name) != 'rhodecode'): # generate temporary password if user is external password = PasswordGenerator().gen_password(length=16) + create_repo_group = Optional.extract(create_personal_repo_group) + if isinstance(create_repo_group, basestring): + create_repo_group = str2bool(create_repo_group) try: user = UserModel().create_or_update( @@ -243,6 +248,7 @@ def create_user(request, apiuser, userna extern_type=Optional.extract(extern_type), extern_name=Optional.extract(extern_name), force_password_change=Optional.extract(force_password_change), + create_repo_group=create_repo_group ) Session().commit() return { diff --git a/rhodecode/controllers/admin/repos.py b/rhodecode/controllers/admin/repos.py --- a/rhodecode/controllers/admin/repos.py +++ b/rhodecode/controllers/admin/repos.py @@ -160,6 +160,7 @@ class ReposController(BaseRepoController self.__load_defaults() form_result = {} task_id = None + c.personal_repo_group = c.rhodecode_user.personal_repo_group try: # CanWriteToGroup validators checks permissions of this POST form_result = RepoForm(repo_groups=c.repo_groups_choices, @@ -173,8 +174,6 @@ class ReposController(BaseRepoController if isinstance(task, BaseAsyncResult): task_id = task.task_id except formencode.Invalid as errors: - c.personal_repo_group = RepoGroup.get_by_group_name( - c.rhodecode_user.username) return htmlfill.render( render('admin/repos/repo_add.html'), defaults=errors.value, @@ -215,7 +214,7 @@ class ReposController(BaseRepoController c.repo_groups = RepoGroup.groups_choices(groups=acl_groups) c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups) choices, c.landing_revs = ScmModel().get_repo_landing_revs() - c.personal_repo_group = RepoGroup.get_by_group_name(c.rhodecode_user.username) + c.personal_repo_group = c.rhodecode_user.personal_repo_group c.new_repo = repo_name_slug(new_repo) ## apply the defaults from defaults page @@ -299,9 +298,8 @@ class ReposController(BaseRepoController repo_model = RepoModel() changed_name = repo_name + c.personal_repo_group = c.rhodecode_user.personal_repo_group # override the choices with extracted revisions ! - c.personal_repo_group = RepoGroup.get_by_group_name( - c.rhodecode_user.username) repo = Repository.get_by_repo_name(repo_name) old_data = { 'repo_name': repo_name, @@ -399,8 +397,7 @@ class ReposController(BaseRepoController c.repo_fields = RepositoryField.query()\ .filter(RepositoryField.repository == c.repo_info).all() - c.personal_repo_group = RepoGroup.get_by_group_name( - c.rhodecode_user.username) + c.personal_repo_group = c.rhodecode_user.personal_repo_group c.active = 'settings' return htmlfill.render( render('admin/repos/repo_edit.html'), diff --git a/rhodecode/controllers/admin/settings.py b/rhodecode/controllers/admin/settings.py --- a/rhodecode/controllers/admin/settings.py +++ b/rhodecode/controllers/admin/settings.py @@ -55,6 +55,7 @@ from rhodecode.model.db import RhodeCode from rhodecode.model.forms import ApplicationSettingsForm, \ ApplicationUiSettingsForm, ApplicationVisualisationForm, \ LabsSettingsForm, IssueTrackerPatternsForm +from rhodecode.model.repo_group import RepoGroupModel from rhodecode.model.scm import ScmModel from rhodecode.model.notification import EmailNotificationModel @@ -245,6 +246,8 @@ class SettingsController(BaseController) """POST /admin/settings/global: All items in the collection""" # url('admin_settings_global') c.active = 'global' + c.personal_repo_group_default_pattern = RepoGroupModel()\ + .get_personal_group_name_pattern() application_form = ApplicationSettingsForm()() try: form_result = application_form.to_python(dict(request.POST)) @@ -259,16 +262,18 @@ class SettingsController(BaseController) try: settings = [ - ('title', 'rhodecode_title'), - ('realm', 'rhodecode_realm'), - ('pre_code', 'rhodecode_pre_code'), - ('post_code', 'rhodecode_post_code'), - ('captcha_public_key', 'rhodecode_captcha_public_key'), - ('captcha_private_key', 'rhodecode_captcha_private_key'), + ('title', 'rhodecode_title', 'unicode'), + ('realm', 'rhodecode_realm', 'unicode'), + ('pre_code', 'rhodecode_pre_code', 'unicode'), + ('post_code', 'rhodecode_post_code', 'unicode'), + ('captcha_public_key', 'rhodecode_captcha_public_key', 'unicode'), + ('captcha_private_key', 'rhodecode_captcha_private_key', 'unicode'), + ('create_personal_repo_group', 'rhodecode_create_personal_repo_group', 'bool'), + ('personal_repo_group_pattern', 'rhodecode_personal_repo_group_pattern', 'unicode'), ] - for setting, form_key in settings: + for setting, form_key, type_ in settings: sett = SettingsModel().create_or_update_setting( - setting, form_result[form_key]) + setting, form_result[form_key], type_) Session().add(sett) Session().commit() @@ -287,6 +292,8 @@ class SettingsController(BaseController) """GET /admin/settings/global: All items in the collection""" # url('admin_settings_global') c.active = 'global' + c.personal_repo_group_default_pattern = RepoGroupModel()\ + .get_personal_group_name_pattern() return htmlfill.render( render('admin/settings/settings.html'), diff --git a/rhodecode/controllers/admin/users.py b/rhodecode/controllers/admin/users.py --- a/rhodecode/controllers/admin/users.py +++ b/rhodecode/controllers/admin/users.py @@ -45,12 +45,13 @@ from rhodecode.model.db import ( PullRequestReviewers, User, UserEmailMap, UserIpMap, RepoGroup) from rhodecode.model.forms import ( UserForm, UserPermissionsForm, UserIndividualPermissionsForm) +from rhodecode.model.repo_group import RepoGroupModel from rhodecode.model.user import UserModel from rhodecode.model.meta import Session from rhodecode.model.permission import PermissionModel from rhodecode.lib.utils import action_logger from rhodecode.lib.ext_json import json -from rhodecode.lib.utils2 import datetime_to_time, safe_int +from rhodecode.lib.utils2 import datetime_to_time, safe_int, AttributeDict log = logging.getLogger(__name__) @@ -120,6 +121,16 @@ class UsersController(BaseController): c.data = json.dumps(users_data) return render('admin/users/users.html') + def _get_personal_repo_group_template_vars(self): + DummyUser = AttributeDict({ + 'username': '${username}', + 'user_id': '${user_id}', + }) + c.default_create_repo_group = RepoGroupModel() \ + .get_default_create_personal_repo_group() + c.personal_repo_group_name = RepoGroupModel() \ + .get_personal_group_name(DummyUser) + @HasPermissionAllDecorator('hg.admin') @auth.CSRFRequired() def create(self): @@ -143,6 +154,7 @@ class UsersController(BaseController): % {'user_link': user_link}), category='success') Session().commit() except formencode.Invalid as errors: + self._get_personal_repo_group_template_vars() return htmlfill.render( render('admin/users/user_add.html'), defaults=errors.value, @@ -163,6 +175,7 @@ class UsersController(BaseController): """GET /users/new: Form to create a new item""" # url('new_user') c.default_extern_type = auth_rhodecode.RhodeCodeAuthPlugin.name + self._get_personal_repo_group_template_vars() return render('admin/users/user_add.html') @HasPermissionAllDecorator('hg.admin') @@ -339,22 +352,41 @@ class UsersController(BaseController): user_id = safe_int(user_id) c.user = User.get_or_404(user_id) + personal_repo_group = RepoGroup.get_user_personal_repo_group( + c.user.user_id) + if personal_repo_group: + return redirect(url('edit_user_advanced', user_id=user_id)) + personal_repo_group_name = RepoGroupModel().get_personal_group_name( + c.user) + named_personal_group = RepoGroup.get_by_group_name( + personal_repo_group_name) try: - desc = RepoGroupModel.PERSONAL_GROUP_DESC % { - 'username': c.user.username} - if not RepoGroup.get_by_group_name(c.user.username): - RepoGroupModel().create(group_name=c.user.username, - group_description=desc, - owner=c.user.username) - msg = _('Created repository group `%s`' % (c.user.username,)) + if named_personal_group and named_personal_group.user_id == c.user.user_id: + # migrate the same named group, and mark it as personal + named_personal_group.personal = True + Session().add(named_personal_group) + Session().commit() + msg = _('Linked repository group `%s` as personal' % ( + personal_repo_group_name,)) h.flash(msg, category='success') + elif not named_personal_group: + RepoGroupModel().create_personal_repo_group(c.user) + + msg = _('Created repository group `%s`' % ( + personal_repo_group_name,)) + h.flash(msg, category='success') + else: + msg = _('Repository group `%s` is already taken' % ( + personal_repo_group_name,)) + h.flash(msg, category='warning') except Exception: log.exception("Exception during repository group creation") msg = _( 'An error occurred during repository group creation for user') h.flash(msg, category='error') + Session().rollback() return redirect(url('edit_user_advanced', user_id=user_id)) @@ -397,7 +429,9 @@ class UsersController(BaseController): c.active = 'advanced' c.perm_user = AuthUser(user_id=user_id, ip_addr=self.ip_addr) - c.personal_repo_group = RepoGroup.get_by_group_name(user.username) + c.personal_repo_group = c.perm_user.personal_repo_group + c.personal_repo_group_name = RepoGroupModel()\ + .get_personal_group_name(user) c.first_admin = User.get_first_super_admin() defaults = user.get_dict() diff --git a/rhodecode/controllers/forks.py b/rhodecode/controllers/forks.py --- a/rhodecode/controllers/forks.py +++ b/rhodecode/controllers/forks.py @@ -60,8 +60,7 @@ class ForksController(BaseRepoController c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups) choices, c.landing_revs = ScmModel().get_repo_landing_revs() c.landing_revs_choices = choices - c.personal_repo_group = RepoGroup.get_by_group_name( - c.rhodecode_user.username) + c.personal_repo_group = c.rhodecode_user.personal_repo_group def __load_data(self, repo_name=None): """ diff --git a/rhodecode/events/__init__.py b/rhodecode/events/__init__.py --- a/rhodecode/events/__init__.py +++ b/rhodecode/events/__init__.py @@ -48,6 +48,7 @@ from rhodecode.events.base import Rhodec from rhodecode.events.user import ( # noqa UserPreCreate, + UserPostCreate, UserPreUpdate, UserRegistered ) diff --git a/rhodecode/events/user.py b/rhodecode/events/user.py --- a/rhodecode/events/user.py +++ b/rhodecode/events/user.py @@ -51,6 +51,19 @@ class UserPreCreate(RhodecodeEvent): self.user_data = user_data +@implementer(IUserPreCreate) +class UserPostCreate(RhodecodeEvent): + """ + An instance of this class is emitted as an :term:`event` after a new user + object is created. + """ + name = 'user-post-create' + display_name = lazy_ugettext('user post create') + + def __init__(self, user_data): + self.user_data = user_data + + @implementer(IUserPreUpdate) class UserPreUpdate(RhodecodeEvent): """ diff --git a/rhodecode/lib/auth.py b/rhodecode/lib/auth.py --- a/rhodecode/lib/auth.py +++ b/rhodecode/lib/auth.py @@ -49,7 +49,7 @@ from rhodecode.model.meta import Session from rhodecode.model.user import UserModel from rhodecode.model.db import ( User, Repository, Permission, UserToPerm, UserGroupToPerm, UserGroupMember, - UserIpMap, UserApiKeys) + UserIpMap, UserApiKeys, RepoGroup) from rhodecode.lib import caches from rhodecode.lib.utils2 import safe_unicode, aslist, safe_str, md5 from rhodecode.lib.utils import ( @@ -983,6 +983,9 @@ class AuthUser(object): inherit = self.inherit_default_permissions return AuthUser.check_ip_allowed(self.user_id, self.ip_addr, inherit_from_default=inherit) + @property + def personal_repo_group(self): + return RepoGroup.get_user_personal_repo_group(self.user_id) @classmethod def check_ip_allowed(cls, user_id, ip_addr, inherit_from_default): diff --git a/rhodecode/lib/dbmigrate/versions/063_version_4_5_0.py b/rhodecode/lib/dbmigrate/versions/063_version_4_5_0.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/dbmigrate/versions/063_version_4_5_0.py @@ -0,0 +1,27 @@ +import logging + +from sqlalchemy import Column, MetaData, Boolean + +from rhodecode.lib.dbmigrate.versions import _reset_base + +log = logging.getLogger(__name__) + + +def upgrade(migrate_engine): + """ + Upgrade operations go here. + Don't create your own engine; bind migrate_engine to your metadata + """ + _reset_base(migrate_engine) + from rhodecode.lib.dbmigrate.schema import db_4_5_0_0 as db + + # Add personal column to RepoGroup table. + rg_table = db.RepoGroup.__table__ + rg_col = Column( + 'personal', Boolean(), nullable=True, unique=None, default=None) + rg_col.create(table=rg_table) + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine diff --git a/rhodecode/lib/utils2.py b/rhodecode/lib/utils2.py --- a/rhodecode/lib/utils2.py +++ b/rhodecode/lib/utils2.py @@ -96,7 +96,7 @@ def __get_lem(extra_mapping=None): def str2bool(_str): """ - returs True/False value from given string, it tries to translate the + returns True/False value from given string, it tries to translate the string into boolean :param _str: string value to translate into boolean diff --git a/rhodecode/model/db.py b/rhodecode/model/db.py --- a/rhodecode/model/db.py +++ b/rhodecode/model/db.py @@ -2028,6 +2028,7 @@ class RepoGroup(Base, BaseModel): enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + personal = Column('personal', Boolean(), nullable=True, unique=None, default=None) repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id') users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') @@ -2083,6 +2084,13 @@ class RepoGroup(Base, BaseModel): return gr.scalar() @classmethod + def get_user_personal_repo_group(cls, user_id): + user = User.get(user_id) + return cls.query()\ + .filter(cls.personal == true())\ + .filter(cls.user == user).scalar() + + @classmethod def get_all_repo_groups(cls, user_id=Optional(None), group_id=Optional(None), case_insensitive=True): q = RepoGroup.query() diff --git a/rhodecode/model/forms.py b/rhodecode/model/forms.py --- a/rhodecode/model/forms.py +++ b/rhodecode/model/forms.py @@ -341,6 +341,8 @@ def ApplicationSettingsForm(): rhodecode_post_code = v.UnicodeString(strip=True, min=1, not_empty=False) rhodecode_captcha_public_key = v.UnicodeString(strip=True, min=1, not_empty=False) rhodecode_captcha_private_key = v.UnicodeString(strip=True, min=1, not_empty=False) + rhodecode_create_personal_repo_group = v.StringBoolean(if_missing=False) + rhodecode_personal_repo_group_pattern = v.UnicodeString(strip=True, min=1, not_empty=False) return _ApplicationSettingsForm diff --git a/rhodecode/model/repo_group.py b/rhodecode/model/repo_group.py --- a/rhodecode/model/repo_group.py +++ b/rhodecode/model/repo_group.py @@ -23,13 +23,13 @@ repo group model for RhodeCode """ - +import os import datetime import itertools import logging -import os import shutil import traceback +import string from zope.cachedescriptors.property import Lazy as LazyProperty @@ -38,7 +38,7 @@ from rhodecode.model import BaseModel from rhodecode.model.db import ( RepoGroup, UserRepoGroupToPerm, User, Permission, UserGroupRepoGroupToPerm, UserGroup, Repository) -from rhodecode.model.settings import VcsSettingsModel +from rhodecode.model.settings import VcsSettingsModel, SettingsModel from rhodecode.lib.caching_query import FromCache from rhodecode.lib.utils2 import action_logger_generic @@ -49,6 +49,7 @@ class RepoGroupModel(BaseModel): cls = RepoGroup PERSONAL_GROUP_DESC = '[personal] repo group: owner `%(username)s`' + PERSONAL_GROUP_PATTERN = '${username}' # default def _get_user_group(self, users_group): return self._get_instance(UserGroup, users_group, @@ -76,6 +77,39 @@ class RepoGroupModel(BaseModel): "sql_cache_short", "get_repo_group_%s" % repo_group_name)) return repo.scalar() + def get_default_create_personal_repo_group(self): + value = SettingsModel().get_setting_by_name( + 'create_personal_repo_group') + return value.app_settings_value if value else None or False + + def get_personal_group_name_pattern(self): + value = SettingsModel().get_setting_by_name( + 'personal_repo_group_pattern') + val = value.app_settings_value if value else None + group_template = val or self.PERSONAL_GROUP_PATTERN + + group_template = group_template.lstrip('/') + return group_template + + def get_personal_group_name(self, user): + template = self.get_personal_group_name_pattern() + return string.Template(template).safe_substitute( + username=user.username, + user_id=user.user_id, + ) + + def create_personal_repo_group(self, user, commit_early=True): + desc = self.PERSONAL_GROUP_DESC % {'username': user.username} + personal_repo_group_name = self.get_personal_group_name(user) + + # create a new one + RepoGroupModel().create( + group_name=personal_repo_group_name, + group_description=desc, + owner=user.username, + personal=True, + commit_early=commit_early) + def _create_default_perms(self, new_group): # create default permission default_perm = 'group.read' @@ -191,7 +225,7 @@ class RepoGroupModel(BaseModel): shutil.move(rm_path, os.path.join(self.repos_path, _d)) def create(self, group_name, group_description, owner, just_db=False, - copy_permissions=False, commit_early=True): + copy_permissions=False, personal=None, commit_early=True): (group_name_cleaned, parent_group_name) = RepoGroupModel()._get_group_name_and_parent(group_name) @@ -199,11 +233,18 @@ class RepoGroupModel(BaseModel): parent_group = None if parent_group_name: parent_group = self._get_repo_group(parent_group_name) + if not parent_group: + # we tried to create a nested group, but the parent is not + # existing + raise ValueError( + 'Parent group `%s` given in `%s` group name ' + 'is not yet existing.' % (parent_group_name, group_name)) - # becase we are doing a cleanup, we need to check if such directory - # already exists. If we don't do that we can accidentally delete existing - # directory via cleanup that can cause data issues, since delete does a - # folder rename to special syntax later cleanup functions can delete this + # because we are doing a cleanup, we need to check if such directory + # already exists. If we don't do that we can accidentally delete + # existing directory via cleanup that can cause data issues, since + # delete does a folder rename to special syntax later cleanup + # functions can delete this cleanup_group = self.check_exist_filesystem(group_name, exc_on_failure=False) try: @@ -213,6 +254,7 @@ class RepoGroupModel(BaseModel): new_repo_group.group_description = group_description or group_name new_repo_group.parent_group = parent_group new_repo_group.group_name = group_name + new_repo_group.personal = personal self.sa.add(new_repo_group) diff --git a/rhodecode/model/user.py b/rhodecode/model/user.py --- a/rhodecode/model/user.py +++ b/rhodecode/model/user.py @@ -35,7 +35,7 @@ from sqlalchemy.sql.expression import tr from rhodecode import events from rhodecode.lib.utils2 import ( safe_unicode, get_current_rhodecode_user, action_logger_generic, - AttributeDict) + AttributeDict, str2bool) from rhodecode.lib.caching_query import FromCache from rhodecode.model import BaseModel from rhodecode.model.auth_token import AuthTokenModel @@ -104,12 +104,13 @@ class UserModel(BaseModel): 'cur_user': cur_user } + if 'create_repo_group' in form_data: + user_data['create_repo_group'] = str2bool( + form_data.get('create_repo_group')) + try: - if form_data.get('create_repo_group'): - user_data['create_repo_group'] = True if form_data.get('password_change'): user_data['force_password_change'] = True - return UserModel().create_or_update(**user_data) except Exception: log.error(traceback.format_exc()) @@ -177,7 +178,7 @@ class UserModel(BaseModel): self, username, password, email, firstname='', lastname='', active=True, admin=False, extern_type=None, extern_name=None, cur_user=None, plugin=None, force_password_change=False, - allow_to_create_user=True, create_repo_group=False, + allow_to_create_user=True, create_repo_group=None, updating_user_id=None, language=None, strict_creation_check=True): """ Creates a new instance if not found, or updates current one @@ -222,8 +223,8 @@ class UserModel(BaseModel): # in case it's a plugin we don't care if not plugin: - # first check if we gave crypted password back, and if it matches - # it's not password change + # first check if we gave crypted password back, and if it + # matches it's not password change if new_user.password == password: return False @@ -233,6 +234,12 @@ class UserModel(BaseModel): return False + # read settings on default personal repo group creation + if create_repo_group is None: + default_create_repo_group = RepoGroupModel()\ + .get_default_create_personal_repo_group() + create_repo_group = default_create_repo_group + user_data = { 'username': username, 'password': password, @@ -319,17 +326,16 @@ class UserModel(BaseModel): self.sa.add(new_user) if not edit and create_repo_group: - # create new group same as username, and make this user an owner - desc = RepoGroupModel.PERSONAL_GROUP_DESC % {'username': username} - RepoGroupModel().create(group_name=username, - group_description=desc, - owner=username, commit_early=False) + RepoGroupModel().create_personal_repo_group( + new_user, commit_early=False) + if not edit: # add the RSS token AuthTokenModel().create(username, description='Generated feed token', role=AuthTokenModel.cls.ROLE_FEED) log_create_user(created_by=cur_user, **new_user.get_dict()) + events.trigger(events.UserPostCreate(user_data)) return new_user except (DatabaseError,): log.error(traceback.format_exc()) diff --git a/rhodecode/templates/admin/settings/settings_global.html b/rhodecode/templates/admin/settings/settings_global.html --- a/rhodecode/templates/admin/settings/settings_global.html +++ b/rhodecode/templates/admin/settings/settings_global.html @@ -30,6 +30,35 @@ + +
+
+

${_('Personal Repository Group')}

+
+
+
+ ${h.checkbox('rhodecode_create_personal_repo_group','True')} + +
+ + ${_('Always create Personal Repository Groups for new users.')}
+ ${_('When creating new users from add user form or API you can still turn this off via a checkbox or flag')} +
+ +
+ +
+
+ ${h.text('rhodecode_personal_repo_group_pattern',size=60, placeholder=c.personal_repo_group_default_pattern)} +
+ + ${_('Pattern used to create Personal Repository Groups. Prefix can be other existing repository group path[s], eg. /u/${username}')}
+ ${_('Available variables are currently ${username} and ${user_id}')} +
+
+
+ +

${_('Registration Captcha')}

diff --git a/rhodecode/templates/admin/users/user_add.html b/rhodecode/templates/admin/users/user_add.html --- a/rhodecode/templates/admin/users/user_add.html +++ b/rhodecode/templates/admin/users/user_add.html @@ -113,11 +113,14 @@
- +
- ${h.checkbox('create_repo_group',value=True)} - ${_('Add repository group with the same name as username. \nUser will be automatically set as this group owner.')} + ${h.checkbox('create_repo_group',value=True, checked=c.default_create_repo_group)} + + ${_('New group will be created at: `/%(path)s`') % {'path': c.personal_repo_group_name}}
+ ${_('User will be automatically set as this group owner.')} +
diff --git a/rhodecode/templates/admin/users/user_edit_advanced.html b/rhodecode/templates/admin/users/user_edit_advanced.html --- a/rhodecode/templates/admin/users/user_edit_advanced.html +++ b/rhodecode/templates/admin/users/user_edit_advanced.html @@ -61,7 +61,11 @@ %if c.personal_repo_group:
${_('Users personal repository group')} : ${h.link_to(c.personal_repo_group.group_name, url('repo_group_home', group_name=c.personal_repo_group.group_name))}
%else: -
${_('This user currently does not have a personal repository group')}
+
+ ${_('This user currently does not have a personal repository group')} +
+ ${_('New group will be created at: `/%(path)s`') % {'path': c.personal_repo_group_name}} +
%endif