##// END OF EJS Templates
create: fixed case for repo groups that didn't pre-fill the repo group from GET param....
marcink -
r4424:cbe581e5 default
parent child Browse files
Show More
@@ -1,360 +1,374 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2020 RhodeCode GmbH
3 # Copyright (C) 2016-2020 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 import datetime
20 import datetime
21 import logging
21 import logging
22 import time
22 import time
23
23
24 import formencode
24 import formencode
25 import formencode.htmlfill
25 import formencode.htmlfill
26
26
27 from pyramid.httpexceptions import HTTPFound, HTTPForbidden
27 from pyramid.httpexceptions import HTTPFound, HTTPForbidden
28 from pyramid.view import view_config
28 from pyramid.view import view_config
29 from pyramid.renderers import render
29 from pyramid.renderers import render
30 from pyramid.response import Response
30 from pyramid.response import Response
31
31
32 from rhodecode import events
32 from rhodecode import events
33 from rhodecode.apps._base import BaseAppView, DataGridAppView
33 from rhodecode.apps._base import BaseAppView, DataGridAppView
34
34
35 from rhodecode.lib.auth import (
35 from rhodecode.lib.auth import (
36 LoginRequired, CSRFRequired, NotAnonymous,
36 LoginRequired, CSRFRequired, NotAnonymous,
37 HasPermissionAny, HasRepoGroupPermissionAny)
37 HasPermissionAny, HasRepoGroupPermissionAny)
38 from rhodecode.lib import helpers as h, audit_logger
38 from rhodecode.lib import helpers as h, audit_logger
39 from rhodecode.lib.utils2 import safe_int, safe_unicode, datetime_to_time
39 from rhodecode.lib.utils2 import safe_int, safe_unicode, datetime_to_time
40 from rhodecode.model.forms import RepoGroupForm
40 from rhodecode.model.forms import RepoGroupForm
41 from rhodecode.model.permission import PermissionModel
41 from rhodecode.model.permission import PermissionModel
42 from rhodecode.model.repo_group import RepoGroupModel
42 from rhodecode.model.repo_group import RepoGroupModel
43 from rhodecode.model.scm import RepoGroupList
43 from rhodecode.model.scm import RepoGroupList
44 from rhodecode.model.db import (
44 from rhodecode.model.db import (
45 or_, count, func, in_filter_generator, Session, RepoGroup, User, Repository)
45 or_, count, func, in_filter_generator, Session, RepoGroup, User, Repository)
46
46
47 log = logging.getLogger(__name__)
47 log = logging.getLogger(__name__)
48
48
49
49
50 class AdminRepoGroupsView(BaseAppView, DataGridAppView):
50 class AdminRepoGroupsView(BaseAppView, DataGridAppView):
51
51
52 def load_default_context(self):
52 def load_default_context(self):
53 c = self._get_local_tmpl_context()
53 c = self._get_local_tmpl_context()
54
54
55 return c
55 return c
56
56
57 def _load_form_data(self, c):
57 def _load_form_data(self, c):
58 allow_empty_group = False
58 allow_empty_group = False
59
59
60 if self._can_create_repo_group():
60 if self._can_create_repo_group():
61 # we're global admin, we're ok and we can create TOP level groups
61 # we're global admin, we're ok and we can create TOP level groups
62 allow_empty_group = True
62 allow_empty_group = True
63
63
64 # override the choices for this form, we need to filter choices
64 # override the choices for this form, we need to filter choices
65 # and display only those we have ADMIN right
65 # and display only those we have ADMIN right
66 groups_with_admin_rights = RepoGroupList(
66 groups_with_admin_rights = RepoGroupList(
67 RepoGroup.query().all(),
67 RepoGroup.query().all(),
68 perm_set=['group.admin'], extra_kwargs=dict(user=self._rhodecode_user))
68 perm_set=['group.admin'], extra_kwargs=dict(user=self._rhodecode_user))
69 c.repo_groups = RepoGroup.groups_choices(
69 c.repo_groups = RepoGroup.groups_choices(
70 groups=groups_with_admin_rights,
70 groups=groups_with_admin_rights,
71 show_empty_group=allow_empty_group)
71 show_empty_group=allow_empty_group)
72 c.personal_repo_group = self._rhodecode_user.personal_repo_group
72
73
73 def _can_create_repo_group(self, parent_group_id=None):
74 def _can_create_repo_group(self, parent_group_id=None):
74 is_admin = HasPermissionAny('hg.admin')('group create controller')
75 is_admin = HasPermissionAny('hg.admin')('group create controller')
75 create_repo_group = HasPermissionAny(
76 create_repo_group = HasPermissionAny(
76 'hg.repogroup.create.true')('group create controller')
77 'hg.repogroup.create.true')('group create controller')
77 if is_admin or (create_repo_group and not parent_group_id):
78 if is_admin or (create_repo_group and not parent_group_id):
78 # we're global admin, or we have global repo group create
79 # we're global admin, or we have global repo group create
79 # permission
80 # permission
80 # we're ok and we can create TOP level groups
81 # we're ok and we can create TOP level groups
81 return True
82 return True
82 elif parent_group_id:
83 elif parent_group_id:
83 # we check the permission if we can write to parent group
84 # we check the permission if we can write to parent group
84 group = RepoGroup.get(parent_group_id)
85 group = RepoGroup.get(parent_group_id)
85 group_name = group.group_name if group else None
86 group_name = group.group_name if group else None
86 if HasRepoGroupPermissionAny('group.admin')(
87 if HasRepoGroupPermissionAny('group.admin')(
87 group_name, 'check if user is an admin of group'):
88 group_name, 'check if user is an admin of group'):
88 # we're an admin of passed in group, we're ok.
89 # we're an admin of passed in group, we're ok.
89 return True
90 return True
90 else:
91 else:
91 return False
92 return False
92 return False
93 return False
93
94
94 # permission check in data loading of
95 # permission check in data loading of
95 # `repo_group_list_data` via RepoGroupList
96 # `repo_group_list_data` via RepoGroupList
96 @LoginRequired()
97 @LoginRequired()
97 @NotAnonymous()
98 @NotAnonymous()
98 @view_config(
99 @view_config(
99 route_name='repo_groups', request_method='GET',
100 route_name='repo_groups', request_method='GET',
100 renderer='rhodecode:templates/admin/repo_groups/repo_groups.mako')
101 renderer='rhodecode:templates/admin/repo_groups/repo_groups.mako')
101 def repo_group_list(self):
102 def repo_group_list(self):
102 c = self.load_default_context()
103 c = self.load_default_context()
103 return self._get_template_context(c)
104 return self._get_template_context(c)
104
105
105 # permission check inside
106 # permission check inside
106 @LoginRequired()
107 @LoginRequired()
107 @NotAnonymous()
108 @NotAnonymous()
108 @view_config(
109 @view_config(
109 route_name='repo_groups_data', request_method='GET',
110 route_name='repo_groups_data', request_method='GET',
110 renderer='json_ext', xhr=True)
111 renderer='json_ext', xhr=True)
111 def repo_group_list_data(self):
112 def repo_group_list_data(self):
112 self.load_default_context()
113 self.load_default_context()
113 column_map = {
114 column_map = {
114 'name': 'group_name_hash',
115 'name': 'group_name_hash',
115 'desc': 'group_description',
116 'desc': 'group_description',
116 'last_change': 'updated_on',
117 'last_change': 'updated_on',
117 'top_level_repos': 'repos_total',
118 'top_level_repos': 'repos_total',
118 'owner': 'user_username',
119 'owner': 'user_username',
119 }
120 }
120 draw, start, limit = self._extract_chunk(self.request)
121 draw, start, limit = self._extract_chunk(self.request)
121 search_q, order_by, order_dir = self._extract_ordering(
122 search_q, order_by, order_dir = self._extract_ordering(
122 self.request, column_map=column_map)
123 self.request, column_map=column_map)
123
124
124 _render = self.request.get_partial_renderer(
125 _render = self.request.get_partial_renderer(
125 'rhodecode:templates/data_table/_dt_elements.mako')
126 'rhodecode:templates/data_table/_dt_elements.mako')
126 c = _render.get_call_context()
127 c = _render.get_call_context()
127
128
128 def quick_menu(repo_group_name):
129 def quick_menu(repo_group_name):
129 return _render('quick_repo_group_menu', repo_group_name)
130 return _render('quick_repo_group_menu', repo_group_name)
130
131
131 def repo_group_lnk(repo_group_name):
132 def repo_group_lnk(repo_group_name):
132 return _render('repo_group_name', repo_group_name)
133 return _render('repo_group_name', repo_group_name)
133
134
134 def last_change(last_change):
135 def last_change(last_change):
135 if isinstance(last_change, datetime.datetime) and not last_change.tzinfo:
136 if isinstance(last_change, datetime.datetime) and not last_change.tzinfo:
136 ts = time.time()
137 ts = time.time()
137 utc_offset = (datetime.datetime.fromtimestamp(ts)
138 utc_offset = (datetime.datetime.fromtimestamp(ts)
138 - datetime.datetime.utcfromtimestamp(ts)).total_seconds()
139 - datetime.datetime.utcfromtimestamp(ts)).total_seconds()
139 last_change = last_change + datetime.timedelta(seconds=utc_offset)
140 last_change = last_change + datetime.timedelta(seconds=utc_offset)
140 return _render("last_change", last_change)
141 return _render("last_change", last_change)
141
142
142 def desc(desc, personal):
143 def desc(desc, personal):
143 return _render(
144 return _render(
144 'repo_group_desc', desc, personal, c.visual.stylify_metatags)
145 'repo_group_desc', desc, personal, c.visual.stylify_metatags)
145
146
146 def repo_group_actions(repo_group_id, repo_group_name, gr_count):
147 def repo_group_actions(repo_group_id, repo_group_name, gr_count):
147 return _render(
148 return _render(
148 'repo_group_actions', repo_group_id, repo_group_name, gr_count)
149 'repo_group_actions', repo_group_id, repo_group_name, gr_count)
149
150
150 def user_profile(username):
151 def user_profile(username):
151 return _render('user_profile', username)
152 return _render('user_profile', username)
152
153
153 _perms = ['group.admin']
154 _perms = ['group.admin']
154 allowed_ids = [-1] + self._rhodecode_user.repo_group_acl_ids_from_stack(_perms)
155 allowed_ids = [-1] + self._rhodecode_user.repo_group_acl_ids_from_stack(_perms)
155
156
156 repo_groups_data_total_count = RepoGroup.query()\
157 repo_groups_data_total_count = RepoGroup.query()\
157 .filter(or_(
158 .filter(or_(
158 # generate multiple IN to fix limitation problems
159 # generate multiple IN to fix limitation problems
159 *in_filter_generator(RepoGroup.group_id, allowed_ids)
160 *in_filter_generator(RepoGroup.group_id, allowed_ids)
160 )) \
161 )) \
161 .count()
162 .count()
162
163
163 repo_groups_data_total_inactive_count = RepoGroup.query()\
164 repo_groups_data_total_inactive_count = RepoGroup.query()\
164 .filter(RepoGroup.group_id.in_(allowed_ids))\
165 .filter(RepoGroup.group_id.in_(allowed_ids))\
165 .count()
166 .count()
166
167
167 repo_count = count(Repository.repo_id)
168 repo_count = count(Repository.repo_id)
168 base_q = Session.query(
169 base_q = Session.query(
169 RepoGroup.group_name,
170 RepoGroup.group_name,
170 RepoGroup.group_name_hash,
171 RepoGroup.group_name_hash,
171 RepoGroup.group_description,
172 RepoGroup.group_description,
172 RepoGroup.group_id,
173 RepoGroup.group_id,
173 RepoGroup.personal,
174 RepoGroup.personal,
174 RepoGroup.updated_on,
175 RepoGroup.updated_on,
175 User,
176 User,
176 repo_count.label('repos_count')
177 repo_count.label('repos_count')
177 ) \
178 ) \
178 .filter(or_(
179 .filter(or_(
179 # generate multiple IN to fix limitation problems
180 # generate multiple IN to fix limitation problems
180 *in_filter_generator(RepoGroup.group_id, allowed_ids)
181 *in_filter_generator(RepoGroup.group_id, allowed_ids)
181 )) \
182 )) \
182 .outerjoin(Repository, Repository.group_id == RepoGroup.group_id) \
183 .outerjoin(Repository, Repository.group_id == RepoGroup.group_id) \
183 .join(User, User.user_id == RepoGroup.user_id) \
184 .join(User, User.user_id == RepoGroup.user_id) \
184 .group_by(RepoGroup, User)
185 .group_by(RepoGroup, User)
185
186
186 if search_q:
187 if search_q:
187 like_expression = u'%{}%'.format(safe_unicode(search_q))
188 like_expression = u'%{}%'.format(safe_unicode(search_q))
188 base_q = base_q.filter(or_(
189 base_q = base_q.filter(or_(
189 RepoGroup.group_name.ilike(like_expression),
190 RepoGroup.group_name.ilike(like_expression),
190 ))
191 ))
191
192
192 repo_groups_data_total_filtered_count = base_q.count()
193 repo_groups_data_total_filtered_count = base_q.count()
193 # the inactive isn't really used, but we still make it same as other data grids
194 # the inactive isn't really used, but we still make it same as other data grids
194 # which use inactive (users,user groups)
195 # which use inactive (users,user groups)
195 repo_groups_data_total_filtered_inactive_count = repo_groups_data_total_filtered_count
196 repo_groups_data_total_filtered_inactive_count = repo_groups_data_total_filtered_count
196
197
197 sort_defined = False
198 sort_defined = False
198 if order_by == 'group_name':
199 if order_by == 'group_name':
199 sort_col = func.lower(RepoGroup.group_name)
200 sort_col = func.lower(RepoGroup.group_name)
200 sort_defined = True
201 sort_defined = True
201 elif order_by == 'repos_total':
202 elif order_by == 'repos_total':
202 sort_col = repo_count
203 sort_col = repo_count
203 sort_defined = True
204 sort_defined = True
204 elif order_by == 'user_username':
205 elif order_by == 'user_username':
205 sort_col = User.username
206 sort_col = User.username
206 else:
207 else:
207 sort_col = getattr(RepoGroup, order_by, None)
208 sort_col = getattr(RepoGroup, order_by, None)
208
209
209 if sort_defined or sort_col:
210 if sort_defined or sort_col:
210 if order_dir == 'asc':
211 if order_dir == 'asc':
211 sort_col = sort_col.asc()
212 sort_col = sort_col.asc()
212 else:
213 else:
213 sort_col = sort_col.desc()
214 sort_col = sort_col.desc()
214
215
215 base_q = base_q.order_by(sort_col)
216 base_q = base_q.order_by(sort_col)
216 base_q = base_q.offset(start).limit(limit)
217 base_q = base_q.offset(start).limit(limit)
217
218
218 # authenticated access to user groups
219 # authenticated access to user groups
219 auth_repo_group_list = base_q.all()
220 auth_repo_group_list = base_q.all()
220
221
221 repo_groups_data = []
222 repo_groups_data = []
222 for repo_gr in auth_repo_group_list:
223 for repo_gr in auth_repo_group_list:
223 row = {
224 row = {
224 "menu": quick_menu(repo_gr.group_name),
225 "menu": quick_menu(repo_gr.group_name),
225 "name": repo_group_lnk(repo_gr.group_name),
226 "name": repo_group_lnk(repo_gr.group_name),
226
227
227 "last_change": last_change(repo_gr.updated_on),
228 "last_change": last_change(repo_gr.updated_on),
228
229
229 "last_changeset": "",
230 "last_changeset": "",
230 "last_changeset_raw": "",
231 "last_changeset_raw": "",
231
232
232 "desc": desc(repo_gr.group_description, repo_gr.personal),
233 "desc": desc(repo_gr.group_description, repo_gr.personal),
233 "owner": user_profile(repo_gr.User.username),
234 "owner": user_profile(repo_gr.User.username),
234 "top_level_repos": repo_gr.repos_count,
235 "top_level_repos": repo_gr.repos_count,
235 "action": repo_group_actions(
236 "action": repo_group_actions(
236 repo_gr.group_id, repo_gr.group_name, repo_gr.repos_count),
237 repo_gr.group_id, repo_gr.group_name, repo_gr.repos_count),
237
238
238 }
239 }
239
240
240 repo_groups_data.append(row)
241 repo_groups_data.append(row)
241
242
242 data = ({
243 data = ({
243 'draw': draw,
244 'draw': draw,
244 'data': repo_groups_data,
245 'data': repo_groups_data,
245 'recordsTotal': repo_groups_data_total_count,
246 'recordsTotal': repo_groups_data_total_count,
246 'recordsTotalInactive': repo_groups_data_total_inactive_count,
247 'recordsTotalInactive': repo_groups_data_total_inactive_count,
247 'recordsFiltered': repo_groups_data_total_filtered_count,
248 'recordsFiltered': repo_groups_data_total_filtered_count,
248 'recordsFilteredInactive': repo_groups_data_total_filtered_inactive_count,
249 'recordsFilteredInactive': repo_groups_data_total_filtered_inactive_count,
249 })
250 })
250
251
251 return data
252 return data
252
253
253 @LoginRequired()
254 @LoginRequired()
254 @NotAnonymous()
255 @NotAnonymous()
255 # perm checks inside
256 # perm checks inside
256 @view_config(
257 @view_config(
257 route_name='repo_group_new', request_method='GET',
258 route_name='repo_group_new', request_method='GET',
258 renderer='rhodecode:templates/admin/repo_groups/repo_group_add.mako')
259 renderer='rhodecode:templates/admin/repo_groups/repo_group_add.mako')
259 def repo_group_new(self):
260 def repo_group_new(self):
260 c = self.load_default_context()
261 c = self.load_default_context()
261
262
262 # perm check for admin, create_group perm or admin of parent_group
263 # perm check for admin, create_group perm or admin of parent_group
263 parent_group_id = safe_int(self.request.GET.get('parent_group'))
264 parent_group_id = safe_int(self.request.GET.get('parent_group'))
265 _gr = RepoGroup.get(parent_group_id)
264 if not self._can_create_repo_group(parent_group_id):
266 if not self._can_create_repo_group(parent_group_id):
265 raise HTTPForbidden()
267 raise HTTPForbidden()
266
268
267 self._load_form_data(c)
269 self._load_form_data(c)
268
270
269 defaults = {} # Future proof for default of repo group
271 defaults = {} # Future proof for default of repo group
272
273 parent_group_choice = '-1'
274 if not self._rhodecode_user.is_admin and self._rhodecode_user.personal_repo_group:
275 parent_group_choice = self._rhodecode_user.personal_repo_group
276
277 if parent_group_id and _gr:
278 if parent_group_id in [x[0] for x in c.repo_groups]:
279 parent_group_choice = safe_unicode(parent_group_id)
280
281 defaults.update({'group_parent_id': parent_group_choice})
282
270 data = render(
283 data = render(
271 'rhodecode:templates/admin/repo_groups/repo_group_add.mako',
284 'rhodecode:templates/admin/repo_groups/repo_group_add.mako',
272 self._get_template_context(c), self.request)
285 self._get_template_context(c), self.request)
286
273 html = formencode.htmlfill.render(
287 html = formencode.htmlfill.render(
274 data,
288 data,
275 defaults=defaults,
289 defaults=defaults,
276 encoding="UTF-8",
290 encoding="UTF-8",
277 force_defaults=False
291 force_defaults=False
278 )
292 )
279 return Response(html)
293 return Response(html)
280
294
281 @LoginRequired()
295 @LoginRequired()
282 @NotAnonymous()
296 @NotAnonymous()
283 @CSRFRequired()
297 @CSRFRequired()
284 # perm checks inside
298 # perm checks inside
285 @view_config(
299 @view_config(
286 route_name='repo_group_create', request_method='POST',
300 route_name='repo_group_create', request_method='POST',
287 renderer='rhodecode:templates/admin/repo_groups/repo_group_add.mako')
301 renderer='rhodecode:templates/admin/repo_groups/repo_group_add.mako')
288 def repo_group_create(self):
302 def repo_group_create(self):
289 c = self.load_default_context()
303 c = self.load_default_context()
290 _ = self.request.translate
304 _ = self.request.translate
291
305
292 parent_group_id = safe_int(self.request.POST.get('group_parent_id'))
306 parent_group_id = safe_int(self.request.POST.get('group_parent_id'))
293 can_create = self._can_create_repo_group(parent_group_id)
307 can_create = self._can_create_repo_group(parent_group_id)
294
308
295 self._load_form_data(c)
309 self._load_form_data(c)
296 # permissions for can create group based on parent_id are checked
310 # permissions for can create group based on parent_id are checked
297 # here in the Form
311 # here in the Form
298 available_groups = map(lambda k: safe_unicode(k[0]), c.repo_groups)
312 available_groups = map(lambda k: safe_unicode(k[0]), c.repo_groups)
299 repo_group_form = RepoGroupForm(
313 repo_group_form = RepoGroupForm(
300 self.request.translate, available_groups=available_groups,
314 self.request.translate, available_groups=available_groups,
301 can_create_in_root=can_create)()
315 can_create_in_root=can_create)()
302
316
303 repo_group_name = self.request.POST.get('group_name')
317 repo_group_name = self.request.POST.get('group_name')
304 try:
318 try:
305 owner = self._rhodecode_user
319 owner = self._rhodecode_user
306 form_result = repo_group_form.to_python(dict(self.request.POST))
320 form_result = repo_group_form.to_python(dict(self.request.POST))
307 copy_permissions = form_result.get('group_copy_permissions')
321 copy_permissions = form_result.get('group_copy_permissions')
308 repo_group = RepoGroupModel().create(
322 repo_group = RepoGroupModel().create(
309 group_name=form_result['group_name_full'],
323 group_name=form_result['group_name_full'],
310 group_description=form_result['group_description'],
324 group_description=form_result['group_description'],
311 owner=owner.user_id,
325 owner=owner.user_id,
312 copy_permissions=form_result['group_copy_permissions']
326 copy_permissions=form_result['group_copy_permissions']
313 )
327 )
314 Session().flush()
328 Session().flush()
315
329
316 repo_group_data = repo_group.get_api_data()
330 repo_group_data = repo_group.get_api_data()
317 audit_logger.store_web(
331 audit_logger.store_web(
318 'repo_group.create', action_data={'data': repo_group_data},
332 'repo_group.create', action_data={'data': repo_group_data},
319 user=self._rhodecode_user)
333 user=self._rhodecode_user)
320
334
321 Session().commit()
335 Session().commit()
322
336
323 _new_group_name = form_result['group_name_full']
337 _new_group_name = form_result['group_name_full']
324
338
325 repo_group_url = h.link_to(
339 repo_group_url = h.link_to(
326 _new_group_name,
340 _new_group_name,
327 h.route_path('repo_group_home', repo_group_name=_new_group_name))
341 h.route_path('repo_group_home', repo_group_name=_new_group_name))
328 h.flash(h.literal(_('Created repository group %s')
342 h.flash(h.literal(_('Created repository group %s')
329 % repo_group_url), category='success')
343 % repo_group_url), category='success')
330
344
331 except formencode.Invalid as errors:
345 except formencode.Invalid as errors:
332 data = render(
346 data = render(
333 'rhodecode:templates/admin/repo_groups/repo_group_add.mako',
347 'rhodecode:templates/admin/repo_groups/repo_group_add.mako',
334 self._get_template_context(c), self.request)
348 self._get_template_context(c), self.request)
335 html = formencode.htmlfill.render(
349 html = formencode.htmlfill.render(
336 data,
350 data,
337 defaults=errors.value,
351 defaults=errors.value,
338 errors=errors.error_dict or {},
352 errors=errors.error_dict or {},
339 prefix_error=False,
353 prefix_error=False,
340 encoding="UTF-8",
354 encoding="UTF-8",
341 force_defaults=False
355 force_defaults=False
342 )
356 )
343 return Response(html)
357 return Response(html)
344 except Exception:
358 except Exception:
345 log.exception("Exception during creation of repository group")
359 log.exception("Exception during creation of repository group")
346 h.flash(_('Error occurred during creation of repository group %s')
360 h.flash(_('Error occurred during creation of repository group %s')
347 % repo_group_name, category='error')
361 % repo_group_name, category='error')
348 raise HTTPFound(h.route_path('home'))
362 raise HTTPFound(h.route_path('home'))
349
363
350 affected_user_ids = [self._rhodecode_user.user_id]
364 affected_user_ids = [self._rhodecode_user.user_id]
351 if copy_permissions:
365 if copy_permissions:
352 user_group_perms = repo_group.permissions(expand_from_user_groups=True)
366 user_group_perms = repo_group.permissions(expand_from_user_groups=True)
353 copy_perms = [perm['user_id'] for perm in user_group_perms]
367 copy_perms = [perm['user_id'] for perm in user_group_perms]
354 # also include those newly created by copy
368 # also include those newly created by copy
355 affected_user_ids.extend(copy_perms)
369 affected_user_ids.extend(copy_perms)
356 PermissionModel().trigger_permission_flush(affected_user_ids)
370 PermissionModel().trigger_permission_flush(affected_user_ids)
357
371
358 raise HTTPFound(
372 raise HTTPFound(
359 h.route_path('repo_group_home',
373 h.route_path('repo_group_home',
360 repo_group_name=form_result['group_name_full']))
374 repo_group_name=form_result['group_name_full']))
@@ -1,266 +1,266 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2020 RhodeCode GmbH
3 # Copyright (C) 2016-2020 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 import formencode
22 import formencode
23 import formencode.htmlfill
23 import formencode.htmlfill
24
24
25 from pyramid.httpexceptions import HTTPFound, HTTPForbidden
25 from pyramid.httpexceptions import HTTPFound, HTTPForbidden
26 from pyramid.view import view_config
26 from pyramid.view import view_config
27 from pyramid.renderers import render
27 from pyramid.renderers import render
28 from pyramid.response import Response
28 from pyramid.response import Response
29
29
30 from rhodecode import events
30 from rhodecode import events
31 from rhodecode.apps._base import BaseAppView, DataGridAppView
31 from rhodecode.apps._base import BaseAppView, DataGridAppView
32 from rhodecode.lib.celerylib.utils import get_task_id
32 from rhodecode.lib.celerylib.utils import get_task_id
33
33
34 from rhodecode.lib.auth import (
34 from rhodecode.lib.auth import (
35 LoginRequired, CSRFRequired, NotAnonymous,
35 LoginRequired, CSRFRequired, NotAnonymous,
36 HasPermissionAny, HasRepoGroupPermissionAny)
36 HasPermissionAny, HasRepoGroupPermissionAny)
37 from rhodecode.lib import helpers as h
37 from rhodecode.lib import helpers as h
38 from rhodecode.lib.utils import repo_name_slug
38 from rhodecode.lib.utils import repo_name_slug
39 from rhodecode.lib.utils2 import safe_int, safe_unicode
39 from rhodecode.lib.utils2 import safe_int, safe_unicode
40 from rhodecode.model.forms import RepoForm
40 from rhodecode.model.forms import RepoForm
41 from rhodecode.model.permission import PermissionModel
41 from rhodecode.model.permission import PermissionModel
42 from rhodecode.model.repo import RepoModel
42 from rhodecode.model.repo import RepoModel
43 from rhodecode.model.scm import RepoList, RepoGroupList, ScmModel
43 from rhodecode.model.scm import RepoList, RepoGroupList, ScmModel
44 from rhodecode.model.settings import SettingsModel
44 from rhodecode.model.settings import SettingsModel
45 from rhodecode.model.db import (
45 from rhodecode.model.db import (
46 in_filter_generator, or_, func, Session, Repository, RepoGroup, User)
46 in_filter_generator, or_, func, Session, Repository, RepoGroup, User)
47
47
48 log = logging.getLogger(__name__)
48 log = logging.getLogger(__name__)
49
49
50
50
51 class AdminReposView(BaseAppView, DataGridAppView):
51 class AdminReposView(BaseAppView, DataGridAppView):
52
52
53 def load_default_context(self):
53 def load_default_context(self):
54 c = self._get_local_tmpl_context()
54 c = self._get_local_tmpl_context()
55
55
56 return c
56 return c
57
57
58 def _load_form_data(self, c):
58 def _load_form_data(self, c):
59 acl_groups = RepoGroupList(RepoGroup.query().all(),
59 acl_groups = RepoGroupList(RepoGroup.query().all(),
60 perm_set=['group.write', 'group.admin'])
60 perm_set=['group.write', 'group.admin'])
61 c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
61 c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
62 c.repo_groups_choices = map(lambda k: safe_unicode(k[0]), c.repo_groups)
62 c.repo_groups_choices = map(lambda k: safe_unicode(k[0]), c.repo_groups)
63 c.personal_repo_group = self._rhodecode_user.personal_repo_group
63 c.personal_repo_group = self._rhodecode_user.personal_repo_group
64
64
65 @LoginRequired()
65 @LoginRequired()
66 @NotAnonymous()
66 @NotAnonymous()
67 # perms check inside
67 # perms check inside
68 @view_config(
68 @view_config(
69 route_name='repos', request_method='GET',
69 route_name='repos', request_method='GET',
70 renderer='rhodecode:templates/admin/repos/repos.mako')
70 renderer='rhodecode:templates/admin/repos/repos.mako')
71 def repository_list(self):
71 def repository_list(self):
72 c = self.load_default_context()
72 c = self.load_default_context()
73 return self._get_template_context(c)
73 return self._get_template_context(c)
74
74
75 @LoginRequired()
75 @LoginRequired()
76 @NotAnonymous()
76 @NotAnonymous()
77 # perms check inside
77 # perms check inside
78 @view_config(
78 @view_config(
79 route_name='repos_data', request_method='GET',
79 route_name='repos_data', request_method='GET',
80 renderer='json_ext', xhr=True)
80 renderer='json_ext', xhr=True)
81 def repository_list_data(self):
81 def repository_list_data(self):
82 self.load_default_context()
82 self.load_default_context()
83 column_map = {
83 column_map = {
84 'name': 'repo_name',
84 'name': 'repo_name',
85 'desc': 'description',
85 'desc': 'description',
86 'last_change': 'updated_on',
86 'last_change': 'updated_on',
87 'owner': 'user_username',
87 'owner': 'user_username',
88 }
88 }
89 draw, start, limit = self._extract_chunk(self.request)
89 draw, start, limit = self._extract_chunk(self.request)
90 search_q, order_by, order_dir = self._extract_ordering(
90 search_q, order_by, order_dir = self._extract_ordering(
91 self.request, column_map=column_map)
91 self.request, column_map=column_map)
92
92
93 _perms = ['repository.admin']
93 _perms = ['repository.admin']
94 allowed_ids = [-1] + self._rhodecode_user.repo_acl_ids_from_stack(_perms)
94 allowed_ids = [-1] + self._rhodecode_user.repo_acl_ids_from_stack(_perms)
95
95
96 repos_data_total_count = Repository.query() \
96 repos_data_total_count = Repository.query() \
97 .filter(or_(
97 .filter(or_(
98 # generate multiple IN to fix limitation problems
98 # generate multiple IN to fix limitation problems
99 *in_filter_generator(Repository.repo_id, allowed_ids))
99 *in_filter_generator(Repository.repo_id, allowed_ids))
100 ) \
100 ) \
101 .count()
101 .count()
102
102
103 base_q = Session.query(
103 base_q = Session.query(
104 Repository.repo_id,
104 Repository.repo_id,
105 Repository.repo_name,
105 Repository.repo_name,
106 Repository.description,
106 Repository.description,
107 Repository.repo_type,
107 Repository.repo_type,
108 Repository.repo_state,
108 Repository.repo_state,
109 Repository.private,
109 Repository.private,
110 Repository.archived,
110 Repository.archived,
111 Repository.fork,
111 Repository.fork,
112 Repository.updated_on,
112 Repository.updated_on,
113 Repository._changeset_cache,
113 Repository._changeset_cache,
114 User,
114 User,
115 ) \
115 ) \
116 .filter(or_(
116 .filter(or_(
117 # generate multiple IN to fix limitation problems
117 # generate multiple IN to fix limitation problems
118 *in_filter_generator(Repository.repo_id, allowed_ids))
118 *in_filter_generator(Repository.repo_id, allowed_ids))
119 ) \
119 ) \
120 .join(User, User.user_id == Repository.user_id) \
120 .join(User, User.user_id == Repository.user_id) \
121 .group_by(Repository, User)
121 .group_by(Repository, User)
122
122
123 if search_q:
123 if search_q:
124 like_expression = u'%{}%'.format(safe_unicode(search_q))
124 like_expression = u'%{}%'.format(safe_unicode(search_q))
125 base_q = base_q.filter(or_(
125 base_q = base_q.filter(or_(
126 Repository.repo_name.ilike(like_expression),
126 Repository.repo_name.ilike(like_expression),
127 ))
127 ))
128
128
129 repos_data_total_filtered_count = base_q.count()
129 repos_data_total_filtered_count = base_q.count()
130
130
131 sort_defined = False
131 sort_defined = False
132 if order_by == 'repo_name':
132 if order_by == 'repo_name':
133 sort_col = func.lower(Repository.repo_name)
133 sort_col = func.lower(Repository.repo_name)
134 sort_defined = True
134 sort_defined = True
135 elif order_by == 'user_username':
135 elif order_by == 'user_username':
136 sort_col = User.username
136 sort_col = User.username
137 else:
137 else:
138 sort_col = getattr(Repository, order_by, None)
138 sort_col = getattr(Repository, order_by, None)
139
139
140 if sort_defined or sort_col:
140 if sort_defined or sort_col:
141 if order_dir == 'asc':
141 if order_dir == 'asc':
142 sort_col = sort_col.asc()
142 sort_col = sort_col.asc()
143 else:
143 else:
144 sort_col = sort_col.desc()
144 sort_col = sort_col.desc()
145
145
146 base_q = base_q.order_by(sort_col)
146 base_q = base_q.order_by(sort_col)
147 base_q = base_q.offset(start).limit(limit)
147 base_q = base_q.offset(start).limit(limit)
148
148
149 repos_list = base_q.all()
149 repos_list = base_q.all()
150
150
151 repos_data = RepoModel().get_repos_as_dict(
151 repos_data = RepoModel().get_repos_as_dict(
152 repo_list=repos_list, admin=True, super_user_actions=True)
152 repo_list=repos_list, admin=True, super_user_actions=True)
153
153
154 data = ({
154 data = ({
155 'draw': draw,
155 'draw': draw,
156 'data': repos_data,
156 'data': repos_data,
157 'recordsTotal': repos_data_total_count,
157 'recordsTotal': repos_data_total_count,
158 'recordsFiltered': repos_data_total_filtered_count,
158 'recordsFiltered': repos_data_total_filtered_count,
159 })
159 })
160 return data
160 return data
161
161
162 @LoginRequired()
162 @LoginRequired()
163 @NotAnonymous()
163 @NotAnonymous()
164 # perms check inside
164 # perms check inside
165 @view_config(
165 @view_config(
166 route_name='repo_new', request_method='GET',
166 route_name='repo_new', request_method='GET',
167 renderer='rhodecode:templates/admin/repos/repo_add.mako')
167 renderer='rhodecode:templates/admin/repos/repo_add.mako')
168 def repository_new(self):
168 def repository_new(self):
169 c = self.load_default_context()
169 c = self.load_default_context()
170
170
171 new_repo = self.request.GET.get('repo', '')
171 new_repo = self.request.GET.get('repo', '')
172 parent_group = safe_int(self.request.GET.get('parent_group'))
172 parent_group_id = safe_int(self.request.GET.get('parent_group'))
173 _gr = RepoGroup.get(parent_group)
173 _gr = RepoGroup.get(parent_group_id)
174
174
175 if not HasPermissionAny('hg.admin', 'hg.create.repository')():
175 if not HasPermissionAny('hg.admin', 'hg.create.repository')():
176 # you're not super admin nor have global create permissions,
176 # you're not super admin nor have global create permissions,
177 # but maybe you have at least write permission to a parent group ?
177 # but maybe you have at least write permission to a parent group ?
178
178
179 gr_name = _gr.group_name if _gr else None
179 gr_name = _gr.group_name if _gr else None
180 # create repositories with write permission on group is set to true
180 # create repositories with write permission on group is set to true
181 create_on_write = HasPermissionAny('hg.create.write_on_repogroup.true')()
181 create_on_write = HasPermissionAny('hg.create.write_on_repogroup.true')()
182 group_admin = HasRepoGroupPermissionAny('group.admin')(group_name=gr_name)
182 group_admin = HasRepoGroupPermissionAny('group.admin')(group_name=gr_name)
183 group_write = HasRepoGroupPermissionAny('group.write')(group_name=gr_name)
183 group_write = HasRepoGroupPermissionAny('group.write')(group_name=gr_name)
184 if not (group_admin or (group_write and create_on_write)):
184 if not (group_admin or (group_write and create_on_write)):
185 raise HTTPForbidden()
185 raise HTTPForbidden()
186
186
187 self._load_form_data(c)
187 self._load_form_data(c)
188 c.new_repo = repo_name_slug(new_repo)
188 c.new_repo = repo_name_slug(new_repo)
189
189
190 # apply the defaults from defaults page
190 # apply the defaults from defaults page
191 defaults = SettingsModel().get_default_repo_settings(strip_prefix=True)
191 defaults = SettingsModel().get_default_repo_settings(strip_prefix=True)
192 # set checkbox to autochecked
192 # set checkbox to autochecked
193 defaults['repo_copy_permissions'] = True
193 defaults['repo_copy_permissions'] = True
194
194
195 parent_group_choice = '-1'
195 parent_group_choice = '-1'
196 if not self._rhodecode_user.is_admin and self._rhodecode_user.personal_repo_group:
196 if not self._rhodecode_user.is_admin and self._rhodecode_user.personal_repo_group:
197 parent_group_choice = self._rhodecode_user.personal_repo_group
197 parent_group_choice = self._rhodecode_user.personal_repo_group
198
198
199 if parent_group and _gr:
199 if parent_group_id and _gr:
200 if parent_group in [x[0] for x in c.repo_groups]:
200 if parent_group_id in [x[0] for x in c.repo_groups]:
201 parent_group_choice = safe_unicode(parent_group)
201 parent_group_choice = safe_unicode(parent_group_id)
202
202
203 defaults.update({'repo_group': parent_group_choice})
203 defaults.update({'repo_group': parent_group_choice})
204
204
205 data = render('rhodecode:templates/admin/repos/repo_add.mako',
205 data = render('rhodecode:templates/admin/repos/repo_add.mako',
206 self._get_template_context(c), self.request)
206 self._get_template_context(c), self.request)
207 html = formencode.htmlfill.render(
207 html = formencode.htmlfill.render(
208 data,
208 data,
209 defaults=defaults,
209 defaults=defaults,
210 encoding="UTF-8",
210 encoding="UTF-8",
211 force_defaults=False
211 force_defaults=False
212 )
212 )
213 return Response(html)
213 return Response(html)
214
214
215 @LoginRequired()
215 @LoginRequired()
216 @NotAnonymous()
216 @NotAnonymous()
217 @CSRFRequired()
217 @CSRFRequired()
218 # perms check inside
218 # perms check inside
219 @view_config(
219 @view_config(
220 route_name='repo_create', request_method='POST',
220 route_name='repo_create', request_method='POST',
221 renderer='rhodecode:templates/admin/repos/repos.mako')
221 renderer='rhodecode:templates/admin/repos/repos.mako')
222 def repository_create(self):
222 def repository_create(self):
223 c = self.load_default_context()
223 c = self.load_default_context()
224
224
225 form_result = {}
225 form_result = {}
226 self._load_form_data(c)
226 self._load_form_data(c)
227
227
228 try:
228 try:
229 # CanWriteToGroup validators checks permissions of this POST
229 # CanWriteToGroup validators checks permissions of this POST
230 form = RepoForm(
230 form = RepoForm(
231 self.request.translate, repo_groups=c.repo_groups_choices)()
231 self.request.translate, repo_groups=c.repo_groups_choices)()
232 form_result = form.to_python(dict(self.request.POST))
232 form_result = form.to_python(dict(self.request.POST))
233 copy_permissions = form_result.get('repo_copy_permissions')
233 copy_permissions = form_result.get('repo_copy_permissions')
234 # create is done sometimes async on celery, db transaction
234 # create is done sometimes async on celery, db transaction
235 # management is handled there.
235 # management is handled there.
236 task = RepoModel().create(form_result, self._rhodecode_user.user_id)
236 task = RepoModel().create(form_result, self._rhodecode_user.user_id)
237 task_id = get_task_id(task)
237 task_id = get_task_id(task)
238 except formencode.Invalid as errors:
238 except formencode.Invalid as errors:
239 data = render('rhodecode:templates/admin/repos/repo_add.mako',
239 data = render('rhodecode:templates/admin/repos/repo_add.mako',
240 self._get_template_context(c), self.request)
240 self._get_template_context(c), self.request)
241 html = formencode.htmlfill.render(
241 html = formencode.htmlfill.render(
242 data,
242 data,
243 defaults=errors.value,
243 defaults=errors.value,
244 errors=errors.error_dict or {},
244 errors=errors.error_dict or {},
245 prefix_error=False,
245 prefix_error=False,
246 encoding="UTF-8",
246 encoding="UTF-8",
247 force_defaults=False
247 force_defaults=False
248 )
248 )
249 return Response(html)
249 return Response(html)
250
250
251 except Exception as e:
251 except Exception as e:
252 msg = self._log_creation_exception(e, form_result.get('repo_name'))
252 msg = self._log_creation_exception(e, form_result.get('repo_name'))
253 h.flash(msg, category='error')
253 h.flash(msg, category='error')
254 raise HTTPFound(h.route_path('home'))
254 raise HTTPFound(h.route_path('home'))
255
255
256 repo_name = form_result.get('repo_name_full')
256 repo_name = form_result.get('repo_name_full')
257
257
258 affected_user_ids = [self._rhodecode_user.user_id]
258 affected_user_ids = [self._rhodecode_user.user_id]
259 if copy_permissions:
259 if copy_permissions:
260 # permission flush is done in repo creating
260 # permission flush is done in repo creating
261 pass
261 pass
262 PermissionModel().trigger_permission_flush(affected_user_ids)
262 PermissionModel().trigger_permission_flush(affected_user_ids)
263
263
264 raise HTTPFound(
264 raise HTTPFound(
265 h.route_path('repo_creating', repo_name=repo_name,
265 h.route_path('repo_creating', repo_name=repo_name,
266 _query=dict(task_id=task_id)))
266 _query=dict(task_id=task_id)))
@@ -1,111 +1,122 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.mako"/>
2 <%inherit file="/base/base.mako"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${_('Add repository group')}
5 ${_('Add repository group')}
6 %if c.rhodecode_name:
6 %if c.rhodecode_name:
7 &middot; ${h.branding(c.rhodecode_name)}
7 &middot; ${h.branding(c.rhodecode_name)}
8 %endif
8 %endif
9 </%def>
9 </%def>
10
10
11 <%def name="breadcrumbs_links()">
11 <%def name="breadcrumbs_links()">
12 ${h.link_to(_('Admin'),h.route_path('admin_home'))}
12 ${h.link_to(_('Admin'),h.route_path('admin_home'))}
13 &raquo;
13 &raquo;
14 ${h.link_to(_('Repository groups'),h.route_path('repo_groups'))}
14 ${h.link_to(_('Repository groups'),h.route_path('repo_groups'))}
15 &raquo;
15 &raquo;
16 ${_('Add Repository Group')}
16 ${_('Add Repository Group')}
17 </%def>
17 </%def>
18
18
19 <%def name="menu_bar_nav()">
19 <%def name="menu_bar_nav()">
20 ${self.menu_items(active='admin')}
20 ${self.menu_items(active='admin')}
21 </%def>
21 </%def>
22
22
23 <%def name="menu_bar_subnav()">
23 <%def name="menu_bar_subnav()">
24 ${self.admin_menu(active='repository_groups')}
24 ${self.admin_menu(active='repository_groups')}
25 </%def>
25 </%def>
26
26
27 <%def name="main()">
27 <%def name="main()">
28 <div class="box">
28 <div class="box">
29 ${h.secure_form(h.route_path('repo_group_create'), request=request)}
29 ${h.secure_form(h.route_path('repo_group_create'), request=request)}
30 <div class="form">
30 <div class="form">
31 <!-- fields -->
31 <!-- fields -->
32 <div class="fields">
32 <div class="fields">
33 <div class="field">
33 <div class="field">
34 <div class="label">
34 <div class="label">
35 <label for="group_name">${_('Group name')}:</label>
35 <label for="group_name">${_('Group name')}:</label>
36 </div>
36 </div>
37 <div class="input">
37 <div class="input">
38 ${h.text('group_name', class_="medium")}
38 ${h.text('group_name', class_="medium")}
39 </div>
39 </div>
40 </div>
40 </div>
41
41
42 <div class="field">
42 <div class="field">
43 <div class="label">
43 <div class="label">
44 <label for="group_parent_id">${_('Repository group')}:</label>
44 <label for="group_parent_id">${_('Repository group')}:</label>
45 </div>
45 </div>
46 <div class="select">
46 <div class="select">
47 ${h.select('group_parent_id',request.GET.get('parent_group'),c.repo_groups,class_="medium")}
47 ${h.select('group_parent_id', request.GET.get('parent_group'),c.repo_groups,class_="medium")}
48 % if c.personal_repo_group:
49 <a class="btn" href="#" id="select_my_group" data-personal-group-id="${c.personal_repo_group.group_id}">
50 ${_('Select my personal group ({})').format(c.personal_repo_group.group_name)}
51 </a>
52 % endif
48 </div>
53 </div>
49 </div>
54 </div>
50
55
51 <div class="field">
56 <div class="field">
52 <div class="label">
57 <div class="label">
53 <label for="group_description">${_('Description')}:</label>
58 <label for="group_description">${_('Description')}:</label>
54 </div>
59 </div>
55 <div class="textarea editor">
60 <div class="textarea editor">
56 ${h.textarea('group_description',cols=23,rows=5,class_="medium")}
61 ${h.textarea('group_description',cols=23,rows=5,class_="medium")}
57 <% metatags_url = h.literal('''<a href="#metatagsShow" onclick="$('#meta-tags-desc').toggle();return false">meta-tags</a>''') %>
62 <% metatags_url = h.literal('''<a href="#metatagsShow" onclick="$('#meta-tags-desc').toggle();return false">meta-tags</a>''') %>
58 <span class="help-block">
63 <span class="help-block">
59 % if c.visual.stylify_metatags:
64 % if c.visual.stylify_metatags:
60 ${_('Plain text format with {metatags} support.').format(metatags=metatags_url)|n}
65 ${_('Plain text format with {metatags} support.').format(metatags=metatags_url)|n}
61 % else:
66 % else:
62 ${_('Plain text format.')}
67 ${_('Plain text format.')}
63 % endif
68 % endif
64 </span>
69 </span>
65 <span id="meta-tags-desc" style="display: none">
70 <span id="meta-tags-desc" style="display: none">
66 <%namespace name="dt" file="/data_table/_dt_elements.mako"/>
71 <%namespace name="dt" file="/data_table/_dt_elements.mako"/>
67 ${dt.metatags_help()}
72 ${dt.metatags_help()}
68 </span>
73 </span>
69 </div>
74 </div>
70 </div>
75 </div>
71
76
72 <div id="copy_perms" class="field">
77 <div id="copy_perms" class="field">
73 <div class="label label-checkbox">
78 <div class="label label-checkbox">
74 <label for="group_copy_permissions">${_('Copy Parent Group Permissions')}:</label>
79 <label for="group_copy_permissions">${_('Copy Parent Group Permissions')}:</label>
75 </div>
80 </div>
76 <div class="checkboxes">
81 <div class="checkboxes">
77 ${h.checkbox('group_copy_permissions', value="True", checked="checked")}
82 ${h.checkbox('group_copy_permissions', value="True", checked="checked")}
78 <span class="help-block">${_('Copy permissions from parent repository group.')}</span>
83 <span class="help-block">${_('Copy permissions from parent repository group.')}</span>
79 </div>
84 </div>
80 </div>
85 </div>
81
86
82 <div class="buttons">
87 <div class="buttons">
83 ${h.submit('save',_('Create Repository Group'),class_="btn")}
88 ${h.submit('save',_('Create Repository Group'),class_="btn")}
84 </div>
89 </div>
85 </div>
90 </div>
86 </div>
91 </div>
87 ${h.end_form()}
92 ${h.end_form()}
88 </div>
93 </div>
89 <script>
94 <script>
90 $(document).ready(function(){
95 $(document).ready(function(){
91 var setCopyPermsOption = function(group_val){
96 var setCopyPermsOption = function(group_val){
92 if(group_val !== "-1"){
97 if(group_val !== "-1"){
93 $('#copy_perms').show()
98 $('#copy_perms').show()
94 }
99 }
95 else{
100 else{
96 $('#copy_perms').hide();
101 $('#copy_perms').hide();
97 }
102 }
98 };
103 };
99 $("#group_parent_id").select2({
104 $("#group_parent_id").select2({
100 'containerCssClass': "drop-menu",
105 'containerCssClass': "drop-menu",
101 'dropdownCssClass': "drop-menu-dropdown",
106 'dropdownCssClass': "drop-menu-dropdown",
102 'dropdownAutoWidth': true
107 'dropdownAutoWidth': true
103 });
108 });
104 setCopyPermsOption($('#group_parent_id').val());
109 setCopyPermsOption($('#group_parent_id').val());
105 $("#group_parent_id").on("change", function(e) {
110 $("#group_parent_id").on("change", function(e) {
106 setCopyPermsOption(e.val)
111 setCopyPermsOption(e.val)
107 });
112 });
108 $('#group_name').focus();
113 $('#group_name').focus();
114
115 $('#select_my_group').on('click', function(e){
116 e.preventDefault();
117 $("#group_parent_id").val($(this).data('personalGroupId')).trigger("change");
118 })
119
109 })
120 })
110 </script>
121 </script>
111 </%def>
122 </%def>
@@ -1,169 +1,169 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2
2
3 ${h.secure_form(h.route_path('repo_create'), request=request)}
3 ${h.secure_form(h.route_path('repo_create'), request=request)}
4 <div class="form">
4 <div class="form">
5 <!-- fields -->
5 <!-- fields -->
6 <div class="fields">
6 <div class="fields">
7 <div class="field">
7 <div class="field">
8 <div class="label">
8 <div class="label">
9 <label for="repo_name">${_('Repository name')}:</label>
9 <label for="repo_name">${_('Repository name')}:</label>
10 </div>
10 </div>
11 <div class="input">
11 <div class="input">
12 ${h.text('repo_name', class_="medium")}
12 ${h.text('repo_name', class_="medium")}
13 <div class="info-block">
13 <div class="info-block">
14 <a id="remote_clone_toggle" href="#">${_('Import Existing Repository ?')}</a>
14 <a id="remote_clone_toggle" href="#">${_('Import Existing Repository ?')}</a>
15 </div>
15 </div>
16 %if not c.rhodecode_user.is_admin:
16 %if not c.rhodecode_user.is_admin:
17 ${h.hidden('user_created',True)}
17 ${h.hidden('user_created',True)}
18 %endif
18 %endif
19 </div>
19 </div>
20 </div>
20 </div>
21 <div id="remote_clone" class="field" style="display: none;">
21 <div id="remote_clone" class="field" style="display: none;">
22 <div class="label">
22 <div class="label">
23 <label for="clone_uri">${_('Clone from')}:</label>
23 <label for="clone_uri">${_('Clone from')}:</label>
24 </div>
24 </div>
25 <div class="input">
25 <div class="input">
26 ${h.text('clone_uri', class_="medium")}
26 ${h.text('clone_uri', class_="medium")}
27 <span class="help-block">
27 <span class="help-block">
28 <pre>
28 <pre>
29 - The repository must be accessible over http:// or https://
29 - The repository must be accessible over http:// or https://
30 - For Git projects it's recommended appending .git to the end of clone url.
30 - For Git projects it's recommended appending .git to the end of clone url.
31 - Make sure to select proper repository type from the below selector before importing it.
31 - Make sure to select proper repository type from the below selector before importing it.
32 - If your HTTP[S] repository is not publicly accessible,
32 - If your HTTP[S] repository is not publicly accessible,
33 add authentication information to the URL: https://username:password@server.company.com/repo-name.
33 add authentication information to the URL: https://username:password@server.company.com/repo-name.
34 - The Git LFS/Mercurial Largefiles objects will not be imported.
34 - The Git LFS/Mercurial Largefiles objects will not be imported.
35 - For very large repositories, it's recommended to manually copy them into the
35 - For very large repositories, it's recommended to manually copy them into the
36 RhodeCode <a href="${h.route_path('admin_settings_vcs', _anchor='vcs-storage-options')}">storage location</a> and run <a href="${h.route_path('admin_settings_mapping')}">Remap and Rescan</a>.
36 RhodeCode <a href="${h.route_path('admin_settings_vcs', _anchor='vcs-storage-options')}">storage location</a> and run <a href="${h.route_path('admin_settings_mapping')}">Remap and Rescan</a>.
37 </pre>
37 </pre>
38 </span>
38 </span>
39 </div>
39 </div>
40 </div>
40 </div>
41 <div class="field">
41 <div class="field">
42 <div class="label">
42 <div class="label">
43 <label for="repo_group">${_('Repository group')}:</label>
43 <label for="repo_group">${_('Repository group')}:</label>
44 </div>
44 </div>
45 <div class="select">
45 <div class="select">
46 ${h.select('repo_group',request.GET.get('parent_group'),c.repo_groups,class_="medium")}
46 ${h.select('repo_group',request.GET.get('parent_group'),c.repo_groups,class_="medium")}
47 % if c.personal_repo_group:
47 % if c.personal_repo_group:
48 <a class="btn" href="#" id="select_my_group" data-personal-group-id="${c.personal_repo_group.group_id}">
48 <a class="btn" href="#" id="select_my_group" data-personal-group-id="${c.personal_repo_group.group_id}">
49 ${_('Select my personal group (%(repo_group_name)s)') % {'repo_group_name': c.personal_repo_group.group_name}}
49 ${_('Select my personal group ({})').format(c.personal_repo_group.group_name)}
50 </a>
50 </a>
51 % endif
51 % endif
52 <span class="help-block">${_('Optionally select a group to put this repository into.')}</span>
52 <span class="help-block">${_('Optionally select a group to put this repository into.')}</span>
53 </div>
53 </div>
54 </div>
54 </div>
55
55
56 <div class="field">
56 <div class="field">
57 <div class="label">
57 <div class="label">
58 <label for="repo_type">${_('Type')}:</label>
58 <label for="repo_type">${_('Type')}:</label>
59 </div>
59 </div>
60 <div class="fields repo-type-radio">
60 <div class="fields repo-type-radio">
61
61
62
62
63 % for backend in c.backends:
63 % for backend in c.backends:
64 % if loop.index == 0:
64 % if loop.index == 0:
65 <input id="repo_type_${backend}" name="repo_type" type="radio" value="${backend}" checked="checked"/>
65 <input id="repo_type_${backend}" name="repo_type" type="radio" value="${backend}" checked="checked"/>
66 % else:
66 % else:
67 <input id="repo_type_${backend}" name="repo_type" type="radio" value="${backend}" />
67 <input id="repo_type_${backend}" name="repo_type" type="radio" value="${backend}" />
68 % endif
68 % endif
69
69
70 <label for="repo_type_${backend}">
70 <label for="repo_type_${backend}">
71 <i class="icon-${backend}" style="font-size: 16px"></i>
71 <i class="icon-${backend}" style="font-size: 16px"></i>
72 ${backend.upper()}
72 ${backend.upper()}
73 </label>
73 </label>
74
74
75 % endfor
75 % endfor
76
76
77
77
78 <span class="help-block">${_('Set the type of repository to create.')}</span>
78 <span class="help-block">${_('Set the type of repository to create.')}</span>
79 </div>
79 </div>
80 </div>
80 </div>
81 <div class="field">
81 <div class="field">
82 <div class="label">
82 <div class="label">
83 <label for="repo_description">${_('Description')}:</label>
83 <label for="repo_description">${_('Description')}:</label>
84 </div>
84 </div>
85 <div class="textarea editor">
85 <div class="textarea editor">
86 ${h.textarea('repo_description',cols=23,rows=5,class_="medium")}
86 ${h.textarea('repo_description',cols=23,rows=5,class_="medium")}
87 <% metatags_url = h.literal('''<a href="#metatagsShow" onclick="$('#meta-tags-desc').toggle();return false">meta-tags</a>''') %>
87 <% metatags_url = h.literal('''<a href="#metatagsShow" onclick="$('#meta-tags-desc').toggle();return false">meta-tags</a>''') %>
88 <span class="help-block">
88 <span class="help-block">
89 % if c.visual.stylify_metatags:
89 % if c.visual.stylify_metatags:
90 ${_('Plain text format with {metatags} support.').format(metatags=metatags_url)|n}
90 ${_('Plain text format with {metatags} support.').format(metatags=metatags_url)|n}
91 % else:
91 % else:
92 ${_('Plain text format.')}
92 ${_('Plain text format.')}
93 % endif
93 % endif
94 ${_('Add a README file for longer descriptions')}
94 ${_('Add a README file for longer descriptions')}
95 </span>
95 </span>
96 <span id="meta-tags-desc" style="display: none">
96 <span id="meta-tags-desc" style="display: none">
97 <%namespace name="dt" file="/data_table/_dt_elements.mako"/>
97 <%namespace name="dt" file="/data_table/_dt_elements.mako"/>
98 ${dt.metatags_help()}
98 ${dt.metatags_help()}
99 </span>
99 </span>
100 </div>
100 </div>
101 </div>
101 </div>
102 <div id="copy_perms" class="field">
102 <div id="copy_perms" class="field">
103 <div class="label label-checkbox">
103 <div class="label label-checkbox">
104 <label for="repo_copy_permissions">${_('Copy Parent Group Permissions')}:</label>
104 <label for="repo_copy_permissions">${_('Copy Parent Group Permissions')}:</label>
105 </div>
105 </div>
106 <div class="checkboxes">
106 <div class="checkboxes">
107 ${h.checkbox('repo_copy_permissions', value="True", checked="checked")}
107 ${h.checkbox('repo_copy_permissions', value="True", checked="checked")}
108 <span class="help-block">${_('Copy permissions from parent repository group.')}</span>
108 <span class="help-block">${_('Copy permissions from parent repository group.')}</span>
109 </div>
109 </div>
110 </div>
110 </div>
111 <div class="field">
111 <div class="field">
112 <div class="label label-checkbox">
112 <div class="label label-checkbox">
113 <label for="repo_private">${_('Private Repository')}:</label>
113 <label for="repo_private">${_('Private Repository')}:</label>
114 </div>
114 </div>
115 <div class="checkboxes">
115 <div class="checkboxes">
116 ${h.checkbox('repo_private',value="True")}
116 ${h.checkbox('repo_private',value="True")}
117 <span class="help-block">${_('Private repositories are only visible to people explicitly added as collaborators.')}</span>
117 <span class="help-block">${_('Private repositories are only visible to people explicitly added as collaborators.')}</span>
118 </div>
118 </div>
119 </div>
119 </div>
120 <div class="buttons">
120 <div class="buttons">
121 ${h.submit('save',_('Create Repository'),class_="btn")}
121 ${h.submit('save',_('Create Repository'),class_="btn")}
122 </div>
122 </div>
123 </div>
123 </div>
124 </div>
124 </div>
125 <script>
125 <script>
126 $(document).ready(function(){
126 $(document).ready(function(){
127 var setCopyPermsOption = function(group_val){
127 var setCopyPermsOption = function(group_val){
128 if(group_val != "-1"){
128 if(group_val != "-1"){
129 $('#copy_perms').show()
129 $('#copy_perms').show()
130 }
130 }
131 else{
131 else{
132 $('#copy_perms').hide();
132 $('#copy_perms').hide();
133 }
133 }
134 };
134 };
135
135
136 $('#remote_clone_toggle').on('click', function(e){
136 $('#remote_clone_toggle').on('click', function(e){
137 $('#remote_clone').show();
137 $('#remote_clone').show();
138 e.preventDefault();
138 e.preventDefault();
139 });
139 });
140
140
141 if($('#remote_clone input').hasClass('error')){
141 if($('#remote_clone input').hasClass('error')){
142 $('#remote_clone').show();
142 $('#remote_clone').show();
143 }
143 }
144 if($('#remote_clone input').val()){
144 if($('#remote_clone input').val()){
145 $('#remote_clone').show();
145 $('#remote_clone').show();
146 }
146 }
147
147
148 $("#repo_group").select2({
148 $("#repo_group").select2({
149 'containerCssClass': "drop-menu",
149 'containerCssClass': "drop-menu",
150 'dropdownCssClass': "drop-menu-dropdown",
150 'dropdownCssClass': "drop-menu-dropdown",
151 'dropdownAutoWidth': true,
151 'dropdownAutoWidth': true,
152 'width': "resolve"
152 'width': "resolve"
153 });
153 });
154
154
155 setCopyPermsOption($('#repo_group').val());
155 setCopyPermsOption($('#repo_group').val());
156 $("#repo_group").on("change", function(e) {
156 $("#repo_group").on("change", function(e) {
157 setCopyPermsOption(e.val)
157 setCopyPermsOption(e.val)
158 });
158 });
159
159
160 $('#repo_name').focus();
160 $('#repo_name').focus();
161
161
162 $('#select_my_group').on('click', function(e){
162 $('#select_my_group').on('click', function(e){
163 e.preventDefault();
163 e.preventDefault();
164 $("#repo_group").val($(this).data('personalGroupId')).trigger("change");
164 $("#repo_group").val($(this).data('personalGroupId')).trigger("change");
165 })
165 })
166
166
167 })
167 })
168 </script>
168 </script>
169 ${h.end_form()}
169 ${h.end_form()}
General Comments 0
You need to be logged in to leave comments. Login now