##// END OF EJS Templates
repo-groups: implemented default personal repo groups logic....
marcink -
r1094:6b71b2c4 default
parent child Browse files
Show More
@@ -0,0 +1,27 b''
1 import logging
2
3 from sqlalchemy import Column, MetaData, Boolean
4
5 from rhodecode.lib.dbmigrate.versions import _reset_base
6
7 log = logging.getLogger(__name__)
8
9
10 def upgrade(migrate_engine):
11 """
12 Upgrade operations go here.
13 Don't create your own engine; bind migrate_engine to your metadata
14 """
15 _reset_base(migrate_engine)
16 from rhodecode.lib.dbmigrate.schema import db_4_5_0_0 as db
17
18 # Add personal column to RepoGroup table.
19 rg_table = db.RepoGroup.__table__
20 rg_col = Column(
21 'personal', Boolean(), nullable=True, unique=None, default=None)
22 rg_col.create(table=rg_table)
23
24
25 def downgrade(migrate_engine):
26 meta = MetaData()
27 meta.bind = migrate_engine
@@ -51,7 +51,7 b' PYRAMID_SETTINGS = {}'
51 EXTENSIONS = {}
51 EXTENSIONS = {}
52
52
53 __version__ = ('.'.join((str(each) for each in VERSION[:3])))
53 __version__ = ('.'.join((str(each) for each in VERSION[:3])))
54 __dbversion__ = 62 # defines current db version for migrations
54 __dbversion__ = 63 # defines current db version for migrations
55 __platform__ = platform.system()
55 __platform__ = platform.system()
56 __license__ = 'AGPLv3, and Commercial License'
56 __license__ = 'AGPLv3, and Commercial License'
57 __author__ = 'RhodeCode GmbH'
57 __author__ = 'RhodeCode GmbH'
@@ -25,7 +25,7 b' from rhodecode.api.utils import ('
25 Optional, OAttr, has_superadmin_permission, get_user_or_error, store_update)
25 Optional, OAttr, has_superadmin_permission, get_user_or_error, store_update)
26 from rhodecode.lib.auth import AuthUser, PasswordGenerator
26 from rhodecode.lib.auth import AuthUser, PasswordGenerator
27 from rhodecode.lib.exceptions import DefaultUserException
27 from rhodecode.lib.exceptions import DefaultUserException
28 from rhodecode.lib.utils2 import safe_int
28 from rhodecode.lib.utils2 import safe_int, str2bool
29 from rhodecode.model.db import Session, User, Repository
29 from rhodecode.model.db import Session, User, Repository
30 from rhodecode.model.user import UserModel
30 from rhodecode.model.user import UserModel
31
31
@@ -155,7 +155,8 b' def create_user(request, apiuser, userna'
155 active=Optional(True), admin=Optional(False),
155 active=Optional(True), admin=Optional(False),
156 extern_name=Optional('rhodecode'),
156 extern_name=Optional('rhodecode'),
157 extern_type=Optional('rhodecode'),
157 extern_type=Optional('rhodecode'),
158 force_password_change=Optional(False)):
158 force_password_change=Optional(False),
159 create_personal_repo_group=Optional(None)):
159 """
160 """
160 Creates a new user and returns the new user object.
161 Creates a new user and returns the new user object.
161
162
@@ -188,7 +189,8 b' def create_user(request, apiuser, userna'
188 :param force_password_change: Force the new user to change password
189 :param force_password_change: Force the new user to change password
189 on next login.
190 on next login.
190 :type force_password_change: Optional(``True`` | ``False``)
191 :type force_password_change: Optional(``True`` | ``False``)
191
192 :param create_personal_repo_group: Create personal repo group for this user
193 :type create_personal_repo_group: Optional(``True`` | ``False``)
192 Example output:
194 Example output:
193
195
194 .. code-block:: bash
196 .. code-block:: bash
@@ -230,6 +232,9 b' def create_user(request, apiuser, userna'
230 Optional.extract(extern_name) != 'rhodecode'):
232 Optional.extract(extern_name) != 'rhodecode'):
231 # generate temporary password if user is external
233 # generate temporary password if user is external
232 password = PasswordGenerator().gen_password(length=16)
234 password = PasswordGenerator().gen_password(length=16)
235 create_repo_group = Optional.extract(create_personal_repo_group)
236 if isinstance(create_repo_group, basestring):
237 create_repo_group = str2bool(create_repo_group)
233
238
234 try:
239 try:
235 user = UserModel().create_or_update(
240 user = UserModel().create_or_update(
@@ -243,6 +248,7 b' def create_user(request, apiuser, userna'
243 extern_type=Optional.extract(extern_type),
248 extern_type=Optional.extract(extern_type),
244 extern_name=Optional.extract(extern_name),
249 extern_name=Optional.extract(extern_name),
245 force_password_change=Optional.extract(force_password_change),
250 force_password_change=Optional.extract(force_password_change),
251 create_repo_group=create_repo_group
246 )
252 )
247 Session().commit()
253 Session().commit()
248 return {
254 return {
@@ -160,6 +160,7 b' class ReposController(BaseRepoController'
160 self.__load_defaults()
160 self.__load_defaults()
161 form_result = {}
161 form_result = {}
162 task_id = None
162 task_id = None
163 c.personal_repo_group = c.rhodecode_user.personal_repo_group
163 try:
164 try:
164 # CanWriteToGroup validators checks permissions of this POST
165 # CanWriteToGroup validators checks permissions of this POST
165 form_result = RepoForm(repo_groups=c.repo_groups_choices,
166 form_result = RepoForm(repo_groups=c.repo_groups_choices,
@@ -173,8 +174,6 b' class ReposController(BaseRepoController'
173 if isinstance(task, BaseAsyncResult):
174 if isinstance(task, BaseAsyncResult):
174 task_id = task.task_id
175 task_id = task.task_id
175 except formencode.Invalid as errors:
176 except formencode.Invalid as errors:
176 c.personal_repo_group = RepoGroup.get_by_group_name(
177 c.rhodecode_user.username)
178 return htmlfill.render(
177 return htmlfill.render(
179 render('admin/repos/repo_add.html'),
178 render('admin/repos/repo_add.html'),
180 defaults=errors.value,
179 defaults=errors.value,
@@ -215,7 +214,7 b' class ReposController(BaseRepoController'
215 c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
214 c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
216 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
215 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
217 choices, c.landing_revs = ScmModel().get_repo_landing_revs()
216 choices, c.landing_revs = ScmModel().get_repo_landing_revs()
218 c.personal_repo_group = RepoGroup.get_by_group_name(c.rhodecode_user.username)
217 c.personal_repo_group = c.rhodecode_user.personal_repo_group
219 c.new_repo = repo_name_slug(new_repo)
218 c.new_repo = repo_name_slug(new_repo)
220
219
221 ## apply the defaults from defaults page
220 ## apply the defaults from defaults page
@@ -299,9 +298,8 b' class ReposController(BaseRepoController'
299 repo_model = RepoModel()
298 repo_model = RepoModel()
300 changed_name = repo_name
299 changed_name = repo_name
301
300
301 c.personal_repo_group = c.rhodecode_user.personal_repo_group
302 # override the choices with extracted revisions !
302 # override the choices with extracted revisions !
303 c.personal_repo_group = RepoGroup.get_by_group_name(
304 c.rhodecode_user.username)
305 repo = Repository.get_by_repo_name(repo_name)
303 repo = Repository.get_by_repo_name(repo_name)
306 old_data = {
304 old_data = {
307 'repo_name': repo_name,
305 'repo_name': repo_name,
@@ -399,8 +397,7 b' class ReposController(BaseRepoController'
399
397
400 c.repo_fields = RepositoryField.query()\
398 c.repo_fields = RepositoryField.query()\
401 .filter(RepositoryField.repository == c.repo_info).all()
399 .filter(RepositoryField.repository == c.repo_info).all()
402 c.personal_repo_group = RepoGroup.get_by_group_name(
400 c.personal_repo_group = c.rhodecode_user.personal_repo_group
403 c.rhodecode_user.username)
404 c.active = 'settings'
401 c.active = 'settings'
405 return htmlfill.render(
402 return htmlfill.render(
406 render('admin/repos/repo_edit.html'),
403 render('admin/repos/repo_edit.html'),
@@ -55,6 +55,7 b' from rhodecode.model.db import RhodeCode'
55 from rhodecode.model.forms import ApplicationSettingsForm, \
55 from rhodecode.model.forms import ApplicationSettingsForm, \
56 ApplicationUiSettingsForm, ApplicationVisualisationForm, \
56 ApplicationUiSettingsForm, ApplicationVisualisationForm, \
57 LabsSettingsForm, IssueTrackerPatternsForm
57 LabsSettingsForm, IssueTrackerPatternsForm
58 from rhodecode.model.repo_group import RepoGroupModel
58
59
59 from rhodecode.model.scm import ScmModel
60 from rhodecode.model.scm import ScmModel
60 from rhodecode.model.notification import EmailNotificationModel
61 from rhodecode.model.notification import EmailNotificationModel
@@ -245,6 +246,8 b' class SettingsController(BaseController)'
245 """POST /admin/settings/global: All items in the collection"""
246 """POST /admin/settings/global: All items in the collection"""
246 # url('admin_settings_global')
247 # url('admin_settings_global')
247 c.active = 'global'
248 c.active = 'global'
249 c.personal_repo_group_default_pattern = RepoGroupModel()\
250 .get_personal_group_name_pattern()
248 application_form = ApplicationSettingsForm()()
251 application_form = ApplicationSettingsForm()()
249 try:
252 try:
250 form_result = application_form.to_python(dict(request.POST))
253 form_result = application_form.to_python(dict(request.POST))
@@ -259,16 +262,18 b' class SettingsController(BaseController)'
259
262
260 try:
263 try:
261 settings = [
264 settings = [
262 ('title', 'rhodecode_title'),
265 ('title', 'rhodecode_title', 'unicode'),
263 ('realm', 'rhodecode_realm'),
266 ('realm', 'rhodecode_realm', 'unicode'),
264 ('pre_code', 'rhodecode_pre_code'),
267 ('pre_code', 'rhodecode_pre_code', 'unicode'),
265 ('post_code', 'rhodecode_post_code'),
268 ('post_code', 'rhodecode_post_code', 'unicode'),
266 ('captcha_public_key', 'rhodecode_captcha_public_key'),
269 ('captcha_public_key', 'rhodecode_captcha_public_key', 'unicode'),
267 ('captcha_private_key', 'rhodecode_captcha_private_key'),
270 ('captcha_private_key', 'rhodecode_captcha_private_key', 'unicode'),
271 ('create_personal_repo_group', 'rhodecode_create_personal_repo_group', 'bool'),
272 ('personal_repo_group_pattern', 'rhodecode_personal_repo_group_pattern', 'unicode'),
268 ]
273 ]
269 for setting, form_key in settings:
274 for setting, form_key, type_ in settings:
270 sett = SettingsModel().create_or_update_setting(
275 sett = SettingsModel().create_or_update_setting(
271 setting, form_result[form_key])
276 setting, form_result[form_key], type_)
272 Session().add(sett)
277 Session().add(sett)
273
278
274 Session().commit()
279 Session().commit()
@@ -287,6 +292,8 b' class SettingsController(BaseController)'
287 """GET /admin/settings/global: All items in the collection"""
292 """GET /admin/settings/global: All items in the collection"""
288 # url('admin_settings_global')
293 # url('admin_settings_global')
289 c.active = 'global'
294 c.active = 'global'
295 c.personal_repo_group_default_pattern = RepoGroupModel()\
296 .get_personal_group_name_pattern()
290
297
291 return htmlfill.render(
298 return htmlfill.render(
292 render('admin/settings/settings.html'),
299 render('admin/settings/settings.html'),
@@ -45,12 +45,13 b' from rhodecode.model.db import ('
45 PullRequestReviewers, User, UserEmailMap, UserIpMap, RepoGroup)
45 PullRequestReviewers, User, UserEmailMap, UserIpMap, RepoGroup)
46 from rhodecode.model.forms import (
46 from rhodecode.model.forms import (
47 UserForm, UserPermissionsForm, UserIndividualPermissionsForm)
47 UserForm, UserPermissionsForm, UserIndividualPermissionsForm)
48 from rhodecode.model.repo_group import RepoGroupModel
48 from rhodecode.model.user import UserModel
49 from rhodecode.model.user import UserModel
49 from rhodecode.model.meta import Session
50 from rhodecode.model.meta import Session
50 from rhodecode.model.permission import PermissionModel
51 from rhodecode.model.permission import PermissionModel
51 from rhodecode.lib.utils import action_logger
52 from rhodecode.lib.utils import action_logger
52 from rhodecode.lib.ext_json import json
53 from rhodecode.lib.ext_json import json
53 from rhodecode.lib.utils2 import datetime_to_time, safe_int
54 from rhodecode.lib.utils2 import datetime_to_time, safe_int, AttributeDict
54
55
55 log = logging.getLogger(__name__)
56 log = logging.getLogger(__name__)
56
57
@@ -120,6 +121,16 b' class UsersController(BaseController):'
120 c.data = json.dumps(users_data)
121 c.data = json.dumps(users_data)
121 return render('admin/users/users.html')
122 return render('admin/users/users.html')
122
123
124 def _get_personal_repo_group_template_vars(self):
125 DummyUser = AttributeDict({
126 'username': '${username}',
127 'user_id': '${user_id}',
128 })
129 c.default_create_repo_group = RepoGroupModel() \
130 .get_default_create_personal_repo_group()
131 c.personal_repo_group_name = RepoGroupModel() \
132 .get_personal_group_name(DummyUser)
133
123 @HasPermissionAllDecorator('hg.admin')
134 @HasPermissionAllDecorator('hg.admin')
124 @auth.CSRFRequired()
135 @auth.CSRFRequired()
125 def create(self):
136 def create(self):
@@ -143,6 +154,7 b' class UsersController(BaseController):'
143 % {'user_link': user_link}), category='success')
154 % {'user_link': user_link}), category='success')
144 Session().commit()
155 Session().commit()
145 except formencode.Invalid as errors:
156 except formencode.Invalid as errors:
157 self._get_personal_repo_group_template_vars()
146 return htmlfill.render(
158 return htmlfill.render(
147 render('admin/users/user_add.html'),
159 render('admin/users/user_add.html'),
148 defaults=errors.value,
160 defaults=errors.value,
@@ -163,6 +175,7 b' class UsersController(BaseController):'
163 """GET /users/new: Form to create a new item"""
175 """GET /users/new: Form to create a new item"""
164 # url('new_user')
176 # url('new_user')
165 c.default_extern_type = auth_rhodecode.RhodeCodeAuthPlugin.name
177 c.default_extern_type = auth_rhodecode.RhodeCodeAuthPlugin.name
178 self._get_personal_repo_group_template_vars()
166 return render('admin/users/user_add.html')
179 return render('admin/users/user_add.html')
167
180
168 @HasPermissionAllDecorator('hg.admin')
181 @HasPermissionAllDecorator('hg.admin')
@@ -339,22 +352,41 b' class UsersController(BaseController):'
339
352
340 user_id = safe_int(user_id)
353 user_id = safe_int(user_id)
341 c.user = User.get_or_404(user_id)
354 c.user = User.get_or_404(user_id)
355 personal_repo_group = RepoGroup.get_user_personal_repo_group(
356 c.user.user_id)
357 if personal_repo_group:
358 return redirect(url('edit_user_advanced', user_id=user_id))
342
359
360 personal_repo_group_name = RepoGroupModel().get_personal_group_name(
361 c.user)
362 named_personal_group = RepoGroup.get_by_group_name(
363 personal_repo_group_name)
343 try:
364 try:
344 desc = RepoGroupModel.PERSONAL_GROUP_DESC % {
345 'username': c.user.username}
346 if not RepoGroup.get_by_group_name(c.user.username):
347 RepoGroupModel().create(group_name=c.user.username,
348 group_description=desc,
349 owner=c.user.username)
350
365
351 msg = _('Created repository group `%s`' % (c.user.username,))
366 if named_personal_group and named_personal_group.user_id == c.user.user_id:
367 # migrate the same named group, and mark it as personal
368 named_personal_group.personal = True
369 Session().add(named_personal_group)
370 Session().commit()
371 msg = _('Linked repository group `%s` as personal' % (
372 personal_repo_group_name,))
352 h.flash(msg, category='success')
373 h.flash(msg, category='success')
374 elif not named_personal_group:
375 RepoGroupModel().create_personal_repo_group(c.user)
376
377 msg = _('Created repository group `%s`' % (
378 personal_repo_group_name,))
379 h.flash(msg, category='success')
380 else:
381 msg = _('Repository group `%s` is already taken' % (
382 personal_repo_group_name,))
383 h.flash(msg, category='warning')
353 except Exception:
384 except Exception:
354 log.exception("Exception during repository group creation")
385 log.exception("Exception during repository group creation")
355 msg = _(
386 msg = _(
356 'An error occurred during repository group creation for user')
387 'An error occurred during repository group creation for user')
357 h.flash(msg, category='error')
388 h.flash(msg, category='error')
389 Session().rollback()
358
390
359 return redirect(url('edit_user_advanced', user_id=user_id))
391 return redirect(url('edit_user_advanced', user_id=user_id))
360
392
@@ -397,7 +429,9 b' class UsersController(BaseController):'
397
429
398 c.active = 'advanced'
430 c.active = 'advanced'
399 c.perm_user = AuthUser(user_id=user_id, ip_addr=self.ip_addr)
431 c.perm_user = AuthUser(user_id=user_id, ip_addr=self.ip_addr)
400 c.personal_repo_group = RepoGroup.get_by_group_name(user.username)
432 c.personal_repo_group = c.perm_user.personal_repo_group
433 c.personal_repo_group_name = RepoGroupModel()\
434 .get_personal_group_name(user)
401 c.first_admin = User.get_first_super_admin()
435 c.first_admin = User.get_first_super_admin()
402 defaults = user.get_dict()
436 defaults = user.get_dict()
403
437
@@ -60,8 +60,7 b' class ForksController(BaseRepoController'
60 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
60 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
61 choices, c.landing_revs = ScmModel().get_repo_landing_revs()
61 choices, c.landing_revs = ScmModel().get_repo_landing_revs()
62 c.landing_revs_choices = choices
62 c.landing_revs_choices = choices
63 c.personal_repo_group = RepoGroup.get_by_group_name(
63 c.personal_repo_group = c.rhodecode_user.personal_repo_group
64 c.rhodecode_user.username)
65
64
66 def __load_data(self, repo_name=None):
65 def __load_data(self, repo_name=None):
67 """
66 """
@@ -48,6 +48,7 b' from rhodecode.events.base import Rhodec'
48
48
49 from rhodecode.events.user import ( # noqa
49 from rhodecode.events.user import ( # noqa
50 UserPreCreate,
50 UserPreCreate,
51 UserPostCreate,
51 UserPreUpdate,
52 UserPreUpdate,
52 UserRegistered
53 UserRegistered
53 )
54 )
@@ -51,6 +51,19 b' class UserPreCreate(RhodecodeEvent):'
51 self.user_data = user_data
51 self.user_data = user_data
52
52
53
53
54 @implementer(IUserPreCreate)
55 class UserPostCreate(RhodecodeEvent):
56 """
57 An instance of this class is emitted as an :term:`event` after a new user
58 object is created.
59 """
60 name = 'user-post-create'
61 display_name = lazy_ugettext('user post create')
62
63 def __init__(self, user_data):
64 self.user_data = user_data
65
66
54 @implementer(IUserPreUpdate)
67 @implementer(IUserPreUpdate)
55 class UserPreUpdate(RhodecodeEvent):
68 class UserPreUpdate(RhodecodeEvent):
56 """
69 """
@@ -49,7 +49,7 b' from rhodecode.model.meta import Session'
49 from rhodecode.model.user import UserModel
49 from rhodecode.model.user import UserModel
50 from rhodecode.model.db import (
50 from rhodecode.model.db import (
51 User, Repository, Permission, UserToPerm, UserGroupToPerm, UserGroupMember,
51 User, Repository, Permission, UserToPerm, UserGroupToPerm, UserGroupMember,
52 UserIpMap, UserApiKeys)
52 UserIpMap, UserApiKeys, RepoGroup)
53 from rhodecode.lib import caches
53 from rhodecode.lib import caches
54 from rhodecode.lib.utils2 import safe_unicode, aslist, safe_str, md5
54 from rhodecode.lib.utils2 import safe_unicode, aslist, safe_str, md5
55 from rhodecode.lib.utils import (
55 from rhodecode.lib.utils import (
@@ -983,6 +983,9 b' class AuthUser(object):'
983 inherit = self.inherit_default_permissions
983 inherit = self.inherit_default_permissions
984 return AuthUser.check_ip_allowed(self.user_id, self.ip_addr,
984 return AuthUser.check_ip_allowed(self.user_id, self.ip_addr,
985 inherit_from_default=inherit)
985 inherit_from_default=inherit)
986 @property
987 def personal_repo_group(self):
988 return RepoGroup.get_user_personal_repo_group(self.user_id)
986
989
987 @classmethod
990 @classmethod
988 def check_ip_allowed(cls, user_id, ip_addr, inherit_from_default):
991 def check_ip_allowed(cls, user_id, ip_addr, inherit_from_default):
@@ -96,7 +96,7 b' def __get_lem(extra_mapping=None):'
96
96
97 def str2bool(_str):
97 def str2bool(_str):
98 """
98 """
99 returs True/False value from given string, it tries to translate the
99 returns True/False value from given string, it tries to translate the
100 string into boolean
100 string into boolean
101
101
102 :param _str: string value to translate into boolean
102 :param _str: string value to translate into boolean
@@ -2028,6 +2028,7 b' class RepoGroup(Base, BaseModel):'
2028 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
2028 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
2029 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
2029 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
2030 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
2030 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
2031 personal = Column('personal', Boolean(), nullable=True, unique=None, default=None)
2031
2032
2032 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
2033 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
2033 users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
2034 users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
@@ -2083,6 +2084,13 b' class RepoGroup(Base, BaseModel):'
2083 return gr.scalar()
2084 return gr.scalar()
2084
2085
2085 @classmethod
2086 @classmethod
2087 def get_user_personal_repo_group(cls, user_id):
2088 user = User.get(user_id)
2089 return cls.query()\
2090 .filter(cls.personal == true())\
2091 .filter(cls.user == user).scalar()
2092
2093 @classmethod
2086 def get_all_repo_groups(cls, user_id=Optional(None), group_id=Optional(None),
2094 def get_all_repo_groups(cls, user_id=Optional(None), group_id=Optional(None),
2087 case_insensitive=True):
2095 case_insensitive=True):
2088 q = RepoGroup.query()
2096 q = RepoGroup.query()
@@ -341,6 +341,8 b' def ApplicationSettingsForm():'
341 rhodecode_post_code = v.UnicodeString(strip=True, min=1, not_empty=False)
341 rhodecode_post_code = v.UnicodeString(strip=True, min=1, not_empty=False)
342 rhodecode_captcha_public_key = v.UnicodeString(strip=True, min=1, not_empty=False)
342 rhodecode_captcha_public_key = v.UnicodeString(strip=True, min=1, not_empty=False)
343 rhodecode_captcha_private_key = v.UnicodeString(strip=True, min=1, not_empty=False)
343 rhodecode_captcha_private_key = v.UnicodeString(strip=True, min=1, not_empty=False)
344 rhodecode_create_personal_repo_group = v.StringBoolean(if_missing=False)
345 rhodecode_personal_repo_group_pattern = v.UnicodeString(strip=True, min=1, not_empty=False)
344
346
345 return _ApplicationSettingsForm
347 return _ApplicationSettingsForm
346
348
@@ -23,13 +23,13 b''
23 repo group model for RhodeCode
23 repo group model for RhodeCode
24 """
24 """
25
25
26
26 import os
27 import datetime
27 import datetime
28 import itertools
28 import itertools
29 import logging
29 import logging
30 import os
31 import shutil
30 import shutil
32 import traceback
31 import traceback
32 import string
33
33
34 from zope.cachedescriptors.property import Lazy as LazyProperty
34 from zope.cachedescriptors.property import Lazy as LazyProperty
35
35
@@ -38,7 +38,7 b' from rhodecode.model import BaseModel'
38 from rhodecode.model.db import (
38 from rhodecode.model.db import (
39 RepoGroup, UserRepoGroupToPerm, User, Permission, UserGroupRepoGroupToPerm,
39 RepoGroup, UserRepoGroupToPerm, User, Permission, UserGroupRepoGroupToPerm,
40 UserGroup, Repository)
40 UserGroup, Repository)
41 from rhodecode.model.settings import VcsSettingsModel
41 from rhodecode.model.settings import VcsSettingsModel, SettingsModel
42 from rhodecode.lib.caching_query import FromCache
42 from rhodecode.lib.caching_query import FromCache
43 from rhodecode.lib.utils2 import action_logger_generic
43 from rhodecode.lib.utils2 import action_logger_generic
44
44
@@ -49,6 +49,7 b' class RepoGroupModel(BaseModel):'
49
49
50 cls = RepoGroup
50 cls = RepoGroup
51 PERSONAL_GROUP_DESC = '[personal] repo group: owner `%(username)s`'
51 PERSONAL_GROUP_DESC = '[personal] repo group: owner `%(username)s`'
52 PERSONAL_GROUP_PATTERN = '${username}' # default
52
53
53 def _get_user_group(self, users_group):
54 def _get_user_group(self, users_group):
54 return self._get_instance(UserGroup, users_group,
55 return self._get_instance(UserGroup, users_group,
@@ -76,6 +77,39 b' class RepoGroupModel(BaseModel):'
76 "sql_cache_short", "get_repo_group_%s" % repo_group_name))
77 "sql_cache_short", "get_repo_group_%s" % repo_group_name))
77 return repo.scalar()
78 return repo.scalar()
78
79
80 def get_default_create_personal_repo_group(self):
81 value = SettingsModel().get_setting_by_name(
82 'create_personal_repo_group')
83 return value.app_settings_value if value else None or False
84
85 def get_personal_group_name_pattern(self):
86 value = SettingsModel().get_setting_by_name(
87 'personal_repo_group_pattern')
88 val = value.app_settings_value if value else None
89 group_template = val or self.PERSONAL_GROUP_PATTERN
90
91 group_template = group_template.lstrip('/')
92 return group_template
93
94 def get_personal_group_name(self, user):
95 template = self.get_personal_group_name_pattern()
96 return string.Template(template).safe_substitute(
97 username=user.username,
98 user_id=user.user_id,
99 )
100
101 def create_personal_repo_group(self, user, commit_early=True):
102 desc = self.PERSONAL_GROUP_DESC % {'username': user.username}
103 personal_repo_group_name = self.get_personal_group_name(user)
104
105 # create a new one
106 RepoGroupModel().create(
107 group_name=personal_repo_group_name,
108 group_description=desc,
109 owner=user.username,
110 personal=True,
111 commit_early=commit_early)
112
79 def _create_default_perms(self, new_group):
113 def _create_default_perms(self, new_group):
80 # create default permission
114 # create default permission
81 default_perm = 'group.read'
115 default_perm = 'group.read'
@@ -191,7 +225,7 b' class RepoGroupModel(BaseModel):'
191 shutil.move(rm_path, os.path.join(self.repos_path, _d))
225 shutil.move(rm_path, os.path.join(self.repos_path, _d))
192
226
193 def create(self, group_name, group_description, owner, just_db=False,
227 def create(self, group_name, group_description, owner, just_db=False,
194 copy_permissions=False, commit_early=True):
228 copy_permissions=False, personal=None, commit_early=True):
195
229
196 (group_name_cleaned,
230 (group_name_cleaned,
197 parent_group_name) = RepoGroupModel()._get_group_name_and_parent(group_name)
231 parent_group_name) = RepoGroupModel()._get_group_name_and_parent(group_name)
@@ -199,11 +233,18 b' class RepoGroupModel(BaseModel):'
199 parent_group = None
233 parent_group = None
200 if parent_group_name:
234 if parent_group_name:
201 parent_group = self._get_repo_group(parent_group_name)
235 parent_group = self._get_repo_group(parent_group_name)
236 if not parent_group:
237 # we tried to create a nested group, but the parent is not
238 # existing
239 raise ValueError(
240 'Parent group `%s` given in `%s` group name '
241 'is not yet existing.' % (parent_group_name, group_name))
202
242
203 # becase we are doing a cleanup, we need to check if such directory
243 # because we are doing a cleanup, we need to check if such directory
204 # already exists. If we don't do that we can accidentally delete existing
244 # already exists. If we don't do that we can accidentally delete
205 # directory via cleanup that can cause data issues, since delete does a
245 # existing directory via cleanup that can cause data issues, since
206 # folder rename to special syntax later cleanup functions can delete this
246 # delete does a folder rename to special syntax later cleanup
247 # functions can delete this
207 cleanup_group = self.check_exist_filesystem(group_name,
248 cleanup_group = self.check_exist_filesystem(group_name,
208 exc_on_failure=False)
249 exc_on_failure=False)
209 try:
250 try:
@@ -213,6 +254,7 b' class RepoGroupModel(BaseModel):'
213 new_repo_group.group_description = group_description or group_name
254 new_repo_group.group_description = group_description or group_name
214 new_repo_group.parent_group = parent_group
255 new_repo_group.parent_group = parent_group
215 new_repo_group.group_name = group_name
256 new_repo_group.group_name = group_name
257 new_repo_group.personal = personal
216
258
217 self.sa.add(new_repo_group)
259 self.sa.add(new_repo_group)
218
260
@@ -35,7 +35,7 b' from sqlalchemy.sql.expression import tr'
35 from rhodecode import events
35 from rhodecode import events
36 from rhodecode.lib.utils2 import (
36 from rhodecode.lib.utils2 import (
37 safe_unicode, get_current_rhodecode_user, action_logger_generic,
37 safe_unicode, get_current_rhodecode_user, action_logger_generic,
38 AttributeDict)
38 AttributeDict, str2bool)
39 from rhodecode.lib.caching_query import FromCache
39 from rhodecode.lib.caching_query import FromCache
40 from rhodecode.model import BaseModel
40 from rhodecode.model import BaseModel
41 from rhodecode.model.auth_token import AuthTokenModel
41 from rhodecode.model.auth_token import AuthTokenModel
@@ -104,12 +104,13 b' class UserModel(BaseModel):'
104 'cur_user': cur_user
104 'cur_user': cur_user
105 }
105 }
106
106
107 if 'create_repo_group' in form_data:
108 user_data['create_repo_group'] = str2bool(
109 form_data.get('create_repo_group'))
110
107 try:
111 try:
108 if form_data.get('create_repo_group'):
109 user_data['create_repo_group'] = True
110 if form_data.get('password_change'):
112 if form_data.get('password_change'):
111 user_data['force_password_change'] = True
113 user_data['force_password_change'] = True
112
113 return UserModel().create_or_update(**user_data)
114 return UserModel().create_or_update(**user_data)
114 except Exception:
115 except Exception:
115 log.error(traceback.format_exc())
116 log.error(traceback.format_exc())
@@ -177,7 +178,7 b' class UserModel(BaseModel):'
177 self, username, password, email, firstname='', lastname='',
178 self, username, password, email, firstname='', lastname='',
178 active=True, admin=False, extern_type=None, extern_name=None,
179 active=True, admin=False, extern_type=None, extern_name=None,
179 cur_user=None, plugin=None, force_password_change=False,
180 cur_user=None, plugin=None, force_password_change=False,
180 allow_to_create_user=True, create_repo_group=False,
181 allow_to_create_user=True, create_repo_group=None,
181 updating_user_id=None, language=None, strict_creation_check=True):
182 updating_user_id=None, language=None, strict_creation_check=True):
182 """
183 """
183 Creates a new instance if not found, or updates current one
184 Creates a new instance if not found, or updates current one
@@ -222,8 +223,8 b' class UserModel(BaseModel):'
222 # in case it's a plugin we don't care
223 # in case it's a plugin we don't care
223 if not plugin:
224 if not plugin:
224
225
225 # first check if we gave crypted password back, and if it matches
226 # first check if we gave crypted password back, and if it
226 # it's not password change
227 # matches it's not password change
227 if new_user.password == password:
228 if new_user.password == password:
228 return False
229 return False
229
230
@@ -233,6 +234,12 b' class UserModel(BaseModel):'
233
234
234 return False
235 return False
235
236
237 # read settings on default personal repo group creation
238 if create_repo_group is None:
239 default_create_repo_group = RepoGroupModel()\
240 .get_default_create_personal_repo_group()
241 create_repo_group = default_create_repo_group
242
236 user_data = {
243 user_data = {
237 'username': username,
244 'username': username,
238 'password': password,
245 'password': password,
@@ -319,17 +326,16 b' class UserModel(BaseModel):'
319 self.sa.add(new_user)
326 self.sa.add(new_user)
320
327
321 if not edit and create_repo_group:
328 if not edit and create_repo_group:
322 # create new group same as username, and make this user an owner
329 RepoGroupModel().create_personal_repo_group(
323 desc = RepoGroupModel.PERSONAL_GROUP_DESC % {'username': username}
330 new_user, commit_early=False)
324 RepoGroupModel().create(group_name=username,
331
325 group_description=desc,
326 owner=username, commit_early=False)
327 if not edit:
332 if not edit:
328 # add the RSS token
333 # add the RSS token
329 AuthTokenModel().create(username,
334 AuthTokenModel().create(username,
330 description='Generated feed token',
335 description='Generated feed token',
331 role=AuthTokenModel.cls.ROLE_FEED)
336 role=AuthTokenModel.cls.ROLE_FEED)
332 log_create_user(created_by=cur_user, **new_user.get_dict())
337 log_create_user(created_by=cur_user, **new_user.get_dict())
338 events.trigger(events.UserPostCreate(user_data))
333 return new_user
339 return new_user
334 except (DatabaseError,):
340 except (DatabaseError,):
335 log.error(traceback.format_exc())
341 log.error(traceback.format_exc())
@@ -30,6 +30,35 b''
30 </div>
30 </div>
31 </div>
31 </div>
32
32
33
34 <div class="panel panel-default">
35 <div class="panel-heading" id="personal-group-options">
36 <h3 class="panel-title">${_('Personal Repository Group')} <a class="permalink" href="#personal-group-options"></a></h3>
37 </div>
38 <div class="panel-body">
39 <div class="checkbox">
40 ${h.checkbox('rhodecode_create_personal_repo_group','True')}
41 <label for="rhodecode_create_personal_repo_group">${_('Create Personal Repository Group')}</label>
42 </div>
43 <span class="help-block">
44 ${_('Always create Personal Repository Groups for new users.')} <br/>
45 ${_('When creating new users from add user form or API you can still turn this off via a checkbox or flag')}
46 </span>
47
48 <div class="label">
49 <label for="rhodecode_personal_repo_group_pattern">${_('Personal Repo Group Pattern')}</label>
50 </div>
51 <div class="field input">
52 ${h.text('rhodecode_personal_repo_group_pattern',size=60, placeholder=c.personal_repo_group_default_pattern)}
53 </div>
54 <span class="help-block">
55 ${_('Pattern used to create Personal Repository Groups. Prefix can be other existing repository group path[s], eg. /u/${username}')} <br/>
56 ${_('Available variables are currently ${username} and ${user_id}')}
57 </span>
58 </div>
59 </div>
60
61
33 <div class="panel panel-default">
62 <div class="panel panel-default">
34 <div class="panel-heading" id="captcha-options">
63 <div class="panel-heading" id="captcha-options">
35 <h3 class="panel-title">${_('Registration Captcha')} <a class="permalink" href="#captcha-options"></a></h3>
64 <h3 class="panel-title">${_('Registration Captcha')} <a class="permalink" href="#captcha-options"></a></h3>
@@ -113,11 +113,14 b''
113
113
114 <div class="field">
114 <div class="field">
115 <div class="label label-checkbox">
115 <div class="label label-checkbox">
116 <label for="create_repo_group">${_('Add repository group')}:</label>
116 <label for="create_repo_group">${_('Add personal repository group')}:</label>
117 </div>
117 </div>
118 <div class="checkboxes">
118 <div class="checkboxes">
119 ${h.checkbox('create_repo_group',value=True)}
119 ${h.checkbox('create_repo_group',value=True, checked=c.default_create_repo_group)}
120 <span class="help-block">${_('Add repository group with the same name as username. \nUser will be automatically set as this group owner.')}</span>
120 <span class="help-block">
121 ${_('New group will be created at: `/%(path)s`') % {'path': c.personal_repo_group_name}}<br/>
122 ${_('User will be automatically set as this group owner.')}
123 </span>
121 </div>
124 </div>
122 </div>
125 </div>
123
126
@@ -61,7 +61,11 b''
61 %if c.personal_repo_group:
61 %if c.personal_repo_group:
62 <div class="panel-body-title-text">${_('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))}</div>
62 <div class="panel-body-title-text">${_('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))}</div>
63 %else:
63 %else:
64 <div class="panel-body-title-text">${_('This user currently does not have a personal repository group')}</div>
64 <div class="panel-body-title-text">
65 ${_('This user currently does not have a personal repository group')}
66 <br/>
67 ${_('New group will be created at: `/%(path)s`') % {'path': c.personal_repo_group_name}}
68 </div>
65 %endif
69 %endif
66 <button class="btn btn-default" type="submit" ${'disabled="disabled"' if c.personal_repo_group else ''}>
70 <button class="btn btn-default" type="submit" ${'disabled="disabled"' if c.personal_repo_group else ''}>
67 <i class="icon-folder-close"></i>
71 <i class="icon-folder-close"></i>
@@ -338,6 +338,9 b''
338 <div class="">
338 <div class="">
339 <ol class="links">
339 <ol class="links">
340 <li>${h.link_to(_(u'My account'),h.url('my_account'))}</li>
340 <li>${h.link_to(_(u'My account'),h.url('my_account'))}</li>
341 % if c.rhodecode_user.personal_repo_group:
342 <li>${h.link_to(_(u'My personal group'), h.url('repo_group_home', group_name=c.rhodecode_user.personal_repo_group.group_name))}</li>
343 % endif
341 <li class="logout">
344 <li class="logout">
342 ${h.secure_form(h.route_path('logout'))}
345 ${h.secure_form(h.route_path('logout'))}
343 ${h.submit('log_out', _(u'Sign Out'),class_="btn btn-primary")}
346 ${h.submit('log_out', _(u'Sign Out'),class_="btn btn-primary")}
General Comments 0
You need to be logged in to leave comments. Login now