##// END OF EJS Templates
permissions: flush all user permissions in case of default user permission changes....
dan -
r4187:0268c0ee stable
parent child Browse files
Show More
@@ -1,103 +1,110 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2019 RhodeCode GmbH
3 # Copyright (C) 2011-2019 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import logging
21 import logging
22
22
23 from pyramid.view import view_config
23 from pyramid.view import view_config
24 from pyramid.httpexceptions import HTTPFound
24 from pyramid.httpexceptions import HTTPFound
25
25
26 from rhodecode.apps._base import RepoGroupAppView
26 from rhodecode.apps._base import RepoGroupAppView
27 from rhodecode.lib import helpers as h
27 from rhodecode.lib import helpers as h
28 from rhodecode.lib import audit_logger
28 from rhodecode.lib import audit_logger
29 from rhodecode.lib.auth import (
29 from rhodecode.lib.auth import (
30 LoginRequired, HasRepoGroupPermissionAnyDecorator, CSRFRequired)
30 LoginRequired, HasRepoGroupPermissionAnyDecorator, CSRFRequired)
31 from rhodecode.model.db import User
31 from rhodecode.model.permission import PermissionModel
32 from rhodecode.model.permission import PermissionModel
32 from rhodecode.model.repo_group import RepoGroupModel
33 from rhodecode.model.repo_group import RepoGroupModel
33 from rhodecode.model.forms import RepoGroupPermsForm
34 from rhodecode.model.forms import RepoGroupPermsForm
34 from rhodecode.model.meta import Session
35 from rhodecode.model.meta import Session
35
36
36 log = logging.getLogger(__name__)
37 log = logging.getLogger(__name__)
37
38
38
39
39 class RepoGroupPermissionsView(RepoGroupAppView):
40 class RepoGroupPermissionsView(RepoGroupAppView):
40 def load_default_context(self):
41 def load_default_context(self):
41 c = self._get_local_tmpl_context()
42 c = self._get_local_tmpl_context()
42
43
43 return c
44 return c
44
45
45 @LoginRequired()
46 @LoginRequired()
46 @HasRepoGroupPermissionAnyDecorator('group.admin')
47 @HasRepoGroupPermissionAnyDecorator('group.admin')
47 @view_config(
48 @view_config(
48 route_name='edit_repo_group_perms', request_method='GET',
49 route_name='edit_repo_group_perms', request_method='GET',
49 renderer='rhodecode:templates/admin/repo_groups/repo_group_edit.mako')
50 renderer='rhodecode:templates/admin/repo_groups/repo_group_edit.mako')
50 def edit_repo_group_permissions(self):
51 def edit_repo_group_permissions(self):
51 c = self.load_default_context()
52 c = self.load_default_context()
52 c.active = 'permissions'
53 c.active = 'permissions'
53 c.repo_group = self.db_repo_group
54 c.repo_group = self.db_repo_group
54 return self._get_template_context(c)
55 return self._get_template_context(c)
55
56
56 @LoginRequired()
57 @LoginRequired()
57 @HasRepoGroupPermissionAnyDecorator('group.admin')
58 @HasRepoGroupPermissionAnyDecorator('group.admin')
58 @CSRFRequired()
59 @CSRFRequired()
59 @view_config(
60 @view_config(
60 route_name='edit_repo_group_perms_update', request_method='POST',
61 route_name='edit_repo_group_perms_update', request_method='POST',
61 renderer='rhodecode:templates/admin/repo_groups/repo_group_edit.mako')
62 renderer='rhodecode:templates/admin/repo_groups/repo_group_edit.mako')
62 def edit_repo_groups_permissions_update(self):
63 def edit_repo_groups_permissions_update(self):
63 _ = self.request.translate
64 _ = self.request.translate
64 c = self.load_default_context()
65 c = self.load_default_context()
65 c.active = 'perms'
66 c.active = 'perms'
66 c.repo_group = self.db_repo_group
67 c.repo_group = self.db_repo_group
67
68
68 valid_recursive_choices = ['none', 'repos', 'groups', 'all']
69 valid_recursive_choices = ['none', 'repos', 'groups', 'all']
69 form = RepoGroupPermsForm(self.request.translate, valid_recursive_choices)()\
70 form = RepoGroupPermsForm(self.request.translate, valid_recursive_choices)()\
70 .to_python(self.request.POST)
71 .to_python(self.request.POST)
71
72
72 if not c.rhodecode_user.is_admin:
73 if not c.rhodecode_user.is_admin:
73 if self._revoke_perms_on_yourself(form):
74 if self._revoke_perms_on_yourself(form):
74 msg = _('Cannot change permission for yourself as admin')
75 msg = _('Cannot change permission for yourself as admin')
75 h.flash(msg, category='warning')
76 h.flash(msg, category='warning')
76 raise HTTPFound(
77 raise HTTPFound(
77 h.route_path('edit_repo_group_perms',
78 h.route_path('edit_repo_group_perms',
78 repo_group_name=self.db_repo_group_name))
79 repo_group_name=self.db_repo_group_name))
79
80
80 # iterate over all members(if in recursive mode) of this groups and
81 # iterate over all members(if in recursive mode) of this groups and
81 # set the permissions !
82 # set the permissions !
82 # this can be potentially heavy operation
83 # this can be potentially heavy operation
83 changes = RepoGroupModel().update_permissions(
84 changes = RepoGroupModel().update_permissions(
84 c.repo_group,
85 c.repo_group,
85 form['perm_additions'], form['perm_updates'], form['perm_deletions'],
86 form['perm_additions'], form['perm_updates'], form['perm_deletions'],
86 form['recursive'])
87 form['recursive'])
87
88
88 action_data = {
89 action_data = {
89 'added': changes['added'],
90 'added': changes['added'],
90 'updated': changes['updated'],
91 'updated': changes['updated'],
91 'deleted': changes['deleted'],
92 'deleted': changes['deleted'],
92 }
93 }
93 audit_logger.store_web(
94 audit_logger.store_web(
94 'repo_group.edit.permissions', action_data=action_data,
95 'repo_group.edit.permissions', action_data=action_data,
95 user=c.rhodecode_user)
96 user=c.rhodecode_user)
96
97
97 Session().commit()
98 Session().commit()
98 h.flash(_('Repository Group permissions updated'), category='success')
99 h.flash(_('Repository Group permissions updated'), category='success')
99 PermissionModel().flush_user_permission_caches(changes)
100
101 affected_user_ids = None
102 if changes.get('default_user_changed', False):
103 # if we change the default user, we need to flush everyone permissions
104 affected_user_ids = [x.user_id for x in User.get_all()]
105 PermissionModel().flush_user_permission_caches(
106 changes, affected_user_ids=affected_user_ids)
100
107
101 raise HTTPFound(
108 raise HTTPFound(
102 h.route_path('edit_repo_group_perms',
109 h.route_path('edit_repo_group_perms',
103 repo_group_name=self.db_repo_group_name))
110 repo_group_name=self.db_repo_group_name))
@@ -1,122 +1,128 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2019 RhodeCode GmbH
3 # Copyright (C) 2011-2019 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import logging
21 import logging
22
22
23 from pyramid.httpexceptions import HTTPFound
23 from pyramid.httpexceptions import HTTPFound
24 from pyramid.view import view_config
24 from pyramid.view import view_config
25
25
26 from rhodecode.apps._base import RepoAppView
26 from rhodecode.apps._base import RepoAppView
27 from rhodecode.lib import helpers as h
27 from rhodecode.lib import helpers as h
28 from rhodecode.lib import audit_logger
28 from rhodecode.lib import audit_logger
29 from rhodecode.lib.auth import (
29 from rhodecode.lib.auth import (
30 LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired)
30 LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired)
31 from rhodecode.model.db import User
31 from rhodecode.model.forms import RepoPermsForm
32 from rhodecode.model.forms import RepoPermsForm
32 from rhodecode.model.meta import Session
33 from rhodecode.model.meta import Session
33 from rhodecode.model.permission import PermissionModel
34 from rhodecode.model.permission import PermissionModel
34 from rhodecode.model.repo import RepoModel
35 from rhodecode.model.repo import RepoModel
35
36
36 log = logging.getLogger(__name__)
37 log = logging.getLogger(__name__)
37
38
38
39
39 class RepoSettingsPermissionsView(RepoAppView):
40 class RepoSettingsPermissionsView(RepoAppView):
40
41
41 def load_default_context(self):
42 def load_default_context(self):
42 c = self._get_local_tmpl_context()
43 c = self._get_local_tmpl_context()
43 return c
44 return c
44
45
45 @LoginRequired()
46 @LoginRequired()
46 @HasRepoPermissionAnyDecorator('repository.admin')
47 @HasRepoPermissionAnyDecorator('repository.admin')
47 @view_config(
48 @view_config(
48 route_name='edit_repo_perms', request_method='GET',
49 route_name='edit_repo_perms', request_method='GET',
49 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
50 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
50 def edit_permissions(self):
51 def edit_permissions(self):
51 _ = self.request.translate
52 _ = self.request.translate
52 c = self.load_default_context()
53 c = self.load_default_context()
53 c.active = 'permissions'
54 c.active = 'permissions'
54 if self.request.GET.get('branch_permissions'):
55 if self.request.GET.get('branch_permissions'):
55 h.flash(_('Explicitly add user or user group with write+ '
56 h.flash(_('Explicitly add user or user group with write+ '
56 'permission to modify their branch permissions.'),
57 'permission to modify their branch permissions.'),
57 category='notice')
58 category='notice')
58 return self._get_template_context(c)
59 return self._get_template_context(c)
59
60
60 @LoginRequired()
61 @LoginRequired()
61 @HasRepoPermissionAnyDecorator('repository.admin')
62 @HasRepoPermissionAnyDecorator('repository.admin')
62 @CSRFRequired()
63 @CSRFRequired()
63 @view_config(
64 @view_config(
64 route_name='edit_repo_perms', request_method='POST',
65 route_name='edit_repo_perms', request_method='POST',
65 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
66 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
66 def edit_permissions_update(self):
67 def edit_permissions_update(self):
67 _ = self.request.translate
68 _ = self.request.translate
68 c = self.load_default_context()
69 c = self.load_default_context()
69 c.active = 'permissions'
70 c.active = 'permissions'
70 data = self.request.POST
71 data = self.request.POST
71 # store private flag outside of HTML to verify if we can modify
72 # store private flag outside of HTML to verify if we can modify
72 # default user permissions, prevents submission of FAKE post data
73 # default user permissions, prevents submission of FAKE post data
73 # into the form for private repos
74 # into the form for private repos
74 data['repo_private'] = self.db_repo.private
75 data['repo_private'] = self.db_repo.private
75 form = RepoPermsForm(self.request.translate)().to_python(data)
76 form = RepoPermsForm(self.request.translate)().to_python(data)
76 changes = RepoModel().update_permissions(
77 changes = RepoModel().update_permissions(
77 self.db_repo_name, form['perm_additions'], form['perm_updates'],
78 self.db_repo_name, form['perm_additions'], form['perm_updates'],
78 form['perm_deletions'])
79 form['perm_deletions'])
79
80
80 action_data = {
81 action_data = {
81 'added': changes['added'],
82 'added': changes['added'],
82 'updated': changes['updated'],
83 'updated': changes['updated'],
83 'deleted': changes['deleted'],
84 'deleted': changes['deleted'],
84 }
85 }
85 audit_logger.store_web(
86 audit_logger.store_web(
86 'repo.edit.permissions', action_data=action_data,
87 'repo.edit.permissions', action_data=action_data,
87 user=self._rhodecode_user, repo=self.db_repo)
88 user=self._rhodecode_user, repo=self.db_repo)
88
89
89 Session().commit()
90 Session().commit()
90 h.flash(_('Repository access permissions updated'), category='success')
91 h.flash(_('Repository access permissions updated'), category='success')
91
92
92 PermissionModel().flush_user_permission_caches(changes)
93 affected_user_ids = None
94 if changes.get('default_user_changed', False):
95 # if we change the default user, we need to flush everyone permissions
96 affected_user_ids = [x.user_id for x in User.get_all()]
97 PermissionModel().flush_user_permission_caches(
98 changes, affected_user_ids=affected_user_ids)
93
99
94 raise HTTPFound(
100 raise HTTPFound(
95 h.route_path('edit_repo_perms', repo_name=self.db_repo_name))
101 h.route_path('edit_repo_perms', repo_name=self.db_repo_name))
96
102
97 @LoginRequired()
103 @LoginRequired()
98 @HasRepoPermissionAnyDecorator('repository.admin')
104 @HasRepoPermissionAnyDecorator('repository.admin')
99 @CSRFRequired()
105 @CSRFRequired()
100 @view_config(
106 @view_config(
101 route_name='edit_repo_perms_set_private', request_method='POST',
107 route_name='edit_repo_perms_set_private', request_method='POST',
102 renderer='json_ext')
108 renderer='json_ext')
103 def edit_permissions_set_private_repo(self):
109 def edit_permissions_set_private_repo(self):
104 _ = self.request.translate
110 _ = self.request.translate
105 self.load_default_context()
111 self.load_default_context()
106
112
107 try:
113 try:
108 RepoModel().update(
114 RepoModel().update(
109 self.db_repo, **{'repo_private': True, 'repo_name': self.db_repo_name})
115 self.db_repo, **{'repo_private': True, 'repo_name': self.db_repo_name})
110 Session().commit()
116 Session().commit()
111
117
112 h.flash(_('Repository `{}` private mode set successfully').format(self.db_repo_name),
118 h.flash(_('Repository `{}` private mode set successfully').format(self.db_repo_name),
113 category='success')
119 category='success')
114 except Exception:
120 except Exception:
115 log.exception("Exception during update of repository")
121 log.exception("Exception during update of repository")
116 h.flash(_('Error occurred during update of repository {}').format(
122 h.flash(_('Error occurred during update of repository {}').format(
117 self.db_repo_name), category='error')
123 self.db_repo_name), category='error')
118
124
119 return {
125 return {
120 'redirect_url': h.route_path('edit_repo_perms', repo_name=self.db_repo_name),
126 'redirect_url': h.route_path('edit_repo_perms', repo_name=self.db_repo_name),
121 'private': True
127 'private': True
122 }
128 }
@@ -1,1158 +1,1171 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2019 RhodeCode GmbH
3 # Copyright (C) 2010-2019 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import os
21 import os
22 import re
22 import re
23 import shutil
23 import shutil
24 import time
24 import time
25 import logging
25 import logging
26 import traceback
26 import traceback
27 import datetime
27 import datetime
28
28
29 from pyramid.threadlocal import get_current_request
29 from pyramid.threadlocal import get_current_request
30 from zope.cachedescriptors.property import Lazy as LazyProperty
30 from zope.cachedescriptors.property import Lazy as LazyProperty
31
31
32 from rhodecode import events
32 from rhodecode import events
33 from rhodecode.lib.auth import HasUserGroupPermissionAny
33 from rhodecode.lib.auth import HasUserGroupPermissionAny
34 from rhodecode.lib.caching_query import FromCache
34 from rhodecode.lib.caching_query import FromCache
35 from rhodecode.lib.exceptions import AttachedForksError, AttachedPullRequestsError
35 from rhodecode.lib.exceptions import AttachedForksError, AttachedPullRequestsError
36 from rhodecode.lib.hooks_base import log_delete_repository
36 from rhodecode.lib.hooks_base import log_delete_repository
37 from rhodecode.lib.user_log_filter import user_log_filter
37 from rhodecode.lib.user_log_filter import user_log_filter
38 from rhodecode.lib.utils import make_db_config
38 from rhodecode.lib.utils import make_db_config
39 from rhodecode.lib.utils2 import (
39 from rhodecode.lib.utils2 import (
40 safe_str, safe_unicode, remove_prefix, obfuscate_url_pw,
40 safe_str, safe_unicode, remove_prefix, obfuscate_url_pw,
41 get_current_rhodecode_user, safe_int, datetime_to_time,
41 get_current_rhodecode_user, safe_int, datetime_to_time,
42 action_logger_generic)
42 action_logger_generic)
43 from rhodecode.lib.vcs.backends import get_backend
43 from rhodecode.lib.vcs.backends import get_backend
44 from rhodecode.model import BaseModel
44 from rhodecode.model import BaseModel
45 from rhodecode.model.db import (
45 from rhodecode.model.db import (
46 _hash_key, func, case, joinedload, or_, in_filter_generator,
46 _hash_key, func, case, joinedload, or_, in_filter_generator,
47 Session, Repository, UserRepoToPerm, UserGroupRepoToPerm,
47 Session, Repository, UserRepoToPerm, UserGroupRepoToPerm,
48 UserRepoGroupToPerm, UserGroupRepoGroupToPerm, User, Permission,
48 UserRepoGroupToPerm, UserGroupRepoGroupToPerm, User, Permission,
49 Statistics, UserGroup, RepoGroup, RepositoryField, UserLog)
49 Statistics, UserGroup, RepoGroup, RepositoryField, UserLog)
50 from rhodecode.model.settings import VcsSettingsModel
50 from rhodecode.model.settings import VcsSettingsModel
51
51
52 log = logging.getLogger(__name__)
52 log = logging.getLogger(__name__)
53
53
54
54
55 class RepoModel(BaseModel):
55 class RepoModel(BaseModel):
56
56
57 cls = Repository
57 cls = Repository
58
58
59 def _get_user_group(self, users_group):
59 def _get_user_group(self, users_group):
60 return self._get_instance(UserGroup, users_group,
60 return self._get_instance(UserGroup, users_group,
61 callback=UserGroup.get_by_group_name)
61 callback=UserGroup.get_by_group_name)
62
62
63 def _get_repo_group(self, repo_group):
63 def _get_repo_group(self, repo_group):
64 return self._get_instance(RepoGroup, repo_group,
64 return self._get_instance(RepoGroup, repo_group,
65 callback=RepoGroup.get_by_group_name)
65 callback=RepoGroup.get_by_group_name)
66
66
67 def _create_default_perms(self, repository, private):
67 def _create_default_perms(self, repository, private):
68 # create default permission
68 # create default permission
69 default = 'repository.read'
69 default = 'repository.read'
70 def_user = User.get_default_user()
70 def_user = User.get_default_user()
71 for p in def_user.user_perms:
71 for p in def_user.user_perms:
72 if p.permission.permission_name.startswith('repository.'):
72 if p.permission.permission_name.startswith('repository.'):
73 default = p.permission.permission_name
73 default = p.permission.permission_name
74 break
74 break
75
75
76 default_perm = 'repository.none' if private else default
76 default_perm = 'repository.none' if private else default
77
77
78 repo_to_perm = UserRepoToPerm()
78 repo_to_perm = UserRepoToPerm()
79 repo_to_perm.permission = Permission.get_by_key(default_perm)
79 repo_to_perm.permission = Permission.get_by_key(default_perm)
80
80
81 repo_to_perm.repository = repository
81 repo_to_perm.repository = repository
82 repo_to_perm.user_id = def_user.user_id
82 repo_to_perm.user_id = def_user.user_id
83
83
84 return repo_to_perm
84 return repo_to_perm
85
85
86 @LazyProperty
86 @LazyProperty
87 def repos_path(self):
87 def repos_path(self):
88 """
88 """
89 Gets the repositories root path from database
89 Gets the repositories root path from database
90 """
90 """
91 settings_model = VcsSettingsModel(sa=self.sa)
91 settings_model = VcsSettingsModel(sa=self.sa)
92 return settings_model.get_repos_location()
92 return settings_model.get_repos_location()
93
93
94 def get(self, repo_id):
94 def get(self, repo_id):
95 repo = self.sa.query(Repository) \
95 repo = self.sa.query(Repository) \
96 .filter(Repository.repo_id == repo_id)
96 .filter(Repository.repo_id == repo_id)
97
97
98 return repo.scalar()
98 return repo.scalar()
99
99
100 def get_repo(self, repository):
100 def get_repo(self, repository):
101 return self._get_repo(repository)
101 return self._get_repo(repository)
102
102
103 def get_by_repo_name(self, repo_name, cache=False):
103 def get_by_repo_name(self, repo_name, cache=False):
104 repo = self.sa.query(Repository) \
104 repo = self.sa.query(Repository) \
105 .filter(Repository.repo_name == repo_name)
105 .filter(Repository.repo_name == repo_name)
106
106
107 if cache:
107 if cache:
108 name_key = _hash_key(repo_name)
108 name_key = _hash_key(repo_name)
109 repo = repo.options(
109 repo = repo.options(
110 FromCache("sql_cache_short", "get_repo_%s" % name_key))
110 FromCache("sql_cache_short", "get_repo_%s" % name_key))
111 return repo.scalar()
111 return repo.scalar()
112
112
113 def _extract_id_from_repo_name(self, repo_name):
113 def _extract_id_from_repo_name(self, repo_name):
114 if repo_name.startswith('/'):
114 if repo_name.startswith('/'):
115 repo_name = repo_name.lstrip('/')
115 repo_name = repo_name.lstrip('/')
116 by_id_match = re.match(r'^_(\d{1,})', repo_name)
116 by_id_match = re.match(r'^_(\d{1,})', repo_name)
117 if by_id_match:
117 if by_id_match:
118 return by_id_match.groups()[0]
118 return by_id_match.groups()[0]
119
119
120 def get_repo_by_id(self, repo_name):
120 def get_repo_by_id(self, repo_name):
121 """
121 """
122 Extracts repo_name by id from special urls.
122 Extracts repo_name by id from special urls.
123 Example url is _11/repo_name
123 Example url is _11/repo_name
124
124
125 :param repo_name:
125 :param repo_name:
126 :return: repo object if matched else None
126 :return: repo object if matched else None
127 """
127 """
128
128
129 try:
129 try:
130 _repo_id = self._extract_id_from_repo_name(repo_name)
130 _repo_id = self._extract_id_from_repo_name(repo_name)
131 if _repo_id:
131 if _repo_id:
132 return self.get(_repo_id)
132 return self.get(_repo_id)
133 except Exception:
133 except Exception:
134 log.exception('Failed to extract repo_name from URL')
134 log.exception('Failed to extract repo_name from URL')
135
135
136 return None
136 return None
137
137
138 def get_repos_for_root(self, root, traverse=False):
138 def get_repos_for_root(self, root, traverse=False):
139 if traverse:
139 if traverse:
140 like_expression = u'{}%'.format(safe_unicode(root))
140 like_expression = u'{}%'.format(safe_unicode(root))
141 repos = Repository.query().filter(
141 repos = Repository.query().filter(
142 Repository.repo_name.like(like_expression)).all()
142 Repository.repo_name.like(like_expression)).all()
143 else:
143 else:
144 if root and not isinstance(root, RepoGroup):
144 if root and not isinstance(root, RepoGroup):
145 raise ValueError(
145 raise ValueError(
146 'Root must be an instance '
146 'Root must be an instance '
147 'of RepoGroup, got:{} instead'.format(type(root)))
147 'of RepoGroup, got:{} instead'.format(type(root)))
148 repos = Repository.query().filter(Repository.group == root).all()
148 repos = Repository.query().filter(Repository.group == root).all()
149 return repos
149 return repos
150
150
151 def get_url(self, repo, request=None, permalink=False):
151 def get_url(self, repo, request=None, permalink=False):
152 if not request:
152 if not request:
153 request = get_current_request()
153 request = get_current_request()
154
154
155 if not request:
155 if not request:
156 return
156 return
157
157
158 if permalink:
158 if permalink:
159 return request.route_url(
159 return request.route_url(
160 'repo_summary', repo_name='_{}'.format(safe_str(repo.repo_id)))
160 'repo_summary', repo_name='_{}'.format(safe_str(repo.repo_id)))
161 else:
161 else:
162 return request.route_url(
162 return request.route_url(
163 'repo_summary', repo_name=safe_str(repo.repo_name))
163 'repo_summary', repo_name=safe_str(repo.repo_name))
164
164
165 def get_commit_url(self, repo, commit_id, request=None, permalink=False):
165 def get_commit_url(self, repo, commit_id, request=None, permalink=False):
166 if not request:
166 if not request:
167 request = get_current_request()
167 request = get_current_request()
168
168
169 if not request:
169 if not request:
170 return
170 return
171
171
172 if permalink:
172 if permalink:
173 return request.route_url(
173 return request.route_url(
174 'repo_commit', repo_name=safe_str(repo.repo_id),
174 'repo_commit', repo_name=safe_str(repo.repo_id),
175 commit_id=commit_id)
175 commit_id=commit_id)
176
176
177 else:
177 else:
178 return request.route_url(
178 return request.route_url(
179 'repo_commit', repo_name=safe_str(repo.repo_name),
179 'repo_commit', repo_name=safe_str(repo.repo_name),
180 commit_id=commit_id)
180 commit_id=commit_id)
181
181
182 def get_repo_log(self, repo, filter_term):
182 def get_repo_log(self, repo, filter_term):
183 repo_log = UserLog.query()\
183 repo_log = UserLog.query()\
184 .filter(or_(UserLog.repository_id == repo.repo_id,
184 .filter(or_(UserLog.repository_id == repo.repo_id,
185 UserLog.repository_name == repo.repo_name))\
185 UserLog.repository_name == repo.repo_name))\
186 .options(joinedload(UserLog.user))\
186 .options(joinedload(UserLog.user))\
187 .options(joinedload(UserLog.repository))\
187 .options(joinedload(UserLog.repository))\
188 .order_by(UserLog.action_date.desc())
188 .order_by(UserLog.action_date.desc())
189
189
190 repo_log = user_log_filter(repo_log, filter_term)
190 repo_log = user_log_filter(repo_log, filter_term)
191 return repo_log
191 return repo_log
192
192
193 @classmethod
193 @classmethod
194 def update_commit_cache(cls, repositories=None):
194 def update_commit_cache(cls, repositories=None):
195 if not repositories:
195 if not repositories:
196 repositories = Repository.getAll()
196 repositories = Repository.getAll()
197 for repo in repositories:
197 for repo in repositories:
198 repo.update_commit_cache()
198 repo.update_commit_cache()
199
199
200 def get_repos_as_dict(self, repo_list=None, admin=False,
200 def get_repos_as_dict(self, repo_list=None, admin=False,
201 super_user_actions=False, short_name=None):
201 super_user_actions=False, short_name=None):
202 _render = get_current_request().get_partial_renderer(
202 _render = get_current_request().get_partial_renderer(
203 'rhodecode:templates/data_table/_dt_elements.mako')
203 'rhodecode:templates/data_table/_dt_elements.mako')
204 c = _render.get_call_context()
204 c = _render.get_call_context()
205
205
206 def quick_menu(repo_name):
206 def quick_menu(repo_name):
207 return _render('quick_menu', repo_name)
207 return _render('quick_menu', repo_name)
208
208
209 def repo_lnk(name, rtype, rstate, private, archived, fork_of):
209 def repo_lnk(name, rtype, rstate, private, archived, fork_of):
210 if short_name is not None:
210 if short_name is not None:
211 short_name_var = short_name
211 short_name_var = short_name
212 else:
212 else:
213 short_name_var = not admin
213 short_name_var = not admin
214 return _render('repo_name', name, rtype, rstate, private, archived, fork_of,
214 return _render('repo_name', name, rtype, rstate, private, archived, fork_of,
215 short_name=short_name_var, admin=False)
215 short_name=short_name_var, admin=False)
216
216
217 def last_change(last_change):
217 def last_change(last_change):
218 if admin and isinstance(last_change, datetime.datetime) and not last_change.tzinfo:
218 if admin and isinstance(last_change, datetime.datetime) and not last_change.tzinfo:
219 ts = time.time()
219 ts = time.time()
220 utc_offset = (datetime.datetime.fromtimestamp(ts)
220 utc_offset = (datetime.datetime.fromtimestamp(ts)
221 - datetime.datetime.utcfromtimestamp(ts)).total_seconds()
221 - datetime.datetime.utcfromtimestamp(ts)).total_seconds()
222 last_change = last_change + datetime.timedelta(seconds=utc_offset)
222 last_change = last_change + datetime.timedelta(seconds=utc_offset)
223
223
224 return _render("last_change", last_change)
224 return _render("last_change", last_change)
225
225
226 def rss_lnk(repo_name):
226 def rss_lnk(repo_name):
227 return _render("rss", repo_name)
227 return _render("rss", repo_name)
228
228
229 def atom_lnk(repo_name):
229 def atom_lnk(repo_name):
230 return _render("atom", repo_name)
230 return _render("atom", repo_name)
231
231
232 def last_rev(repo_name, cs_cache):
232 def last_rev(repo_name, cs_cache):
233 return _render('revision', repo_name, cs_cache.get('revision'),
233 return _render('revision', repo_name, cs_cache.get('revision'),
234 cs_cache.get('raw_id'), cs_cache.get('author'),
234 cs_cache.get('raw_id'), cs_cache.get('author'),
235 cs_cache.get('message'), cs_cache.get('date'))
235 cs_cache.get('message'), cs_cache.get('date'))
236
236
237 def desc(desc):
237 def desc(desc):
238 return _render('repo_desc', desc, c.visual.stylify_metatags)
238 return _render('repo_desc', desc, c.visual.stylify_metatags)
239
239
240 def state(repo_state):
240 def state(repo_state):
241 return _render("repo_state", repo_state)
241 return _render("repo_state", repo_state)
242
242
243 def repo_actions(repo_name):
243 def repo_actions(repo_name):
244 return _render('repo_actions', repo_name, super_user_actions)
244 return _render('repo_actions', repo_name, super_user_actions)
245
245
246 def user_profile(username):
246 def user_profile(username):
247 return _render('user_profile', username)
247 return _render('user_profile', username)
248
248
249 repos_data = []
249 repos_data = []
250 for repo in repo_list:
250 for repo in repo_list:
251 # NOTE(marcink): because we use only raw column we need to load it like that
251 # NOTE(marcink): because we use only raw column we need to load it like that
252 changeset_cache = Repository._load_changeset_cache(
252 changeset_cache = Repository._load_changeset_cache(
253 repo.repo_id, repo._changeset_cache)
253 repo.repo_id, repo._changeset_cache)
254
254
255 row = {
255 row = {
256 "menu": quick_menu(repo.repo_name),
256 "menu": quick_menu(repo.repo_name),
257
257
258 "name": repo_lnk(repo.repo_name, repo.repo_type, repo.repo_state,
258 "name": repo_lnk(repo.repo_name, repo.repo_type, repo.repo_state,
259 repo.private, repo.archived, repo.fork),
259 repo.private, repo.archived, repo.fork),
260
260
261 "desc": desc(repo.description),
261 "desc": desc(repo.description),
262
262
263 "last_change": last_change(repo.updated_on),
263 "last_change": last_change(repo.updated_on),
264
264
265 "last_changeset": last_rev(repo.repo_name, changeset_cache),
265 "last_changeset": last_rev(repo.repo_name, changeset_cache),
266 "last_changeset_raw": changeset_cache.get('revision'),
266 "last_changeset_raw": changeset_cache.get('revision'),
267
267
268 "owner": user_profile(repo.User.username),
268 "owner": user_profile(repo.User.username),
269
269
270 "state": state(repo.repo_state),
270 "state": state(repo.repo_state),
271 "rss": rss_lnk(repo.repo_name),
271 "rss": rss_lnk(repo.repo_name),
272 "atom": atom_lnk(repo.repo_name),
272 "atom": atom_lnk(repo.repo_name),
273 }
273 }
274 if admin:
274 if admin:
275 row.update({
275 row.update({
276 "action": repo_actions(repo.repo_name),
276 "action": repo_actions(repo.repo_name),
277 })
277 })
278 repos_data.append(row)
278 repos_data.append(row)
279
279
280 return repos_data
280 return repos_data
281
281
282 def get_repos_data_table(
282 def get_repos_data_table(
283 self, draw, start, limit,
283 self, draw, start, limit,
284 search_q, order_by, order_dir,
284 search_q, order_by, order_dir,
285 auth_user, repo_group_id):
285 auth_user, repo_group_id):
286 from rhodecode.model.scm import RepoList
286 from rhodecode.model.scm import RepoList
287
287
288 _perms = ['repository.read', 'repository.write', 'repository.admin']
288 _perms = ['repository.read', 'repository.write', 'repository.admin']
289
289
290 repos = Repository.query() \
290 repos = Repository.query() \
291 .filter(Repository.group_id == repo_group_id) \
291 .filter(Repository.group_id == repo_group_id) \
292 .all()
292 .all()
293 auth_repo_list = RepoList(
293 auth_repo_list = RepoList(
294 repos, perm_set=_perms,
294 repos, perm_set=_perms,
295 extra_kwargs=dict(user=auth_user))
295 extra_kwargs=dict(user=auth_user))
296
296
297 allowed_ids = [-1]
297 allowed_ids = [-1]
298 for repo in auth_repo_list:
298 for repo in auth_repo_list:
299 allowed_ids.append(repo.repo_id)
299 allowed_ids.append(repo.repo_id)
300
300
301 repos_data_total_count = Repository.query() \
301 repos_data_total_count = Repository.query() \
302 .filter(Repository.group_id == repo_group_id) \
302 .filter(Repository.group_id == repo_group_id) \
303 .filter(or_(
303 .filter(or_(
304 # generate multiple IN to fix limitation problems
304 # generate multiple IN to fix limitation problems
305 *in_filter_generator(Repository.repo_id, allowed_ids))
305 *in_filter_generator(Repository.repo_id, allowed_ids))
306 ) \
306 ) \
307 .count()
307 .count()
308
308
309 base_q = Session.query(
309 base_q = Session.query(
310 Repository.repo_id,
310 Repository.repo_id,
311 Repository.repo_name,
311 Repository.repo_name,
312 Repository.description,
312 Repository.description,
313 Repository.repo_type,
313 Repository.repo_type,
314 Repository.repo_state,
314 Repository.repo_state,
315 Repository.private,
315 Repository.private,
316 Repository.archived,
316 Repository.archived,
317 Repository.fork,
317 Repository.fork,
318 Repository.updated_on,
318 Repository.updated_on,
319 Repository._changeset_cache,
319 Repository._changeset_cache,
320 User,
320 User,
321 ) \
321 ) \
322 .filter(Repository.group_id == repo_group_id) \
322 .filter(Repository.group_id == repo_group_id) \
323 .filter(or_(
323 .filter(or_(
324 # generate multiple IN to fix limitation problems
324 # generate multiple IN to fix limitation problems
325 *in_filter_generator(Repository.repo_id, allowed_ids))
325 *in_filter_generator(Repository.repo_id, allowed_ids))
326 ) \
326 ) \
327 .join(User, User.user_id == Repository.user_id) \
327 .join(User, User.user_id == Repository.user_id) \
328 .group_by(Repository, User)
328 .group_by(Repository, User)
329
329
330 repos_data_total_filtered_count = base_q.count()
330 repos_data_total_filtered_count = base_q.count()
331
331
332 sort_defined = False
332 sort_defined = False
333 if order_by == 'repo_name':
333 if order_by == 'repo_name':
334 sort_col = func.lower(Repository.repo_name)
334 sort_col = func.lower(Repository.repo_name)
335 sort_defined = True
335 sort_defined = True
336 elif order_by == 'user_username':
336 elif order_by == 'user_username':
337 sort_col = User.username
337 sort_col = User.username
338 else:
338 else:
339 sort_col = getattr(Repository, order_by, None)
339 sort_col = getattr(Repository, order_by, None)
340
340
341 if sort_defined or sort_col:
341 if sort_defined or sort_col:
342 if order_dir == 'asc':
342 if order_dir == 'asc':
343 sort_col = sort_col.asc()
343 sort_col = sort_col.asc()
344 else:
344 else:
345 sort_col = sort_col.desc()
345 sort_col = sort_col.desc()
346
346
347 base_q = base_q.order_by(sort_col)
347 base_q = base_q.order_by(sort_col)
348 base_q = base_q.offset(start).limit(limit)
348 base_q = base_q.offset(start).limit(limit)
349
349
350 repos_list = base_q.all()
350 repos_list = base_q.all()
351
351
352 repos_data = RepoModel().get_repos_as_dict(
352 repos_data = RepoModel().get_repos_as_dict(
353 repo_list=repos_list, admin=False)
353 repo_list=repos_list, admin=False)
354
354
355 data = ({
355 data = ({
356 'draw': draw,
356 'draw': draw,
357 'data': repos_data,
357 'data': repos_data,
358 'recordsTotal': repos_data_total_count,
358 'recordsTotal': repos_data_total_count,
359 'recordsFiltered': repos_data_total_filtered_count,
359 'recordsFiltered': repos_data_total_filtered_count,
360 })
360 })
361 return data
361 return data
362
362
363 def _get_defaults(self, repo_name):
363 def _get_defaults(self, repo_name):
364 """
364 """
365 Gets information about repository, and returns a dict for
365 Gets information about repository, and returns a dict for
366 usage in forms
366 usage in forms
367
367
368 :param repo_name:
368 :param repo_name:
369 """
369 """
370
370
371 repo_info = Repository.get_by_repo_name(repo_name)
371 repo_info = Repository.get_by_repo_name(repo_name)
372
372
373 if repo_info is None:
373 if repo_info is None:
374 return None
374 return None
375
375
376 defaults = repo_info.get_dict()
376 defaults = repo_info.get_dict()
377 defaults['repo_name'] = repo_info.just_name
377 defaults['repo_name'] = repo_info.just_name
378
378
379 groups = repo_info.groups_with_parents
379 groups = repo_info.groups_with_parents
380 parent_group = groups[-1] if groups else None
380 parent_group = groups[-1] if groups else None
381
381
382 # we use -1 as this is how in HTML, we mark an empty group
382 # we use -1 as this is how in HTML, we mark an empty group
383 defaults['repo_group'] = getattr(parent_group, 'group_id', -1)
383 defaults['repo_group'] = getattr(parent_group, 'group_id', -1)
384
384
385 keys_to_process = (
385 keys_to_process = (
386 {'k': 'repo_type', 'strip': False},
386 {'k': 'repo_type', 'strip': False},
387 {'k': 'repo_enable_downloads', 'strip': True},
387 {'k': 'repo_enable_downloads', 'strip': True},
388 {'k': 'repo_description', 'strip': True},
388 {'k': 'repo_description', 'strip': True},
389 {'k': 'repo_enable_locking', 'strip': True},
389 {'k': 'repo_enable_locking', 'strip': True},
390 {'k': 'repo_landing_rev', 'strip': True},
390 {'k': 'repo_landing_rev', 'strip': True},
391 {'k': 'clone_uri', 'strip': False},
391 {'k': 'clone_uri', 'strip': False},
392 {'k': 'push_uri', 'strip': False},
392 {'k': 'push_uri', 'strip': False},
393 {'k': 'repo_private', 'strip': True},
393 {'k': 'repo_private', 'strip': True},
394 {'k': 'repo_enable_statistics', 'strip': True}
394 {'k': 'repo_enable_statistics', 'strip': True}
395 )
395 )
396
396
397 for item in keys_to_process:
397 for item in keys_to_process:
398 attr = item['k']
398 attr = item['k']
399 if item['strip']:
399 if item['strip']:
400 attr = remove_prefix(item['k'], 'repo_')
400 attr = remove_prefix(item['k'], 'repo_')
401
401
402 val = defaults[attr]
402 val = defaults[attr]
403 if item['k'] == 'repo_landing_rev':
403 if item['k'] == 'repo_landing_rev':
404 val = ':'.join(defaults[attr])
404 val = ':'.join(defaults[attr])
405 defaults[item['k']] = val
405 defaults[item['k']] = val
406 if item['k'] == 'clone_uri':
406 if item['k'] == 'clone_uri':
407 defaults['clone_uri_hidden'] = repo_info.clone_uri_hidden
407 defaults['clone_uri_hidden'] = repo_info.clone_uri_hidden
408 if item['k'] == 'push_uri':
408 if item['k'] == 'push_uri':
409 defaults['push_uri_hidden'] = repo_info.push_uri_hidden
409 defaults['push_uri_hidden'] = repo_info.push_uri_hidden
410
410
411 # fill owner
411 # fill owner
412 if repo_info.user:
412 if repo_info.user:
413 defaults.update({'user': repo_info.user.username})
413 defaults.update({'user': repo_info.user.username})
414 else:
414 else:
415 replacement_user = User.get_first_super_admin().username
415 replacement_user = User.get_first_super_admin().username
416 defaults.update({'user': replacement_user})
416 defaults.update({'user': replacement_user})
417
417
418 return defaults
418 return defaults
419
419
420 def update(self, repo, **kwargs):
420 def update(self, repo, **kwargs):
421 try:
421 try:
422 cur_repo = self._get_repo(repo)
422 cur_repo = self._get_repo(repo)
423 source_repo_name = cur_repo.repo_name
423 source_repo_name = cur_repo.repo_name
424 if 'user' in kwargs:
424 if 'user' in kwargs:
425 cur_repo.user = User.get_by_username(kwargs['user'])
425 cur_repo.user = User.get_by_username(kwargs['user'])
426
426
427 if 'repo_group' in kwargs:
427 if 'repo_group' in kwargs:
428 cur_repo.group = RepoGroup.get(kwargs['repo_group'])
428 cur_repo.group = RepoGroup.get(kwargs['repo_group'])
429 log.debug('Updating repo %s with params:%s', cur_repo, kwargs)
429 log.debug('Updating repo %s with params:%s', cur_repo, kwargs)
430
430
431 update_keys = [
431 update_keys = [
432 (1, 'repo_description'),
432 (1, 'repo_description'),
433 (1, 'repo_landing_rev'),
433 (1, 'repo_landing_rev'),
434 (1, 'repo_private'),
434 (1, 'repo_private'),
435 (1, 'repo_enable_downloads'),
435 (1, 'repo_enable_downloads'),
436 (1, 'repo_enable_locking'),
436 (1, 'repo_enable_locking'),
437 (1, 'repo_enable_statistics'),
437 (1, 'repo_enable_statistics'),
438 (0, 'clone_uri'),
438 (0, 'clone_uri'),
439 (0, 'push_uri'),
439 (0, 'push_uri'),
440 (0, 'fork_id')
440 (0, 'fork_id')
441 ]
441 ]
442 for strip, k in update_keys:
442 for strip, k in update_keys:
443 if k in kwargs:
443 if k in kwargs:
444 val = kwargs[k]
444 val = kwargs[k]
445 if strip:
445 if strip:
446 k = remove_prefix(k, 'repo_')
446 k = remove_prefix(k, 'repo_')
447
447
448 setattr(cur_repo, k, val)
448 setattr(cur_repo, k, val)
449
449
450 new_name = cur_repo.get_new_name(kwargs['repo_name'])
450 new_name = cur_repo.get_new_name(kwargs['repo_name'])
451 cur_repo.repo_name = new_name
451 cur_repo.repo_name = new_name
452
452
453 # if private flag is set, reset default permission to NONE
453 # if private flag is set, reset default permission to NONE
454 if kwargs.get('repo_private'):
454 if kwargs.get('repo_private'):
455 EMPTY_PERM = 'repository.none'
455 EMPTY_PERM = 'repository.none'
456 RepoModel().grant_user_permission(
456 RepoModel().grant_user_permission(
457 repo=cur_repo, user=User.DEFAULT_USER, perm=EMPTY_PERM
457 repo=cur_repo, user=User.DEFAULT_USER, perm=EMPTY_PERM
458 )
458 )
459
459
460 # handle extra fields
460 # handle extra fields
461 for field in filter(lambda k: k.startswith(RepositoryField.PREFIX), kwargs):
461 for field in filter(lambda k: k.startswith(RepositoryField.PREFIX), kwargs):
462 k = RepositoryField.un_prefix_key(field)
462 k = RepositoryField.un_prefix_key(field)
463 ex_field = RepositoryField.get_by_key_name(
463 ex_field = RepositoryField.get_by_key_name(
464 key=k, repo=cur_repo)
464 key=k, repo=cur_repo)
465 if ex_field:
465 if ex_field:
466 ex_field.field_value = kwargs[field]
466 ex_field.field_value = kwargs[field]
467 self.sa.add(ex_field)
467 self.sa.add(ex_field)
468
468
469 self.sa.add(cur_repo)
469 self.sa.add(cur_repo)
470
470
471 if source_repo_name != new_name:
471 if source_repo_name != new_name:
472 # rename repository
472 # rename repository
473 self._rename_filesystem_repo(
473 self._rename_filesystem_repo(
474 old=source_repo_name, new=new_name)
474 old=source_repo_name, new=new_name)
475
475
476 return cur_repo
476 return cur_repo
477 except Exception:
477 except Exception:
478 log.error(traceback.format_exc())
478 log.error(traceback.format_exc())
479 raise
479 raise
480
480
481 def _create_repo(self, repo_name, repo_type, description, owner,
481 def _create_repo(self, repo_name, repo_type, description, owner,
482 private=False, clone_uri=None, repo_group=None,
482 private=False, clone_uri=None, repo_group=None,
483 landing_rev='rev:tip', fork_of=None,
483 landing_rev='rev:tip', fork_of=None,
484 copy_fork_permissions=False, enable_statistics=False,
484 copy_fork_permissions=False, enable_statistics=False,
485 enable_locking=False, enable_downloads=False,
485 enable_locking=False, enable_downloads=False,
486 copy_group_permissions=False,
486 copy_group_permissions=False,
487 state=Repository.STATE_PENDING):
487 state=Repository.STATE_PENDING):
488 """
488 """
489 Create repository inside database with PENDING state, this should be
489 Create repository inside database with PENDING state, this should be
490 only executed by create() repo. With exception of importing existing
490 only executed by create() repo. With exception of importing existing
491 repos
491 repos
492 """
492 """
493 from rhodecode.model.scm import ScmModel
493 from rhodecode.model.scm import ScmModel
494
494
495 owner = self._get_user(owner)
495 owner = self._get_user(owner)
496 fork_of = self._get_repo(fork_of)
496 fork_of = self._get_repo(fork_of)
497 repo_group = self._get_repo_group(safe_int(repo_group))
497 repo_group = self._get_repo_group(safe_int(repo_group))
498
498
499 try:
499 try:
500 repo_name = safe_unicode(repo_name)
500 repo_name = safe_unicode(repo_name)
501 description = safe_unicode(description)
501 description = safe_unicode(description)
502 # repo name is just a name of repository
502 # repo name is just a name of repository
503 # while repo_name_full is a full qualified name that is combined
503 # while repo_name_full is a full qualified name that is combined
504 # with name and path of group
504 # with name and path of group
505 repo_name_full = repo_name
505 repo_name_full = repo_name
506 repo_name = repo_name.split(Repository.NAME_SEP)[-1]
506 repo_name = repo_name.split(Repository.NAME_SEP)[-1]
507
507
508 new_repo = Repository()
508 new_repo = Repository()
509 new_repo.repo_state = state
509 new_repo.repo_state = state
510 new_repo.enable_statistics = False
510 new_repo.enable_statistics = False
511 new_repo.repo_name = repo_name_full
511 new_repo.repo_name = repo_name_full
512 new_repo.repo_type = repo_type
512 new_repo.repo_type = repo_type
513 new_repo.user = owner
513 new_repo.user = owner
514 new_repo.group = repo_group
514 new_repo.group = repo_group
515 new_repo.description = description or repo_name
515 new_repo.description = description or repo_name
516 new_repo.private = private
516 new_repo.private = private
517 new_repo.archived = False
517 new_repo.archived = False
518 new_repo.clone_uri = clone_uri
518 new_repo.clone_uri = clone_uri
519 new_repo.landing_rev = landing_rev
519 new_repo.landing_rev = landing_rev
520
520
521 new_repo.enable_statistics = enable_statistics
521 new_repo.enable_statistics = enable_statistics
522 new_repo.enable_locking = enable_locking
522 new_repo.enable_locking = enable_locking
523 new_repo.enable_downloads = enable_downloads
523 new_repo.enable_downloads = enable_downloads
524
524
525 if repo_group:
525 if repo_group:
526 new_repo.enable_locking = repo_group.enable_locking
526 new_repo.enable_locking = repo_group.enable_locking
527
527
528 if fork_of:
528 if fork_of:
529 parent_repo = fork_of
529 parent_repo = fork_of
530 new_repo.fork = parent_repo
530 new_repo.fork = parent_repo
531
531
532 events.trigger(events.RepoPreCreateEvent(new_repo))
532 events.trigger(events.RepoPreCreateEvent(new_repo))
533
533
534 self.sa.add(new_repo)
534 self.sa.add(new_repo)
535
535
536 EMPTY_PERM = 'repository.none'
536 EMPTY_PERM = 'repository.none'
537 if fork_of and copy_fork_permissions:
537 if fork_of and copy_fork_permissions:
538 repo = fork_of
538 repo = fork_of
539 user_perms = UserRepoToPerm.query() \
539 user_perms = UserRepoToPerm.query() \
540 .filter(UserRepoToPerm.repository == repo).all()
540 .filter(UserRepoToPerm.repository == repo).all()
541 group_perms = UserGroupRepoToPerm.query() \
541 group_perms = UserGroupRepoToPerm.query() \
542 .filter(UserGroupRepoToPerm.repository == repo).all()
542 .filter(UserGroupRepoToPerm.repository == repo).all()
543
543
544 for perm in user_perms:
544 for perm in user_perms:
545 UserRepoToPerm.create(
545 UserRepoToPerm.create(
546 perm.user, new_repo, perm.permission)
546 perm.user, new_repo, perm.permission)
547
547
548 for perm in group_perms:
548 for perm in group_perms:
549 UserGroupRepoToPerm.create(
549 UserGroupRepoToPerm.create(
550 perm.users_group, new_repo, perm.permission)
550 perm.users_group, new_repo, perm.permission)
551 # in case we copy permissions and also set this repo to private
551 # in case we copy permissions and also set this repo to private
552 # override the default user permission to make it a private repo
552 # override the default user permission to make it a private repo
553 if private:
553 if private:
554 RepoModel(self.sa).grant_user_permission(
554 RepoModel(self.sa).grant_user_permission(
555 repo=new_repo, user=User.DEFAULT_USER, perm=EMPTY_PERM)
555 repo=new_repo, user=User.DEFAULT_USER, perm=EMPTY_PERM)
556
556
557 elif repo_group and copy_group_permissions:
557 elif repo_group and copy_group_permissions:
558 user_perms = UserRepoGroupToPerm.query() \
558 user_perms = UserRepoGroupToPerm.query() \
559 .filter(UserRepoGroupToPerm.group == repo_group).all()
559 .filter(UserRepoGroupToPerm.group == repo_group).all()
560
560
561 group_perms = UserGroupRepoGroupToPerm.query() \
561 group_perms = UserGroupRepoGroupToPerm.query() \
562 .filter(UserGroupRepoGroupToPerm.group == repo_group).all()
562 .filter(UserGroupRepoGroupToPerm.group == repo_group).all()
563
563
564 for perm in user_perms:
564 for perm in user_perms:
565 perm_name = perm.permission.permission_name.replace(
565 perm_name = perm.permission.permission_name.replace(
566 'group.', 'repository.')
566 'group.', 'repository.')
567 perm_obj = Permission.get_by_key(perm_name)
567 perm_obj = Permission.get_by_key(perm_name)
568 UserRepoToPerm.create(perm.user, new_repo, perm_obj)
568 UserRepoToPerm.create(perm.user, new_repo, perm_obj)
569
569
570 for perm in group_perms:
570 for perm in group_perms:
571 perm_name = perm.permission.permission_name.replace(
571 perm_name = perm.permission.permission_name.replace(
572 'group.', 'repository.')
572 'group.', 'repository.')
573 perm_obj = Permission.get_by_key(perm_name)
573 perm_obj = Permission.get_by_key(perm_name)
574 UserGroupRepoToPerm.create(perm.users_group, new_repo, perm_obj)
574 UserGroupRepoToPerm.create(perm.users_group, new_repo, perm_obj)
575
575
576 if private:
576 if private:
577 RepoModel(self.sa).grant_user_permission(
577 RepoModel(self.sa).grant_user_permission(
578 repo=new_repo, user=User.DEFAULT_USER, perm=EMPTY_PERM)
578 repo=new_repo, user=User.DEFAULT_USER, perm=EMPTY_PERM)
579
579
580 else:
580 else:
581 perm_obj = self._create_default_perms(new_repo, private)
581 perm_obj = self._create_default_perms(new_repo, private)
582 self.sa.add(perm_obj)
582 self.sa.add(perm_obj)
583
583
584 # now automatically start following this repository as owner
584 # now automatically start following this repository as owner
585 ScmModel(self.sa).toggle_following_repo(new_repo.repo_id, owner.user_id)
585 ScmModel(self.sa).toggle_following_repo(new_repo.repo_id, owner.user_id)
586
586
587 # we need to flush here, in order to check if database won't
587 # we need to flush here, in order to check if database won't
588 # throw any exceptions, create filesystem dirs at the very end
588 # throw any exceptions, create filesystem dirs at the very end
589 self.sa.flush()
589 self.sa.flush()
590 events.trigger(events.RepoCreateEvent(new_repo))
590 events.trigger(events.RepoCreateEvent(new_repo))
591 return new_repo
591 return new_repo
592
592
593 except Exception:
593 except Exception:
594 log.error(traceback.format_exc())
594 log.error(traceback.format_exc())
595 raise
595 raise
596
596
597 def create(self, form_data, cur_user):
597 def create(self, form_data, cur_user):
598 """
598 """
599 Create repository using celery tasks
599 Create repository using celery tasks
600
600
601 :param form_data:
601 :param form_data:
602 :param cur_user:
602 :param cur_user:
603 """
603 """
604 from rhodecode.lib.celerylib import tasks, run_task
604 from rhodecode.lib.celerylib import tasks, run_task
605 return run_task(tasks.create_repo, form_data, cur_user)
605 return run_task(tasks.create_repo, form_data, cur_user)
606
606
607 def update_permissions(self, repo, perm_additions=None, perm_updates=None,
607 def update_permissions(self, repo, perm_additions=None, perm_updates=None,
608 perm_deletions=None, check_perms=True,
608 perm_deletions=None, check_perms=True,
609 cur_user=None):
609 cur_user=None):
610 if not perm_additions:
610 if not perm_additions:
611 perm_additions = []
611 perm_additions = []
612 if not perm_updates:
612 if not perm_updates:
613 perm_updates = []
613 perm_updates = []
614 if not perm_deletions:
614 if not perm_deletions:
615 perm_deletions = []
615 perm_deletions = []
616
616
617 req_perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin')
617 req_perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin')
618
618
619 changes = {
619 changes = {
620 'added': [],
620 'added': [],
621 'updated': [],
621 'updated': [],
622 'deleted': []
622 'deleted': [],
623 'default_user_changed': None
623 }
624 }
625
626 repo = self._get_repo(repo)
627
624 # update permissions
628 # update permissions
625 for member_id, perm, member_type in perm_updates:
629 for member_id, perm, member_type in perm_updates:
626 member_id = int(member_id)
630 member_id = int(member_id)
627 if member_type == 'user':
631 if member_type == 'user':
628 member_name = User.get(member_id).username
632 member_name = User.get(member_id).username
633 if member_name == User.DEFAULT_USER:
634 # NOTE(dan): detect if we changed permissions for default user
635 perm_obj = self.sa.query(UserRepoToPerm) \
636 .filter(UserRepoToPerm.user_id == member_id) \
637 .filter(UserRepoToPerm.repository == repo) \
638 .scalar()
639 if perm_obj and perm_obj.permission.permission_name != perm:
640 changes['default_user_changed'] = True
641
629 # this updates also current one if found
642 # this updates also current one if found
630 self.grant_user_permission(
643 self.grant_user_permission(
631 repo=repo, user=member_id, perm=perm)
644 repo=repo, user=member_id, perm=perm)
632 elif member_type == 'user_group':
645 elif member_type == 'user_group':
633 # check if we have permissions to alter this usergroup
646 # check if we have permissions to alter this usergroup
634 member_name = UserGroup.get(member_id).users_group_name
647 member_name = UserGroup.get(member_id).users_group_name
635 if not check_perms or HasUserGroupPermissionAny(
648 if not check_perms or HasUserGroupPermissionAny(
636 *req_perms)(member_name, user=cur_user):
649 *req_perms)(member_name, user=cur_user):
637 self.grant_user_group_permission(
650 self.grant_user_group_permission(
638 repo=repo, group_name=member_id, perm=perm)
651 repo=repo, group_name=member_id, perm=perm)
639 else:
652 else:
640 raise ValueError("member_type must be 'user' or 'user_group' "
653 raise ValueError("member_type must be 'user' or 'user_group' "
641 "got {} instead".format(member_type))
654 "got {} instead".format(member_type))
642 changes['updated'].append({'type': member_type, 'id': member_id,
655 changes['updated'].append({'type': member_type, 'id': member_id,
643 'name': member_name, 'new_perm': perm})
656 'name': member_name, 'new_perm': perm})
644
657
645 # set new permissions
658 # set new permissions
646 for member_id, perm, member_type in perm_additions:
659 for member_id, perm, member_type in perm_additions:
647 member_id = int(member_id)
660 member_id = int(member_id)
648 if member_type == 'user':
661 if member_type == 'user':
649 member_name = User.get(member_id).username
662 member_name = User.get(member_id).username
650 self.grant_user_permission(
663 self.grant_user_permission(
651 repo=repo, user=member_id, perm=perm)
664 repo=repo, user=member_id, perm=perm)
652 elif member_type == 'user_group':
665 elif member_type == 'user_group':
653 # check if we have permissions to alter this usergroup
666 # check if we have permissions to alter this usergroup
654 member_name = UserGroup.get(member_id).users_group_name
667 member_name = UserGroup.get(member_id).users_group_name
655 if not check_perms or HasUserGroupPermissionAny(
668 if not check_perms or HasUserGroupPermissionAny(
656 *req_perms)(member_name, user=cur_user):
669 *req_perms)(member_name, user=cur_user):
657 self.grant_user_group_permission(
670 self.grant_user_group_permission(
658 repo=repo, group_name=member_id, perm=perm)
671 repo=repo, group_name=member_id, perm=perm)
659 else:
672 else:
660 raise ValueError("member_type must be 'user' or 'user_group' "
673 raise ValueError("member_type must be 'user' or 'user_group' "
661 "got {} instead".format(member_type))
674 "got {} instead".format(member_type))
662
675
663 changes['added'].append({'type': member_type, 'id': member_id,
676 changes['added'].append({'type': member_type, 'id': member_id,
664 'name': member_name, 'new_perm': perm})
677 'name': member_name, 'new_perm': perm})
665 # delete permissions
678 # delete permissions
666 for member_id, perm, member_type in perm_deletions:
679 for member_id, perm, member_type in perm_deletions:
667 member_id = int(member_id)
680 member_id = int(member_id)
668 if member_type == 'user':
681 if member_type == 'user':
669 member_name = User.get(member_id).username
682 member_name = User.get(member_id).username
670 self.revoke_user_permission(repo=repo, user=member_id)
683 self.revoke_user_permission(repo=repo, user=member_id)
671 elif member_type == 'user_group':
684 elif member_type == 'user_group':
672 # check if we have permissions to alter this usergroup
685 # check if we have permissions to alter this usergroup
673 member_name = UserGroup.get(member_id).users_group_name
686 member_name = UserGroup.get(member_id).users_group_name
674 if not check_perms or HasUserGroupPermissionAny(
687 if not check_perms or HasUserGroupPermissionAny(
675 *req_perms)(member_name, user=cur_user):
688 *req_perms)(member_name, user=cur_user):
676 self.revoke_user_group_permission(
689 self.revoke_user_group_permission(
677 repo=repo, group_name=member_id)
690 repo=repo, group_name=member_id)
678 else:
691 else:
679 raise ValueError("member_type must be 'user' or 'user_group' "
692 raise ValueError("member_type must be 'user' or 'user_group' "
680 "got {} instead".format(member_type))
693 "got {} instead".format(member_type))
681
694
682 changes['deleted'].append({'type': member_type, 'id': member_id,
695 changes['deleted'].append({'type': member_type, 'id': member_id,
683 'name': member_name, 'new_perm': perm})
696 'name': member_name, 'new_perm': perm})
684 return changes
697 return changes
685
698
686 def create_fork(self, form_data, cur_user):
699 def create_fork(self, form_data, cur_user):
687 """
700 """
688 Simple wrapper into executing celery task for fork creation
701 Simple wrapper into executing celery task for fork creation
689
702
690 :param form_data:
703 :param form_data:
691 :param cur_user:
704 :param cur_user:
692 """
705 """
693 from rhodecode.lib.celerylib import tasks, run_task
706 from rhodecode.lib.celerylib import tasks, run_task
694 return run_task(tasks.create_repo_fork, form_data, cur_user)
707 return run_task(tasks.create_repo_fork, form_data, cur_user)
695
708
696 def archive(self, repo):
709 def archive(self, repo):
697 """
710 """
698 Archive given repository. Set archive flag.
711 Archive given repository. Set archive flag.
699
712
700 :param repo:
713 :param repo:
701 """
714 """
702 repo = self._get_repo(repo)
715 repo = self._get_repo(repo)
703 if repo:
716 if repo:
704
717
705 try:
718 try:
706 repo.archived = True
719 repo.archived = True
707 self.sa.add(repo)
720 self.sa.add(repo)
708 self.sa.commit()
721 self.sa.commit()
709 except Exception:
722 except Exception:
710 log.error(traceback.format_exc())
723 log.error(traceback.format_exc())
711 raise
724 raise
712
725
713 def delete(self, repo, forks=None, pull_requests=None, fs_remove=True, cur_user=None):
726 def delete(self, repo, forks=None, pull_requests=None, fs_remove=True, cur_user=None):
714 """
727 """
715 Delete given repository, forks parameter defines what do do with
728 Delete given repository, forks parameter defines what do do with
716 attached forks. Throws AttachedForksError if deleted repo has attached
729 attached forks. Throws AttachedForksError if deleted repo has attached
717 forks
730 forks
718
731
719 :param repo:
732 :param repo:
720 :param forks: str 'delete' or 'detach'
733 :param forks: str 'delete' or 'detach'
721 :param pull_requests: str 'delete' or None
734 :param pull_requests: str 'delete' or None
722 :param fs_remove: remove(archive) repo from filesystem
735 :param fs_remove: remove(archive) repo from filesystem
723 """
736 """
724 if not cur_user:
737 if not cur_user:
725 cur_user = getattr(get_current_rhodecode_user(), 'username', None)
738 cur_user = getattr(get_current_rhodecode_user(), 'username', None)
726 repo = self._get_repo(repo)
739 repo = self._get_repo(repo)
727 if repo:
740 if repo:
728 if forks == 'detach':
741 if forks == 'detach':
729 for r in repo.forks:
742 for r in repo.forks:
730 r.fork = None
743 r.fork = None
731 self.sa.add(r)
744 self.sa.add(r)
732 elif forks == 'delete':
745 elif forks == 'delete':
733 for r in repo.forks:
746 for r in repo.forks:
734 self.delete(r, forks='delete')
747 self.delete(r, forks='delete')
735 elif [f for f in repo.forks]:
748 elif [f for f in repo.forks]:
736 raise AttachedForksError()
749 raise AttachedForksError()
737
750
738 # check for pull requests
751 # check for pull requests
739 pr_sources = repo.pull_requests_source
752 pr_sources = repo.pull_requests_source
740 pr_targets = repo.pull_requests_target
753 pr_targets = repo.pull_requests_target
741 if pull_requests != 'delete' and (pr_sources or pr_targets):
754 if pull_requests != 'delete' and (pr_sources or pr_targets):
742 raise AttachedPullRequestsError()
755 raise AttachedPullRequestsError()
743
756
744 old_repo_dict = repo.get_dict()
757 old_repo_dict = repo.get_dict()
745 events.trigger(events.RepoPreDeleteEvent(repo))
758 events.trigger(events.RepoPreDeleteEvent(repo))
746 try:
759 try:
747 self.sa.delete(repo)
760 self.sa.delete(repo)
748 if fs_remove:
761 if fs_remove:
749 self._delete_filesystem_repo(repo)
762 self._delete_filesystem_repo(repo)
750 else:
763 else:
751 log.debug('skipping removal from filesystem')
764 log.debug('skipping removal from filesystem')
752 old_repo_dict.update({
765 old_repo_dict.update({
753 'deleted_by': cur_user,
766 'deleted_by': cur_user,
754 'deleted_on': time.time(),
767 'deleted_on': time.time(),
755 })
768 })
756 log_delete_repository(**old_repo_dict)
769 log_delete_repository(**old_repo_dict)
757 events.trigger(events.RepoDeleteEvent(repo))
770 events.trigger(events.RepoDeleteEvent(repo))
758 except Exception:
771 except Exception:
759 log.error(traceback.format_exc())
772 log.error(traceback.format_exc())
760 raise
773 raise
761
774
762 def grant_user_permission(self, repo, user, perm):
775 def grant_user_permission(self, repo, user, perm):
763 """
776 """
764 Grant permission for user on given repository, or update existing one
777 Grant permission for user on given repository, or update existing one
765 if found
778 if found
766
779
767 :param repo: Instance of Repository, repository_id, or repository name
780 :param repo: Instance of Repository, repository_id, or repository name
768 :param user: Instance of User, user_id or username
781 :param user: Instance of User, user_id or username
769 :param perm: Instance of Permission, or permission_name
782 :param perm: Instance of Permission, or permission_name
770 """
783 """
771 user = self._get_user(user)
784 user = self._get_user(user)
772 repo = self._get_repo(repo)
785 repo = self._get_repo(repo)
773 permission = self._get_perm(perm)
786 permission = self._get_perm(perm)
774
787
775 # check if we have that permission already
788 # check if we have that permission already
776 obj = self.sa.query(UserRepoToPerm) \
789 obj = self.sa.query(UserRepoToPerm) \
777 .filter(UserRepoToPerm.user == user) \
790 .filter(UserRepoToPerm.user == user) \
778 .filter(UserRepoToPerm.repository == repo) \
791 .filter(UserRepoToPerm.repository == repo) \
779 .scalar()
792 .scalar()
780 if obj is None:
793 if obj is None:
781 # create new !
794 # create new !
782 obj = UserRepoToPerm()
795 obj = UserRepoToPerm()
783 obj.repository = repo
796 obj.repository = repo
784 obj.user = user
797 obj.user = user
785 obj.permission = permission
798 obj.permission = permission
786 self.sa.add(obj)
799 self.sa.add(obj)
787 log.debug('Granted perm %s to %s on %s', perm, user, repo)
800 log.debug('Granted perm %s to %s on %s', perm, user, repo)
788 action_logger_generic(
801 action_logger_generic(
789 'granted permission: {} to user: {} on repo: {}'.format(
802 'granted permission: {} to user: {} on repo: {}'.format(
790 perm, user, repo), namespace='security.repo')
803 perm, user, repo), namespace='security.repo')
791 return obj
804 return obj
792
805
793 def revoke_user_permission(self, repo, user):
806 def revoke_user_permission(self, repo, user):
794 """
807 """
795 Revoke permission for user on given repository
808 Revoke permission for user on given repository
796
809
797 :param repo: Instance of Repository, repository_id, or repository name
810 :param repo: Instance of Repository, repository_id, or repository name
798 :param user: Instance of User, user_id or username
811 :param user: Instance of User, user_id or username
799 """
812 """
800
813
801 user = self._get_user(user)
814 user = self._get_user(user)
802 repo = self._get_repo(repo)
815 repo = self._get_repo(repo)
803
816
804 obj = self.sa.query(UserRepoToPerm) \
817 obj = self.sa.query(UserRepoToPerm) \
805 .filter(UserRepoToPerm.repository == repo) \
818 .filter(UserRepoToPerm.repository == repo) \
806 .filter(UserRepoToPerm.user == user) \
819 .filter(UserRepoToPerm.user == user) \
807 .scalar()
820 .scalar()
808 if obj:
821 if obj:
809 self.sa.delete(obj)
822 self.sa.delete(obj)
810 log.debug('Revoked perm on %s on %s', repo, user)
823 log.debug('Revoked perm on %s on %s', repo, user)
811 action_logger_generic(
824 action_logger_generic(
812 'revoked permission from user: {} on repo: {}'.format(
825 'revoked permission from user: {} on repo: {}'.format(
813 user, repo), namespace='security.repo')
826 user, repo), namespace='security.repo')
814
827
815 def grant_user_group_permission(self, repo, group_name, perm):
828 def grant_user_group_permission(self, repo, group_name, perm):
816 """
829 """
817 Grant permission for user group on given repository, or update
830 Grant permission for user group on given repository, or update
818 existing one if found
831 existing one if found
819
832
820 :param repo: Instance of Repository, repository_id, or repository name
833 :param repo: Instance of Repository, repository_id, or repository name
821 :param group_name: Instance of UserGroup, users_group_id,
834 :param group_name: Instance of UserGroup, users_group_id,
822 or user group name
835 or user group name
823 :param perm: Instance of Permission, or permission_name
836 :param perm: Instance of Permission, or permission_name
824 """
837 """
825 repo = self._get_repo(repo)
838 repo = self._get_repo(repo)
826 group_name = self._get_user_group(group_name)
839 group_name = self._get_user_group(group_name)
827 permission = self._get_perm(perm)
840 permission = self._get_perm(perm)
828
841
829 # check if we have that permission already
842 # check if we have that permission already
830 obj = self.sa.query(UserGroupRepoToPerm) \
843 obj = self.sa.query(UserGroupRepoToPerm) \
831 .filter(UserGroupRepoToPerm.users_group == group_name) \
844 .filter(UserGroupRepoToPerm.users_group == group_name) \
832 .filter(UserGroupRepoToPerm.repository == repo) \
845 .filter(UserGroupRepoToPerm.repository == repo) \
833 .scalar()
846 .scalar()
834
847
835 if obj is None:
848 if obj is None:
836 # create new
849 # create new
837 obj = UserGroupRepoToPerm()
850 obj = UserGroupRepoToPerm()
838
851
839 obj.repository = repo
852 obj.repository = repo
840 obj.users_group = group_name
853 obj.users_group = group_name
841 obj.permission = permission
854 obj.permission = permission
842 self.sa.add(obj)
855 self.sa.add(obj)
843 log.debug('Granted perm %s to %s on %s', perm, group_name, repo)
856 log.debug('Granted perm %s to %s on %s', perm, group_name, repo)
844 action_logger_generic(
857 action_logger_generic(
845 'granted permission: {} to usergroup: {} on repo: {}'.format(
858 'granted permission: {} to usergroup: {} on repo: {}'.format(
846 perm, group_name, repo), namespace='security.repo')
859 perm, group_name, repo), namespace='security.repo')
847
860
848 return obj
861 return obj
849
862
850 def revoke_user_group_permission(self, repo, group_name):
863 def revoke_user_group_permission(self, repo, group_name):
851 """
864 """
852 Revoke permission for user group on given repository
865 Revoke permission for user group on given repository
853
866
854 :param repo: Instance of Repository, repository_id, or repository name
867 :param repo: Instance of Repository, repository_id, or repository name
855 :param group_name: Instance of UserGroup, users_group_id,
868 :param group_name: Instance of UserGroup, users_group_id,
856 or user group name
869 or user group name
857 """
870 """
858 repo = self._get_repo(repo)
871 repo = self._get_repo(repo)
859 group_name = self._get_user_group(group_name)
872 group_name = self._get_user_group(group_name)
860
873
861 obj = self.sa.query(UserGroupRepoToPerm) \
874 obj = self.sa.query(UserGroupRepoToPerm) \
862 .filter(UserGroupRepoToPerm.repository == repo) \
875 .filter(UserGroupRepoToPerm.repository == repo) \
863 .filter(UserGroupRepoToPerm.users_group == group_name) \
876 .filter(UserGroupRepoToPerm.users_group == group_name) \
864 .scalar()
877 .scalar()
865 if obj:
878 if obj:
866 self.sa.delete(obj)
879 self.sa.delete(obj)
867 log.debug('Revoked perm to %s on %s', repo, group_name)
880 log.debug('Revoked perm to %s on %s', repo, group_name)
868 action_logger_generic(
881 action_logger_generic(
869 'revoked permission from usergroup: {} on repo: {}'.format(
882 'revoked permission from usergroup: {} on repo: {}'.format(
870 group_name, repo), namespace='security.repo')
883 group_name, repo), namespace='security.repo')
871
884
872 def delete_stats(self, repo_name):
885 def delete_stats(self, repo_name):
873 """
886 """
874 removes stats for given repo
887 removes stats for given repo
875
888
876 :param repo_name:
889 :param repo_name:
877 """
890 """
878 repo = self._get_repo(repo_name)
891 repo = self._get_repo(repo_name)
879 try:
892 try:
880 obj = self.sa.query(Statistics) \
893 obj = self.sa.query(Statistics) \
881 .filter(Statistics.repository == repo).scalar()
894 .filter(Statistics.repository == repo).scalar()
882 if obj:
895 if obj:
883 self.sa.delete(obj)
896 self.sa.delete(obj)
884 except Exception:
897 except Exception:
885 log.error(traceback.format_exc())
898 log.error(traceback.format_exc())
886 raise
899 raise
887
900
888 def add_repo_field(self, repo_name, field_key, field_label, field_value='',
901 def add_repo_field(self, repo_name, field_key, field_label, field_value='',
889 field_type='str', field_desc=''):
902 field_type='str', field_desc=''):
890
903
891 repo = self._get_repo(repo_name)
904 repo = self._get_repo(repo_name)
892
905
893 new_field = RepositoryField()
906 new_field = RepositoryField()
894 new_field.repository = repo
907 new_field.repository = repo
895 new_field.field_key = field_key
908 new_field.field_key = field_key
896 new_field.field_type = field_type # python type
909 new_field.field_type = field_type # python type
897 new_field.field_value = field_value
910 new_field.field_value = field_value
898 new_field.field_desc = field_desc
911 new_field.field_desc = field_desc
899 new_field.field_label = field_label
912 new_field.field_label = field_label
900 self.sa.add(new_field)
913 self.sa.add(new_field)
901 return new_field
914 return new_field
902
915
903 def delete_repo_field(self, repo_name, field_key):
916 def delete_repo_field(self, repo_name, field_key):
904 repo = self._get_repo(repo_name)
917 repo = self._get_repo(repo_name)
905 field = RepositoryField.get_by_key_name(field_key, repo)
918 field = RepositoryField.get_by_key_name(field_key, repo)
906 if field:
919 if field:
907 self.sa.delete(field)
920 self.sa.delete(field)
908
921
909 def _create_filesystem_repo(self, repo_name, repo_type, repo_group,
922 def _create_filesystem_repo(self, repo_name, repo_type, repo_group,
910 clone_uri=None, repo_store_location=None,
923 clone_uri=None, repo_store_location=None,
911 use_global_config=False, install_hooks=True):
924 use_global_config=False, install_hooks=True):
912 """
925 """
913 makes repository on filesystem. It's group aware means it'll create
926 makes repository on filesystem. It's group aware means it'll create
914 a repository within a group, and alter the paths accordingly of
927 a repository within a group, and alter the paths accordingly of
915 group location
928 group location
916
929
917 :param repo_name:
930 :param repo_name:
918 :param alias:
931 :param alias:
919 :param parent:
932 :param parent:
920 :param clone_uri:
933 :param clone_uri:
921 :param repo_store_location:
934 :param repo_store_location:
922 """
935 """
923 from rhodecode.lib.utils import is_valid_repo, is_valid_repo_group
936 from rhodecode.lib.utils import is_valid_repo, is_valid_repo_group
924 from rhodecode.model.scm import ScmModel
937 from rhodecode.model.scm import ScmModel
925
938
926 if Repository.NAME_SEP in repo_name:
939 if Repository.NAME_SEP in repo_name:
927 raise ValueError(
940 raise ValueError(
928 'repo_name must not contain groups got `%s`' % repo_name)
941 'repo_name must not contain groups got `%s`' % repo_name)
929
942
930 if isinstance(repo_group, RepoGroup):
943 if isinstance(repo_group, RepoGroup):
931 new_parent_path = os.sep.join(repo_group.full_path_splitted)
944 new_parent_path = os.sep.join(repo_group.full_path_splitted)
932 else:
945 else:
933 new_parent_path = repo_group or ''
946 new_parent_path = repo_group or ''
934
947
935 if repo_store_location:
948 if repo_store_location:
936 _paths = [repo_store_location]
949 _paths = [repo_store_location]
937 else:
950 else:
938 _paths = [self.repos_path, new_parent_path, repo_name]
951 _paths = [self.repos_path, new_parent_path, repo_name]
939 # we need to make it str for mercurial
952 # we need to make it str for mercurial
940 repo_path = os.path.join(*map(lambda x: safe_str(x), _paths))
953 repo_path = os.path.join(*map(lambda x: safe_str(x), _paths))
941
954
942 # check if this path is not a repository
955 # check if this path is not a repository
943 if is_valid_repo(repo_path, self.repos_path):
956 if is_valid_repo(repo_path, self.repos_path):
944 raise Exception('This path %s is a valid repository' % repo_path)
957 raise Exception('This path %s is a valid repository' % repo_path)
945
958
946 # check if this path is a group
959 # check if this path is a group
947 if is_valid_repo_group(repo_path, self.repos_path):
960 if is_valid_repo_group(repo_path, self.repos_path):
948 raise Exception('This path %s is a valid group' % repo_path)
961 raise Exception('This path %s is a valid group' % repo_path)
949
962
950 log.info('creating repo %s in %s from url: `%s`',
963 log.info('creating repo %s in %s from url: `%s`',
951 repo_name, safe_unicode(repo_path),
964 repo_name, safe_unicode(repo_path),
952 obfuscate_url_pw(clone_uri))
965 obfuscate_url_pw(clone_uri))
953
966
954 backend = get_backend(repo_type)
967 backend = get_backend(repo_type)
955
968
956 config_repo = None if use_global_config else repo_name
969 config_repo = None if use_global_config else repo_name
957 if config_repo and new_parent_path:
970 if config_repo and new_parent_path:
958 config_repo = Repository.NAME_SEP.join(
971 config_repo = Repository.NAME_SEP.join(
959 (new_parent_path, config_repo))
972 (new_parent_path, config_repo))
960 config = make_db_config(clear_session=False, repo=config_repo)
973 config = make_db_config(clear_session=False, repo=config_repo)
961 config.set('extensions', 'largefiles', '')
974 config.set('extensions', 'largefiles', '')
962
975
963 # patch and reset hooks section of UI config to not run any
976 # patch and reset hooks section of UI config to not run any
964 # hooks on creating remote repo
977 # hooks on creating remote repo
965 config.clear_section('hooks')
978 config.clear_section('hooks')
966
979
967 # TODO: johbo: Unify this, hardcoded "bare=True" does not look nice
980 # TODO: johbo: Unify this, hardcoded "bare=True" does not look nice
968 if repo_type == 'git':
981 if repo_type == 'git':
969 repo = backend(
982 repo = backend(
970 repo_path, config=config, create=True, src_url=clone_uri, bare=True,
983 repo_path, config=config, create=True, src_url=clone_uri, bare=True,
971 with_wire={"cache": False})
984 with_wire={"cache": False})
972 else:
985 else:
973 repo = backend(
986 repo = backend(
974 repo_path, config=config, create=True, src_url=clone_uri,
987 repo_path, config=config, create=True, src_url=clone_uri,
975 with_wire={"cache": False})
988 with_wire={"cache": False})
976
989
977 if install_hooks:
990 if install_hooks:
978 repo.install_hooks()
991 repo.install_hooks()
979
992
980 log.debug('Created repo %s with %s backend',
993 log.debug('Created repo %s with %s backend',
981 safe_unicode(repo_name), safe_unicode(repo_type))
994 safe_unicode(repo_name), safe_unicode(repo_type))
982 return repo
995 return repo
983
996
984 def _rename_filesystem_repo(self, old, new):
997 def _rename_filesystem_repo(self, old, new):
985 """
998 """
986 renames repository on filesystem
999 renames repository on filesystem
987
1000
988 :param old: old name
1001 :param old: old name
989 :param new: new name
1002 :param new: new name
990 """
1003 """
991 log.info('renaming repo from %s to %s', old, new)
1004 log.info('renaming repo from %s to %s', old, new)
992
1005
993 old_path = os.path.join(self.repos_path, old)
1006 old_path = os.path.join(self.repos_path, old)
994 new_path = os.path.join(self.repos_path, new)
1007 new_path = os.path.join(self.repos_path, new)
995 if os.path.isdir(new_path):
1008 if os.path.isdir(new_path):
996 raise Exception(
1009 raise Exception(
997 'Was trying to rename to already existing dir %s' % new_path
1010 'Was trying to rename to already existing dir %s' % new_path
998 )
1011 )
999 shutil.move(old_path, new_path)
1012 shutil.move(old_path, new_path)
1000
1013
1001 def _delete_filesystem_repo(self, repo):
1014 def _delete_filesystem_repo(self, repo):
1002 """
1015 """
1003 removes repo from filesystem, the removal is acctually made by
1016 removes repo from filesystem, the removal is acctually made by
1004 added rm__ prefix into dir, and rename internat .hg/.git dirs so this
1017 added rm__ prefix into dir, and rename internat .hg/.git dirs so this
1005 repository is no longer valid for rhodecode, can be undeleted later on
1018 repository is no longer valid for rhodecode, can be undeleted later on
1006 by reverting the renames on this repository
1019 by reverting the renames on this repository
1007
1020
1008 :param repo: repo object
1021 :param repo: repo object
1009 """
1022 """
1010 rm_path = os.path.join(self.repos_path, repo.repo_name)
1023 rm_path = os.path.join(self.repos_path, repo.repo_name)
1011 repo_group = repo.group
1024 repo_group = repo.group
1012 log.info("Removing repository %s", rm_path)
1025 log.info("Removing repository %s", rm_path)
1013 # disable hg/git internal that it doesn't get detected as repo
1026 # disable hg/git internal that it doesn't get detected as repo
1014 alias = repo.repo_type
1027 alias = repo.repo_type
1015
1028
1016 config = make_db_config(clear_session=False)
1029 config = make_db_config(clear_session=False)
1017 config.set('extensions', 'largefiles', '')
1030 config.set('extensions', 'largefiles', '')
1018 bare = getattr(repo.scm_instance(config=config), 'bare', False)
1031 bare = getattr(repo.scm_instance(config=config), 'bare', False)
1019
1032
1020 # skip this for bare git repos
1033 # skip this for bare git repos
1021 if not bare:
1034 if not bare:
1022 # disable VCS repo
1035 # disable VCS repo
1023 vcs_path = os.path.join(rm_path, '.%s' % alias)
1036 vcs_path = os.path.join(rm_path, '.%s' % alias)
1024 if os.path.exists(vcs_path):
1037 if os.path.exists(vcs_path):
1025 shutil.move(vcs_path, os.path.join(rm_path, 'rm__.%s' % alias))
1038 shutil.move(vcs_path, os.path.join(rm_path, 'rm__.%s' % alias))
1026
1039
1027 _now = datetime.datetime.now()
1040 _now = datetime.datetime.now()
1028 _ms = str(_now.microsecond).rjust(6, '0')
1041 _ms = str(_now.microsecond).rjust(6, '0')
1029 _d = 'rm__%s__%s' % (_now.strftime('%Y%m%d_%H%M%S_' + _ms),
1042 _d = 'rm__%s__%s' % (_now.strftime('%Y%m%d_%H%M%S_' + _ms),
1030 repo.just_name)
1043 repo.just_name)
1031 if repo_group:
1044 if repo_group:
1032 # if repository is in group, prefix the removal path with the group
1045 # if repository is in group, prefix the removal path with the group
1033 args = repo_group.full_path_splitted + [_d]
1046 args = repo_group.full_path_splitted + [_d]
1034 _d = os.path.join(*args)
1047 _d = os.path.join(*args)
1035
1048
1036 if os.path.isdir(rm_path):
1049 if os.path.isdir(rm_path):
1037 shutil.move(rm_path, os.path.join(self.repos_path, _d))
1050 shutil.move(rm_path, os.path.join(self.repos_path, _d))
1038
1051
1039 # finally cleanup diff-cache if it exists
1052 # finally cleanup diff-cache if it exists
1040 cached_diffs_dir = repo.cached_diffs_dir
1053 cached_diffs_dir = repo.cached_diffs_dir
1041 if os.path.isdir(cached_diffs_dir):
1054 if os.path.isdir(cached_diffs_dir):
1042 shutil.rmtree(cached_diffs_dir)
1055 shutil.rmtree(cached_diffs_dir)
1043
1056
1044
1057
1045 class ReadmeFinder:
1058 class ReadmeFinder:
1046 """
1059 """
1047 Utility which knows how to find a readme for a specific commit.
1060 Utility which knows how to find a readme for a specific commit.
1048
1061
1049 The main idea is that this is a configurable algorithm. When creating an
1062 The main idea is that this is a configurable algorithm. When creating an
1050 instance you can define parameters, currently only the `default_renderer`.
1063 instance you can define parameters, currently only the `default_renderer`.
1051 Based on this configuration the method :meth:`search` behaves slightly
1064 Based on this configuration the method :meth:`search` behaves slightly
1052 different.
1065 different.
1053 """
1066 """
1054
1067
1055 readme_re = re.compile(r'^readme(\.[^\.]+)?$', re.IGNORECASE)
1068 readme_re = re.compile(r'^readme(\.[^\.]+)?$', re.IGNORECASE)
1056 path_re = re.compile(r'^docs?', re.IGNORECASE)
1069 path_re = re.compile(r'^docs?', re.IGNORECASE)
1057
1070
1058 default_priorities = {
1071 default_priorities = {
1059 None: 0,
1072 None: 0,
1060 '.text': 2,
1073 '.text': 2,
1061 '.txt': 3,
1074 '.txt': 3,
1062 '.rst': 1,
1075 '.rst': 1,
1063 '.rest': 2,
1076 '.rest': 2,
1064 '.md': 1,
1077 '.md': 1,
1065 '.mkdn': 2,
1078 '.mkdn': 2,
1066 '.mdown': 3,
1079 '.mdown': 3,
1067 '.markdown': 4,
1080 '.markdown': 4,
1068 }
1081 }
1069
1082
1070 path_priority = {
1083 path_priority = {
1071 'doc': 0,
1084 'doc': 0,
1072 'docs': 1,
1085 'docs': 1,
1073 }
1086 }
1074
1087
1075 FALLBACK_PRIORITY = 99
1088 FALLBACK_PRIORITY = 99
1076
1089
1077 RENDERER_TO_EXTENSION = {
1090 RENDERER_TO_EXTENSION = {
1078 'rst': ['.rst', '.rest'],
1091 'rst': ['.rst', '.rest'],
1079 'markdown': ['.md', 'mkdn', '.mdown', '.markdown'],
1092 'markdown': ['.md', 'mkdn', '.mdown', '.markdown'],
1080 }
1093 }
1081
1094
1082 def __init__(self, default_renderer=None):
1095 def __init__(self, default_renderer=None):
1083 self._default_renderer = default_renderer
1096 self._default_renderer = default_renderer
1084 self._renderer_extensions = self.RENDERER_TO_EXTENSION.get(
1097 self._renderer_extensions = self.RENDERER_TO_EXTENSION.get(
1085 default_renderer, [])
1098 default_renderer, [])
1086
1099
1087 def search(self, commit, path='/'):
1100 def search(self, commit, path='/'):
1088 """
1101 """
1089 Find a readme in the given `commit`.
1102 Find a readme in the given `commit`.
1090 """
1103 """
1091 nodes = commit.get_nodes(path)
1104 nodes = commit.get_nodes(path)
1092 matches = self._match_readmes(nodes)
1105 matches = self._match_readmes(nodes)
1093 matches = self._sort_according_to_priority(matches)
1106 matches = self._sort_according_to_priority(matches)
1094 if matches:
1107 if matches:
1095 return matches[0].node
1108 return matches[0].node
1096
1109
1097 paths = self._match_paths(nodes)
1110 paths = self._match_paths(nodes)
1098 paths = self._sort_paths_according_to_priority(paths)
1111 paths = self._sort_paths_according_to_priority(paths)
1099 for path in paths:
1112 for path in paths:
1100 match = self.search(commit, path=path)
1113 match = self.search(commit, path=path)
1101 if match:
1114 if match:
1102 return match
1115 return match
1103
1116
1104 return None
1117 return None
1105
1118
1106 def _match_readmes(self, nodes):
1119 def _match_readmes(self, nodes):
1107 for node in nodes:
1120 for node in nodes:
1108 if not node.is_file():
1121 if not node.is_file():
1109 continue
1122 continue
1110 path = node.path.rsplit('/', 1)[-1]
1123 path = node.path.rsplit('/', 1)[-1]
1111 match = self.readme_re.match(path)
1124 match = self.readme_re.match(path)
1112 if match:
1125 if match:
1113 extension = match.group(1)
1126 extension = match.group(1)
1114 yield ReadmeMatch(node, match, self._priority(extension))
1127 yield ReadmeMatch(node, match, self._priority(extension))
1115
1128
1116 def _match_paths(self, nodes):
1129 def _match_paths(self, nodes):
1117 for node in nodes:
1130 for node in nodes:
1118 if not node.is_dir():
1131 if not node.is_dir():
1119 continue
1132 continue
1120 match = self.path_re.match(node.path)
1133 match = self.path_re.match(node.path)
1121 if match:
1134 if match:
1122 yield node.path
1135 yield node.path
1123
1136
1124 def _priority(self, extension):
1137 def _priority(self, extension):
1125 renderer_priority = (
1138 renderer_priority = (
1126 0 if extension in self._renderer_extensions else 1)
1139 0 if extension in self._renderer_extensions else 1)
1127 extension_priority = self.default_priorities.get(
1140 extension_priority = self.default_priorities.get(
1128 extension, self.FALLBACK_PRIORITY)
1141 extension, self.FALLBACK_PRIORITY)
1129 return (renderer_priority, extension_priority)
1142 return (renderer_priority, extension_priority)
1130
1143
1131 def _sort_according_to_priority(self, matches):
1144 def _sort_according_to_priority(self, matches):
1132
1145
1133 def priority_and_path(match):
1146 def priority_and_path(match):
1134 return (match.priority, match.path)
1147 return (match.priority, match.path)
1135
1148
1136 return sorted(matches, key=priority_and_path)
1149 return sorted(matches, key=priority_and_path)
1137
1150
1138 def _sort_paths_according_to_priority(self, paths):
1151 def _sort_paths_according_to_priority(self, paths):
1139
1152
1140 def priority_and_path(path):
1153 def priority_and_path(path):
1141 return (self.path_priority.get(path, self.FALLBACK_PRIORITY), path)
1154 return (self.path_priority.get(path, self.FALLBACK_PRIORITY), path)
1142
1155
1143 return sorted(paths, key=priority_and_path)
1156 return sorted(paths, key=priority_and_path)
1144
1157
1145
1158
1146 class ReadmeMatch:
1159 class ReadmeMatch:
1147
1160
1148 def __init__(self, node, match, priority):
1161 def __init__(self, node, match, priority):
1149 self.node = node
1162 self.node = node
1150 self._match = match
1163 self._match = match
1151 self.priority = priority
1164 self.priority = priority
1152
1165
1153 @property
1166 @property
1154 def path(self):
1167 def path(self):
1155 return self.node.path
1168 return self.node.path
1156
1169
1157 def __repr__(self):
1170 def __repr__(self):
1158 return '<ReadmeMatch {} priority={}'.format(self.path, self.priority)
1171 return '<ReadmeMatch {} priority={}'.format(self.path, self.priority)
@@ -1,876 +1,886 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2019 RhodeCode GmbH
3 # Copyright (C) 2011-2019 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21
21
22 """
22 """
23 repo group model for RhodeCode
23 repo group model for RhodeCode
24 """
24 """
25
25
26 import os
26 import os
27 import datetime
27 import datetime
28 import itertools
28 import itertools
29 import logging
29 import logging
30 import shutil
30 import shutil
31 import time
31 import time
32 import traceback
32 import traceback
33 import string
33 import string
34
34
35 from zope.cachedescriptors.property import Lazy as LazyProperty
35 from zope.cachedescriptors.property import Lazy as LazyProperty
36
36
37 from rhodecode import events
37 from rhodecode import events
38 from rhodecode.model import BaseModel
38 from rhodecode.model import BaseModel
39 from rhodecode.model.db import (_hash_key, func, or_, in_filter_generator,
39 from rhodecode.model.db import (_hash_key, func, or_, in_filter_generator,
40 Session, RepoGroup, UserRepoGroupToPerm, User, Permission, UserGroupRepoGroupToPerm,
40 Session, RepoGroup, UserRepoGroupToPerm, User, Permission, UserGroupRepoGroupToPerm,
41 UserGroup, Repository)
41 UserGroup, Repository)
42 from rhodecode.model.settings import VcsSettingsModel, SettingsModel
42 from rhodecode.model.settings import VcsSettingsModel, SettingsModel
43 from rhodecode.lib.caching_query import FromCache
43 from rhodecode.lib.caching_query import FromCache
44 from rhodecode.lib.utils2 import action_logger_generic, datetime_to_time
44 from rhodecode.lib.utils2 import action_logger_generic, datetime_to_time
45
45
46 log = logging.getLogger(__name__)
46 log = logging.getLogger(__name__)
47
47
48
48
49 class RepoGroupModel(BaseModel):
49 class RepoGroupModel(BaseModel):
50
50
51 cls = RepoGroup
51 cls = RepoGroup
52 PERSONAL_GROUP_DESC = 'personal repo group of user `%(username)s`'
52 PERSONAL_GROUP_DESC = 'personal repo group of user `%(username)s`'
53 PERSONAL_GROUP_PATTERN = '${username}' # default
53 PERSONAL_GROUP_PATTERN = '${username}' # default
54
54
55 def _get_user_group(self, users_group):
55 def _get_user_group(self, users_group):
56 return self._get_instance(UserGroup, users_group,
56 return self._get_instance(UserGroup, users_group,
57 callback=UserGroup.get_by_group_name)
57 callback=UserGroup.get_by_group_name)
58
58
59 def _get_repo_group(self, repo_group):
59 def _get_repo_group(self, repo_group):
60 return self._get_instance(RepoGroup, repo_group,
60 return self._get_instance(RepoGroup, repo_group,
61 callback=RepoGroup.get_by_group_name)
61 callback=RepoGroup.get_by_group_name)
62
62
63 @LazyProperty
63 @LazyProperty
64 def repos_path(self):
64 def repos_path(self):
65 """
65 """
66 Gets the repositories root path from database
66 Gets the repositories root path from database
67 """
67 """
68
68
69 settings_model = VcsSettingsModel(sa=self.sa)
69 settings_model = VcsSettingsModel(sa=self.sa)
70 return settings_model.get_repos_location()
70 return settings_model.get_repos_location()
71
71
72 def get_by_group_name(self, repo_group_name, cache=None):
72 def get_by_group_name(self, repo_group_name, cache=None):
73 repo = self.sa.query(RepoGroup) \
73 repo = self.sa.query(RepoGroup) \
74 .filter(RepoGroup.group_name == repo_group_name)
74 .filter(RepoGroup.group_name == repo_group_name)
75
75
76 if cache:
76 if cache:
77 name_key = _hash_key(repo_group_name)
77 name_key = _hash_key(repo_group_name)
78 repo = repo.options(
78 repo = repo.options(
79 FromCache("sql_cache_short", "get_repo_group_%s" % name_key))
79 FromCache("sql_cache_short", "get_repo_group_%s" % name_key))
80 return repo.scalar()
80 return repo.scalar()
81
81
82 def get_default_create_personal_repo_group(self):
82 def get_default_create_personal_repo_group(self):
83 value = SettingsModel().get_setting_by_name(
83 value = SettingsModel().get_setting_by_name(
84 'create_personal_repo_group')
84 'create_personal_repo_group')
85 return value.app_settings_value if value else None or False
85 return value.app_settings_value if value else None or False
86
86
87 def get_personal_group_name_pattern(self):
87 def get_personal_group_name_pattern(self):
88 value = SettingsModel().get_setting_by_name(
88 value = SettingsModel().get_setting_by_name(
89 'personal_repo_group_pattern')
89 'personal_repo_group_pattern')
90 val = value.app_settings_value if value else None
90 val = value.app_settings_value if value else None
91 group_template = val or self.PERSONAL_GROUP_PATTERN
91 group_template = val or self.PERSONAL_GROUP_PATTERN
92
92
93 group_template = group_template.lstrip('/')
93 group_template = group_template.lstrip('/')
94 return group_template
94 return group_template
95
95
96 def get_personal_group_name(self, user):
96 def get_personal_group_name(self, user):
97 template = self.get_personal_group_name_pattern()
97 template = self.get_personal_group_name_pattern()
98 return string.Template(template).safe_substitute(
98 return string.Template(template).safe_substitute(
99 username=user.username,
99 username=user.username,
100 user_id=user.user_id,
100 user_id=user.user_id,
101 first_name=user.first_name,
101 first_name=user.first_name,
102 last_name=user.last_name,
102 last_name=user.last_name,
103 )
103 )
104
104
105 def create_personal_repo_group(self, user, commit_early=True):
105 def create_personal_repo_group(self, user, commit_early=True):
106 desc = self.PERSONAL_GROUP_DESC % {'username': user.username}
106 desc = self.PERSONAL_GROUP_DESC % {'username': user.username}
107 personal_repo_group_name = self.get_personal_group_name(user)
107 personal_repo_group_name = self.get_personal_group_name(user)
108
108
109 # create a new one
109 # create a new one
110 RepoGroupModel().create(
110 RepoGroupModel().create(
111 group_name=personal_repo_group_name,
111 group_name=personal_repo_group_name,
112 group_description=desc,
112 group_description=desc,
113 owner=user.username,
113 owner=user.username,
114 personal=True,
114 personal=True,
115 commit_early=commit_early)
115 commit_early=commit_early)
116
116
117 def _create_default_perms(self, new_group):
117 def _create_default_perms(self, new_group):
118 # create default permission
118 # create default permission
119 default_perm = 'group.read'
119 default_perm = 'group.read'
120 def_user = User.get_default_user()
120 def_user = User.get_default_user()
121 for p in def_user.user_perms:
121 for p in def_user.user_perms:
122 if p.permission.permission_name.startswith('group.'):
122 if p.permission.permission_name.startswith('group.'):
123 default_perm = p.permission.permission_name
123 default_perm = p.permission.permission_name
124 break
124 break
125
125
126 repo_group_to_perm = UserRepoGroupToPerm()
126 repo_group_to_perm = UserRepoGroupToPerm()
127 repo_group_to_perm.permission = Permission.get_by_key(default_perm)
127 repo_group_to_perm.permission = Permission.get_by_key(default_perm)
128
128
129 repo_group_to_perm.group = new_group
129 repo_group_to_perm.group = new_group
130 repo_group_to_perm.user_id = def_user.user_id
130 repo_group_to_perm.user_id = def_user.user_id
131 return repo_group_to_perm
131 return repo_group_to_perm
132
132
133 def _get_group_name_and_parent(self, group_name_full, repo_in_path=False,
133 def _get_group_name_and_parent(self, group_name_full, repo_in_path=False,
134 get_object=False):
134 get_object=False):
135 """
135 """
136 Get's the group name and a parent group name from given group name.
136 Get's the group name and a parent group name from given group name.
137 If repo_in_path is set to truth, we asume the full path also includes
137 If repo_in_path is set to truth, we asume the full path also includes
138 repo name, in such case we clean the last element.
138 repo name, in such case we clean the last element.
139
139
140 :param group_name_full:
140 :param group_name_full:
141 """
141 """
142 split_paths = 1
142 split_paths = 1
143 if repo_in_path:
143 if repo_in_path:
144 split_paths = 2
144 split_paths = 2
145 _parts = group_name_full.rsplit(RepoGroup.url_sep(), split_paths)
145 _parts = group_name_full.rsplit(RepoGroup.url_sep(), split_paths)
146
146
147 if repo_in_path and len(_parts) > 1:
147 if repo_in_path and len(_parts) > 1:
148 # such case last element is the repo_name
148 # such case last element is the repo_name
149 _parts.pop(-1)
149 _parts.pop(-1)
150 group_name_cleaned = _parts[-1] # just the group name
150 group_name_cleaned = _parts[-1] # just the group name
151 parent_repo_group_name = None
151 parent_repo_group_name = None
152
152
153 if len(_parts) > 1:
153 if len(_parts) > 1:
154 parent_repo_group_name = _parts[0]
154 parent_repo_group_name = _parts[0]
155
155
156 parent_group = None
156 parent_group = None
157 if parent_repo_group_name:
157 if parent_repo_group_name:
158 parent_group = RepoGroup.get_by_group_name(parent_repo_group_name)
158 parent_group = RepoGroup.get_by_group_name(parent_repo_group_name)
159
159
160 if get_object:
160 if get_object:
161 return group_name_cleaned, parent_repo_group_name, parent_group
161 return group_name_cleaned, parent_repo_group_name, parent_group
162
162
163 return group_name_cleaned, parent_repo_group_name
163 return group_name_cleaned, parent_repo_group_name
164
164
165 def check_exist_filesystem(self, group_name, exc_on_failure=True):
165 def check_exist_filesystem(self, group_name, exc_on_failure=True):
166 create_path = os.path.join(self.repos_path, group_name)
166 create_path = os.path.join(self.repos_path, group_name)
167 log.debug('creating new group in %s', create_path)
167 log.debug('creating new group in %s', create_path)
168
168
169 if os.path.isdir(create_path):
169 if os.path.isdir(create_path):
170 if exc_on_failure:
170 if exc_on_failure:
171 abs_create_path = os.path.abspath(create_path)
171 abs_create_path = os.path.abspath(create_path)
172 raise Exception('Directory `{}` already exists !'.format(abs_create_path))
172 raise Exception('Directory `{}` already exists !'.format(abs_create_path))
173 return False
173 return False
174 return True
174 return True
175
175
176 def _create_group(self, group_name):
176 def _create_group(self, group_name):
177 """
177 """
178 makes repository group on filesystem
178 makes repository group on filesystem
179
179
180 :param repo_name:
180 :param repo_name:
181 :param parent_id:
181 :param parent_id:
182 """
182 """
183
183
184 self.check_exist_filesystem(group_name)
184 self.check_exist_filesystem(group_name)
185 create_path = os.path.join(self.repos_path, group_name)
185 create_path = os.path.join(self.repos_path, group_name)
186 log.debug('creating new group in %s', create_path)
186 log.debug('creating new group in %s', create_path)
187 os.makedirs(create_path, mode=0o755)
187 os.makedirs(create_path, mode=0o755)
188 log.debug('created group in %s', create_path)
188 log.debug('created group in %s', create_path)
189
189
190 def _rename_group(self, old, new):
190 def _rename_group(self, old, new):
191 """
191 """
192 Renames a group on filesystem
192 Renames a group on filesystem
193
193
194 :param group_name:
194 :param group_name:
195 """
195 """
196
196
197 if old == new:
197 if old == new:
198 log.debug('skipping group rename')
198 log.debug('skipping group rename')
199 return
199 return
200
200
201 log.debug('renaming repository group from %s to %s', old, new)
201 log.debug('renaming repository group from %s to %s', old, new)
202
202
203 old_path = os.path.join(self.repos_path, old)
203 old_path = os.path.join(self.repos_path, old)
204 new_path = os.path.join(self.repos_path, new)
204 new_path = os.path.join(self.repos_path, new)
205
205
206 log.debug('renaming repos paths from %s to %s', old_path, new_path)
206 log.debug('renaming repos paths from %s to %s', old_path, new_path)
207
207
208 if os.path.isdir(new_path):
208 if os.path.isdir(new_path):
209 raise Exception('Was trying to rename to already '
209 raise Exception('Was trying to rename to already '
210 'existing dir %s' % new_path)
210 'existing dir %s' % new_path)
211 shutil.move(old_path, new_path)
211 shutil.move(old_path, new_path)
212
212
213 def _delete_filesystem_group(self, group, force_delete=False):
213 def _delete_filesystem_group(self, group, force_delete=False):
214 """
214 """
215 Deletes a group from a filesystem
215 Deletes a group from a filesystem
216
216
217 :param group: instance of group from database
217 :param group: instance of group from database
218 :param force_delete: use shutil rmtree to remove all objects
218 :param force_delete: use shutil rmtree to remove all objects
219 """
219 """
220 paths = group.full_path.split(RepoGroup.url_sep())
220 paths = group.full_path.split(RepoGroup.url_sep())
221 paths = os.sep.join(paths)
221 paths = os.sep.join(paths)
222
222
223 rm_path = os.path.join(self.repos_path, paths)
223 rm_path = os.path.join(self.repos_path, paths)
224 log.info("Removing group %s", rm_path)
224 log.info("Removing group %s", rm_path)
225 # delete only if that path really exists
225 # delete only if that path really exists
226 if os.path.isdir(rm_path):
226 if os.path.isdir(rm_path):
227 if force_delete:
227 if force_delete:
228 shutil.rmtree(rm_path)
228 shutil.rmtree(rm_path)
229 else:
229 else:
230 # archive that group`
230 # archive that group`
231 _now = datetime.datetime.now()
231 _now = datetime.datetime.now()
232 _ms = str(_now.microsecond).rjust(6, '0')
232 _ms = str(_now.microsecond).rjust(6, '0')
233 _d = 'rm__%s_GROUP_%s' % (
233 _d = 'rm__%s_GROUP_%s' % (
234 _now.strftime('%Y%m%d_%H%M%S_' + _ms), group.name)
234 _now.strftime('%Y%m%d_%H%M%S_' + _ms), group.name)
235 shutil.move(rm_path, os.path.join(self.repos_path, _d))
235 shutil.move(rm_path, os.path.join(self.repos_path, _d))
236
236
237 def create(self, group_name, group_description, owner, just_db=False,
237 def create(self, group_name, group_description, owner, just_db=False,
238 copy_permissions=False, personal=None, commit_early=True):
238 copy_permissions=False, personal=None, commit_early=True):
239
239
240 (group_name_cleaned,
240 (group_name_cleaned,
241 parent_group_name) = RepoGroupModel()._get_group_name_and_parent(group_name)
241 parent_group_name) = RepoGroupModel()._get_group_name_and_parent(group_name)
242
242
243 parent_group = None
243 parent_group = None
244 if parent_group_name:
244 if parent_group_name:
245 parent_group = self._get_repo_group(parent_group_name)
245 parent_group = self._get_repo_group(parent_group_name)
246 if not parent_group:
246 if not parent_group:
247 # we tried to create a nested group, but the parent is not
247 # we tried to create a nested group, but the parent is not
248 # existing
248 # existing
249 raise ValueError(
249 raise ValueError(
250 'Parent group `%s` given in `%s` group name '
250 'Parent group `%s` given in `%s` group name '
251 'is not yet existing.' % (parent_group_name, group_name))
251 'is not yet existing.' % (parent_group_name, group_name))
252
252
253 # because we are doing a cleanup, we need to check if such directory
253 # because we are doing a cleanup, we need to check if such directory
254 # already exists. If we don't do that we can accidentally delete
254 # already exists. If we don't do that we can accidentally delete
255 # existing directory via cleanup that can cause data issues, since
255 # existing directory via cleanup that can cause data issues, since
256 # delete does a folder rename to special syntax later cleanup
256 # delete does a folder rename to special syntax later cleanup
257 # functions can delete this
257 # functions can delete this
258 cleanup_group = self.check_exist_filesystem(group_name,
258 cleanup_group = self.check_exist_filesystem(group_name,
259 exc_on_failure=False)
259 exc_on_failure=False)
260 user = self._get_user(owner)
260 user = self._get_user(owner)
261 if not user:
261 if not user:
262 raise ValueError('Owner %s not found as rhodecode user', owner)
262 raise ValueError('Owner %s not found as rhodecode user', owner)
263
263
264 try:
264 try:
265 new_repo_group = RepoGroup()
265 new_repo_group = RepoGroup()
266 new_repo_group.user = user
266 new_repo_group.user = user
267 new_repo_group.group_description = group_description or group_name
267 new_repo_group.group_description = group_description or group_name
268 new_repo_group.parent_group = parent_group
268 new_repo_group.parent_group = parent_group
269 new_repo_group.group_name = group_name
269 new_repo_group.group_name = group_name
270 new_repo_group.personal = personal
270 new_repo_group.personal = personal
271
271
272 self.sa.add(new_repo_group)
272 self.sa.add(new_repo_group)
273
273
274 # create an ADMIN permission for owner except if we're super admin,
274 # create an ADMIN permission for owner except if we're super admin,
275 # later owner should go into the owner field of groups
275 # later owner should go into the owner field of groups
276 if not user.is_admin:
276 if not user.is_admin:
277 self.grant_user_permission(repo_group=new_repo_group,
277 self.grant_user_permission(repo_group=new_repo_group,
278 user=owner, perm='group.admin')
278 user=owner, perm='group.admin')
279
279
280 if parent_group and copy_permissions:
280 if parent_group and copy_permissions:
281 # copy permissions from parent
281 # copy permissions from parent
282 user_perms = UserRepoGroupToPerm.query() \
282 user_perms = UserRepoGroupToPerm.query() \
283 .filter(UserRepoGroupToPerm.group == parent_group).all()
283 .filter(UserRepoGroupToPerm.group == parent_group).all()
284
284
285 group_perms = UserGroupRepoGroupToPerm.query() \
285 group_perms = UserGroupRepoGroupToPerm.query() \
286 .filter(UserGroupRepoGroupToPerm.group == parent_group).all()
286 .filter(UserGroupRepoGroupToPerm.group == parent_group).all()
287
287
288 for perm in user_perms:
288 for perm in user_perms:
289 # don't copy over the permission for user who is creating
289 # don't copy over the permission for user who is creating
290 # this group, if he is not super admin he get's admin
290 # this group, if he is not super admin he get's admin
291 # permission set above
291 # permission set above
292 if perm.user != user or user.is_admin:
292 if perm.user != user or user.is_admin:
293 UserRepoGroupToPerm.create(
293 UserRepoGroupToPerm.create(
294 perm.user, new_repo_group, perm.permission)
294 perm.user, new_repo_group, perm.permission)
295
295
296 for perm in group_perms:
296 for perm in group_perms:
297 UserGroupRepoGroupToPerm.create(
297 UserGroupRepoGroupToPerm.create(
298 perm.users_group, new_repo_group, perm.permission)
298 perm.users_group, new_repo_group, perm.permission)
299 else:
299 else:
300 perm_obj = self._create_default_perms(new_repo_group)
300 perm_obj = self._create_default_perms(new_repo_group)
301 self.sa.add(perm_obj)
301 self.sa.add(perm_obj)
302
302
303 # now commit the changes, earlier so we are sure everything is in
303 # now commit the changes, earlier so we are sure everything is in
304 # the database.
304 # the database.
305 if commit_early:
305 if commit_early:
306 self.sa.commit()
306 self.sa.commit()
307 if not just_db:
307 if not just_db:
308 self._create_group(new_repo_group.group_name)
308 self._create_group(new_repo_group.group_name)
309
309
310 # trigger the post hook
310 # trigger the post hook
311 from rhodecode.lib.hooks_base import log_create_repository_group
311 from rhodecode.lib.hooks_base import log_create_repository_group
312 repo_group = RepoGroup.get_by_group_name(group_name)
312 repo_group = RepoGroup.get_by_group_name(group_name)
313
313
314 # update repo group commit caches initially
314 # update repo group commit caches initially
315 repo_group.update_commit_cache()
315 repo_group.update_commit_cache()
316
316
317 log_create_repository_group(
317 log_create_repository_group(
318 created_by=user.username, **repo_group.get_dict())
318 created_by=user.username, **repo_group.get_dict())
319
319
320 # Trigger create event.
320 # Trigger create event.
321 events.trigger(events.RepoGroupCreateEvent(repo_group))
321 events.trigger(events.RepoGroupCreateEvent(repo_group))
322
322
323 return new_repo_group
323 return new_repo_group
324 except Exception:
324 except Exception:
325 self.sa.rollback()
325 self.sa.rollback()
326 log.exception('Exception occurred when creating repository group, '
326 log.exception('Exception occurred when creating repository group, '
327 'doing cleanup...')
327 'doing cleanup...')
328 # rollback things manually !
328 # rollback things manually !
329 repo_group = RepoGroup.get_by_group_name(group_name)
329 repo_group = RepoGroup.get_by_group_name(group_name)
330 if repo_group:
330 if repo_group:
331 RepoGroup.delete(repo_group.group_id)
331 RepoGroup.delete(repo_group.group_id)
332 self.sa.commit()
332 self.sa.commit()
333 if cleanup_group:
333 if cleanup_group:
334 RepoGroupModel()._delete_filesystem_group(repo_group)
334 RepoGroupModel()._delete_filesystem_group(repo_group)
335 raise
335 raise
336
336
337 def update_permissions(
337 def update_permissions(
338 self, repo_group, perm_additions=None, perm_updates=None,
338 self, repo_group, perm_additions=None, perm_updates=None,
339 perm_deletions=None, recursive=None, check_perms=True,
339 perm_deletions=None, recursive=None, check_perms=True,
340 cur_user=None):
340 cur_user=None):
341 from rhodecode.model.repo import RepoModel
341 from rhodecode.model.repo import RepoModel
342 from rhodecode.lib.auth import HasUserGroupPermissionAny
342 from rhodecode.lib.auth import HasUserGroupPermissionAny
343
343
344 if not perm_additions:
344 if not perm_additions:
345 perm_additions = []
345 perm_additions = []
346 if not perm_updates:
346 if not perm_updates:
347 perm_updates = []
347 perm_updates = []
348 if not perm_deletions:
348 if not perm_deletions:
349 perm_deletions = []
349 perm_deletions = []
350
350
351 req_perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin')
351 req_perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin')
352
352
353 changes = {
353 changes = {
354 'added': [],
354 'added': [],
355 'updated': [],
355 'updated': [],
356 'deleted': []
356 'deleted': [],
357 'default_user_changed': None
357 }
358 }
358
359
359 def _set_perm_user(obj, user, perm):
360 def _set_perm_user(obj, user, perm):
360 if isinstance(obj, RepoGroup):
361 if isinstance(obj, RepoGroup):
361 self.grant_user_permission(
362 self.grant_user_permission(
362 repo_group=obj, user=user, perm=perm)
363 repo_group=obj, user=user, perm=perm)
363 elif isinstance(obj, Repository):
364 elif isinstance(obj, Repository):
364 # private repos will not allow to change the default
365 # private repos will not allow to change the default
365 # permissions using recursive mode
366 # permissions using recursive mode
366 if obj.private and user == User.DEFAULT_USER:
367 if obj.private and user == User.DEFAULT_USER:
367 return
368 return
368
369
369 # we set group permission but we have to switch to repo
370 # we set group permission but we have to switch to repo
370 # permission
371 # permission
371 perm = perm.replace('group.', 'repository.')
372 perm = perm.replace('group.', 'repository.')
372 RepoModel().grant_user_permission(
373 RepoModel().grant_user_permission(
373 repo=obj, user=user, perm=perm)
374 repo=obj, user=user, perm=perm)
374
375
375 def _set_perm_group(obj, users_group, perm):
376 def _set_perm_group(obj, users_group, perm):
376 if isinstance(obj, RepoGroup):
377 if isinstance(obj, RepoGroup):
377 self.grant_user_group_permission(
378 self.grant_user_group_permission(
378 repo_group=obj, group_name=users_group, perm=perm)
379 repo_group=obj, group_name=users_group, perm=perm)
379 elif isinstance(obj, Repository):
380 elif isinstance(obj, Repository):
380 # we set group permission but we have to switch to repo
381 # we set group permission but we have to switch to repo
381 # permission
382 # permission
382 perm = perm.replace('group.', 'repository.')
383 perm = perm.replace('group.', 'repository.')
383 RepoModel().grant_user_group_permission(
384 RepoModel().grant_user_group_permission(
384 repo=obj, group_name=users_group, perm=perm)
385 repo=obj, group_name=users_group, perm=perm)
385
386
386 def _revoke_perm_user(obj, user):
387 def _revoke_perm_user(obj, user):
387 if isinstance(obj, RepoGroup):
388 if isinstance(obj, RepoGroup):
388 self.revoke_user_permission(repo_group=obj, user=user)
389 self.revoke_user_permission(repo_group=obj, user=user)
389 elif isinstance(obj, Repository):
390 elif isinstance(obj, Repository):
390 RepoModel().revoke_user_permission(repo=obj, user=user)
391 RepoModel().revoke_user_permission(repo=obj, user=user)
391
392
392 def _revoke_perm_group(obj, user_group):
393 def _revoke_perm_group(obj, user_group):
393 if isinstance(obj, RepoGroup):
394 if isinstance(obj, RepoGroup):
394 self.revoke_user_group_permission(
395 self.revoke_user_group_permission(
395 repo_group=obj, group_name=user_group)
396 repo_group=obj, group_name=user_group)
396 elif isinstance(obj, Repository):
397 elif isinstance(obj, Repository):
397 RepoModel().revoke_user_group_permission(
398 RepoModel().revoke_user_group_permission(
398 repo=obj, group_name=user_group)
399 repo=obj, group_name=user_group)
399
400
400 # start updates
401 # start updates
401 log.debug('Now updating permissions for %s in recursive mode:%s',
402 log.debug('Now updating permissions for %s in recursive mode:%s',
402 repo_group, recursive)
403 repo_group, recursive)
403
404
404 # initialize check function, we'll call that multiple times
405 # initialize check function, we'll call that multiple times
405 has_group_perm = HasUserGroupPermissionAny(*req_perms)
406 has_group_perm = HasUserGroupPermissionAny(*req_perms)
406
407
407 for obj in repo_group.recursive_groups_and_repos():
408 for obj in repo_group.recursive_groups_and_repos():
408 # iterated obj is an instance of a repos group or repository in
409 # iterated obj is an instance of a repos group or repository in
409 # that group, recursive option can be: none, repos, groups, all
410 # that group, recursive option can be: none, repos, groups, all
410 if recursive == 'all':
411 if recursive == 'all':
411 obj = obj
412 obj = obj
412 elif recursive == 'repos':
413 elif recursive == 'repos':
413 # skip groups, other than this one
414 # skip groups, other than this one
414 if isinstance(obj, RepoGroup) and not obj == repo_group:
415 if isinstance(obj, RepoGroup) and not obj == repo_group:
415 continue
416 continue
416 elif recursive == 'groups':
417 elif recursive == 'groups':
417 # skip repos
418 # skip repos
418 if isinstance(obj, Repository):
419 if isinstance(obj, Repository):
419 continue
420 continue
420 else: # recursive == 'none':
421 else: # recursive == 'none':
421 # DEFAULT option - don't apply to iterated objects
422 # DEFAULT option - don't apply to iterated objects
422 # also we do a break at the end of this loop. if we are not
423 # also we do a break at the end of this loop. if we are not
423 # in recursive mode
424 # in recursive mode
424 obj = repo_group
425 obj = repo_group
425
426
426 change_obj = obj.get_api_data()
427 change_obj = obj.get_api_data()
427
428
428 # update permissions
429 # update permissions
429 for member_id, perm, member_type in perm_updates:
430 for member_id, perm, member_type in perm_updates:
430 member_id = int(member_id)
431 member_id = int(member_id)
431 if member_type == 'user':
432 if member_type == 'user':
432 member_name = User.get(member_id).username
433 member_name = User.get(member_id).username
434 if isinstance(obj, RepoGroup) and obj == repo_group and member_name == User.DEFAULT_USER:
435 # NOTE(dan): detect if we changed permissions for default user
436 perm_obj = self.sa.query(UserRepoGroupToPerm) \
437 .filter(UserRepoGroupToPerm.user_id == member_id) \
438 .filter(UserRepoGroupToPerm.group == repo_group) \
439 .scalar()
440 if perm_obj and perm_obj.permission.permission_name != perm:
441 changes['default_user_changed'] = True
442
433 # this updates also current one if found
443 # this updates also current one if found
434 _set_perm_user(obj, user=member_id, perm=perm)
444 _set_perm_user(obj, user=member_id, perm=perm)
435 elif member_type == 'user_group':
445 elif member_type == 'user_group':
436 member_name = UserGroup.get(member_id).users_group_name
446 member_name = UserGroup.get(member_id).users_group_name
437 if not check_perms or has_group_perm(member_name,
447 if not check_perms or has_group_perm(member_name,
438 user=cur_user):
448 user=cur_user):
439 _set_perm_group(obj, users_group=member_id, perm=perm)
449 _set_perm_group(obj, users_group=member_id, perm=perm)
440 else:
450 else:
441 raise ValueError("member_type must be 'user' or 'user_group' "
451 raise ValueError("member_type must be 'user' or 'user_group' "
442 "got {} instead".format(member_type))
452 "got {} instead".format(member_type))
443
453
444 changes['updated'].append(
454 changes['updated'].append(
445 {'change_obj': change_obj, 'type': member_type,
455 {'change_obj': change_obj, 'type': member_type,
446 'id': member_id, 'name': member_name, 'new_perm': perm})
456 'id': member_id, 'name': member_name, 'new_perm': perm})
447
457
448 # set new permissions
458 # set new permissions
449 for member_id, perm, member_type in perm_additions:
459 for member_id, perm, member_type in perm_additions:
450 member_id = int(member_id)
460 member_id = int(member_id)
451 if member_type == 'user':
461 if member_type == 'user':
452 member_name = User.get(member_id).username
462 member_name = User.get(member_id).username
453 _set_perm_user(obj, user=member_id, perm=perm)
463 _set_perm_user(obj, user=member_id, perm=perm)
454 elif member_type == 'user_group':
464 elif member_type == 'user_group':
455 # check if we have permissions to alter this usergroup
465 # check if we have permissions to alter this usergroup
456 member_name = UserGroup.get(member_id).users_group_name
466 member_name = UserGroup.get(member_id).users_group_name
457 if not check_perms or has_group_perm(member_name,
467 if not check_perms or has_group_perm(member_name,
458 user=cur_user):
468 user=cur_user):
459 _set_perm_group(obj, users_group=member_id, perm=perm)
469 _set_perm_group(obj, users_group=member_id, perm=perm)
460 else:
470 else:
461 raise ValueError("member_type must be 'user' or 'user_group' "
471 raise ValueError("member_type must be 'user' or 'user_group' "
462 "got {} instead".format(member_type))
472 "got {} instead".format(member_type))
463
473
464 changes['added'].append(
474 changes['added'].append(
465 {'change_obj': change_obj, 'type': member_type,
475 {'change_obj': change_obj, 'type': member_type,
466 'id': member_id, 'name': member_name, 'new_perm': perm})
476 'id': member_id, 'name': member_name, 'new_perm': perm})
467
477
468 # delete permissions
478 # delete permissions
469 for member_id, perm, member_type in perm_deletions:
479 for member_id, perm, member_type in perm_deletions:
470 member_id = int(member_id)
480 member_id = int(member_id)
471 if member_type == 'user':
481 if member_type == 'user':
472 member_name = User.get(member_id).username
482 member_name = User.get(member_id).username
473 _revoke_perm_user(obj, user=member_id)
483 _revoke_perm_user(obj, user=member_id)
474 elif member_type == 'user_group':
484 elif member_type == 'user_group':
475 # check if we have permissions to alter this usergroup
485 # check if we have permissions to alter this usergroup
476 member_name = UserGroup.get(member_id).users_group_name
486 member_name = UserGroup.get(member_id).users_group_name
477 if not check_perms or has_group_perm(member_name,
487 if not check_perms or has_group_perm(member_name,
478 user=cur_user):
488 user=cur_user):
479 _revoke_perm_group(obj, user_group=member_id)
489 _revoke_perm_group(obj, user_group=member_id)
480 else:
490 else:
481 raise ValueError("member_type must be 'user' or 'user_group' "
491 raise ValueError("member_type must be 'user' or 'user_group' "
482 "got {} instead".format(member_type))
492 "got {} instead".format(member_type))
483
493
484 changes['deleted'].append(
494 changes['deleted'].append(
485 {'change_obj': change_obj, 'type': member_type,
495 {'change_obj': change_obj, 'type': member_type,
486 'id': member_id, 'name': member_name, 'new_perm': perm})
496 'id': member_id, 'name': member_name, 'new_perm': perm})
487
497
488 # if it's not recursive call for all,repos,groups
498 # if it's not recursive call for all,repos,groups
489 # break the loop and don't proceed with other changes
499 # break the loop and don't proceed with other changes
490 if recursive not in ['all', 'repos', 'groups']:
500 if recursive not in ['all', 'repos', 'groups']:
491 break
501 break
492
502
493 return changes
503 return changes
494
504
495 def update(self, repo_group, form_data):
505 def update(self, repo_group, form_data):
496 try:
506 try:
497 repo_group = self._get_repo_group(repo_group)
507 repo_group = self._get_repo_group(repo_group)
498 old_path = repo_group.full_path
508 old_path = repo_group.full_path
499
509
500 # change properties
510 # change properties
501 if 'group_description' in form_data:
511 if 'group_description' in form_data:
502 repo_group.group_description = form_data['group_description']
512 repo_group.group_description = form_data['group_description']
503
513
504 if 'enable_locking' in form_data:
514 if 'enable_locking' in form_data:
505 repo_group.enable_locking = form_data['enable_locking']
515 repo_group.enable_locking = form_data['enable_locking']
506
516
507 if 'group_parent_id' in form_data:
517 if 'group_parent_id' in form_data:
508 parent_group = (
518 parent_group = (
509 self._get_repo_group(form_data['group_parent_id']))
519 self._get_repo_group(form_data['group_parent_id']))
510 repo_group.group_parent_id = (
520 repo_group.group_parent_id = (
511 parent_group.group_id if parent_group else None)
521 parent_group.group_id if parent_group else None)
512 repo_group.parent_group = parent_group
522 repo_group.parent_group = parent_group
513
523
514 # mikhail: to update the full_path, we have to explicitly
524 # mikhail: to update the full_path, we have to explicitly
515 # update group_name
525 # update group_name
516 group_name = form_data.get('group_name', repo_group.name)
526 group_name = form_data.get('group_name', repo_group.name)
517 repo_group.group_name = repo_group.get_new_name(group_name)
527 repo_group.group_name = repo_group.get_new_name(group_name)
518
528
519 new_path = repo_group.full_path
529 new_path = repo_group.full_path
520
530
521 if 'user' in form_data:
531 if 'user' in form_data:
522 repo_group.user = User.get_by_username(form_data['user'])
532 repo_group.user = User.get_by_username(form_data['user'])
523
533
524 self.sa.add(repo_group)
534 self.sa.add(repo_group)
525
535
526 # iterate over all members of this groups and do fixes
536 # iterate over all members of this groups and do fixes
527 # set locking if given
537 # set locking if given
528 # if obj is a repoGroup also fix the name of the group according
538 # if obj is a repoGroup also fix the name of the group according
529 # to the parent
539 # to the parent
530 # if obj is a Repo fix it's name
540 # if obj is a Repo fix it's name
531 # this can be potentially heavy operation
541 # this can be potentially heavy operation
532 for obj in repo_group.recursive_groups_and_repos():
542 for obj in repo_group.recursive_groups_and_repos():
533 # set the value from it's parent
543 # set the value from it's parent
534 obj.enable_locking = repo_group.enable_locking
544 obj.enable_locking = repo_group.enable_locking
535 if isinstance(obj, RepoGroup):
545 if isinstance(obj, RepoGroup):
536 new_name = obj.get_new_name(obj.name)
546 new_name = obj.get_new_name(obj.name)
537 log.debug('Fixing group %s to new name %s',
547 log.debug('Fixing group %s to new name %s',
538 obj.group_name, new_name)
548 obj.group_name, new_name)
539 obj.group_name = new_name
549 obj.group_name = new_name
540
550
541 elif isinstance(obj, Repository):
551 elif isinstance(obj, Repository):
542 # we need to get all repositories from this new group and
552 # we need to get all repositories from this new group and
543 # rename them accordingly to new group path
553 # rename them accordingly to new group path
544 new_name = obj.get_new_name(obj.just_name)
554 new_name = obj.get_new_name(obj.just_name)
545 log.debug('Fixing repo %s to new name %s',
555 log.debug('Fixing repo %s to new name %s',
546 obj.repo_name, new_name)
556 obj.repo_name, new_name)
547 obj.repo_name = new_name
557 obj.repo_name = new_name
548
558
549 self.sa.add(obj)
559 self.sa.add(obj)
550
560
551 self._rename_group(old_path, new_path)
561 self._rename_group(old_path, new_path)
552
562
553 # Trigger update event.
563 # Trigger update event.
554 events.trigger(events.RepoGroupUpdateEvent(repo_group))
564 events.trigger(events.RepoGroupUpdateEvent(repo_group))
555
565
556 return repo_group
566 return repo_group
557 except Exception:
567 except Exception:
558 log.error(traceback.format_exc())
568 log.error(traceback.format_exc())
559 raise
569 raise
560
570
561 def delete(self, repo_group, force_delete=False, fs_remove=True):
571 def delete(self, repo_group, force_delete=False, fs_remove=True):
562 repo_group = self._get_repo_group(repo_group)
572 repo_group = self._get_repo_group(repo_group)
563 if not repo_group:
573 if not repo_group:
564 return False
574 return False
565 try:
575 try:
566 self.sa.delete(repo_group)
576 self.sa.delete(repo_group)
567 if fs_remove:
577 if fs_remove:
568 self._delete_filesystem_group(repo_group, force_delete)
578 self._delete_filesystem_group(repo_group, force_delete)
569 else:
579 else:
570 log.debug('skipping removal from filesystem')
580 log.debug('skipping removal from filesystem')
571
581
572 # Trigger delete event.
582 # Trigger delete event.
573 events.trigger(events.RepoGroupDeleteEvent(repo_group))
583 events.trigger(events.RepoGroupDeleteEvent(repo_group))
574 return True
584 return True
575
585
576 except Exception:
586 except Exception:
577 log.error('Error removing repo_group %s', repo_group)
587 log.error('Error removing repo_group %s', repo_group)
578 raise
588 raise
579
589
580 def grant_user_permission(self, repo_group, user, perm):
590 def grant_user_permission(self, repo_group, user, perm):
581 """
591 """
582 Grant permission for user on given repository group, or update
592 Grant permission for user on given repository group, or update
583 existing one if found
593 existing one if found
584
594
585 :param repo_group: Instance of RepoGroup, repositories_group_id,
595 :param repo_group: Instance of RepoGroup, repositories_group_id,
586 or repositories_group name
596 or repositories_group name
587 :param user: Instance of User, user_id or username
597 :param user: Instance of User, user_id or username
588 :param perm: Instance of Permission, or permission_name
598 :param perm: Instance of Permission, or permission_name
589 """
599 """
590
600
591 repo_group = self._get_repo_group(repo_group)
601 repo_group = self._get_repo_group(repo_group)
592 user = self._get_user(user)
602 user = self._get_user(user)
593 permission = self._get_perm(perm)
603 permission = self._get_perm(perm)
594
604
595 # check if we have that permission already
605 # check if we have that permission already
596 obj = self.sa.query(UserRepoGroupToPerm)\
606 obj = self.sa.query(UserRepoGroupToPerm)\
597 .filter(UserRepoGroupToPerm.user == user)\
607 .filter(UserRepoGroupToPerm.user == user)\
598 .filter(UserRepoGroupToPerm.group == repo_group)\
608 .filter(UserRepoGroupToPerm.group == repo_group)\
599 .scalar()
609 .scalar()
600 if obj is None:
610 if obj is None:
601 # create new !
611 # create new !
602 obj = UserRepoGroupToPerm()
612 obj = UserRepoGroupToPerm()
603 obj.group = repo_group
613 obj.group = repo_group
604 obj.user = user
614 obj.user = user
605 obj.permission = permission
615 obj.permission = permission
606 self.sa.add(obj)
616 self.sa.add(obj)
607 log.debug('Granted perm %s to %s on %s', perm, user, repo_group)
617 log.debug('Granted perm %s to %s on %s', perm, user, repo_group)
608 action_logger_generic(
618 action_logger_generic(
609 'granted permission: {} to user: {} on repogroup: {}'.format(
619 'granted permission: {} to user: {} on repogroup: {}'.format(
610 perm, user, repo_group), namespace='security.repogroup')
620 perm, user, repo_group), namespace='security.repogroup')
611 return obj
621 return obj
612
622
613 def revoke_user_permission(self, repo_group, user):
623 def revoke_user_permission(self, repo_group, user):
614 """
624 """
615 Revoke permission for user on given repository group
625 Revoke permission for user on given repository group
616
626
617 :param repo_group: Instance of RepoGroup, repositories_group_id,
627 :param repo_group: Instance of RepoGroup, repositories_group_id,
618 or repositories_group name
628 or repositories_group name
619 :param user: Instance of User, user_id or username
629 :param user: Instance of User, user_id or username
620 """
630 """
621
631
622 repo_group = self._get_repo_group(repo_group)
632 repo_group = self._get_repo_group(repo_group)
623 user = self._get_user(user)
633 user = self._get_user(user)
624
634
625 obj = self.sa.query(UserRepoGroupToPerm)\
635 obj = self.sa.query(UserRepoGroupToPerm)\
626 .filter(UserRepoGroupToPerm.user == user)\
636 .filter(UserRepoGroupToPerm.user == user)\
627 .filter(UserRepoGroupToPerm.group == repo_group)\
637 .filter(UserRepoGroupToPerm.group == repo_group)\
628 .scalar()
638 .scalar()
629 if obj:
639 if obj:
630 self.sa.delete(obj)
640 self.sa.delete(obj)
631 log.debug('Revoked perm on %s on %s', repo_group, user)
641 log.debug('Revoked perm on %s on %s', repo_group, user)
632 action_logger_generic(
642 action_logger_generic(
633 'revoked permission from user: {} on repogroup: {}'.format(
643 'revoked permission from user: {} on repogroup: {}'.format(
634 user, repo_group), namespace='security.repogroup')
644 user, repo_group), namespace='security.repogroup')
635
645
636 def grant_user_group_permission(self, repo_group, group_name, perm):
646 def grant_user_group_permission(self, repo_group, group_name, perm):
637 """
647 """
638 Grant permission for user group on given repository group, or update
648 Grant permission for user group on given repository group, or update
639 existing one if found
649 existing one if found
640
650
641 :param repo_group: Instance of RepoGroup, repositories_group_id,
651 :param repo_group: Instance of RepoGroup, repositories_group_id,
642 or repositories_group name
652 or repositories_group name
643 :param group_name: Instance of UserGroup, users_group_id,
653 :param group_name: Instance of UserGroup, users_group_id,
644 or user group name
654 or user group name
645 :param perm: Instance of Permission, or permission_name
655 :param perm: Instance of Permission, or permission_name
646 """
656 """
647 repo_group = self._get_repo_group(repo_group)
657 repo_group = self._get_repo_group(repo_group)
648 group_name = self._get_user_group(group_name)
658 group_name = self._get_user_group(group_name)
649 permission = self._get_perm(perm)
659 permission = self._get_perm(perm)
650
660
651 # check if we have that permission already
661 # check if we have that permission already
652 obj = self.sa.query(UserGroupRepoGroupToPerm)\
662 obj = self.sa.query(UserGroupRepoGroupToPerm)\
653 .filter(UserGroupRepoGroupToPerm.group == repo_group)\
663 .filter(UserGroupRepoGroupToPerm.group == repo_group)\
654 .filter(UserGroupRepoGroupToPerm.users_group == group_name)\
664 .filter(UserGroupRepoGroupToPerm.users_group == group_name)\
655 .scalar()
665 .scalar()
656
666
657 if obj is None:
667 if obj is None:
658 # create new
668 # create new
659 obj = UserGroupRepoGroupToPerm()
669 obj = UserGroupRepoGroupToPerm()
660
670
661 obj.group = repo_group
671 obj.group = repo_group
662 obj.users_group = group_name
672 obj.users_group = group_name
663 obj.permission = permission
673 obj.permission = permission
664 self.sa.add(obj)
674 self.sa.add(obj)
665 log.debug('Granted perm %s to %s on %s', perm, group_name, repo_group)
675 log.debug('Granted perm %s to %s on %s', perm, group_name, repo_group)
666 action_logger_generic(
676 action_logger_generic(
667 'granted permission: {} to usergroup: {} on repogroup: {}'.format(
677 'granted permission: {} to usergroup: {} on repogroup: {}'.format(
668 perm, group_name, repo_group), namespace='security.repogroup')
678 perm, group_name, repo_group), namespace='security.repogroup')
669 return obj
679 return obj
670
680
671 def revoke_user_group_permission(self, repo_group, group_name):
681 def revoke_user_group_permission(self, repo_group, group_name):
672 """
682 """
673 Revoke permission for user group on given repository group
683 Revoke permission for user group on given repository group
674
684
675 :param repo_group: Instance of RepoGroup, repositories_group_id,
685 :param repo_group: Instance of RepoGroup, repositories_group_id,
676 or repositories_group name
686 or repositories_group name
677 :param group_name: Instance of UserGroup, users_group_id,
687 :param group_name: Instance of UserGroup, users_group_id,
678 or user group name
688 or user group name
679 """
689 """
680 repo_group = self._get_repo_group(repo_group)
690 repo_group = self._get_repo_group(repo_group)
681 group_name = self._get_user_group(group_name)
691 group_name = self._get_user_group(group_name)
682
692
683 obj = self.sa.query(UserGroupRepoGroupToPerm)\
693 obj = self.sa.query(UserGroupRepoGroupToPerm)\
684 .filter(UserGroupRepoGroupToPerm.group == repo_group)\
694 .filter(UserGroupRepoGroupToPerm.group == repo_group)\
685 .filter(UserGroupRepoGroupToPerm.users_group == group_name)\
695 .filter(UserGroupRepoGroupToPerm.users_group == group_name)\
686 .scalar()
696 .scalar()
687 if obj:
697 if obj:
688 self.sa.delete(obj)
698 self.sa.delete(obj)
689 log.debug('Revoked perm to %s on %s', repo_group, group_name)
699 log.debug('Revoked perm to %s on %s', repo_group, group_name)
690 action_logger_generic(
700 action_logger_generic(
691 'revoked permission from usergroup: {} on repogroup: {}'.format(
701 'revoked permission from usergroup: {} on repogroup: {}'.format(
692 group_name, repo_group), namespace='security.repogroup')
702 group_name, repo_group), namespace='security.repogroup')
693
703
694 @classmethod
704 @classmethod
695 def update_commit_cache(cls, repo_groups=None):
705 def update_commit_cache(cls, repo_groups=None):
696 if not repo_groups:
706 if not repo_groups:
697 repo_groups = RepoGroup.getAll()
707 repo_groups = RepoGroup.getAll()
698 for repo_group in repo_groups:
708 for repo_group in repo_groups:
699 repo_group.update_commit_cache()
709 repo_group.update_commit_cache()
700
710
701
711
702
712
703 def get_repo_groups_as_dict(self, repo_group_list=None, admin=False,
713 def get_repo_groups_as_dict(self, repo_group_list=None, admin=False,
704 super_user_actions=False):
714 super_user_actions=False):
705
715
706 from pyramid.threadlocal import get_current_request
716 from pyramid.threadlocal import get_current_request
707 _render = get_current_request().get_partial_renderer(
717 _render = get_current_request().get_partial_renderer(
708 'rhodecode:templates/data_table/_dt_elements.mako')
718 'rhodecode:templates/data_table/_dt_elements.mako')
709 c = _render.get_call_context()
719 c = _render.get_call_context()
710 h = _render.get_helpers()
720 h = _render.get_helpers()
711
721
712 def quick_menu(repo_group_name):
722 def quick_menu(repo_group_name):
713 return _render('quick_repo_group_menu', repo_group_name)
723 return _render('quick_repo_group_menu', repo_group_name)
714
724
715 def repo_group_lnk(repo_group_name):
725 def repo_group_lnk(repo_group_name):
716 return _render('repo_group_name', repo_group_name)
726 return _render('repo_group_name', repo_group_name)
717
727
718 def last_change(last_change):
728 def last_change(last_change):
719 if admin and isinstance(last_change, datetime.datetime) and not last_change.tzinfo:
729 if admin and isinstance(last_change, datetime.datetime) and not last_change.tzinfo:
720 ts = time.time()
730 ts = time.time()
721 utc_offset = (datetime.datetime.fromtimestamp(ts)
731 utc_offset = (datetime.datetime.fromtimestamp(ts)
722 - datetime.datetime.utcfromtimestamp(ts)).total_seconds()
732 - datetime.datetime.utcfromtimestamp(ts)).total_seconds()
723 last_change = last_change + datetime.timedelta(seconds=utc_offset)
733 last_change = last_change + datetime.timedelta(seconds=utc_offset)
724 return _render("last_change", last_change)
734 return _render("last_change", last_change)
725
735
726 def desc(desc, personal):
736 def desc(desc, personal):
727 return _render(
737 return _render(
728 'repo_group_desc', desc, personal, c.visual.stylify_metatags)
738 'repo_group_desc', desc, personal, c.visual.stylify_metatags)
729
739
730 def repo_group_actions(repo_group_id, repo_group_name, gr_count):
740 def repo_group_actions(repo_group_id, repo_group_name, gr_count):
731 return _render(
741 return _render(
732 'repo_group_actions', repo_group_id, repo_group_name, gr_count)
742 'repo_group_actions', repo_group_id, repo_group_name, gr_count)
733
743
734 def repo_group_name(repo_group_name, children_groups):
744 def repo_group_name(repo_group_name, children_groups):
735 return _render("repo_group_name", repo_group_name, children_groups)
745 return _render("repo_group_name", repo_group_name, children_groups)
736
746
737 def user_profile(username):
747 def user_profile(username):
738 return _render('user_profile', username)
748 return _render('user_profile', username)
739
749
740 repo_group_data = []
750 repo_group_data = []
741 for group in repo_group_list:
751 for group in repo_group_list:
742 # NOTE(marcink): because we use only raw column we need to load it like that
752 # NOTE(marcink): because we use only raw column we need to load it like that
743 changeset_cache = RepoGroup._load_changeset_cache(
753 changeset_cache = RepoGroup._load_changeset_cache(
744 '', group._changeset_cache)
754 '', group._changeset_cache)
745 last_commit_change = RepoGroup._load_commit_change(changeset_cache)
755 last_commit_change = RepoGroup._load_commit_change(changeset_cache)
746 row = {
756 row = {
747 "menu": quick_menu(group.group_name),
757 "menu": quick_menu(group.group_name),
748 "name": repo_group_lnk(group.group_name),
758 "name": repo_group_lnk(group.group_name),
749 "name_raw": group.group_name,
759 "name_raw": group.group_name,
750
760
751 "last_change": last_change(last_commit_change),
761 "last_change": last_change(last_commit_change),
752
762
753 "last_changeset": "",
763 "last_changeset": "",
754 "last_changeset_raw": "",
764 "last_changeset_raw": "",
755
765
756 "desc": desc(group.group_description, group.personal),
766 "desc": desc(group.group_description, group.personal),
757 "top_level_repos": 0,
767 "top_level_repos": 0,
758 "owner": user_profile(group.User.username)
768 "owner": user_profile(group.User.username)
759 }
769 }
760 if admin:
770 if admin:
761 repo_count = group.repositories.count()
771 repo_count = group.repositories.count()
762 children_groups = map(
772 children_groups = map(
763 h.safe_unicode,
773 h.safe_unicode,
764 itertools.chain((g.name for g in group.parents),
774 itertools.chain((g.name for g in group.parents),
765 (x.name for x in [group])))
775 (x.name for x in [group])))
766 row.update({
776 row.update({
767 "action": repo_group_actions(
777 "action": repo_group_actions(
768 group.group_id, group.group_name, repo_count),
778 group.group_id, group.group_name, repo_count),
769 "top_level_repos": repo_count,
779 "top_level_repos": repo_count,
770 "name": repo_group_name(group.group_name, children_groups),
780 "name": repo_group_name(group.group_name, children_groups),
771
781
772 })
782 })
773 repo_group_data.append(row)
783 repo_group_data.append(row)
774
784
775 return repo_group_data
785 return repo_group_data
776
786
777 def get_repo_groups_data_table(
787 def get_repo_groups_data_table(
778 self, draw, start, limit,
788 self, draw, start, limit,
779 search_q, order_by, order_dir,
789 search_q, order_by, order_dir,
780 auth_user, repo_group_id):
790 auth_user, repo_group_id):
781 from rhodecode.model.scm import RepoGroupList
791 from rhodecode.model.scm import RepoGroupList
782
792
783 _perms = ['group.read', 'group.write', 'group.admin']
793 _perms = ['group.read', 'group.write', 'group.admin']
784 repo_groups = RepoGroup.query() \
794 repo_groups = RepoGroup.query() \
785 .filter(RepoGroup.group_parent_id == repo_group_id) \
795 .filter(RepoGroup.group_parent_id == repo_group_id) \
786 .all()
796 .all()
787 auth_repo_group_list = RepoGroupList(
797 auth_repo_group_list = RepoGroupList(
788 repo_groups, perm_set=_perms,
798 repo_groups, perm_set=_perms,
789 extra_kwargs=dict(user=auth_user))
799 extra_kwargs=dict(user=auth_user))
790
800
791 allowed_ids = [-1]
801 allowed_ids = [-1]
792 for repo_group in auth_repo_group_list:
802 for repo_group in auth_repo_group_list:
793 allowed_ids.append(repo_group.group_id)
803 allowed_ids.append(repo_group.group_id)
794
804
795 repo_groups_data_total_count = RepoGroup.query() \
805 repo_groups_data_total_count = RepoGroup.query() \
796 .filter(RepoGroup.group_parent_id == repo_group_id) \
806 .filter(RepoGroup.group_parent_id == repo_group_id) \
797 .filter(or_(
807 .filter(or_(
798 # generate multiple IN to fix limitation problems
808 # generate multiple IN to fix limitation problems
799 *in_filter_generator(RepoGroup.group_id, allowed_ids))
809 *in_filter_generator(RepoGroup.group_id, allowed_ids))
800 ) \
810 ) \
801 .count()
811 .count()
802
812
803 base_q = Session.query(
813 base_q = Session.query(
804 RepoGroup.group_name,
814 RepoGroup.group_name,
805 RepoGroup.group_name_hash,
815 RepoGroup.group_name_hash,
806 RepoGroup.group_description,
816 RepoGroup.group_description,
807 RepoGroup.group_id,
817 RepoGroup.group_id,
808 RepoGroup.personal,
818 RepoGroup.personal,
809 RepoGroup.updated_on,
819 RepoGroup.updated_on,
810 RepoGroup._changeset_cache,
820 RepoGroup._changeset_cache,
811 User,
821 User,
812 ) \
822 ) \
813 .filter(RepoGroup.group_parent_id == repo_group_id) \
823 .filter(RepoGroup.group_parent_id == repo_group_id) \
814 .filter(or_(
824 .filter(or_(
815 # generate multiple IN to fix limitation problems
825 # generate multiple IN to fix limitation problems
816 *in_filter_generator(RepoGroup.group_id, allowed_ids))
826 *in_filter_generator(RepoGroup.group_id, allowed_ids))
817 ) \
827 ) \
818 .join(User, User.user_id == RepoGroup.user_id) \
828 .join(User, User.user_id == RepoGroup.user_id) \
819 .group_by(RepoGroup, User)
829 .group_by(RepoGroup, User)
820
830
821 repo_groups_data_total_filtered_count = base_q.count()
831 repo_groups_data_total_filtered_count = base_q.count()
822
832
823 sort_defined = False
833 sort_defined = False
824
834
825 if order_by == 'group_name':
835 if order_by == 'group_name':
826 sort_col = func.lower(RepoGroup.group_name)
836 sort_col = func.lower(RepoGroup.group_name)
827 sort_defined = True
837 sort_defined = True
828 elif order_by == 'user_username':
838 elif order_by == 'user_username':
829 sort_col = User.username
839 sort_col = User.username
830 else:
840 else:
831 sort_col = getattr(RepoGroup, order_by, None)
841 sort_col = getattr(RepoGroup, order_by, None)
832
842
833 if sort_defined or sort_col:
843 if sort_defined or sort_col:
834 if order_dir == 'asc':
844 if order_dir == 'asc':
835 sort_col = sort_col.asc()
845 sort_col = sort_col.asc()
836 else:
846 else:
837 sort_col = sort_col.desc()
847 sort_col = sort_col.desc()
838
848
839 base_q = base_q.order_by(sort_col)
849 base_q = base_q.order_by(sort_col)
840 base_q = base_q.offset(start).limit(limit)
850 base_q = base_q.offset(start).limit(limit)
841
851
842 repo_group_list = base_q.all()
852 repo_group_list = base_q.all()
843
853
844 repo_groups_data = RepoGroupModel().get_repo_groups_as_dict(
854 repo_groups_data = RepoGroupModel().get_repo_groups_as_dict(
845 repo_group_list=repo_group_list, admin=False)
855 repo_group_list=repo_group_list, admin=False)
846
856
847 data = ({
857 data = ({
848 'draw': draw,
858 'draw': draw,
849 'data': repo_groups_data,
859 'data': repo_groups_data,
850 'recordsTotal': repo_groups_data_total_count,
860 'recordsTotal': repo_groups_data_total_count,
851 'recordsFiltered': repo_groups_data_total_filtered_count,
861 'recordsFiltered': repo_groups_data_total_filtered_count,
852 })
862 })
853 return data
863 return data
854
864
855 def _get_defaults(self, repo_group_name):
865 def _get_defaults(self, repo_group_name):
856 repo_group = RepoGroup.get_by_group_name(repo_group_name)
866 repo_group = RepoGroup.get_by_group_name(repo_group_name)
857
867
858 if repo_group is None:
868 if repo_group is None:
859 return None
869 return None
860
870
861 defaults = repo_group.get_dict()
871 defaults = repo_group.get_dict()
862 defaults['repo_group_name'] = repo_group.name
872 defaults['repo_group_name'] = repo_group.name
863 defaults['repo_group_description'] = repo_group.group_description
873 defaults['repo_group_description'] = repo_group.group_description
864 defaults['repo_group_enable_locking'] = repo_group.enable_locking
874 defaults['repo_group_enable_locking'] = repo_group.enable_locking
865
875
866 # we use -1 as this is how in HTML, we mark an empty group
876 # we use -1 as this is how in HTML, we mark an empty group
867 defaults['repo_group'] = defaults['group_parent_id'] or -1
877 defaults['repo_group'] = defaults['group_parent_id'] or -1
868
878
869 # fill owner
879 # fill owner
870 if repo_group.user:
880 if repo_group.user:
871 defaults.update({'user': repo_group.user.username})
881 defaults.update({'user': repo_group.user.username})
872 else:
882 else:
873 replacement_user = User.get_first_super_admin().username
883 replacement_user = User.get_first_super_admin().username
874 defaults.update({'user': replacement_user})
884 defaults.update({'user': replacement_user})
875
885
876 return defaults
886 return defaults
General Comments 0
You need to be logged in to leave comments. Login now