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