##// END OF EJS Templates
db: prevent empty IN queries that generally are performance problem, and triggers sql warnings.
marcink -
r2176:d21fb0df default
parent child Browse files
Show More
@@ -1,247 +1,247 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 import logging
22 22
23 23 import formencode
24 24 import formencode.htmlfill
25 25
26 26 from pyramid.httpexceptions import HTTPFound
27 27 from pyramid.view import view_config
28 28 from pyramid.response import Response
29 29 from pyramid.renderers import render
30 30
31 31 from rhodecode.apps._base import BaseAppView, DataGridAppView
32 32 from rhodecode.lib.auth import (
33 33 LoginRequired, NotAnonymous, CSRFRequired, HasPermissionAnyDecorator)
34 34 from rhodecode.lib import helpers as h, audit_logger
35 35 from rhodecode.lib.utils2 import safe_unicode
36 36
37 37 from rhodecode.model.forms import UserGroupForm
38 38 from rhodecode.model.permission import PermissionModel
39 39 from rhodecode.model.scm import UserGroupList
40 40 from rhodecode.model.db import (
41 41 or_, count, User, UserGroup, UserGroupMember)
42 42 from rhodecode.model.meta import Session
43 43 from rhodecode.model.user_group import UserGroupModel
44 44
45 45 log = logging.getLogger(__name__)
46 46
47 47
48 48 class AdminUserGroupsView(BaseAppView, DataGridAppView):
49 49
50 50 def load_default_context(self):
51 51 c = self._get_local_tmpl_context()
52 52
53 53 PermissionModel().set_global_permission_choices(
54 54 c, gettext_translator=self.request.translate)
55 55
56 56 self._register_global_c(c)
57 57 return c
58 58
59 59 # permission check in data loading of
60 60 # `user_groups_list_data` via UserGroupList
61 61 @LoginRequired()
62 62 @NotAnonymous()
63 63 @view_config(
64 64 route_name='user_groups', request_method='GET',
65 65 renderer='rhodecode:templates/admin/user_groups/user_groups.mako')
66 66 def user_groups_list(self):
67 67 c = self.load_default_context()
68 68 return self._get_template_context(c)
69 69
70 70 # permission check inside
71 71 @LoginRequired()
72 72 @NotAnonymous()
73 73 @view_config(
74 74 route_name='user_groups_data', request_method='GET',
75 75 renderer='json_ext', xhr=True)
76 76 def user_groups_list_data(self):
77 77 column_map = {
78 78 'active': 'users_group_active',
79 79 'description': 'user_group_description',
80 80 'members': 'members_total',
81 81 'owner': 'user_username',
82 82 'sync': 'group_data'
83 83 }
84 84 draw, start, limit = self._extract_chunk(self.request)
85 85 search_q, order_by, order_dir = self._extract_ordering(
86 86 self.request, column_map=column_map)
87 87
88 88 _render = self.request.get_partial_renderer(
89 89 'data_table/_dt_elements.mako')
90 90
91 91 def user_group_name(user_group_id, user_group_name):
92 92 return _render("user_group_name", user_group_id, user_group_name)
93 93
94 94 def user_group_actions(user_group_id, user_group_name):
95 95 return _render("user_group_actions", user_group_id, user_group_name)
96 96
97 97 def user_profile(username):
98 98 return _render('user_profile', username)
99 99
100 100 auth_user_group_list = UserGroupList(
101 101 UserGroup.query().all(), perm_set=['usergroup.admin'])
102 102
103 allowed_ids = []
103 allowed_ids = [-1]
104 104 for user_group in auth_user_group_list:
105 105 allowed_ids.append(user_group.users_group_id)
106 106
107 107 user_groups_data_total_count = UserGroup.query()\
108 108 .filter(UserGroup.users_group_id.in_(allowed_ids))\
109 109 .count()
110 110
111 111 member_count = count(UserGroupMember.user_id)
112 112 base_q = Session.query(
113 113 UserGroup.users_group_name,
114 114 UserGroup.user_group_description,
115 115 UserGroup.users_group_active,
116 116 UserGroup.users_group_id,
117 117 UserGroup.group_data,
118 118 User,
119 119 member_count.label('member_count')
120 120 ) \
121 121 .filter(UserGroup.users_group_id.in_(allowed_ids)) \
122 122 .outerjoin(UserGroupMember) \
123 123 .join(User, User.user_id == UserGroup.user_id) \
124 124 .group_by(UserGroup, User)
125 125
126 126 if search_q:
127 127 like_expression = u'%{}%'.format(safe_unicode(search_q))
128 128 base_q = base_q.filter(or_(
129 129 UserGroup.users_group_name.ilike(like_expression),
130 130 ))
131 131
132 132 user_groups_data_total_filtered_count = base_q.count()
133 133
134 134 if order_by == 'members_total':
135 135 sort_col = member_count
136 136 elif order_by == 'user_username':
137 137 sort_col = User.username
138 138 else:
139 139 sort_col = getattr(UserGroup, order_by, None)
140 140
141 141 if isinstance(sort_col, count) or sort_col:
142 142 if order_dir == 'asc':
143 143 sort_col = sort_col.asc()
144 144 else:
145 145 sort_col = sort_col.desc()
146 146
147 147 base_q = base_q.order_by(sort_col)
148 148 base_q = base_q.offset(start).limit(limit)
149 149
150 150 # authenticated access to user groups
151 151 auth_user_group_list = base_q.all()
152 152
153 153 user_groups_data = []
154 154 for user_gr in auth_user_group_list:
155 155 user_groups_data.append({
156 156 "users_group_name": user_group_name(
157 157 user_gr.users_group_id, h.escape(user_gr.users_group_name)),
158 158 "name_raw": h.escape(user_gr.users_group_name),
159 159 "description": h.escape(user_gr.user_group_description),
160 160 "members": user_gr.member_count,
161 161 # NOTE(marcink): because of advanced query we
162 162 # need to load it like that
163 163 "sync": UserGroup._load_group_data(
164 164 user_gr.group_data).get('extern_type'),
165 165 "active": h.bool2icon(user_gr.users_group_active),
166 166 "owner": user_profile(user_gr.User.username),
167 167 "action": user_group_actions(
168 168 user_gr.users_group_id, user_gr.users_group_name)
169 169 })
170 170
171 171 data = ({
172 172 'draw': draw,
173 173 'data': user_groups_data,
174 174 'recordsTotal': user_groups_data_total_count,
175 175 'recordsFiltered': user_groups_data_total_filtered_count,
176 176 })
177 177
178 178 return data
179 179
180 180 @LoginRequired()
181 181 @HasPermissionAnyDecorator('hg.admin', 'hg.usergroup.create.true')
182 182 @view_config(
183 183 route_name='user_groups_new', request_method='GET',
184 184 renderer='rhodecode:templates/admin/user_groups/user_group_add.mako')
185 185 def user_groups_new(self):
186 186 c = self.load_default_context()
187 187 return self._get_template_context(c)
188 188
189 189 @LoginRequired()
190 190 @HasPermissionAnyDecorator('hg.admin', 'hg.usergroup.create.true')
191 191 @CSRFRequired()
192 192 @view_config(
193 193 route_name='user_groups_create', request_method='POST',
194 194 renderer='rhodecode:templates/admin/user_groups/user_group_add.mako')
195 195 def user_groups_create(self):
196 196 _ = self.request.translate
197 197 c = self.load_default_context()
198 198 users_group_form = UserGroupForm()()
199 199
200 200 user_group_name = self.request.POST.get('users_group_name')
201 201 try:
202 202 form_result = users_group_form.to_python(dict(self.request.POST))
203 203 user_group = UserGroupModel().create(
204 204 name=form_result['users_group_name'],
205 205 description=form_result['user_group_description'],
206 206 owner=self._rhodecode_user.user_id,
207 207 active=form_result['users_group_active'])
208 208 Session().flush()
209 209 creation_data = user_group.get_api_data()
210 210 user_group_name = form_result['users_group_name']
211 211
212 212 audit_logger.store_web(
213 213 'user_group.create', action_data={'data': creation_data},
214 214 user=self._rhodecode_user)
215 215
216 216 user_group_link = h.link_to(
217 217 h.escape(user_group_name),
218 218 h.route_path(
219 219 'edit_user_group', user_group_id=user_group.users_group_id))
220 220 h.flash(h.literal(_('Created user group %(user_group_link)s')
221 221 % {'user_group_link': user_group_link}),
222 222 category='success')
223 223 Session().commit()
224 224 user_group_id = user_group.users_group_id
225 225 except formencode.Invalid as errors:
226 226
227 227 data = render(
228 228 'rhodecode:templates/admin/user_groups/user_group_add.mako',
229 229 self._get_template_context(c), self.request)
230 230 html = formencode.htmlfill.render(
231 231 data,
232 232 defaults=errors.value,
233 233 errors=errors.error_dict or {},
234 234 prefix_error=False,
235 235 encoding="UTF-8",
236 236 force_defaults=False
237 237 )
238 238 return Response(html)
239 239
240 240 except Exception:
241 241 log.exception("Exception creating user group")
242 242 h.flash(_('Error occurred during creation of user group %s') \
243 243 % user_group_name, category='error')
244 244 raise HTTPFound(h.route_path('user_groups_new'))
245 245
246 246 raise HTTPFound(
247 247 h.route_path('edit_user_group', user_group_id=user_group_id))
@@ -1,258 +1,258 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2011-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 import logging
22 22 import datetime
23 23 import formencode
24 24 import formencode.htmlfill
25 25
26 26 from pyramid.httpexceptions import HTTPFound
27 27 from pyramid.view import view_config
28 28 from pyramid.renderers import render
29 29 from pyramid.response import Response
30 30
31 31 from rhodecode.apps._base import RepoAppView, DataGridAppView
32 32 from rhodecode.lib.auth import (
33 33 LoginRequired, HasRepoPermissionAnyDecorator, NotAnonymous,
34 34 HasRepoPermissionAny, HasPermissionAnyDecorator, CSRFRequired)
35 35 import rhodecode.lib.helpers as h
36 36 from rhodecode.model.db import coalesce, or_, Repository, RepoGroup
37 37 from rhodecode.model.repo import RepoModel
38 38 from rhodecode.model.forms import RepoForkForm
39 39 from rhodecode.model.scm import ScmModel, RepoGroupList
40 40 from rhodecode.lib.utils2 import safe_int, safe_unicode
41 41
42 42 log = logging.getLogger(__name__)
43 43
44 44
45 45 class RepoForksView(RepoAppView, DataGridAppView):
46 46
47 47 def load_default_context(self):
48 48 c = self._get_local_tmpl_context(include_app_defaults=True)
49 49 c.rhodecode_repo = self.rhodecode_vcs_repo
50 50
51 51 acl_groups = RepoGroupList(
52 52 RepoGroup.query().all(),
53 53 perm_set=['group.write', 'group.admin'])
54 54 c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
55 55 c.repo_groups_choices = map(lambda k: safe_unicode(k[0]), c.repo_groups)
56 56 choices, c.landing_revs = ScmModel().get_repo_landing_revs()
57 57 c.landing_revs_choices = choices
58 58 c.personal_repo_group = c.rhodecode_user.personal_repo_group
59 59
60 60 self._register_global_c(c)
61 61 return c
62 62
63 63 @LoginRequired()
64 64 @HasRepoPermissionAnyDecorator(
65 65 'repository.read', 'repository.write', 'repository.admin')
66 66 @view_config(
67 67 route_name='repo_forks_show_all', request_method='GET',
68 68 renderer='rhodecode:templates/forks/forks.mako')
69 69 def repo_forks_show_all(self):
70 70 c = self.load_default_context()
71 71 return self._get_template_context(c)
72 72
73 73 @LoginRequired()
74 74 @HasRepoPermissionAnyDecorator(
75 75 'repository.read', 'repository.write', 'repository.admin')
76 76 @view_config(
77 77 route_name='repo_forks_data', request_method='GET',
78 78 renderer='json_ext', xhr=True)
79 79 def repo_forks_data(self):
80 80 _ = self.request.translate
81 81 column_map = {
82 82 'fork_name': 'repo_name',
83 83 'fork_date': 'created_on',
84 84 'last_activity': 'updated_on'
85 85 }
86 86 draw, start, limit = self._extract_chunk(self.request)
87 87 search_q, order_by, order_dir = self._extract_ordering(
88 88 self.request, column_map=column_map)
89 89
90 90 acl_check = HasRepoPermissionAny(
91 91 'repository.read', 'repository.write', 'repository.admin')
92 92 repo_id = self.db_repo.repo_id
93 allowed_ids = []
93 allowed_ids = [-1]
94 94 for f in Repository.query().filter(Repository.fork_id == repo_id):
95 95 if acl_check(f.repo_name, 'get forks check'):
96 96 allowed_ids.append(f.repo_id)
97 97
98 98 forks_data_total_count = Repository.query()\
99 99 .filter(Repository.fork_id == repo_id)\
100 100 .filter(Repository.repo_id.in_(allowed_ids))\
101 101 .count()
102 102
103 103 # json generate
104 104 base_q = Repository.query()\
105 105 .filter(Repository.fork_id == repo_id)\
106 106 .filter(Repository.repo_id.in_(allowed_ids))\
107 107
108 108 if search_q:
109 109 like_expression = u'%{}%'.format(safe_unicode(search_q))
110 110 base_q = base_q.filter(or_(
111 111 Repository.repo_name.ilike(like_expression),
112 112 Repository.description.ilike(like_expression),
113 113 ))
114 114
115 115 forks_data_total_filtered_count = base_q.count()
116 116
117 117 sort_col = getattr(Repository, order_by, None)
118 118 if sort_col:
119 119 if order_dir == 'asc':
120 120 # handle null values properly to order by NULL last
121 121 if order_by in ['last_activity']:
122 122 sort_col = coalesce(sort_col, datetime.date.max)
123 123 sort_col = sort_col.asc()
124 124 else:
125 125 # handle null values properly to order by NULL last
126 126 if order_by in ['last_activity']:
127 127 sort_col = coalesce(sort_col, datetime.date.min)
128 128 sort_col = sort_col.desc()
129 129
130 130 base_q = base_q.order_by(sort_col)
131 131 base_q = base_q.offset(start).limit(limit)
132 132
133 133 fork_list = base_q.all()
134 134
135 135 def fork_actions(fork):
136 136 url_link = h.route_path(
137 137 'repo_compare',
138 138 repo_name=fork.repo_name,
139 139 source_ref_type=self.db_repo.landing_rev[0],
140 140 source_ref=self.db_repo.landing_rev[1],
141 141 target_ref_type=self.db_repo.landing_rev[0],
142 142 target_ref=self.db_repo.landing_rev[1],
143 143 _query=dict(merge=1, target_repo=f.repo_name))
144 144 return h.link_to(_('Compare fork'), url_link, class_='btn-link')
145 145
146 146 def fork_name(fork):
147 147 return h.link_to(fork.repo_name,
148 148 h.route_path('repo_summary', repo_name=fork.repo_name))
149 149
150 150 forks_data = []
151 151 for fork in fork_list:
152 152 forks_data.append({
153 153 "username": h.gravatar_with_user(self.request, fork.user.username),
154 154 "fork_name": fork_name(fork),
155 155 "description": fork.description,
156 156 "fork_date": h.age_component(fork.created_on, time_is_local=True),
157 157 "last_activity": h.format_date(fork.updated_on),
158 158 "action": fork_actions(fork),
159 159 })
160 160
161 161 data = ({
162 162 'draw': draw,
163 163 'data': forks_data,
164 164 'recordsTotal': forks_data_total_count,
165 165 'recordsFiltered': forks_data_total_filtered_count,
166 166 })
167 167
168 168 return data
169 169
170 170 @LoginRequired()
171 171 @NotAnonymous()
172 172 @HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository')
173 173 @HasRepoPermissionAnyDecorator(
174 174 'repository.read', 'repository.write', 'repository.admin')
175 175 @view_config(
176 176 route_name='repo_fork_new', request_method='GET',
177 177 renderer='rhodecode:templates/forks/forks.mako')
178 178 def repo_fork_new(self):
179 179 c = self.load_default_context()
180 180
181 181 defaults = RepoModel()._get_defaults(self.db_repo_name)
182 182 # alter the description to indicate a fork
183 183 defaults['description'] = (
184 184 'fork of repository: %s \n%s' % (
185 185 defaults['repo_name'], defaults['description']))
186 186 # add suffix to fork
187 187 defaults['repo_name'] = '%s-fork' % defaults['repo_name']
188 188
189 189 data = render('rhodecode:templates/forks/fork.mako',
190 190 self._get_template_context(c), self.request)
191 191 html = formencode.htmlfill.render(
192 192 data,
193 193 defaults=defaults,
194 194 encoding="UTF-8",
195 195 force_defaults=False
196 196 )
197 197 return Response(html)
198 198
199 199 @LoginRequired()
200 200 @NotAnonymous()
201 201 @HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository')
202 202 @HasRepoPermissionAnyDecorator(
203 203 'repository.read', 'repository.write', 'repository.admin')
204 204 @CSRFRequired()
205 205 @view_config(
206 206 route_name='repo_fork_create', request_method='POST',
207 207 renderer='rhodecode:templates/forks/fork.mako')
208 208 def repo_fork_create(self):
209 209 _ = self.request.translate
210 210 c = self.load_default_context()
211 211
212 212 _form = RepoForkForm(old_data={'repo_type': self.db_repo.repo_type},
213 213 repo_groups=c.repo_groups_choices,
214 214 landing_revs=c.landing_revs_choices)()
215 215 post_data = dict(self.request.POST)
216 216
217 217 # forbid injecting other repo by forging a request
218 218 post_data['fork_parent_id'] = self.db_repo.repo_id
219 219
220 220 form_result = {}
221 221 task_id = None
222 222 try:
223 223 form_result = _form.to_python(post_data)
224 224 # create fork is done sometimes async on celery, db transaction
225 225 # management is handled there.
226 226 task = RepoModel().create_fork(
227 227 form_result, c.rhodecode_user.user_id)
228 228 from celery.result import BaseAsyncResult
229 229 if isinstance(task, BaseAsyncResult):
230 230 task_id = task.task_id
231 231 except formencode.Invalid as errors:
232 232 c.rhodecode_db_repo = self.db_repo
233 233
234 234 data = render('rhodecode:templates/forks/fork.mako',
235 235 self._get_template_context(c), self.request)
236 236 html = formencode.htmlfill.render(
237 237 data,
238 238 defaults=errors.value,
239 239 errors=errors.error_dict or {},
240 240 prefix_error=False,
241 241 encoding="UTF-8",
242 242 force_defaults=False
243 243 )
244 244 return Response(html)
245 245 except Exception:
246 246 log.exception(
247 247 u'Exception while trying to fork the repository %s',
248 248 self.db_repo_name)
249 249 msg = (
250 250 _('An error occurred during repository forking %s') % (
251 251 self.db_repo_name, ))
252 252 h.flash(msg, category='error')
253 253
254 254 repo_name = form_result.get('repo_name_full', self.db_repo_name)
255 255 raise HTTPFound(
256 256 h.route_path('repo_creating',
257 257 repo_name=repo_name,
258 258 _query=dict(task_id=task_id)))
General Comments 0
You need to be logged in to leave comments. Login now