##// END OF EJS Templates
permissions: show user group count in permissions summary, and unified some text labels.
marcink -
r3385:5a371ab1 default
parent child Browse files
Show More
@@ -1,1072 +1,1069 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2019 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 os
22 22 import re
23 23 import shutil
24 24 import time
25 25 import logging
26 26 import traceback
27 27 import datetime
28 28
29 29 from pyramid.threadlocal import get_current_request
30 30 from zope.cachedescriptors.property import Lazy as LazyProperty
31 31
32 32 from rhodecode import events
33 33 from rhodecode.lib.auth import HasUserGroupPermissionAny
34 34 from rhodecode.lib.caching_query import FromCache
35 35 from rhodecode.lib.exceptions import AttachedForksError, AttachedPullRequestsError
36 36 from rhodecode.lib.hooks_base import log_delete_repository
37 37 from rhodecode.lib.user_log_filter import user_log_filter
38 38 from rhodecode.lib.utils import make_db_config
39 39 from rhodecode.lib.utils2 import (
40 40 safe_str, safe_unicode, remove_prefix, obfuscate_url_pw,
41 41 get_current_rhodecode_user, safe_int, datetime_to_time,
42 42 action_logger_generic)
43 43 from rhodecode.lib.vcs.backends import get_backend
44 44 from rhodecode.model import BaseModel
45 45 from rhodecode.model.db import (
46 46 _hash_key, joinedload, or_, Repository, UserRepoToPerm, UserGroupRepoToPerm,
47 47 UserRepoGroupToPerm, UserGroupRepoGroupToPerm, User, Permission,
48 48 Statistics, UserGroup, RepoGroup, RepositoryField, UserLog)
49 49
50 50 from rhodecode.model.settings import VcsSettingsModel
51 51
52 52
53 53 log = logging.getLogger(__name__)
54 54
55 55
56 56 class RepoModel(BaseModel):
57 57
58 58 cls = Repository
59 59
60 60 def _get_user_group(self, users_group):
61 61 return self._get_instance(UserGroup, users_group,
62 62 callback=UserGroup.get_by_group_name)
63 63
64 64 def _get_repo_group(self, repo_group):
65 65 return self._get_instance(RepoGroup, repo_group,
66 66 callback=RepoGroup.get_by_group_name)
67 67
68 68 def _create_default_perms(self, repository, private):
69 69 # create default permission
70 70 default = 'repository.read'
71 71 def_user = User.get_default_user()
72 72 for p in def_user.user_perms:
73 73 if p.permission.permission_name.startswith('repository.'):
74 74 default = p.permission.permission_name
75 75 break
76 76
77 77 default_perm = 'repository.none' if private else default
78 78
79 79 repo_to_perm = UserRepoToPerm()
80 80 repo_to_perm.permission = Permission.get_by_key(default_perm)
81 81
82 82 repo_to_perm.repository = repository
83 83 repo_to_perm.user_id = def_user.user_id
84 84
85 85 return repo_to_perm
86 86
87 87 @LazyProperty
88 88 def repos_path(self):
89 89 """
90 90 Gets the repositories root path from database
91 91 """
92 92 settings_model = VcsSettingsModel(sa=self.sa)
93 93 return settings_model.get_repos_location()
94 94
95 95 def get(self, repo_id):
96 96 repo = self.sa.query(Repository) \
97 97 .filter(Repository.repo_id == repo_id)
98 98
99 99 return repo.scalar()
100 100
101 101 def get_repo(self, repository):
102 102 return self._get_repo(repository)
103 103
104 104 def get_by_repo_name(self, repo_name, cache=False):
105 105 repo = self.sa.query(Repository) \
106 106 .filter(Repository.repo_name == repo_name)
107 107
108 108 if cache:
109 109 name_key = _hash_key(repo_name)
110 110 repo = repo.options(
111 111 FromCache("sql_cache_short", "get_repo_%s" % name_key))
112 112 return repo.scalar()
113 113
114 114 def _extract_id_from_repo_name(self, repo_name):
115 115 if repo_name.startswith('/'):
116 116 repo_name = repo_name.lstrip('/')
117 117 by_id_match = re.match(r'^_(\d{1,})', repo_name)
118 118 if by_id_match:
119 119 return by_id_match.groups()[0]
120 120
121 121 def get_repo_by_id(self, repo_name):
122 122 """
123 123 Extracts repo_name by id from special urls.
124 124 Example url is _11/repo_name
125 125
126 126 :param repo_name:
127 127 :return: repo object if matched else None
128 128 """
129 129
130 130 try:
131 131 _repo_id = self._extract_id_from_repo_name(repo_name)
132 132 if _repo_id:
133 133 return self.get(_repo_id)
134 134 except Exception:
135 135 log.exception('Failed to extract repo_name from URL')
136 136
137 137 return None
138 138
139 139 def get_repos_for_root(self, root, traverse=False):
140 140 if traverse:
141 141 like_expression = u'{}%'.format(safe_unicode(root))
142 142 repos = Repository.query().filter(
143 143 Repository.repo_name.like(like_expression)).all()
144 144 else:
145 145 if root and not isinstance(root, RepoGroup):
146 146 raise ValueError(
147 147 'Root must be an instance '
148 148 'of RepoGroup, got:{} instead'.format(type(root)))
149 149 repos = Repository.query().filter(Repository.group == root).all()
150 150 return repos
151 151
152 152 def get_url(self, repo, request=None, permalink=False):
153 153 if not request:
154 154 request = get_current_request()
155 155
156 156 if not request:
157 157 return
158 158
159 159 if permalink:
160 160 return request.route_url(
161 161 'repo_summary', repo_name='_{}'.format(safe_str(repo.repo_id)))
162 162 else:
163 163 return request.route_url(
164 164 'repo_summary', repo_name=safe_str(repo.repo_name))
165 165
166 166 def get_commit_url(self, repo, commit_id, request=None, permalink=False):
167 167 if not request:
168 168 request = get_current_request()
169 169
170 170 if not request:
171 171 return
172 172
173 173 if permalink:
174 174 return request.route_url(
175 175 'repo_commit', repo_name=safe_str(repo.repo_id),
176 176 commit_id=commit_id)
177 177
178 178 else:
179 179 return request.route_url(
180 180 'repo_commit', repo_name=safe_str(repo.repo_name),
181 181 commit_id=commit_id)
182 182
183 183 def get_repo_log(self, repo, filter_term):
184 184 repo_log = UserLog.query()\
185 185 .filter(or_(UserLog.repository_id == repo.repo_id,
186 186 UserLog.repository_name == repo.repo_name))\
187 187 .options(joinedload(UserLog.user))\
188 188 .options(joinedload(UserLog.repository))\
189 189 .order_by(UserLog.action_date.desc())
190 190
191 191 repo_log = user_log_filter(repo_log, filter_term)
192 192 return repo_log
193 193
194 194 @classmethod
195 195 def update_repoinfo(cls, repositories=None):
196 196 if not repositories:
197 197 repositories = Repository.getAll()
198 198 for repo in repositories:
199 199 repo.update_commit_cache()
200 200
201 201 def get_repos_as_dict(self, repo_list=None, admin=False,
202 202 super_user_actions=False):
203 203 _render = get_current_request().get_partial_renderer(
204 204 'rhodecode:templates/data_table/_dt_elements.mako')
205 205 c = _render.get_call_context()
206 206
207 207 def quick_menu(repo_name):
208 208 return _render('quick_menu', repo_name)
209 209
210 210 def repo_lnk(name, rtype, rstate, private, archived, fork_of):
211 211 return _render('repo_name', name, rtype, rstate, private, archived, fork_of,
212 212 short_name=not admin, admin=False)
213 213
214 214 def last_change(last_change):
215 215 if admin and isinstance(last_change, datetime.datetime) and not last_change.tzinfo:
216 216 last_change = last_change + datetime.timedelta(seconds=
217 217 (datetime.datetime.now() - datetime.datetime.utcnow()).seconds)
218 218 return _render("last_change", last_change)
219 219
220 220 def rss_lnk(repo_name):
221 221 return _render("rss", repo_name)
222 222
223 223 def atom_lnk(repo_name):
224 224 return _render("atom", repo_name)
225 225
226 226 def last_rev(repo_name, cs_cache):
227 227 return _render('revision', repo_name, cs_cache.get('revision'),
228 228 cs_cache.get('raw_id'), cs_cache.get('author'),
229 229 cs_cache.get('message'), cs_cache.get('date'))
230 230
231 231 def desc(desc):
232 232 return _render('repo_desc', desc, c.visual.stylify_metatags)
233 233
234 234 def state(repo_state):
235 235 return _render("repo_state", repo_state)
236 236
237 237 def repo_actions(repo_name):
238 238 return _render('repo_actions', repo_name, super_user_actions)
239 239
240 240 def user_profile(username):
241 241 return _render('user_profile', username)
242 242
243 243 repos_data = []
244 244 for repo in repo_list:
245 245 cs_cache = repo.changeset_cache
246 246 row = {
247 247 "menu": quick_menu(repo.repo_name),
248 248
249 249 "name": repo_lnk(repo.repo_name, repo.repo_type, repo.repo_state,
250 250 repo.private, repo.archived, repo.fork),
251 251 "name_raw": repo.repo_name.lower(),
252 252
253 253 "last_change": last_change(repo.last_db_change),
254 254 "last_change_raw": datetime_to_time(repo.last_db_change),
255 255
256 256 "last_changeset": last_rev(repo.repo_name, cs_cache),
257 257 "last_changeset_raw": cs_cache.get('revision'),
258 258
259 259 "desc": desc(repo.description_safe),
260 260 "owner": user_profile(repo.user.username),
261 261
262 262 "state": state(repo.repo_state),
263 263 "rss": rss_lnk(repo.repo_name),
264 264
265 265 "atom": atom_lnk(repo.repo_name),
266 266 }
267 267 if admin:
268 268 row.update({
269 269 "action": repo_actions(repo.repo_name),
270 270 })
271 271 repos_data.append(row)
272 272
273 273 return repos_data
274 274
275 275 def _get_defaults(self, repo_name):
276 276 """
277 277 Gets information about repository, and returns a dict for
278 278 usage in forms
279 279
280 280 :param repo_name:
281 281 """
282 282
283 283 repo_info = Repository.get_by_repo_name(repo_name)
284 284
285 285 if repo_info is None:
286 286 return None
287 287
288 288 defaults = repo_info.get_dict()
289 289 defaults['repo_name'] = repo_info.just_name
290 290
291 291 groups = repo_info.groups_with_parents
292 292 parent_group = groups[-1] if groups else None
293 293
294 294 # we use -1 as this is how in HTML, we mark an empty group
295 295 defaults['repo_group'] = getattr(parent_group, 'group_id', -1)
296 296
297 297 keys_to_process = (
298 298 {'k': 'repo_type', 'strip': False},
299 299 {'k': 'repo_enable_downloads', 'strip': True},
300 300 {'k': 'repo_description', 'strip': True},
301 301 {'k': 'repo_enable_locking', 'strip': True},
302 302 {'k': 'repo_landing_rev', 'strip': True},
303 303 {'k': 'clone_uri', 'strip': False},
304 304 {'k': 'push_uri', 'strip': False},
305 305 {'k': 'repo_private', 'strip': True},
306 306 {'k': 'repo_enable_statistics', 'strip': True}
307 307 )
308 308
309 309 for item in keys_to_process:
310 310 attr = item['k']
311 311 if item['strip']:
312 312 attr = remove_prefix(item['k'], 'repo_')
313 313
314 314 val = defaults[attr]
315 315 if item['k'] == 'repo_landing_rev':
316 316 val = ':'.join(defaults[attr])
317 317 defaults[item['k']] = val
318 318 if item['k'] == 'clone_uri':
319 319 defaults['clone_uri_hidden'] = repo_info.clone_uri_hidden
320 320 if item['k'] == 'push_uri':
321 321 defaults['push_uri_hidden'] = repo_info.push_uri_hidden
322 322
323 323 # fill owner
324 324 if repo_info.user:
325 325 defaults.update({'user': repo_info.user.username})
326 326 else:
327 327 replacement_user = User.get_first_super_admin().username
328 328 defaults.update({'user': replacement_user})
329 329
330 330 return defaults
331 331
332 332 def update(self, repo, **kwargs):
333 333 try:
334 334 cur_repo = self._get_repo(repo)
335 335 source_repo_name = cur_repo.repo_name
336 336 if 'user' in kwargs:
337 337 cur_repo.user = User.get_by_username(kwargs['user'])
338 338
339 339 if 'repo_group' in kwargs:
340 340 cur_repo.group = RepoGroup.get(kwargs['repo_group'])
341 341 log.debug('Updating repo %s with params:%s', cur_repo, kwargs)
342 342
343 343 update_keys = [
344 344 (1, 'repo_description'),
345 345 (1, 'repo_landing_rev'),
346 346 (1, 'repo_private'),
347 347 (1, 'repo_enable_downloads'),
348 348 (1, 'repo_enable_locking'),
349 349 (1, 'repo_enable_statistics'),
350 350 (0, 'clone_uri'),
351 351 (0, 'push_uri'),
352 352 (0, 'fork_id')
353 353 ]
354 354 for strip, k in update_keys:
355 355 if k in kwargs:
356 356 val = kwargs[k]
357 357 if strip:
358 358 k = remove_prefix(k, 'repo_')
359 359
360 360 setattr(cur_repo, k, val)
361 361
362 362 new_name = cur_repo.get_new_name(kwargs['repo_name'])
363 363 cur_repo.repo_name = new_name
364 364
365 365 # if private flag is set, reset default permission to NONE
366 366 if kwargs.get('repo_private'):
367 367 EMPTY_PERM = 'repository.none'
368 368 RepoModel().grant_user_permission(
369 369 repo=cur_repo, user=User.DEFAULT_USER, perm=EMPTY_PERM
370 370 )
371 371
372 372 # handle extra fields
373 373 for field in filter(lambda k: k.startswith(RepositoryField.PREFIX),
374 374 kwargs):
375 375 k = RepositoryField.un_prefix_key(field)
376 376 ex_field = RepositoryField.get_by_key_name(
377 377 key=k, repo=cur_repo)
378 378 if ex_field:
379 379 ex_field.field_value = kwargs[field]
380 380 self.sa.add(ex_field)
381 381 cur_repo.updated_on = datetime.datetime.now()
382 382 self.sa.add(cur_repo)
383 383
384 384 if source_repo_name != new_name:
385 385 # rename repository
386 386 self._rename_filesystem_repo(
387 387 old=source_repo_name, new=new_name)
388 388
389 389 return cur_repo
390 390 except Exception:
391 391 log.error(traceback.format_exc())
392 392 raise
393 393
394 394 def _create_repo(self, repo_name, repo_type, description, owner,
395 395 private=False, clone_uri=None, repo_group=None,
396 396 landing_rev='rev:tip', fork_of=None,
397 397 copy_fork_permissions=False, enable_statistics=False,
398 398 enable_locking=False, enable_downloads=False,
399 399 copy_group_permissions=False,
400 400 state=Repository.STATE_PENDING):
401 401 """
402 402 Create repository inside database with PENDING state, this should be
403 403 only executed by create() repo. With exception of importing existing
404 404 repos
405 405 """
406 406 from rhodecode.model.scm import ScmModel
407 407
408 408 owner = self._get_user(owner)
409 409 fork_of = self._get_repo(fork_of)
410 410 repo_group = self._get_repo_group(safe_int(repo_group))
411 411
412 412 try:
413 413 repo_name = safe_unicode(repo_name)
414 414 description = safe_unicode(description)
415 415 # repo name is just a name of repository
416 416 # while repo_name_full is a full qualified name that is combined
417 417 # with name and path of group
418 418 repo_name_full = repo_name
419 419 repo_name = repo_name.split(Repository.NAME_SEP)[-1]
420 420
421 421 new_repo = Repository()
422 422 new_repo.repo_state = state
423 423 new_repo.enable_statistics = False
424 424 new_repo.repo_name = repo_name_full
425 425 new_repo.repo_type = repo_type
426 426 new_repo.user = owner
427 427 new_repo.group = repo_group
428 428 new_repo.description = description or repo_name
429 429 new_repo.private = private
430 430 new_repo.archived = False
431 431 new_repo.clone_uri = clone_uri
432 432 new_repo.landing_rev = landing_rev
433 433
434 434 new_repo.enable_statistics = enable_statistics
435 435 new_repo.enable_locking = enable_locking
436 436 new_repo.enable_downloads = enable_downloads
437 437
438 438 if repo_group:
439 439 new_repo.enable_locking = repo_group.enable_locking
440 440
441 441 if fork_of:
442 442 parent_repo = fork_of
443 443 new_repo.fork = parent_repo
444 444
445 445 events.trigger(events.RepoPreCreateEvent(new_repo))
446 446
447 447 self.sa.add(new_repo)
448 448
449 449 EMPTY_PERM = 'repository.none'
450 450 if fork_of and copy_fork_permissions:
451 451 repo = fork_of
452 452 user_perms = UserRepoToPerm.query() \
453 453 .filter(UserRepoToPerm.repository == repo).all()
454 454 group_perms = UserGroupRepoToPerm.query() \
455 455 .filter(UserGroupRepoToPerm.repository == repo).all()
456 456
457 457 for perm in user_perms:
458 458 UserRepoToPerm.create(
459 459 perm.user, new_repo, perm.permission)
460 460
461 461 for perm in group_perms:
462 462 UserGroupRepoToPerm.create(
463 463 perm.users_group, new_repo, perm.permission)
464 464 # in case we copy permissions and also set this repo to private
465 # override the default user permission to make it a private
466 # repo
465 # override the default user permission to make it a private repo
467 466 if private:
468 467 RepoModel(self.sa).grant_user_permission(
469 468 repo=new_repo, user=User.DEFAULT_USER, perm=EMPTY_PERM)
470 469
471 470 elif repo_group and copy_group_permissions:
472 471 user_perms = UserRepoGroupToPerm.query() \
473 472 .filter(UserRepoGroupToPerm.group == repo_group).all()
474 473
475 474 group_perms = UserGroupRepoGroupToPerm.query() \
476 475 .filter(UserGroupRepoGroupToPerm.group == repo_group).all()
477 476
478 477 for perm in user_perms:
479 478 perm_name = perm.permission.permission_name.replace(
480 479 'group.', 'repository.')
481 480 perm_obj = Permission.get_by_key(perm_name)
482 481 UserRepoToPerm.create(perm.user, new_repo, perm_obj)
483 482
484 483 for perm in group_perms:
485 484 perm_name = perm.permission.permission_name.replace(
486 485 'group.', 'repository.')
487 486 perm_obj = Permission.get_by_key(perm_name)
488 UserGroupRepoToPerm.create(
489 perm.users_group, new_repo, perm_obj)
487 UserGroupRepoToPerm.create(perm.users_group, new_repo, perm_obj)
490 488
491 489 if private:
492 490 RepoModel(self.sa).grant_user_permission(
493 491 repo=new_repo, user=User.DEFAULT_USER, perm=EMPTY_PERM)
494 492
495 493 else:
496 494 perm_obj = self._create_default_perms(new_repo, private)
497 495 self.sa.add(perm_obj)
498 496
499 497 # now automatically start following this repository as owner
500 ScmModel(self.sa).toggle_following_repo(new_repo.repo_id,
501 owner.user_id)
498 ScmModel(self.sa).toggle_following_repo(new_repo.repo_id, owner.user_id)
502 499
503 500 # we need to flush here, in order to check if database won't
504 501 # throw any exceptions, create filesystem dirs at the very end
505 502 self.sa.flush()
506 503 events.trigger(events.RepoCreateEvent(new_repo))
507 504 return new_repo
508 505
509 506 except Exception:
510 507 log.error(traceback.format_exc())
511 508 raise
512 509
513 510 def create(self, form_data, cur_user):
514 511 """
515 512 Create repository using celery tasks
516 513
517 514 :param form_data:
518 515 :param cur_user:
519 516 """
520 517 from rhodecode.lib.celerylib import tasks, run_task
521 518 return run_task(tasks.create_repo, form_data, cur_user)
522 519
523 520 def update_permissions(self, repo, perm_additions=None, perm_updates=None,
524 521 perm_deletions=None, check_perms=True,
525 522 cur_user=None):
526 523 if not perm_additions:
527 524 perm_additions = []
528 525 if not perm_updates:
529 526 perm_updates = []
530 527 if not perm_deletions:
531 528 perm_deletions = []
532 529
533 530 req_perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin')
534 531
535 532 changes = {
536 533 'added': [],
537 534 'updated': [],
538 535 'deleted': []
539 536 }
540 537 # update permissions
541 538 for member_id, perm, member_type in perm_updates:
542 539 member_id = int(member_id)
543 540 if member_type == 'user':
544 541 member_name = User.get(member_id).username
545 542 # this updates also current one if found
546 543 self.grant_user_permission(
547 544 repo=repo, user=member_id, perm=perm)
548 545 elif member_type == 'user_group':
549 546 # check if we have permissions to alter this usergroup
550 547 member_name = UserGroup.get(member_id).users_group_name
551 548 if not check_perms or HasUserGroupPermissionAny(
552 549 *req_perms)(member_name, user=cur_user):
553 550 self.grant_user_group_permission(
554 551 repo=repo, group_name=member_id, perm=perm)
555 552 else:
556 553 raise ValueError("member_type must be 'user' or 'user_group' "
557 554 "got {} instead".format(member_type))
558 555 changes['updated'].append({'type': member_type, 'id': member_id,
559 556 'name': member_name, 'new_perm': perm})
560 557
561 558 # set new permissions
562 559 for member_id, perm, member_type in perm_additions:
563 560 member_id = int(member_id)
564 561 if member_type == 'user':
565 562 member_name = User.get(member_id).username
566 563 self.grant_user_permission(
567 564 repo=repo, user=member_id, perm=perm)
568 565 elif member_type == 'user_group':
569 566 # check if we have permissions to alter this usergroup
570 567 member_name = UserGroup.get(member_id).users_group_name
571 568 if not check_perms or HasUserGroupPermissionAny(
572 569 *req_perms)(member_name, user=cur_user):
573 570 self.grant_user_group_permission(
574 571 repo=repo, group_name=member_id, perm=perm)
575 572 else:
576 573 raise ValueError("member_type must be 'user' or 'user_group' "
577 574 "got {} instead".format(member_type))
578 575
579 576 changes['added'].append({'type': member_type, 'id': member_id,
580 577 'name': member_name, 'new_perm': perm})
581 578 # delete permissions
582 579 for member_id, perm, member_type in perm_deletions:
583 580 member_id = int(member_id)
584 581 if member_type == 'user':
585 582 member_name = User.get(member_id).username
586 583 self.revoke_user_permission(repo=repo, user=member_id)
587 584 elif member_type == 'user_group':
588 585 # check if we have permissions to alter this usergroup
589 586 member_name = UserGroup.get(member_id).users_group_name
590 587 if not check_perms or HasUserGroupPermissionAny(
591 588 *req_perms)(member_name, user=cur_user):
592 589 self.revoke_user_group_permission(
593 590 repo=repo, group_name=member_id)
594 591 else:
595 592 raise ValueError("member_type must be 'user' or 'user_group' "
596 593 "got {} instead".format(member_type))
597 594
598 595 changes['deleted'].append({'type': member_type, 'id': member_id,
599 596 'name': member_name, 'new_perm': perm})
600 597 return changes
601 598
602 599 def create_fork(self, form_data, cur_user):
603 600 """
604 601 Simple wrapper into executing celery task for fork creation
605 602
606 603 :param form_data:
607 604 :param cur_user:
608 605 """
609 606 from rhodecode.lib.celerylib import tasks, run_task
610 607 return run_task(tasks.create_repo_fork, form_data, cur_user)
611 608
612 609 def archive(self, repo):
613 610 """
614 611 Archive given repository. Set archive flag.
615 612
616 613 :param repo:
617 614 """
618 615 repo = self._get_repo(repo)
619 616 if repo:
620 617
621 618 try:
622 619 repo.archived = True
623 620 self.sa.add(repo)
624 621 self.sa.commit()
625 622 except Exception:
626 623 log.error(traceback.format_exc())
627 624 raise
628 625
629 626 def delete(self, repo, forks=None, pull_requests=None, fs_remove=True, cur_user=None):
630 627 """
631 628 Delete given repository, forks parameter defines what do do with
632 629 attached forks. Throws AttachedForksError if deleted repo has attached
633 630 forks
634 631
635 632 :param repo:
636 633 :param forks: str 'delete' or 'detach'
637 634 :param pull_requests: str 'delete' or None
638 635 :param fs_remove: remove(archive) repo from filesystem
639 636 """
640 637 if not cur_user:
641 638 cur_user = getattr(get_current_rhodecode_user(), 'username', None)
642 639 repo = self._get_repo(repo)
643 640 if repo:
644 641 if forks == 'detach':
645 642 for r in repo.forks:
646 643 r.fork = None
647 644 self.sa.add(r)
648 645 elif forks == 'delete':
649 646 for r in repo.forks:
650 647 self.delete(r, forks='delete')
651 648 elif [f for f in repo.forks]:
652 649 raise AttachedForksError()
653 650
654 651 # check for pull requests
655 652 pr_sources = repo.pull_requests_source
656 653 pr_targets = repo.pull_requests_target
657 654 if pull_requests != 'delete' and (pr_sources or pr_targets):
658 655 raise AttachedPullRequestsError()
659 656
660 657 old_repo_dict = repo.get_dict()
661 658 events.trigger(events.RepoPreDeleteEvent(repo))
662 659 try:
663 660 self.sa.delete(repo)
664 661 if fs_remove:
665 662 self._delete_filesystem_repo(repo)
666 663 else:
667 664 log.debug('skipping removal from filesystem')
668 665 old_repo_dict.update({
669 666 'deleted_by': cur_user,
670 667 'deleted_on': time.time(),
671 668 })
672 669 log_delete_repository(**old_repo_dict)
673 670 events.trigger(events.RepoDeleteEvent(repo))
674 671 except Exception:
675 672 log.error(traceback.format_exc())
676 673 raise
677 674
678 675 def grant_user_permission(self, repo, user, perm):
679 676 """
680 677 Grant permission for user on given repository, or update existing one
681 678 if found
682 679
683 680 :param repo: Instance of Repository, repository_id, or repository name
684 681 :param user: Instance of User, user_id or username
685 682 :param perm: Instance of Permission, or permission_name
686 683 """
687 684 user = self._get_user(user)
688 685 repo = self._get_repo(repo)
689 686 permission = self._get_perm(perm)
690 687
691 688 # check if we have that permission already
692 689 obj = self.sa.query(UserRepoToPerm) \
693 690 .filter(UserRepoToPerm.user == user) \
694 691 .filter(UserRepoToPerm.repository == repo) \
695 692 .scalar()
696 693 if obj is None:
697 694 # create new !
698 695 obj = UserRepoToPerm()
699 696 obj.repository = repo
700 697 obj.user = user
701 698 obj.permission = permission
702 699 self.sa.add(obj)
703 700 log.debug('Granted perm %s to %s on %s', perm, user, repo)
704 701 action_logger_generic(
705 702 'granted permission: {} to user: {} on repo: {}'.format(
706 703 perm, user, repo), namespace='security.repo')
707 704 return obj
708 705
709 706 def revoke_user_permission(self, repo, user):
710 707 """
711 708 Revoke permission for user on given repository
712 709
713 710 :param repo: Instance of Repository, repository_id, or repository name
714 711 :param user: Instance of User, user_id or username
715 712 """
716 713
717 714 user = self._get_user(user)
718 715 repo = self._get_repo(repo)
719 716
720 717 obj = self.sa.query(UserRepoToPerm) \
721 718 .filter(UserRepoToPerm.repository == repo) \
722 719 .filter(UserRepoToPerm.user == user) \
723 720 .scalar()
724 721 if obj:
725 722 self.sa.delete(obj)
726 723 log.debug('Revoked perm on %s on %s', repo, user)
727 724 action_logger_generic(
728 725 'revoked permission from user: {} on repo: {}'.format(
729 726 user, repo), namespace='security.repo')
730 727
731 728 def grant_user_group_permission(self, repo, group_name, perm):
732 729 """
733 730 Grant permission for user group on given repository, or update
734 731 existing one if found
735 732
736 733 :param repo: Instance of Repository, repository_id, or repository name
737 734 :param group_name: Instance of UserGroup, users_group_id,
738 735 or user group name
739 736 :param perm: Instance of Permission, or permission_name
740 737 """
741 738 repo = self._get_repo(repo)
742 739 group_name = self._get_user_group(group_name)
743 740 permission = self._get_perm(perm)
744 741
745 742 # check if we have that permission already
746 743 obj = self.sa.query(UserGroupRepoToPerm) \
747 744 .filter(UserGroupRepoToPerm.users_group == group_name) \
748 745 .filter(UserGroupRepoToPerm.repository == repo) \
749 746 .scalar()
750 747
751 748 if obj is None:
752 749 # create new
753 750 obj = UserGroupRepoToPerm()
754 751
755 752 obj.repository = repo
756 753 obj.users_group = group_name
757 754 obj.permission = permission
758 755 self.sa.add(obj)
759 756 log.debug('Granted perm %s to %s on %s', perm, group_name, repo)
760 757 action_logger_generic(
761 758 'granted permission: {} to usergroup: {} on repo: {}'.format(
762 759 perm, group_name, repo), namespace='security.repo')
763 760
764 761 return obj
765 762
766 763 def revoke_user_group_permission(self, repo, group_name):
767 764 """
768 765 Revoke permission for user group on given repository
769 766
770 767 :param repo: Instance of Repository, repository_id, or repository name
771 768 :param group_name: Instance of UserGroup, users_group_id,
772 769 or user group name
773 770 """
774 771 repo = self._get_repo(repo)
775 772 group_name = self._get_user_group(group_name)
776 773
777 774 obj = self.sa.query(UserGroupRepoToPerm) \
778 775 .filter(UserGroupRepoToPerm.repository == repo) \
779 776 .filter(UserGroupRepoToPerm.users_group == group_name) \
780 777 .scalar()
781 778 if obj:
782 779 self.sa.delete(obj)
783 780 log.debug('Revoked perm to %s on %s', repo, group_name)
784 781 action_logger_generic(
785 782 'revoked permission from usergroup: {} on repo: {}'.format(
786 783 group_name, repo), namespace='security.repo')
787 784
788 785 def delete_stats(self, repo_name):
789 786 """
790 787 removes stats for given repo
791 788
792 789 :param repo_name:
793 790 """
794 791 repo = self._get_repo(repo_name)
795 792 try:
796 793 obj = self.sa.query(Statistics) \
797 794 .filter(Statistics.repository == repo).scalar()
798 795 if obj:
799 796 self.sa.delete(obj)
800 797 except Exception:
801 798 log.error(traceback.format_exc())
802 799 raise
803 800
804 801 def add_repo_field(self, repo_name, field_key, field_label, field_value='',
805 802 field_type='str', field_desc=''):
806 803
807 804 repo = self._get_repo(repo_name)
808 805
809 806 new_field = RepositoryField()
810 807 new_field.repository = repo
811 808 new_field.field_key = field_key
812 809 new_field.field_type = field_type # python type
813 810 new_field.field_value = field_value
814 811 new_field.field_desc = field_desc
815 812 new_field.field_label = field_label
816 813 self.sa.add(new_field)
817 814 return new_field
818 815
819 816 def delete_repo_field(self, repo_name, field_key):
820 817 repo = self._get_repo(repo_name)
821 818 field = RepositoryField.get_by_key_name(field_key, repo)
822 819 if field:
823 820 self.sa.delete(field)
824 821
825 822 def _create_filesystem_repo(self, repo_name, repo_type, repo_group,
826 823 clone_uri=None, repo_store_location=None,
827 824 use_global_config=False):
828 825 """
829 826 makes repository on filesystem. It's group aware means it'll create
830 827 a repository within a group, and alter the paths accordingly of
831 828 group location
832 829
833 830 :param repo_name:
834 831 :param alias:
835 832 :param parent:
836 833 :param clone_uri:
837 834 :param repo_store_location:
838 835 """
839 836 from rhodecode.lib.utils import is_valid_repo, is_valid_repo_group
840 837 from rhodecode.model.scm import ScmModel
841 838
842 839 if Repository.NAME_SEP in repo_name:
843 840 raise ValueError(
844 841 'repo_name must not contain groups got `%s`' % repo_name)
845 842
846 843 if isinstance(repo_group, RepoGroup):
847 844 new_parent_path = os.sep.join(repo_group.full_path_splitted)
848 845 else:
849 846 new_parent_path = repo_group or ''
850 847
851 848 if repo_store_location:
852 849 _paths = [repo_store_location]
853 850 else:
854 851 _paths = [self.repos_path, new_parent_path, repo_name]
855 852 # we need to make it str for mercurial
856 853 repo_path = os.path.join(*map(lambda x: safe_str(x), _paths))
857 854
858 855 # check if this path is not a repository
859 856 if is_valid_repo(repo_path, self.repos_path):
860 857 raise Exception('This path %s is a valid repository' % repo_path)
861 858
862 859 # check if this path is a group
863 860 if is_valid_repo_group(repo_path, self.repos_path):
864 861 raise Exception('This path %s is a valid group' % repo_path)
865 862
866 863 log.info('creating repo %s in %s from url: `%s`',
867 864 repo_name, safe_unicode(repo_path),
868 865 obfuscate_url_pw(clone_uri))
869 866
870 867 backend = get_backend(repo_type)
871 868
872 869 config_repo = None if use_global_config else repo_name
873 870 if config_repo and new_parent_path:
874 871 config_repo = Repository.NAME_SEP.join(
875 872 (new_parent_path, config_repo))
876 873 config = make_db_config(clear_session=False, repo=config_repo)
877 874 config.set('extensions', 'largefiles', '')
878 875
879 876 # patch and reset hooks section of UI config to not run any
880 877 # hooks on creating remote repo
881 878 config.clear_section('hooks')
882 879
883 880 # TODO: johbo: Unify this, hardcoded "bare=True" does not look nice
884 881 if repo_type == 'git':
885 882 repo = backend(
886 883 repo_path, config=config, create=True, src_url=clone_uri,
887 884 bare=True)
888 885 else:
889 886 repo = backend(
890 887 repo_path, config=config, create=True, src_url=clone_uri)
891 888
892 889 repo.install_hooks()
893 890
894 891 log.debug('Created repo %s with %s backend',
895 892 safe_unicode(repo_name), safe_unicode(repo_type))
896 893 return repo
897 894
898 895 def _rename_filesystem_repo(self, old, new):
899 896 """
900 897 renames repository on filesystem
901 898
902 899 :param old: old name
903 900 :param new: new name
904 901 """
905 902 log.info('renaming repo from %s to %s', old, new)
906 903
907 904 old_path = os.path.join(self.repos_path, old)
908 905 new_path = os.path.join(self.repos_path, new)
909 906 if os.path.isdir(new_path):
910 907 raise Exception(
911 908 'Was trying to rename to already existing dir %s' % new_path
912 909 )
913 910 shutil.move(old_path, new_path)
914 911
915 912 def _delete_filesystem_repo(self, repo):
916 913 """
917 914 removes repo from filesystem, the removal is acctually made by
918 915 added rm__ prefix into dir, and rename internat .hg/.git dirs so this
919 916 repository is no longer valid for rhodecode, can be undeleted later on
920 917 by reverting the renames on this repository
921 918
922 919 :param repo: repo object
923 920 """
924 921 rm_path = os.path.join(self.repos_path, repo.repo_name)
925 922 repo_group = repo.group
926 923 log.info("Removing repository %s", rm_path)
927 924 # disable hg/git internal that it doesn't get detected as repo
928 925 alias = repo.repo_type
929 926
930 927 config = make_db_config(clear_session=False)
931 928 config.set('extensions', 'largefiles', '')
932 929 bare = getattr(repo.scm_instance(config=config), 'bare', False)
933 930
934 931 # skip this for bare git repos
935 932 if not bare:
936 933 # disable VCS repo
937 934 vcs_path = os.path.join(rm_path, '.%s' % alias)
938 935 if os.path.exists(vcs_path):
939 936 shutil.move(vcs_path, os.path.join(rm_path, 'rm__.%s' % alias))
940 937
941 938 _now = datetime.datetime.now()
942 939 _ms = str(_now.microsecond).rjust(6, '0')
943 940 _d = 'rm__%s__%s' % (_now.strftime('%Y%m%d_%H%M%S_' + _ms),
944 941 repo.just_name)
945 942 if repo_group:
946 943 # if repository is in group, prefix the removal path with the group
947 944 args = repo_group.full_path_splitted + [_d]
948 945 _d = os.path.join(*args)
949 946
950 947 if os.path.isdir(rm_path):
951 948 shutil.move(rm_path, os.path.join(self.repos_path, _d))
952 949
953 950 # finally cleanup diff-cache if it exists
954 951 cached_diffs_dir = repo.cached_diffs_dir
955 952 if os.path.isdir(cached_diffs_dir):
956 953 shutil.rmtree(cached_diffs_dir)
957 954
958 955
959 956 class ReadmeFinder:
960 957 """
961 958 Utility which knows how to find a readme for a specific commit.
962 959
963 960 The main idea is that this is a configurable algorithm. When creating an
964 961 instance you can define parameters, currently only the `default_renderer`.
965 962 Based on this configuration the method :meth:`search` behaves slightly
966 963 different.
967 964 """
968 965
969 966 readme_re = re.compile(r'^readme(\.[^\.]+)?$', re.IGNORECASE)
970 967 path_re = re.compile(r'^docs?', re.IGNORECASE)
971 968
972 969 default_priorities = {
973 970 None: 0,
974 971 '.text': 2,
975 972 '.txt': 3,
976 973 '.rst': 1,
977 974 '.rest': 2,
978 975 '.md': 1,
979 976 '.mkdn': 2,
980 977 '.mdown': 3,
981 978 '.markdown': 4,
982 979 }
983 980
984 981 path_priority = {
985 982 'doc': 0,
986 983 'docs': 1,
987 984 }
988 985
989 986 FALLBACK_PRIORITY = 99
990 987
991 988 RENDERER_TO_EXTENSION = {
992 989 'rst': ['.rst', '.rest'],
993 990 'markdown': ['.md', 'mkdn', '.mdown', '.markdown'],
994 991 }
995 992
996 993 def __init__(self, default_renderer=None):
997 994 self._default_renderer = default_renderer
998 995 self._renderer_extensions = self.RENDERER_TO_EXTENSION.get(
999 996 default_renderer, [])
1000 997
1001 998 def search(self, commit, path='/'):
1002 999 """
1003 1000 Find a readme in the given `commit`.
1004 1001 """
1005 1002 nodes = commit.get_nodes(path)
1006 1003 matches = self._match_readmes(nodes)
1007 1004 matches = self._sort_according_to_priority(matches)
1008 1005 if matches:
1009 1006 return matches[0].node
1010 1007
1011 1008 paths = self._match_paths(nodes)
1012 1009 paths = self._sort_paths_according_to_priority(paths)
1013 1010 for path in paths:
1014 1011 match = self.search(commit, path=path)
1015 1012 if match:
1016 1013 return match
1017 1014
1018 1015 return None
1019 1016
1020 1017 def _match_readmes(self, nodes):
1021 1018 for node in nodes:
1022 1019 if not node.is_file():
1023 1020 continue
1024 1021 path = node.path.rsplit('/', 1)[-1]
1025 1022 match = self.readme_re.match(path)
1026 1023 if match:
1027 1024 extension = match.group(1)
1028 1025 yield ReadmeMatch(node, match, self._priority(extension))
1029 1026
1030 1027 def _match_paths(self, nodes):
1031 1028 for node in nodes:
1032 1029 if not node.is_dir():
1033 1030 continue
1034 1031 match = self.path_re.match(node.path)
1035 1032 if match:
1036 1033 yield node.path
1037 1034
1038 1035 def _priority(self, extension):
1039 1036 renderer_priority = (
1040 1037 0 if extension in self._renderer_extensions else 1)
1041 1038 extension_priority = self.default_priorities.get(
1042 1039 extension, self.FALLBACK_PRIORITY)
1043 1040 return (renderer_priority, extension_priority)
1044 1041
1045 1042 def _sort_according_to_priority(self, matches):
1046 1043
1047 1044 def priority_and_path(match):
1048 1045 return (match.priority, match.path)
1049 1046
1050 1047 return sorted(matches, key=priority_and_path)
1051 1048
1052 1049 def _sort_paths_according_to_priority(self, paths):
1053 1050
1054 1051 def priority_and_path(path):
1055 1052 return (self.path_priority.get(path, self.FALLBACK_PRIORITY), path)
1056 1053
1057 1054 return sorted(paths, key=priority_and_path)
1058 1055
1059 1056
1060 1057 class ReadmeMatch:
1061 1058
1062 1059 def __init__(self, node, match, priority):
1063 1060 self.node = node
1064 1061 self._match = match
1065 1062 self.priority = priority
1066 1063
1067 1064 @property
1068 1065 def path(self):
1069 1066 return self.node.path
1070 1067
1071 1068 def __repr__(self):
1072 1069 return '<ReadmeMatch {} priority={}'.format(self.path, self.priority)
@@ -1,106 +1,106 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 &middot; ${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 &raquo;
14 14 ${h.link_to(_('Repository groups'),h.route_path('repo_groups'))}
15 15 &raquo;
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="main()">
24 24 <div class="box">
25 25 <!-- box / title -->
26 26 <div class="title">
27 27 ${self.breadcrumbs()}
28 28 </div>
29 29 <!-- end box / title -->
30 30 ${h.secure_form(h.route_path('repo_group_create'), request=request)}
31 31 <div class="form">
32 32 <!-- fields -->
33 33 <div class="fields">
34 34 <div class="field">
35 35 <div class="label">
36 36 <label for="group_name">${_('Group name')}:</label>
37 37 </div>
38 38 <div class="input">
39 39 ${h.text('group_name', class_="medium")}
40 40 </div>
41 41 </div>
42 42
43 43 <div class="field">
44 44 <div class="label">
45 45 <label for="group_parent_id">${_('Repository group')}:</label>
46 46 </div>
47 47 <div class="select">
48 48 ${h.select('group_parent_id',request.GET.get('parent_group'),c.repo_groups,class_="medium")}
49 49 </div>
50 50 </div>
51 51
52 52 <div class="field">
53 53 <div class="label">
54 54 <label for="group_description">${_('Description')}:</label>
55 55 </div>
56 56 <div class="textarea editor">
57 57 ${h.textarea('group_description',cols=23,rows=5,class_="medium")}
58 58 <% metatags_url = h.literal('''<a href="#metatagsShow" onclick="$('#meta-tags-desc').toggle();return false">meta-tags</a>''') %>
59 59 <span class="help-block">${_('Plain text format with support of {metatags}').format(metatags=metatags_url)|n}</span>
60 60 <span id="meta-tags-desc" style="display: none">
61 61 <%namespace name="dt" file="/data_table/_dt_elements.mako"/>
62 62 ${dt.metatags_help()}
63 63 </span>
64 64 </div>
65 65 </div>
66 66
67 67 <div id="copy_perms" class="field">
68 68 <div class="label label-checkbox">
69 69 <label for="group_copy_permissions">${_('Copy Parent Group Permissions')}:</label>
70 70 </div>
71 71 <div class="checkboxes">
72 72 ${h.checkbox('group_copy_permissions', value="True", checked="checked")}
73 <span class="help-block">${_('Copy permission settings from parent repository group.')}</span>
73 <span class="help-block">${_('Copy permissions from parent repository group.')}</span>
74 74 </div>
75 75 </div>
76 76
77 77 <div class="buttons">
78 78 ${h.submit('save',_('Save'),class_="btn")}
79 79 </div>
80 80 </div>
81 81 </div>
82 82 ${h.end_form()}
83 83 </div>
84 84 <script>
85 85 $(document).ready(function(){
86 86 var setCopyPermsOption = function(group_val){
87 87 if(group_val !== "-1"){
88 88 $('#copy_perms').show()
89 89 }
90 90 else{
91 91 $('#copy_perms').hide();
92 92 }
93 93 };
94 94 $("#group_parent_id").select2({
95 95 'containerCssClass': "drop-menu",
96 96 'dropdownCssClass': "drop-menu-dropdown",
97 97 'dropdownAutoWidth': true
98 98 });
99 99 setCopyPermsOption($('#group_parent_id').val());
100 100 $("#group_parent_id").on("change", function(e) {
101 101 setCopyPermsOption(e.val)
102 102 });
103 103 $('#group_name').focus();
104 104 })
105 105 </script>
106 106 </%def>
@@ -1,218 +1,219 b''
1 1 <%namespace name="base" file="/base/base.mako"/>
2 2
3 3 <div class="panel panel-default">
4 4 <div class="panel-heading">
5 5 <h3 class="panel-title">${_('Repository Group Permissions')}</h3>
6 6 </div>
7 7 <div class="panel-body">
8 8 ${h.secure_form(h.route_path('edit_repo_group_perms_update', repo_group_name=c.repo_group.group_name), request=request)}
9 9 <table id="permissions_manage" class="rctable permissions">
10 10 <tr>
11 11 <th class="td-radio">${_('None')}</th>
12 12 <th class="td-radio">${_('Read')}</th>
13 13 <th class="td-radio">${_('Write')}</th>
14 14 <th class="td-radio">${_('Admin')}</th>
15 15 <th class="td-owner">${_('User/User Group')}</th>
16 16 <th class="td-action"></th>
17 17 <th class="td-action"></th>
18 18 </tr>
19 19 ## USERS
20 20 %for _user in c.repo_group.permissions():
21 21 ## super admin/owner row
22 22 %if getattr(_user, 'admin_row', None) or getattr(_user, 'owner_row', None):
23 23 <tr class="perm_admin_row">
24 24 <td class="td-radio">${h.radio('admin_perm_%s' % _user.user_id,'repository.none', disabled="disabled")}</td>
25 25 <td class="td-radio">${h.radio('admin_perm_%s' % _user.user_id,'repository.read', disabled="disabled")}</td>
26 26 <td class="td-radio">${h.radio('admin_perm_%s' % _user.user_id,'repository.write', disabled="disabled")}</td>
27 27 <td class="td-radio">${h.radio('admin_perm_%s' % _user.user_id,'repository.admin', 'repository.admin', disabled="disabled")}</td>
28 28 <td class="td-user">
29 29 ${base.gravatar(_user.email, 16)}
30 30 ${h.link_to_user(_user.username)}
31 31 %if getattr(_user, 'admin_row', None):
32 32 (${_('super admin')})
33 33 %endif
34 34 %if getattr(_user, 'owner_row', None):
35 35 (${_('owner')})
36 36 %endif
37 37 </td>
38 38 <td></td>
39 39 <td class="quick_repo_menu">
40 40 % if c.rhodecode_user.is_admin:
41 41 <i class="icon-more"></i>
42 42 <div class="menu_items_container" style="display: none;">
43 43 <ul class="menu_items">
44 44 <li>
45 45 ${h.link_to('show permissions', h.route_path('edit_user_perms_summary', user_id=_user.user_id, _anchor='repositories-groups-permissions'))}
46 46 </li>
47 47 </ul>
48 48 </div>
49 49 % endif
50 50 </td>
51 51 </tr>
52 52 %else:
53 53 <tr>
54 54 ##forbid revoking permission from yourself, except if you're an super admin
55 55 %if c.rhodecode_user.user_id != _user.user_id or c.rhodecode_user.is_admin:
56 56 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'group.none', checked=_user.permission=='group.none')}</td>
57 57 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'group.read', checked=_user.permission=='group.read')}</td>
58 58 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'group.write', checked=_user.permission=='group.write')}</td>
59 59 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'group.admin', checked=_user.permission=='group.admin')}</td>
60 60 <td class="td-user">
61 61 ${base.gravatar(_user.email, 16)}
62 62 <span class="user">
63 63 % if _user.username == h.DEFAULT_USER:
64 64 ${h.DEFAULT_USER} <span class="user-perm-help-text"> - ${_('permission for all other users')}</span>
65 65 % else:
66 66 ${h.link_to_user(_user.username)}
67 67 %if getattr(_user, 'duplicate_perm', None):
68 68 (${_('inactive duplicate')})
69 69 %endif
70 70 % endif
71 71 </span>
72 72 </td>
73 73 <td class="td-action">
74 74 %if _user.username != h.DEFAULT_USER:
75 75 <span class="btn btn-link btn-danger revoke_perm"
76 76 member="${_user.user_id}" member_type="user">
77 77 ${_('Remove')}
78 78 </span>
79 79 %endif
80 80 </td>
81 81 <td class="quick_repo_menu">
82 82 % if c.rhodecode_user.is_admin:
83 83 <i class="icon-more"></i>
84 84 <div class="menu_items_container" style="display: none;">
85 85 <ul class="menu_items">
86 86 <li>
87 87 % if _user.username == h.DEFAULT_USER:
88 88 ${h.link_to('show permissions', h.route_path('admin_permissions_overview', _anchor='repositories-groups-permissions'))}
89 89 % else:
90 90 ${h.link_to('show permissions', h.route_path('edit_user_perms_summary', user_id=_user.user_id, _anchor='repositories-groups-permissions'))}
91 91 % endif
92 92 </li>
93 93 </ul>
94 94 </div>
95 95 % endif
96 96 </td>
97 97 %else:
98 98 ## special case for currently logged-in user permissions, we make sure he cannot take his own permissions
99 99 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'group.none', disabled="disabled")}</td>
100 100 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'group.read', disabled="disabled")}</td>
101 101 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'group.write', disabled="disabled")}</td>
102 102 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'group.admin', disabled="disabled")}</td>
103 103 <td class="td-user">
104 104 ${base.gravatar(_user.email, 16)}
105 105 <span class="user">
106 106 % if _user.username == h.DEFAULT_USER:
107 107 ${h.DEFAULT_USER} <span class="user-perm-help-text"> - ${_('permission for all other users')}</span>
108 108 % else:
109 109 ${h.link_to_user(_user.username)}
110 110 %if getattr(_user, 'duplicate_perm', None):
111 111 (${_('inactive duplicate')})
112 112 %endif
113 113 % endif
114 114 <span class="user-perm-help-text">(${_('delegated admin')})</span>
115 115 </span>
116 116 </td>
117 117 <td></td>
118 118 <td class="quick_repo_menu">
119 119 % if c.rhodecode_user.is_admin:
120 120 <i class="icon-more"></i>
121 121 <div class="menu_items_container" style="display: none;">
122 122 <ul class="menu_items">
123 123 <li>
124 124 ${h.link_to('show permissions', h.route_path('edit_user_perms_summary', user_id=_user.user_id, _anchor='repositories-groups-permissions'))}
125 125 </li>
126 126 </ul>
127 127 </div>
128 128 % endif
129 129 </td>
130 130 %endif
131 131 </tr>
132 132 %endif
133 133 %endfor
134 134
135 135 ## USER GROUPS
136 %for _user_group in c.repo_group.permission_user_groups():
136 %for _user_group in c.repo_group.permission_user_groups(with_members=True):
137 137 <tr id="id${id(_user_group.users_group_name)}">
138 138 <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'group.none', checked=_user_group.permission=='group.none')}</td>
139 139 <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'group.read', checked=_user_group.permission=='group.read')}</td>
140 140 <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'group.write', checked=_user_group.permission=='group.write')}</td>
141 141 <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'group.admin', checked=_user_group.permission=='group.admin')}</td>
142 142 <td class="td-componentname">
143 143 <i class="icon-user-group"></i>
144 144 %if h.HasPermissionAny('hg.admin')():
145 145 <a href="${h.route_path('edit_user_group',user_group_id=_user_group.users_group_id)}">
146 146 ${_user_group.users_group_name}
147 147 </a>
148 148 %else:
149 149 ${h.link_to_group(_user_group.users_group_name)}
150 150 %endif
151 (${_('members')}: ${len(_user_group.members)})
151 152 </td>
152 153 <td class="td-action">
153 154 <span class="btn btn-link btn-danger revoke_perm"
154 155 member="${_user_group.users_group_id}" member_type="user_group">
155 156 ${_('Remove')}
156 157 </span>
157 158 </td>
158 159 <td class="quick_repo_menu">
159 160 % if c.rhodecode_user.is_admin:
160 161 <i class="icon-more"></i>
161 162 <div class="menu_items_container" style="display: none;">
162 163 <ul class="menu_items">
163 164 <li>
164 165 ${h.link_to('show permissions', h.route_path('edit_user_group_perms_summary', user_group_id=_user_group.users_group_id, _anchor='repositories-groups-permissions'))}
165 166 </li>
166 167 </ul>
167 168 </div>
168 169 % endif
169 170 </td>
170 171 </tr>
171 172 %endfor
172 173
173 174 <tr class="new_members" id="add_perm_input"></tr>
174 175 <tr>
175 176 <td></td>
176 177 <td></td>
177 178 <td></td>
178 179 <td></td>
179 180 <td></td>
180 181 <td>
181 182 <span id="add_perm" class="link">
182 183 ${_('Add user/user group')}
183 184 </span>
184 185 </td>
185 186 <td></td>
186 187 </tr>
187 188 </table>
188 189
189 190 <div class="fields">
190 191 <div class="field">
191 192 <div class="label label-radio">
192 193 ${_('Apply to children')}:
193 194 </div>
194 195 <div class="radios">
195 196 ${h.radio('recursive', 'none', label=_('None'), checked="checked")}
196 197 ${h.radio('recursive', 'groups', label=_('Repository Groups'))}
197 198 ${h.radio('recursive', 'repos', label=_('Repositories'))}
198 199 ${h.radio('recursive', 'all', label=_('Both'))}
199 200 <span class="help-block">${_('Set or revoke permissions to selected types of children of this group, including non-private repositories and other groups if chosen.')}</span>
200 201 </div>
201 202 </div>
202 203 </div>
203 204 <div class="buttons">
204 205 ${h.submit('save',_('Save'),class_="btn btn-primary")}
205 206 ${h.reset('reset',_('Reset'),class_="btn btn-danger")}
206 207 </div>
207 208 ${h.end_form()}
208 209 </div>
209 210 </div>
210 211 <script type="text/javascript">
211 212 $('#add_perm').on('click', function(e){
212 213 addNewPermInput($(this), 'group');
213 214 });
214 215 $('.revoke_perm').on('click', function(e){
215 216 markRevokePermInput($(this), 'group');
216 217 });
217 218 quick_repo_menu();
218 219 </script>
@@ -1,164 +1,164 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="#"><i class="icon-download-alt"></i> ${_('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_type">${_('Type')}:</label>
44 44 </div>
45 45 <div class="select">
46 46 ${h.select('repo_type','hg',c.backends)}
47 47 <span class="help-block">${_('Set the type of repository to create.')}</span>
48 48 </div>
49 49 </div>
50 50 <div class="field">
51 51 <div class="label">
52 52 <label for="repo_group">${_('Repository group')}:</label>
53 53 </div>
54 54 <div class="select">
55 55 ${h.select('repo_group',request.GET.get('parent_group'),c.repo_groups,class_="medium")}
56 56 % if c.personal_repo_group:
57 57 <a class="btn" href="#" id="select_my_group" data-personal-group-id="${c.personal_repo_group.group_id}">
58 58 ${_('Select my personal group (%(repo_group_name)s)') % {'repo_group_name': c.personal_repo_group.group_name}}
59 59 </a>
60 60 % endif
61 61 <span class="help-block">${_('Optionally select a group to put this repository into.')}</span>
62 62 </div>
63 63 </div>
64 64 <div class="field">
65 65 <div class="label">
66 66 <label for="repo_description">${_('Description')}:</label>
67 67 </div>
68 68 <div class="textarea editor">
69 69 ${h.textarea('repo_description',cols=23,rows=5,class_="medium")}
70 70 <% metatags_url = h.literal('''<a href="#metatagsShow" onclick="$('#meta-tags-desc').toggle();return false">meta-tags</a>''') %>
71 71 <span class="help-block">${_('Plain text format with support of {metatags}. Add a README file for longer descriptions').format(metatags=metatags_url)|n}</span>
72 72 <span id="meta-tags-desc" style="display: none">
73 73 <%namespace name="dt" file="/data_table/_dt_elements.mako"/>
74 74 ${dt.metatags_help()}
75 75 </span>
76 76 </div>
77 77 </div>
78 78 <div class="field">
79 79 <div class="label">
80 80 <label for="repo_landing_rev">${_('Landing commit')}:</label>
81 81 </div>
82 82 <div class="select">
83 83 ${h.select('repo_landing_rev','',c.landing_revs,class_="medium")}
84 84 <span class="help-block">${_('The default commit for file pages, downloads, full text search index, and README generation.')}</span>
85 85 </div>
86 86 </div>
87 87 <div id="copy_perms" class="field">
88 88 <div class="label label-checkbox">
89 89 <label for="repo_copy_permissions">${_('Copy Parent Group Permissions')}:</label>
90 90 </div>
91 91 <div class="checkboxes">
92 92 ${h.checkbox('repo_copy_permissions', value="True", checked="checked")}
93 <span class="help-block">${_('Copy permission set from the parent repository group.')}</span>
93 <span class="help-block">${_('Copy permissions from parent repository group.')}</span>
94 94 </div>
95 95 </div>
96 96 <div class="field">
97 97 <div class="label label-checkbox">
98 98 <label for="repo_private">${_('Private Repository')}:</label>
99 99 </div>
100 100 <div class="checkboxes">
101 101 ${h.checkbox('repo_private',value="True")}
102 102 <span class="help-block">${_('Private repositories are only visible to people explicitly added as collaborators.')}</span>
103 103 </div>
104 104 </div>
105 105 <div class="buttons">
106 106 ${h.submit('save',_('Save'),class_="btn")}
107 107 </div>
108 108 </div>
109 109 </div>
110 110 <script>
111 111 $(document).ready(function(){
112 112 var setCopyPermsOption = function(group_val){
113 113 if(group_val != "-1"){
114 114 $('#copy_perms').show()
115 115 }
116 116 else{
117 117 $('#copy_perms').hide();
118 118 }
119 119 };
120 120
121 121 $('#remote_clone_toggle').on('click', function(e){
122 122 $('#remote_clone').show();
123 123 e.preventDefault();
124 124 });
125 125
126 126 if($('#remote_clone input').hasClass('error')){
127 127 $('#remote_clone').show();
128 128 }
129 129 if($('#remote_clone input').val()){
130 130 $('#remote_clone').show();
131 131 }
132 132
133 133 $("#repo_group").select2({
134 134 'containerCssClass': "drop-menu",
135 135 'dropdownCssClass': "drop-menu-dropdown",
136 136 'dropdownAutoWidth': true,
137 137 'width': "resolve"
138 138 });
139 139
140 140 setCopyPermsOption($('#repo_group').val());
141 141 $("#repo_group").on("change", function(e) {
142 142 setCopyPermsOption(e.val)
143 143 });
144 144
145 145 $("#repo_type").select2({
146 146 'containerCssClass': "drop-menu",
147 147 'dropdownCssClass': "drop-menu-dropdown",
148 148 'minimumResultsForSearch': -1,
149 149 });
150 150 $("#repo_landing_rev").select2({
151 151 'containerCssClass': "drop-menu",
152 152 'dropdownCssClass': "drop-menu-dropdown",
153 153 'minimumResultsForSearch': -1,
154 154 });
155 155 $('#repo_name').focus();
156 156
157 157 $('#select_my_group').on('click', function(e){
158 158 e.preventDefault();
159 159 $("#repo_group").val($(this).data('personalGroupId')).trigger("change");
160 160 })
161 161
162 162 })
163 163 </script>
164 164 ${h.end_form()}
@@ -1,201 +1,202 b''
1 1 <%namespace name="base" file="/base/base.mako"/>
2 2
3 3 <div class="panel panel-default">
4 4 <div class="panel-heading">
5 5 <h3 class="panel-title">${_('Repository Permissions')}</h3>
6 6 </div>
7 7 <div class="panel-body">
8 8 ${h.secure_form(h.route_path('edit_repo_perms', repo_name=c.repo_name), request=request)}
9 9 <table id="permissions_manage" class="rctable permissions">
10 10 <tr>
11 11 <th class="td-radio">${_('None')}</th>
12 12 <th class="td-radio">${_('Read')}</th>
13 13 <th class="td-radio">${_('Write')}</th>
14 14 <th class="td-radio">${_('Admin')}</th>
15 15 <th class="td-owner">${_('User/User Group')}</th>
16 16 <th class="td-action"></th>
17 17 <th class="td-action"></th>
18 18 </tr>
19 19 ## USERS
20 20 %for _user in c.rhodecode_db_repo.permissions():
21 21 %if getattr(_user, 'admin_row', None) or getattr(_user, 'owner_row', None):
22 22 <tr class="perm_admin_row">
23 23 <td class="td-radio">${h.radio('admin_perm_%s' % _user.user_id,'repository.none', disabled="disabled")}</td>
24 24 <td class="td-radio">${h.radio('admin_perm_%s' % _user.user_id,'repository.read', disabled="disabled")}</td>
25 25 <td class="td-radio">${h.radio('admin_perm_%s' % _user.user_id,'repository.write', disabled="disabled")}</td>
26 26 <td class="td-radio">${h.radio('admin_perm_%s' % _user.user_id,'repository.admin', 'repository.admin', disabled="disabled")}</td>
27 27 <td class="td-user">
28 28 ${base.gravatar(_user.email, 16)}
29 29 ${h.link_to_user(_user.username)}
30 30 %if getattr(_user, 'admin_row', None):
31 31 (${_('super admin')})
32 32 %endif
33 33 %if getattr(_user, 'owner_row', None):
34 34 (${_('owner')})
35 35 %endif
36 36 </td>
37 37 <td></td>
38 38 <td class="quick_repo_menu">
39 39 % if c.rhodecode_user.is_admin:
40 40 <i class="icon-more"></i>
41 41 <div class="menu_items_container" style="display: none;">
42 42 <ul class="menu_items">
43 43 <li>
44 44 ${h.link_to('show permissions', h.route_path('edit_user_perms_summary', user_id=_user.user_id, _anchor='repositories-permissions'))}
45 45 </li>
46 46 </ul>
47 47 </div>
48 48 % endif
49 49 </td>
50 50 </tr>
51 51 %elif _user.username == h.DEFAULT_USER and c.rhodecode_db_repo.private:
52 52 <tr>
53 53 <td colspan="4">
54 54 <span class="private_repo_msg">
55 55 <strong title="${h.tooltip(_user.permission)}">${_('private repository')}</strong>
56 56 </span>
57 57 </td>
58 58 <td class="private_repo_msg">
59 59 ${base.gravatar(h.DEFAULT_USER_EMAIL, 16)}
60 60 ${h.DEFAULT_USER} - ${_('only users/user groups explicitly added here will have access')}</td>
61 61 <td></td>
62 62 <td class="quick_repo_menu">
63 63 % if c.rhodecode_user.is_admin:
64 64 <i class="icon-more"></i>
65 65 <div class="menu_items_container" style="display: none;">
66 66 <ul class="menu_items">
67 67 <li>
68 68 ${h.link_to('show permissions', h.route_path('admin_permissions_overview', _anchor='repositories-permissions'))}
69 69 </li>
70 70 </ul>
71 71 </div>
72 72 % endif
73 73 </td>
74 74 </tr>
75 75 %else:
76 76 <% used_by_n_rules = len(getattr(_user, 'branch_rules', None) or []) %>
77 77 <tr>
78 78 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'repository.none', checked=_user.permission=='repository.none', disabled="disabled" if (used_by_n_rules and _user.username != h.DEFAULT_USER) else None)}</td>
79 79 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'repository.read', checked=_user.permission=='repository.read', disabled="disabled" if (used_by_n_rules and _user.username != h.DEFAULT_USER) else None)}</td>
80 80 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'repository.write', checked=_user.permission=='repository.write')}</td>
81 81 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'repository.admin', checked=_user.permission=='repository.admin')}</td>
82 82 <td class="td-user">
83 83 ${base.gravatar(_user.email, 16)}
84 84 <span class="user">
85 85 % if _user.username == h.DEFAULT_USER:
86 86 ${h.DEFAULT_USER} <span class="user-perm-help-text"> - ${_('permission for all other users')}</span>
87 87 % else:
88 88 ${h.link_to_user(_user.username)}
89 89 %if getattr(_user, 'duplicate_perm', None):
90 90 (${_('inactive duplicate')})
91 91 %endif
92 92 %if getattr(_user, 'branch_rules', None):
93 93 % if used_by_n_rules == 1:
94 94 (${_('used by {} branch rule, requires write+ permissions').format(used_by_n_rules)})
95 95 % else:
96 96 (${_('used by {} branch rules, requires write+ permissions').format(used_by_n_rules)})
97 97 % endif
98 98 %endif
99 99 % endif
100 100 </span>
101 101 </td>
102 102 <td class="td-action">
103 103 %if _user.username != h.DEFAULT_USER and getattr(_user, 'branch_rules', None) is None:
104 104 <span class="btn btn-link btn-danger revoke_perm"
105 105 member="${_user.user_id}" member_type="user">
106 106 ${_('Remove')}
107 107 </span>
108 108 %endif
109 109 </td>
110 110 <td class="quick_repo_menu">
111 111 % if c.rhodecode_user.is_admin:
112 112 <i class="icon-more"></i>
113 113 <div class="menu_items_container" style="display: none;">
114 114 <ul class="menu_items">
115 115 <li>
116 116 % if _user.username == h.DEFAULT_USER:
117 117 ${h.link_to('show permissions', h.route_path('admin_permissions_overview', _anchor='repositories-permissions'))}
118 118 % else:
119 119 ${h.link_to('show permissions', h.route_path('edit_user_perms_summary', user_id=_user.user_id, _anchor='repositories-permissions'))}
120 120 % endif
121 121 </li>
122 122 </ul>
123 123 </div>
124 124 % endif
125 125 </td>
126 126 </tr>
127 127 %endif
128 128 %endfor
129 129
130 130 ## USER GROUPS
131 %for _user_group in c.rhodecode_db_repo.permission_user_groups():
131 %for _user_group in c.rhodecode_db_repo.permission_user_groups(with_members=True):
132 132 <tr>
133 133 <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'repository.none', checked=_user_group.permission=='repository.none')}</td>
134 134 <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'repository.read', checked=_user_group.permission=='repository.read')}</td>
135 135 <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'repository.write', checked=_user_group.permission=='repository.write')}</td>
136 136 <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'repository.admin', checked=_user_group.permission=='repository.admin')}</td>
137 137 <td class="td-componentname">
138 138 <i class="icon-user-group"></i>
139 139 %if h.HasPermissionAny('hg.admin')():
140 140 <a href="${h.route_path('edit_user_group',user_group_id=_user_group.users_group_id)}">
141 141 ${_user_group.users_group_name}
142 142 </a>
143 143 %else:
144 144 ${h.link_to_group(_user_group.users_group_name)}
145 145 %endif
146 (${_('members')}: ${len(_user_group.members)})
146 147 </td>
147 148 <td class="td-action">
148 149 <span class="btn btn-link btn-danger revoke_perm"
149 150 member="${_user_group.users_group_id}" member_type="user_group">
150 151 ${_('Remove')}
151 152 </span>
152 153 </td>
153 154 <td class="quick_repo_menu">
154 155 % if c.rhodecode_user.is_admin:
155 156 <i class="icon-more"></i>
156 157 <div class="menu_items_container" style="display: none;">
157 158 <ul class="menu_items">
158 159 <li>
159 160 ${h.link_to('show permissions', h.route_path('edit_user_group_perms_summary', user_group_id=_user_group.users_group_id, _anchor='repositories-permissions'))}
160 161 </li>
161 162 </ul>
162 163 </div>
163 164 % endif
164 165 </td>
165 166 </tr>
166 167 %endfor
167 168 <tr class="new_members" id="add_perm_input"></tr>
168 169
169 170 <tr>
170 171 <td></td>
171 172 <td></td>
172 173 <td></td>
173 174 <td></td>
174 175 <td></td>
175 176 <td>
176 177 <span id="add_perm" class="link">
177 178 ${_('Add user/user group')}
178 179 </span>
179 180 </td>
180 181 <td></td>
181 182 </tr>
182 183
183 184 </table>
184 185
185 186 <div class="buttons">
186 187 ${h.submit('save',_('Save'),class_="btn btn-primary")}
187 188 ${h.reset('reset',_('Reset'),class_="btn btn-danger")}
188 189 </div>
189 190 ${h.end_form()}
190 191 </div>
191 192 </div>
192 193
193 194 <script type="text/javascript">
194 195 $('#add_perm').on('click', function(e){
195 196 addNewPermInput($(this), 'repository');
196 197 });
197 198 $('.revoke_perm').on('click', function(e){
198 199 markRevokePermInput($(this), 'repository');
199 200 });
200 201 quick_repo_menu();
201 202 </script>
@@ -1,206 +1,207 b''
1 1 <%namespace name="base" file="/base/base.mako"/>
2 2
3 3 <div class="panel panel-default">
4 4 <div class="panel-heading">
5 5 <h3 class="panel-title">${_('User Group Permissions')}</h3>
6 6 </div>
7 7 <div class="panel-body">
8 8 ${h.secure_form(h.route_path('edit_user_group_perms_update', user_group_id=c.user_group.users_group_id), request=request)}
9 9 <table id="permissions_manage" class="rctable permissions">
10 10 <tr>
11 11 <th class="td-radio">${_('None')}</th>
12 12 <th class="td-radio">${_('Read')}</th>
13 13 <th class="td-radio">${_('Write')}</th>
14 14 <th class="td-radio">${_('Admin')}</th>
15 15 <th>${_('User/User Group')}</th>
16 16 <th class="td-action"></th>
17 17 <th class="td-action"></th>
18 18 </tr>
19 19 ## USERS
20 20 %for _user in c.user_group.permissions():
21 21 ## super admin/owner row
22 22 %if getattr(_user, 'admin_row', None) or getattr(_user, 'owner_row', None):
23 23 <tr class="perm_admin_row">
24 24 <td class="td-radio">${h.radio('admin_perm_%s' % _user.user_id,'repository.none', disabled="disabled")}</td>
25 25 <td class="td-radio">${h.radio('admin_perm_%s' % _user.user_id,'repository.read', disabled="disabled")}</td>
26 26 <td class="td-radio">${h.radio('admin_perm_%s' % _user.user_id,'repository.write', disabled="disabled")}</td>
27 27 <td class="td-radio">${h.radio('admin_perm_%s' % _user.user_id,'repository.admin', 'repository.admin', disabled="disabled")}</td>
28 28 <td class="td-user">
29 29 ${base.gravatar(_user.email, 16)}
30 30 <span class="user">
31 31 ${h.link_to_user(_user.username)}
32 32 %if getattr(_user, 'admin_row', None):
33 33 (${_('super admin')})
34 34 %endif
35 35 %if getattr(_user, 'owner_row', None):
36 36 (${_('owner')})
37 37 %endif
38 38 </span>
39 39 </td>
40 40 <td></td>
41 41 <td class="quick_repo_menu">
42 42 % if c.rhodecode_user.is_admin:
43 43 <i class="icon-more"></i>
44 44 <div class="menu_items_container" style="display: none;">
45 45 <ul class="menu_items">
46 46 <li>
47 47 ${h.link_to('show permissions', h.route_path('edit_user_perms_summary', user_id=_user.user_id, _anchor='user-groups-permissions'))}
48 48 </li>
49 49 </ul>
50 50 </div>
51 51 % endif
52 52 </td>
53 53 </tr>
54 54 %else:
55 55 ##forbid revoking permission from yourself, except if you're an super admin
56 56 <tr>
57 57 %if c.rhodecode_user.user_id != _user.user_id or c.rhodecode_user.is_admin:
58 58 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'usergroup.none')}</td>
59 59 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'usergroup.read')}</td>
60 60 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'usergroup.write')}</td>
61 61 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'usergroup.admin')}</td>
62 62 <td class="td-user">
63 63 ${base.gravatar(_user.email, 16)}
64 64 <span class="user">
65 65 % if _user.username == h.DEFAULT_USER:
66 66 ${h.DEFAULT_USER} <span class="user-perm-help-text"> - ${_('permission for all other users')}</span>
67 67 % else:
68 68 ${h.link_to_user(_user.username)}
69 69 %if getattr(_user, 'duplicate_perm', None):
70 70 (${_('inactive duplicate')})
71 71 %endif
72 72 % endif
73 73 </span>
74 74 </td>
75 75 <td class="td-action">
76 76 %if _user.username != h.DEFAULT_USER:
77 77 <span class="btn btn-link btn-danger revoke_perm"
78 78 member="${_user.user_id}" member_type="user">
79 79 ${_('Remove')}
80 80 </span>
81 81 %endif
82 82 </td>
83 83 <td class="quick_repo_menu">
84 84 % if c.rhodecode_user.is_admin:
85 85 <i class="icon-more"></i>
86 86 <div class="menu_items_container" style="display: none;">
87 87 <ul class="menu_items">
88 88 <li>
89 89 % if _user.username == h.DEFAULT_USER:
90 90 ${h.link_to('show permissions', h.route_path('admin_permissions_overview', _anchor='user-groups-permissions'))}
91 91 % else:
92 92 ${h.link_to('show permissions', h.route_path('edit_user_perms_summary', user_id=_user.user_id, _anchor='user-groups-permissions'))}
93 93 % endif
94 94 </li>
95 95 </ul>
96 96 </div>
97 97 % endif
98 98 </td>
99 99 %else:
100 100 ## special case for currently logged-in user permissions, we make sure he cannot take his own permissions
101 101 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'usergroup.none', disabled="disabled")}</td>
102 102 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'usergroup.read', disabled="disabled")}</td>
103 103 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'usergroup.write', disabled="disabled")}</td>
104 104 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'usergroup.admin', disabled="disabled")}</td>
105 105 <td class="td-user">
106 106 ${base.gravatar(_user.email, 16)}
107 107 <span class="user">
108 108 % if _user.username == h.DEFAULT_USER:
109 109 ${h.DEFAULT_USER} <span class="user-perm-help-text"> - ${_('permission for all other users')}</span>
110 110 % else:
111 111 ${h.link_to_user(_user.username)}
112 112 %if getattr(_user, 'duplicate_perm', None):
113 113 (${_('inactive duplicate')})
114 114 %endif
115 115 % endif
116 116 <span class="user-perm-help-text">(${_('delegated admin')})</span>
117 117 </span>
118 118 </td>
119 119 <td></td>
120 120 <td class="quick_repo_menu">
121 121 % if c.rhodecode_user.is_admin:
122 122 <i class="icon-more"></i>
123 123 <div class="menu_items_container" style="display: none;">
124 124 <ul class="menu_items">
125 125 <li>
126 126 ${h.link_to('show permissions', h.route_path('edit_user_perms_summary', user_id=_user.user_id, _anchor='user-groups-permissions'))}
127 127 </li>
128 128 </ul>
129 129 </div>
130 130 % endif
131 131 </td>
132 132 %endif
133 133 </tr>
134 134 %endif
135 135 %endfor
136 136
137 137 ## USER GROUPS
138 %for _user_group in c.user_group.permission_user_groups():
138 %for _user_group in c.user_group.permission_user_groups(with_members=True):
139 139 <tr>
140 140 <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'usergroup.none')}</td>
141 141 <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'usergroup.read')}</td>
142 142 <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'usergroup.write')}</td>
143 143 <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'usergroup.admin')}</td>
144 144 <td class="td-user">
145 145 <i class="icon-user-group"></i>
146 146 %if h.HasPermissionAny('hg.admin')():
147 147 <a href="${h.route_path('edit_user_group',user_group_id=_user_group.users_group_id)}">
148 148 ${_user_group.users_group_name}
149 149 </a>
150 150 %else:
151 151 ${h.link_to_group(_user_group.users_group_name)}
152 152 %endif
153 (${_('members')}: ${len(_user_group.members)})
153 154 </td>
154 155 <td class="td-action">
155 156 <span class="btn btn-link btn-danger revoke_perm"
156 157 member="${_user_group.users_group_id}" member_type="user_group">
157 158 ${_('Remove')}
158 159 </span>
159 160 </td>
160 161 <td class="quick_repo_menu">
161 162 % if c.rhodecode_user.is_admin:
162 163 <i class="icon-more"></i>
163 164 <div class="menu_items_container" style="display: none;">
164 165 <ul class="menu_items">
165 166 <li>
166 167 ${h.link_to('show permissions', h.route_path('edit_user_group_perms_summary', user_group_id=_user_group.users_group_id, _anchor='user-groups-permissions'))}
167 168 </li>
168 169 </ul>
169 170 </div>
170 171 % endif
171 172 </td>
172 173 </tr>
173 174 %endfor
174 175 <tr class="new_members" id="add_perm_input"></tr>
175 176 <tr>
176 177 <td></td>
177 178 <td></td>
178 179 <td></td>
179 180 <td></td>
180 181 <td></td>
181 182 <td>
182 183 <span id="add_perm" class="link">
183 184 ${_('Add user/user group')}
184 185 </span>
185 186 </td>
186 187 <td></td>
187 188 </tr>
188 189 </table>
189 190
190 191 <div class="buttons">
191 192 ${h.submit('save',_('Save'),class_="btn btn-primary")}
192 193 ${h.reset('reset',_('Reset'),class_="btn btn-danger")}
193 194 </div>
194 195 ${h.end_form()}
195 196 </div>
196 197 </div>
197 198
198 199 <script type="text/javascript">
199 200 $('#add_perm').on('click', function(e){
200 201 addNewPermInput($(this), 'usergroup');
201 202 });
202 203 $('.revoke_perm').on('click', function(e){
203 204 markRevokePermInput($(this), 'usergroup');
204 205 });
205 206 quick_repo_menu()
206 207 </script>
@@ -1,131 +1,131 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <%inherit file="/base/base.mako"/>
3 3
4 4 <%def name="title()">
5 5 ${_('Fork repository %s') % c.repo_name}
6 6 %if c.rhodecode_name:
7 7 &middot; ${h.branding(c.rhodecode_name)}
8 8 %endif
9 9 </%def>
10 10
11 11 <%def name="breadcrumbs_links()"></%def>
12 12
13 13 <%def name="menu_bar_nav()">
14 14 ${self.menu_items(active='repositories')}
15 15 </%def>
16 16
17 17 <%def name="menu_bar_subnav()">
18 18 ${self.repo_menu(active='options')}
19 19 </%def>
20 20
21 21 <%def name="main()">
22 22 <div class="box">
23 23 <div class="title">
24 24 ${self.repo_page_title(c.rhodecode_db_repo)}
25 25 </div>
26 26
27 27 ${h.secure_form(h.route_path('repo_fork_create',repo_name=c.rhodecode_db_repo.repo_name), request=request)}
28 28 <div class="form">
29 29 <!-- fields -->
30 30 <div class="fields">
31 31
32 32 <div class="field">
33 33 <div class="label">
34 34 <label for="repo_name">${_('Fork name')}:</label>
35 35 </div>
36 36 <div class="input">
37 37 ${h.text('repo_name', class_="medium")}
38 38 ${h.hidden('repo_type',c.rhodecode_db_repo.repo_type)}
39 39 ${h.hidden('fork_parent_id',c.rhodecode_db_repo.repo_id)}
40 40 </div>
41 41 </div>
42 42
43 43 <div class="field">
44 44 <div class="label">
45 45 <label for="repo_group">${_('Repository group')}:</label>
46 46 </div>
47 47 <div class="select">
48 48 ${h.select('repo_group','',c.repo_groups,class_="medium")}
49 49 % if c.personal_repo_group:
50 50 <a class="btn" href="#" id="select_my_group" data-personal-group-id="${c.personal_repo_group.group_id}">
51 51 ${_('Select my personal group (%(repo_group_name)s)') % {'repo_group_name': c.personal_repo_group.group_name}}
52 52 </a>
53 53 % endif
54 54 <span class="help-block">${_('Optionally select a group to put this repository into.')}</span>
55 55 </div>
56 56 </div>
57 57
58 58 <div class="field">
59 59 <div class="label label-textarea">
60 60 <label for="description">${_('Description')}:</label>
61 61 </div>
62 62 <div class="textarea editor">
63 63 ${h.textarea('description',cols=23,rows=5,class_="medium")}
64 64 <% metatags_url = h.literal('''<a href="#metatagsShow" onclick="$('#meta-tags-desc').toggle();return false">meta-tags</a>''') %>
65 65 <span class="help-block">${_('Plain text format with support of {metatags}. Add a README file for longer descriptions').format(metatags=metatags_url)|n}</span>
66 66 <span id="meta-tags-desc" style="display: none">
67 67 <%namespace name="dt" file="/data_table/_dt_elements.mako"/>
68 68 ${dt.metatags_help()}
69 69 </span>
70 70 </div>
71 71 </div>
72 72
73 73 <div class="field">
74 74 <div class="label">
75 75 <label for="landing_rev">${_('Landing commit')}:</label>
76 76 </div>
77 77 <div class="select">
78 78 ${h.select('landing_rev','',c.landing_revs,class_="medium")}
79 79 <span class="help-block">${_('The default commit for file pages, downloads, full text search index, and README generation.')}</span>
80 80 </div>
81 81 </div>
82 82
83 83 <div class="field">
84 84 <div class="label label-checkbox">
85 85 <label for="private">${_('Copy permissions')}:</label>
86 86 </div>
87 87 <div class="checkboxes">
88 88 ${h.checkbox('copy_permissions',value="True", checked="checked")}
89 <span class="help-block">${_('Copy permissions from forked repository')}</span>
89 <span class="help-block">${_('Copy permissions from parent repository.')}</span>
90 90 </div>
91 91 </div>
92 92
93 93 <div class="field">
94 94 <div class="label label-checkbox">
95 95 <label for="private">${_('Private')}:</label>
96 96 </div>
97 97 <div class="checkboxes">
98 98 ${h.checkbox('private',value="True")}
99 99 <span class="help-block">${_('Private repositories are only visible to people explicitly added as collaborators.')}</span>
100 100 </div>
101 101 </div>
102 102
103 103 <div class="buttons">
104 104 ${h.submit('',_('Fork this Repository'),class_="btn")}
105 105 </div>
106 106 </div>
107 107 </div>
108 108 ${h.end_form()}
109 109 </div>
110 110 <script>
111 111 $(document).ready(function(){
112 112 $("#repo_group").select2({
113 113 'dropdownAutoWidth': true,
114 114 'containerCssClass': "drop-menu",
115 115 'dropdownCssClass': "drop-menu-dropdown",
116 116 'width': "resolve"
117 117 });
118 118 $("#landing_rev").select2({
119 119 'containerCssClass': "drop-menu",
120 120 'dropdownCssClass': "drop-menu-dropdown",
121 121 'minimumResultsForSearch': -1
122 122 });
123 123 $('#repo_name').focus();
124 124
125 125 $('#select_my_group').on('click', function(e){
126 126 e.preventDefault();
127 127 $("#repo_group").val($(this).data('personalGroupId')).trigger("change");
128 128 })
129 129 })
130 130 </script>
131 131 </%def>
General Comments 0
You need to be logged in to leave comments. Login now