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