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 | 51 | EXTENSIONS = {} |
|
52 | 52 | |
|
53 | 53 | __version__ = ('.'.join((str(each) for each in VERSION[:3]))) |
|
54 |
__dbversion__ = 6 |
|
|
54 | __dbversion__ = 63 # defines current db version for migrations | |
|
55 | 55 | __platform__ = platform.system() |
|
56 | 56 | __license__ = 'AGPLv3, and Commercial License' |
|
57 | 57 | __author__ = 'RhodeCode GmbH' |
@@ -25,7 +25,7 b' from rhodecode.api.utils import (' | |||
|
25 | 25 | Optional, OAttr, has_superadmin_permission, get_user_or_error, store_update) |
|
26 | 26 | from rhodecode.lib.auth import AuthUser, PasswordGenerator |
|
27 | 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 | 29 | from rhodecode.model.db import Session, User, Repository |
|
30 | 30 | from rhodecode.model.user import UserModel |
|
31 | 31 | |
@@ -155,7 +155,8 b' def create_user(request, apiuser, userna' | |||
|
155 | 155 | active=Optional(True), admin=Optional(False), |
|
156 | 156 | extern_name=Optional('rhodecode'), |
|
157 | 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 | 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 | 189 | :param force_password_change: Force the new user to change password |
|
189 | 190 | on next login. |
|
190 | 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 | 194 | Example output: |
|
193 | 195 | |
|
194 | 196 | .. code-block:: bash |
@@ -230,6 +232,9 b' def create_user(request, apiuser, userna' | |||
|
230 | 232 | Optional.extract(extern_name) != 'rhodecode'): |
|
231 | 233 | # generate temporary password if user is external |
|
232 | 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 | 239 | try: |
|
235 | 240 | user = UserModel().create_or_update( |
@@ -243,6 +248,7 b' def create_user(request, apiuser, userna' | |||
|
243 | 248 | extern_type=Optional.extract(extern_type), |
|
244 | 249 | extern_name=Optional.extract(extern_name), |
|
245 | 250 | force_password_change=Optional.extract(force_password_change), |
|
251 | create_repo_group=create_repo_group | |
|
246 | 252 | ) |
|
247 | 253 | Session().commit() |
|
248 | 254 | return { |
@@ -160,6 +160,7 b' class ReposController(BaseRepoController' | |||
|
160 | 160 | self.__load_defaults() |
|
161 | 161 | form_result = {} |
|
162 | 162 | task_id = None |
|
163 | c.personal_repo_group = c.rhodecode_user.personal_repo_group | |
|
163 | 164 | try: |
|
164 | 165 | # CanWriteToGroup validators checks permissions of this POST |
|
165 | 166 | form_result = RepoForm(repo_groups=c.repo_groups_choices, |
@@ -173,8 +174,6 b' class ReposController(BaseRepoController' | |||
|
173 | 174 | if isinstance(task, BaseAsyncResult): |
|
174 | 175 | task_id = task.task_id |
|
175 | 176 | except formencode.Invalid as errors: |
|
176 | c.personal_repo_group = RepoGroup.get_by_group_name( | |
|
177 | c.rhodecode_user.username) | |
|
178 | 177 | return htmlfill.render( |
|
179 | 178 | render('admin/repos/repo_add.html'), |
|
180 | 179 | defaults=errors.value, |
@@ -215,7 +214,7 b' class ReposController(BaseRepoController' | |||
|
215 | 214 | c.repo_groups = RepoGroup.groups_choices(groups=acl_groups) |
|
216 | 215 | c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups) |
|
217 | 216 | choices, c.landing_revs = ScmModel().get_repo_landing_revs() |
|
218 |
c.personal_repo_group = |
|
|
217 | c.personal_repo_group = c.rhodecode_user.personal_repo_group | |
|
219 | 218 | c.new_repo = repo_name_slug(new_repo) |
|
220 | 219 | |
|
221 | 220 | ## apply the defaults from defaults page |
@@ -299,9 +298,8 b' class ReposController(BaseRepoController' | |||
|
299 | 298 | repo_model = RepoModel() |
|
300 | 299 | changed_name = repo_name |
|
301 | 300 | |
|
301 | c.personal_repo_group = c.rhodecode_user.personal_repo_group | |
|
302 | 302 | # override the choices with extracted revisions ! |
|
303 | c.personal_repo_group = RepoGroup.get_by_group_name( | |
|
304 | c.rhodecode_user.username) | |
|
305 | 303 | repo = Repository.get_by_repo_name(repo_name) |
|
306 | 304 | old_data = { |
|
307 | 305 | 'repo_name': repo_name, |
@@ -399,8 +397,7 b' class ReposController(BaseRepoController' | |||
|
399 | 397 | |
|
400 | 398 | c.repo_fields = RepositoryField.query()\ |
|
401 | 399 | .filter(RepositoryField.repository == c.repo_info).all() |
|
402 |
c.personal_repo_group = |
|
|
403 | c.rhodecode_user.username) | |
|
400 | c.personal_repo_group = c.rhodecode_user.personal_repo_group | |
|
404 | 401 | c.active = 'settings' |
|
405 | 402 | return htmlfill.render( |
|
406 | 403 | render('admin/repos/repo_edit.html'), |
@@ -55,6 +55,7 b' from rhodecode.model.db import RhodeCode' | |||
|
55 | 55 | from rhodecode.model.forms import ApplicationSettingsForm, \ |
|
56 | 56 | ApplicationUiSettingsForm, ApplicationVisualisationForm, \ |
|
57 | 57 | LabsSettingsForm, IssueTrackerPatternsForm |
|
58 | from rhodecode.model.repo_group import RepoGroupModel | |
|
58 | 59 | |
|
59 | 60 | from rhodecode.model.scm import ScmModel |
|
60 | 61 | from rhodecode.model.notification import EmailNotificationModel |
@@ -245,6 +246,8 b' class SettingsController(BaseController)' | |||
|
245 | 246 | """POST /admin/settings/global: All items in the collection""" |
|
246 | 247 | # url('admin_settings_global') |
|
247 | 248 | c.active = 'global' |
|
249 | c.personal_repo_group_default_pattern = RepoGroupModel()\ | |
|
250 | .get_personal_group_name_pattern() | |
|
248 | 251 | application_form = ApplicationSettingsForm()() |
|
249 | 252 | try: |
|
250 | 253 | form_result = application_form.to_python(dict(request.POST)) |
@@ -259,16 +262,18 b' class SettingsController(BaseController)' | |||
|
259 | 262 | |
|
260 | 263 | try: |
|
261 | 264 | settings = [ |
|
262 | ('title', 'rhodecode_title'), | |
|
263 | ('realm', 'rhodecode_realm'), | |
|
264 | ('pre_code', 'rhodecode_pre_code'), | |
|
265 | ('post_code', 'rhodecode_post_code'), | |
|
266 | ('captcha_public_key', 'rhodecode_captcha_public_key'), | |
|
267 | ('captcha_private_key', 'rhodecode_captcha_private_key'), | |
|
265 | ('title', 'rhodecode_title', 'unicode'), | |
|
266 | ('realm', 'rhodecode_realm', 'unicode'), | |
|
267 | ('pre_code', 'rhodecode_pre_code', 'unicode'), | |
|
268 | ('post_code', 'rhodecode_post_code', 'unicode'), | |
|
269 | ('captcha_public_key', 'rhodecode_captcha_public_key', 'unicode'), | |
|
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 | 275 | sett = SettingsModel().create_or_update_setting( |
|
271 | setting, form_result[form_key]) | |
|
276 | setting, form_result[form_key], type_) | |
|
272 | 277 | Session().add(sett) |
|
273 | 278 | |
|
274 | 279 | Session().commit() |
@@ -287,6 +292,8 b' class SettingsController(BaseController)' | |||
|
287 | 292 | """GET /admin/settings/global: All items in the collection""" |
|
288 | 293 | # url('admin_settings_global') |
|
289 | 294 | c.active = 'global' |
|
295 | c.personal_repo_group_default_pattern = RepoGroupModel()\ | |
|
296 | .get_personal_group_name_pattern() | |
|
290 | 297 | |
|
291 | 298 | return htmlfill.render( |
|
292 | 299 | render('admin/settings/settings.html'), |
@@ -45,12 +45,13 b' from rhodecode.model.db import (' | |||
|
45 | 45 | PullRequestReviewers, User, UserEmailMap, UserIpMap, RepoGroup) |
|
46 | 46 | from rhodecode.model.forms import ( |
|
47 | 47 | UserForm, UserPermissionsForm, UserIndividualPermissionsForm) |
|
48 | from rhodecode.model.repo_group import RepoGroupModel | |
|
48 | 49 | from rhodecode.model.user import UserModel |
|
49 | 50 | from rhodecode.model.meta import Session |
|
50 | 51 | from rhodecode.model.permission import PermissionModel |
|
51 | 52 | from rhodecode.lib.utils import action_logger |
|
52 | 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 | 56 | log = logging.getLogger(__name__) |
|
56 | 57 | |
@@ -120,6 +121,16 b' class UsersController(BaseController):' | |||
|
120 | 121 | c.data = json.dumps(users_data) |
|
121 | 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 | 134 | @HasPermissionAllDecorator('hg.admin') |
|
124 | 135 | @auth.CSRFRequired() |
|
125 | 136 | def create(self): |
@@ -143,6 +154,7 b' class UsersController(BaseController):' | |||
|
143 | 154 | % {'user_link': user_link}), category='success') |
|
144 | 155 | Session().commit() |
|
145 | 156 | except formencode.Invalid as errors: |
|
157 | self._get_personal_repo_group_template_vars() | |
|
146 | 158 | return htmlfill.render( |
|
147 | 159 | render('admin/users/user_add.html'), |
|
148 | 160 | defaults=errors.value, |
@@ -163,6 +175,7 b' class UsersController(BaseController):' | |||
|
163 | 175 | """GET /users/new: Form to create a new item""" |
|
164 | 176 | # url('new_user') |
|
165 | 177 | c.default_extern_type = auth_rhodecode.RhodeCodeAuthPlugin.name |
|
178 | self._get_personal_repo_group_template_vars() | |
|
166 | 179 | return render('admin/users/user_add.html') |
|
167 | 180 | |
|
168 | 181 | @HasPermissionAllDecorator('hg.admin') |
@@ -339,22 +352,41 b' class UsersController(BaseController):' | |||
|
339 | 352 | |
|
340 | 353 | user_id = safe_int(user_id) |
|
341 | 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 | 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 | 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 | 384 | except Exception: |
|
354 | 385 | log.exception("Exception during repository group creation") |
|
355 | 386 | msg = _( |
|
356 | 387 | 'An error occurred during repository group creation for user') |
|
357 | 388 | h.flash(msg, category='error') |
|
389 | Session().rollback() | |
|
358 | 390 | |
|
359 | 391 | return redirect(url('edit_user_advanced', user_id=user_id)) |
|
360 | 392 | |
@@ -397,7 +429,9 b' class UsersController(BaseController):' | |||
|
397 | 429 | |
|
398 | 430 | c.active = 'advanced' |
|
399 | 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 | 435 | c.first_admin = User.get_first_super_admin() |
|
402 | 436 | defaults = user.get_dict() |
|
403 | 437 |
@@ -60,8 +60,7 b' class ForksController(BaseRepoController' | |||
|
60 | 60 | c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups) |
|
61 | 61 | choices, c.landing_revs = ScmModel().get_repo_landing_revs() |
|
62 | 62 | c.landing_revs_choices = choices |
|
63 |
c.personal_repo_group = |
|
|
64 | c.rhodecode_user.username) | |
|
63 | c.personal_repo_group = c.rhodecode_user.personal_repo_group | |
|
65 | 64 | |
|
66 | 65 | def __load_data(self, repo_name=None): |
|
67 | 66 | """ |
@@ -48,6 +48,7 b' from rhodecode.events.base import Rhodec' | |||
|
48 | 48 | |
|
49 | 49 | from rhodecode.events.user import ( # noqa |
|
50 | 50 | UserPreCreate, |
|
51 | UserPostCreate, | |
|
51 | 52 | UserPreUpdate, |
|
52 | 53 | UserRegistered |
|
53 | 54 | ) |
@@ -51,6 +51,19 b' class UserPreCreate(RhodecodeEvent):' | |||
|
51 | 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 | 67 | @implementer(IUserPreUpdate) |
|
55 | 68 | class UserPreUpdate(RhodecodeEvent): |
|
56 | 69 | """ |
@@ -49,7 +49,7 b' from rhodecode.model.meta import Session' | |||
|
49 | 49 | from rhodecode.model.user import UserModel |
|
50 | 50 | from rhodecode.model.db import ( |
|
51 | 51 | User, Repository, Permission, UserToPerm, UserGroupToPerm, UserGroupMember, |
|
52 | UserIpMap, UserApiKeys) | |
|
52 | UserIpMap, UserApiKeys, RepoGroup) | |
|
53 | 53 | from rhodecode.lib import caches |
|
54 | 54 | from rhodecode.lib.utils2 import safe_unicode, aslist, safe_str, md5 |
|
55 | 55 | from rhodecode.lib.utils import ( |
@@ -983,6 +983,9 b' class AuthUser(object):' | |||
|
983 | 983 | inherit = self.inherit_default_permissions |
|
984 | 984 | return AuthUser.check_ip_allowed(self.user_id, self.ip_addr, |
|
985 | 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 | 990 | @classmethod |
|
988 | 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 | 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 | 100 | string into boolean |
|
101 | 101 | |
|
102 | 102 | :param _str: string value to translate into boolean |
@@ -2028,6 +2028,7 b' class RepoGroup(Base, BaseModel):' | |||
|
2028 | 2028 | enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False) |
|
2029 | 2029 | user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) |
|
2030 | 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 | 2033 | repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id') |
|
2033 | 2034 | users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all') |
@@ -2083,6 +2084,13 b' class RepoGroup(Base, BaseModel):' | |||
|
2083 | 2084 | return gr.scalar() |
|
2084 | 2085 | |
|
2085 | 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 | 2094 | def get_all_repo_groups(cls, user_id=Optional(None), group_id=Optional(None), |
|
2087 | 2095 | case_insensitive=True): |
|
2088 | 2096 | q = RepoGroup.query() |
@@ -341,6 +341,8 b' def ApplicationSettingsForm():' | |||
|
341 | 341 | rhodecode_post_code = v.UnicodeString(strip=True, min=1, not_empty=False) |
|
342 | 342 | rhodecode_captcha_public_key = v.UnicodeString(strip=True, min=1, not_empty=False) |
|
343 | 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 | 347 | return _ApplicationSettingsForm |
|
346 | 348 |
@@ -23,13 +23,13 b'' | |||
|
23 | 23 | repo group model for RhodeCode |
|
24 | 24 | """ |
|
25 | 25 | |
|
26 | ||
|
26 | import os | |
|
27 | 27 | import datetime |
|
28 | 28 | import itertools |
|
29 | 29 | import logging |
|
30 | import os | |
|
31 | 30 | import shutil |
|
32 | 31 | import traceback |
|
32 | import string | |
|
33 | 33 | |
|
34 | 34 | from zope.cachedescriptors.property import Lazy as LazyProperty |
|
35 | 35 | |
@@ -38,7 +38,7 b' from rhodecode.model import BaseModel' | |||
|
38 | 38 | from rhodecode.model.db import ( |
|
39 | 39 | RepoGroup, UserRepoGroupToPerm, User, Permission, UserGroupRepoGroupToPerm, |
|
40 | 40 | UserGroup, Repository) |
|
41 | from rhodecode.model.settings import VcsSettingsModel | |
|
41 | from rhodecode.model.settings import VcsSettingsModel, SettingsModel | |
|
42 | 42 | from rhodecode.lib.caching_query import FromCache |
|
43 | 43 | from rhodecode.lib.utils2 import action_logger_generic |
|
44 | 44 | |
@@ -49,6 +49,7 b' class RepoGroupModel(BaseModel):' | |||
|
49 | 49 | |
|
50 | 50 | cls = RepoGroup |
|
51 | 51 | PERSONAL_GROUP_DESC = '[personal] repo group: owner `%(username)s`' |
|
52 | PERSONAL_GROUP_PATTERN = '${username}' # default | |
|
52 | 53 | |
|
53 | 54 | def _get_user_group(self, users_group): |
|
54 | 55 | return self._get_instance(UserGroup, users_group, |
@@ -76,6 +77,39 b' class RepoGroupModel(BaseModel):' | |||
|
76 | 77 | "sql_cache_short", "get_repo_group_%s" % repo_group_name)) |
|
77 | 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 | 113 | def _create_default_perms(self, new_group): |
|
80 | 114 | # create default permission |
|
81 | 115 | default_perm = 'group.read' |
@@ -191,7 +225,7 b' class RepoGroupModel(BaseModel):' | |||
|
191 | 225 | shutil.move(rm_path, os.path.join(self.repos_path, _d)) |
|
192 | 226 | |
|
193 | 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 | 230 | (group_name_cleaned, |
|
197 | 231 | parent_group_name) = RepoGroupModel()._get_group_name_and_parent(group_name) |
@@ -199,11 +233,18 b' class RepoGroupModel(BaseModel):' | |||
|
199 | 233 | parent_group = None |
|
200 | 234 | if parent_group_name: |
|
201 | 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 | |
|
204 |
# already exists. If we don't do that we can accidentally delete |
|
|
205 |
# directory via cleanup that can cause data issues, since |
|
|
206 |
# folder rename to special syntax later cleanup |
|
|
243 | # because we are doing a cleanup, we need to check if such directory | |
|
244 | # already exists. If we don't do that we can accidentally delete | |
|
245 | # existing directory via cleanup that can cause data issues, since | |
|
246 | # delete does a folder rename to special syntax later cleanup | |
|
247 | # functions can delete this | |
|
207 | 248 | cleanup_group = self.check_exist_filesystem(group_name, |
|
208 | 249 | exc_on_failure=False) |
|
209 | 250 | try: |
@@ -213,6 +254,7 b' class RepoGroupModel(BaseModel):' | |||
|
213 | 254 | new_repo_group.group_description = group_description or group_name |
|
214 | 255 | new_repo_group.parent_group = parent_group |
|
215 | 256 | new_repo_group.group_name = group_name |
|
257 | new_repo_group.personal = personal | |
|
216 | 258 | |
|
217 | 259 | self.sa.add(new_repo_group) |
|
218 | 260 |
@@ -35,7 +35,7 b' from sqlalchemy.sql.expression import tr' | |||
|
35 | 35 | from rhodecode import events |
|
36 | 36 | from rhodecode.lib.utils2 import ( |
|
37 | 37 | safe_unicode, get_current_rhodecode_user, action_logger_generic, |
|
38 | AttributeDict) | |
|
38 | AttributeDict, str2bool) | |
|
39 | 39 | from rhodecode.lib.caching_query import FromCache |
|
40 | 40 | from rhodecode.model import BaseModel |
|
41 | 41 | from rhodecode.model.auth_token import AuthTokenModel |
@@ -104,12 +104,13 b' class UserModel(BaseModel):' | |||
|
104 | 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 | 111 | try: |
|
108 | if form_data.get('create_repo_group'): | |
|
109 | user_data['create_repo_group'] = True | |
|
110 | 112 | if form_data.get('password_change'): |
|
111 | 113 | user_data['force_password_change'] = True |
|
112 | ||
|
113 | 114 | return UserModel().create_or_update(**user_data) |
|
114 | 115 | except Exception: |
|
115 | 116 | log.error(traceback.format_exc()) |
@@ -177,7 +178,7 b' class UserModel(BaseModel):' | |||
|
177 | 178 | self, username, password, email, firstname='', lastname='', |
|
178 | 179 | active=True, admin=False, extern_type=None, extern_name=None, |
|
179 | 180 | cur_user=None, plugin=None, force_password_change=False, |
|
180 |
allow_to_create_user=True, create_repo_group= |
|
|
181 | allow_to_create_user=True, create_repo_group=None, | |
|
181 | 182 | updating_user_id=None, language=None, strict_creation_check=True): |
|
182 | 183 | """ |
|
183 | 184 | Creates a new instance if not found, or updates current one |
@@ -222,8 +223,8 b' class UserModel(BaseModel):' | |||
|
222 | 223 | # in case it's a plugin we don't care |
|
223 | 224 | if not plugin: |
|
224 | 225 | |
|
225 |
# first check if we gave crypted password back, and if it |
|
|
226 | # it's not password change | |
|
226 | # first check if we gave crypted password back, and if it | |
|
227 | # matches it's not password change | |
|
227 | 228 | if new_user.password == password: |
|
228 | 229 | return False |
|
229 | 230 | |
@@ -233,6 +234,12 b' class UserModel(BaseModel):' | |||
|
233 | 234 | |
|
234 | 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 | 243 | user_data = { |
|
237 | 244 | 'username': username, |
|
238 | 245 | 'password': password, |
@@ -319,17 +326,16 b' class UserModel(BaseModel):' | |||
|
319 | 326 | self.sa.add(new_user) |
|
320 | 327 | |
|
321 | 328 | if not edit and create_repo_group: |
|
322 | # create new group same as username, and make this user an owner | |
|
323 | desc = RepoGroupModel.PERSONAL_GROUP_DESC % {'username': username} | |
|
324 | RepoGroupModel().create(group_name=username, | |
|
325 | group_description=desc, | |
|
326 | owner=username, commit_early=False) | |
|
329 | RepoGroupModel().create_personal_repo_group( | |
|
330 | new_user, commit_early=False) | |
|
331 | ||
|
327 | 332 | if not edit: |
|
328 | 333 | # add the RSS token |
|
329 | 334 | AuthTokenModel().create(username, |
|
330 | 335 | description='Generated feed token', |
|
331 | 336 | role=AuthTokenModel.cls.ROLE_FEED) |
|
332 | 337 | log_create_user(created_by=cur_user, **new_user.get_dict()) |
|
338 | events.trigger(events.UserPostCreate(user_data)) | |
|
333 | 339 | return new_user |
|
334 | 340 | except (DatabaseError,): |
|
335 | 341 | log.error(traceback.format_exc()) |
@@ -30,6 +30,35 b'' | |||
|
30 | 30 | </div> |
|
31 | 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 | 62 | <div class="panel panel-default"> |
|
34 | 63 | <div class="panel-heading" id="captcha-options"> |
|
35 | 64 | <h3 class="panel-title">${_('Registration Captcha')} <a class="permalink" href="#captcha-options"> ¶</a></h3> |
@@ -113,11 +113,14 b'' | |||
|
113 | 113 | |
|
114 | 114 | <div class="field"> |
|
115 | 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 | 117 | </div> |
|
118 | 118 | <div class="checkboxes"> |
|
119 | ${h.checkbox('create_repo_group',value=True)} | |
|
120 | <span class="help-block">${_('Add repository group with the same name as username. \nUser will be automatically set as this group owner.')}</span> | |
|
119 | ${h.checkbox('create_repo_group',value=True, checked=c.default_create_repo_group)} | |
|
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 | 124 | </div> |
|
122 | 125 | </div> |
|
123 | 126 |
@@ -61,7 +61,11 b'' | |||
|
61 | 61 | %if c.personal_repo_group: |
|
62 | 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 | 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 | 69 | %endif |
|
66 | 70 | <button class="btn btn-default" type="submit" ${'disabled="disabled"' if c.personal_repo_group else ''}> |
|
67 | 71 | <i class="icon-folder-close"></i> |
@@ -338,6 +338,9 b'' | |||
|
338 | 338 | <div class=""> |
|
339 | 339 | <ol class="links"> |
|
340 | 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 | 344 | <li class="logout"> |
|
342 | 345 | ${h.secure_form(h.route_path('logout'))} |
|
343 | 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