##// END OF EJS Templates
Repo type can't be changed. Fixes issue 836
Simon Lopez -
r3859:c3232212 beta
parent child Browse files
Show More
@@ -1,755 +1,755 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.model.repo
3 rhodecode.model.repo
4 ~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~
5
5
6 Repository model for rhodecode
6 Repository model for rhodecode
7
7
8 :created_on: Jun 5, 2010
8 :created_on: Jun 5, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 from __future__ import with_statement
25 from __future__ import with_statement
26 import os
26 import os
27 import shutil
27 import shutil
28 import logging
28 import logging
29 import traceback
29 import traceback
30 from datetime import datetime
30 from datetime import datetime
31
31
32 from rhodecode.lib.vcs.backends import get_backend
32 from rhodecode.lib.vcs.backends import get_backend
33 from rhodecode.lib.compat import json
33 from rhodecode.lib.compat import json
34 from rhodecode.lib.utils2 import LazyProperty, safe_str, safe_unicode,\
34 from rhodecode.lib.utils2 import LazyProperty, safe_str, safe_unicode,\
35 remove_prefix, obfuscate_url_pw
35 remove_prefix, obfuscate_url_pw
36 from rhodecode.lib.caching_query import FromCache
36 from rhodecode.lib.caching_query import FromCache
37 from rhodecode.lib.hooks import log_create_repository, log_delete_repository
37 from rhodecode.lib.hooks import log_create_repository, log_delete_repository
38
38
39 from rhodecode.model import BaseModel
39 from rhodecode.model import BaseModel
40 from rhodecode.model.db import Repository, UserRepoToPerm, User, Permission, \
40 from rhodecode.model.db import Repository, UserRepoToPerm, User, Permission, \
41 Statistics, UserGroup, UserGroupRepoToPerm, RhodeCodeUi, RepoGroup,\
41 Statistics, UserGroup, UserGroupRepoToPerm, RhodeCodeUi, RepoGroup,\
42 RhodeCodeSetting, RepositoryField
42 RhodeCodeSetting, RepositoryField
43 from rhodecode.lib import helpers as h
43 from rhodecode.lib import helpers as h
44 from rhodecode.lib.auth import HasRepoPermissionAny, HasUserGroupPermissionAny
44 from rhodecode.lib.auth import HasRepoPermissionAny, HasUserGroupPermissionAny
45 from rhodecode.lib.exceptions import AttachedForksError
45 from rhodecode.lib.exceptions import AttachedForksError
46 from rhodecode.model.scm import UserGroupList
46 from rhodecode.model.scm import UserGroupList
47
47
48 log = logging.getLogger(__name__)
48 log = logging.getLogger(__name__)
49
49
50
50
51 class RepoModel(BaseModel):
51 class RepoModel(BaseModel):
52
52
53 cls = Repository
53 cls = Repository
54 URL_SEPARATOR = Repository.url_sep()
54 URL_SEPARATOR = Repository.url_sep()
55
55
56 def _get_user_group(self, users_group):
56 def _get_user_group(self, users_group):
57 return self._get_instance(UserGroup, users_group,
57 return self._get_instance(UserGroup, users_group,
58 callback=UserGroup.get_by_group_name)
58 callback=UserGroup.get_by_group_name)
59
59
60 def _get_repo_group(self, repos_group):
60 def _get_repo_group(self, repos_group):
61 return self._get_instance(RepoGroup, repos_group,
61 return self._get_instance(RepoGroup, repos_group,
62 callback=RepoGroup.get_by_group_name)
62 callback=RepoGroup.get_by_group_name)
63
63
64 def _create_default_perms(self, repository, private):
64 def _create_default_perms(self, repository, private):
65 # create default permission
65 # create default permission
66 default = 'repository.read'
66 default = 'repository.read'
67 def_user = User.get_default_user()
67 def_user = User.get_default_user()
68 for p in def_user.user_perms:
68 for p in def_user.user_perms:
69 if p.permission.permission_name.startswith('repository.'):
69 if p.permission.permission_name.startswith('repository.'):
70 default = p.permission.permission_name
70 default = p.permission.permission_name
71 break
71 break
72
72
73 default_perm = 'repository.none' if private else default
73 default_perm = 'repository.none' if private else default
74
74
75 repo_to_perm = UserRepoToPerm()
75 repo_to_perm = UserRepoToPerm()
76 repo_to_perm.permission = Permission.get_by_key(default_perm)
76 repo_to_perm.permission = Permission.get_by_key(default_perm)
77
77
78 repo_to_perm.repository = repository
78 repo_to_perm.repository = repository
79 repo_to_perm.user_id = def_user.user_id
79 repo_to_perm.user_id = def_user.user_id
80
80
81 return repo_to_perm
81 return repo_to_perm
82
82
83 @LazyProperty
83 @LazyProperty
84 def repos_path(self):
84 def repos_path(self):
85 """
85 """
86 Get's the repositories root path from database
86 Get's the repositories root path from database
87 """
87 """
88
88
89 q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
89 q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
90 return q.ui_value
90 return q.ui_value
91
91
92 def get(self, repo_id, cache=False):
92 def get(self, repo_id, cache=False):
93 repo = self.sa.query(Repository)\
93 repo = self.sa.query(Repository)\
94 .filter(Repository.repo_id == repo_id)
94 .filter(Repository.repo_id == repo_id)
95
95
96 if cache:
96 if cache:
97 repo = repo.options(FromCache("sql_cache_short",
97 repo = repo.options(FromCache("sql_cache_short",
98 "get_repo_%s" % repo_id))
98 "get_repo_%s" % repo_id))
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 repo = repo.options(FromCache("sql_cache_short",
109 repo = repo.options(FromCache("sql_cache_short",
110 "get_repo_%s" % repo_name))
110 "get_repo_%s" % repo_name))
111 return repo.scalar()
111 return repo.scalar()
112
112
113 def get_all_user_repos(self, user):
113 def get_all_user_repos(self, user):
114 """
114 """
115 Get's all repositories that user have at least read access
115 Get's all repositories that user have at least read access
116
116
117 :param user:
117 :param user:
118 """
118 """
119 from rhodecode.lib.auth import AuthUser
119 from rhodecode.lib.auth import AuthUser
120 user = self._get_user(user)
120 user = self._get_user(user)
121 repos = AuthUser(user_id=user.user_id).permissions['repositories']
121 repos = AuthUser(user_id=user.user_id).permissions['repositories']
122 access_check = lambda r: r[1] in ['repository.read',
122 access_check = lambda r: r[1] in ['repository.read',
123 'repository.write',
123 'repository.write',
124 'repository.admin']
124 'repository.admin']
125 repos = [x[0] for x in filter(access_check, repos.items())]
125 repos = [x[0] for x in filter(access_check, repos.items())]
126 return Repository.query().filter(Repository.repo_name.in_(repos))
126 return Repository.query().filter(Repository.repo_name.in_(repos))
127
127
128 def get_users_js(self):
128 def get_users_js(self):
129 users = self.sa.query(User).filter(User.active == True).all()
129 users = self.sa.query(User).filter(User.active == True).all()
130 return json.dumps([
130 return json.dumps([
131 {
131 {
132 'id': u.user_id,
132 'id': u.user_id,
133 'fname': u.name,
133 'fname': u.name,
134 'lname': u.lastname,
134 'lname': u.lastname,
135 'nname': u.username,
135 'nname': u.username,
136 'gravatar_lnk': h.gravatar_url(u.email, 14)
136 'gravatar_lnk': h.gravatar_url(u.email, 14)
137 } for u in users]
137 } for u in users]
138 )
138 )
139
139
140 def get_users_groups_js(self):
140 def get_users_groups_js(self):
141 users_groups = self.sa.query(UserGroup)\
141 users_groups = self.sa.query(UserGroup)\
142 .filter(UserGroup.users_group_active == True).all()
142 .filter(UserGroup.users_group_active == True).all()
143 users_groups = UserGroupList(users_groups, perm_set=['usergroup.read',
143 users_groups = UserGroupList(users_groups, perm_set=['usergroup.read',
144 'usergroup.write',
144 'usergroup.write',
145 'usergroup.admin'])
145 'usergroup.admin'])
146 return json.dumps([
146 return json.dumps([
147 {
147 {
148 'id': gr.users_group_id,
148 'id': gr.users_group_id,
149 'grname': gr.users_group_name,
149 'grname': gr.users_group_name,
150 'grmembers': len(gr.members),
150 'grmembers': len(gr.members),
151 } for gr in users_groups]
151 } for gr in users_groups]
152 )
152 )
153
153
154 @classmethod
154 @classmethod
155 def _render_datatable(cls, tmpl, *args, **kwargs):
155 def _render_datatable(cls, tmpl, *args, **kwargs):
156 import rhodecode
156 import rhodecode
157 from pylons import tmpl_context as c
157 from pylons import tmpl_context as c
158 from pylons.i18n.translation import _
158 from pylons.i18n.translation import _
159
159
160 _tmpl_lookup = rhodecode.CONFIG['pylons.app_globals'].mako_lookup
160 _tmpl_lookup = rhodecode.CONFIG['pylons.app_globals'].mako_lookup
161 template = _tmpl_lookup.get_template('data_table/_dt_elements.html')
161 template = _tmpl_lookup.get_template('data_table/_dt_elements.html')
162
162
163 tmpl = template.get_def(tmpl)
163 tmpl = template.get_def(tmpl)
164 kwargs.update(dict(_=_, h=h, c=c))
164 kwargs.update(dict(_=_, h=h, c=c))
165 return tmpl.render(*args, **kwargs)
165 return tmpl.render(*args, **kwargs)
166
166
167 @classmethod
167 @classmethod
168 def update_repoinfo(cls, repositories=None):
168 def update_repoinfo(cls, repositories=None):
169 if not repositories:
169 if not repositories:
170 repositories = Repository.getAll()
170 repositories = Repository.getAll()
171 for repo in repositories:
171 for repo in repositories:
172 repo.update_changeset_cache()
172 repo.update_changeset_cache()
173
173
174 def get_repos_as_dict(self, repos_list=None, admin=False, perm_check=True,
174 def get_repos_as_dict(self, repos_list=None, admin=False, perm_check=True,
175 super_user_actions=False):
175 super_user_actions=False):
176 _render = self._render_datatable
176 _render = self._render_datatable
177 from pylons import tmpl_context as c
177 from pylons import tmpl_context as c
178
178
179 def quick_menu(repo_name):
179 def quick_menu(repo_name):
180 return _render('quick_menu', repo_name)
180 return _render('quick_menu', repo_name)
181
181
182 def repo_lnk(name, rtype, private, fork_of):
182 def repo_lnk(name, rtype, private, fork_of):
183 return _render('repo_name', name, rtype, private, fork_of,
183 return _render('repo_name', name, rtype, private, fork_of,
184 short_name=not admin, admin=False)
184 short_name=not admin, admin=False)
185
185
186 def last_change(last_change):
186 def last_change(last_change):
187 return _render("last_change", last_change)
187 return _render("last_change", last_change)
188
188
189 def rss_lnk(repo_name):
189 def rss_lnk(repo_name):
190 return _render("rss", repo_name)
190 return _render("rss", repo_name)
191
191
192 def atom_lnk(repo_name):
192 def atom_lnk(repo_name):
193 return _render("atom", repo_name)
193 return _render("atom", repo_name)
194
194
195 def last_rev(repo_name, cs_cache):
195 def last_rev(repo_name, cs_cache):
196 return _render('revision', repo_name, cs_cache.get('revision'),
196 return _render('revision', repo_name, cs_cache.get('revision'),
197 cs_cache.get('raw_id'), cs_cache.get('author'),
197 cs_cache.get('raw_id'), cs_cache.get('author'),
198 cs_cache.get('message'))
198 cs_cache.get('message'))
199
199
200 def desc(desc):
200 def desc(desc):
201 if c.visual.stylify_metatags:
201 if c.visual.stylify_metatags:
202 return h.urlify_text(h.desc_stylize(h.truncate(desc, 60)))
202 return h.urlify_text(h.desc_stylize(h.truncate(desc, 60)))
203 else:
203 else:
204 return h.urlify_text(h.truncate(desc, 60))
204 return h.urlify_text(h.truncate(desc, 60))
205
205
206 def repo_actions(repo_name):
206 def repo_actions(repo_name):
207 return _render('repo_actions', repo_name, super_user_actions)
207 return _render('repo_actions', repo_name, super_user_actions)
208
208
209 def owner_actions(user_id, username):
209 def owner_actions(user_id, username):
210 return _render('user_name', user_id, username)
210 return _render('user_name', user_id, username)
211
211
212 repos_data = []
212 repos_data = []
213 for repo in repos_list:
213 for repo in repos_list:
214 if perm_check:
214 if perm_check:
215 # check permission at this level
215 # check permission at this level
216 if not HasRepoPermissionAny(
216 if not HasRepoPermissionAny(
217 'repository.read', 'repository.write', 'repository.admin'
217 'repository.read', 'repository.write', 'repository.admin'
218 )(repo.repo_name, 'get_repos_as_dict check'):
218 )(repo.repo_name, 'get_repos_as_dict check'):
219 continue
219 continue
220 cs_cache = repo.changeset_cache
220 cs_cache = repo.changeset_cache
221 row = {
221 row = {
222 "menu": quick_menu(repo.repo_name),
222 "menu": quick_menu(repo.repo_name),
223 "raw_name": repo.repo_name.lower(),
223 "raw_name": repo.repo_name.lower(),
224 "name": repo_lnk(repo.repo_name, repo.repo_type,
224 "name": repo_lnk(repo.repo_name, repo.repo_type,
225 repo.private, repo.fork),
225 repo.private, repo.fork),
226 "last_change": last_change(repo.last_db_change),
226 "last_change": last_change(repo.last_db_change),
227 "last_changeset": last_rev(repo.repo_name, cs_cache),
227 "last_changeset": last_rev(repo.repo_name, cs_cache),
228 "raw_tip": cs_cache.get('revision'),
228 "raw_tip": cs_cache.get('revision'),
229 "desc": desc(repo.description),
229 "desc": desc(repo.description),
230 "owner": h.person(repo.user.username),
230 "owner": h.person(repo.user.username),
231 "rss": rss_lnk(repo.repo_name),
231 "rss": rss_lnk(repo.repo_name),
232 "atom": atom_lnk(repo.repo_name),
232 "atom": atom_lnk(repo.repo_name),
233
233
234 }
234 }
235 if admin:
235 if admin:
236 row.update({
236 row.update({
237 "action": repo_actions(repo.repo_name),
237 "action": repo_actions(repo.repo_name),
238 "owner": owner_actions(repo.user.user_id,
238 "owner": owner_actions(repo.user.user_id,
239 h.person(repo.user.username))
239 h.person(repo.user.username))
240 })
240 })
241 repos_data.append(row)
241 repos_data.append(row)
242
242
243 return {
243 return {
244 "totalRecords": len(repos_list),
244 "totalRecords": len(repos_list),
245 "startIndex": 0,
245 "startIndex": 0,
246 "sort": "name",
246 "sort": "name",
247 "dir": "asc",
247 "dir": "asc",
248 "records": repos_data
248 "records": repos_data
249 }
249 }
250
250
251 def _get_defaults(self, repo_name):
251 def _get_defaults(self, repo_name):
252 """
252 """
253 Get's information about repository, and returns a dict for
253 Get's information about repository, and returns a dict for
254 usage in forms
254 usage in forms
255
255
256 :param repo_name:
256 :param repo_name:
257 """
257 """
258
258
259 repo_info = Repository.get_by_repo_name(repo_name)
259 repo_info = Repository.get_by_repo_name(repo_name)
260
260
261 if repo_info is None:
261 if repo_info is None:
262 return None
262 return None
263
263
264 defaults = repo_info.get_dict()
264 defaults = repo_info.get_dict()
265 group, repo_name, repo_name_full = repo_info.groups_and_repo
265 group, repo_name, repo_name_full = repo_info.groups_and_repo
266 defaults['repo_name'] = repo_name
266 defaults['repo_name'] = repo_name
267 defaults['repo_group'] = getattr(group[-1] if group else None,
267 defaults['repo_group'] = getattr(group[-1] if group else None,
268 'group_id', None)
268 'group_id', None)
269
269
270 for strip, k in [(0, 'repo_type'), (1, 'repo_enable_downloads'),
270 for strip, k in [(0, 'repo_type'), (1, 'repo_enable_downloads'),
271 (1, 'repo_description'), (1, 'repo_enable_locking'),
271 (1, 'repo_description'), (1, 'repo_enable_locking'),
272 (1, 'repo_landing_rev'), (0, 'clone_uri'),
272 (1, 'repo_landing_rev'), (0, 'clone_uri'),
273 (1, 'repo_private'), (1, 'repo_enable_statistics')]:
273 (1, 'repo_private'), (1, 'repo_enable_statistics')]:
274 attr = k
274 attr = k
275 if strip:
275 if strip:
276 attr = remove_prefix(k, 'repo_')
276 attr = remove_prefix(k, 'repo_')
277
277
278 defaults[k] = defaults[attr]
278 defaults[k] = defaults[attr]
279
279
280 # fill owner
280 # fill owner
281 if repo_info.user:
281 if repo_info.user:
282 defaults.update({'user': repo_info.user.username})
282 defaults.update({'user': repo_info.user.username})
283 else:
283 else:
284 replacement_user = User.query().filter(User.admin ==
284 replacement_user = User.query().filter(User.admin ==
285 True).first().username
285 True).first().username
286 defaults.update({'user': replacement_user})
286 defaults.update({'user': replacement_user})
287
287
288 # fill repository users
288 # fill repository users
289 for p in repo_info.repo_to_perm:
289 for p in repo_info.repo_to_perm:
290 defaults.update({'u_perm_%s' % p.user.username:
290 defaults.update({'u_perm_%s' % p.user.username:
291 p.permission.permission_name})
291 p.permission.permission_name})
292
292
293 # fill repository groups
293 # fill repository groups
294 for p in repo_info.users_group_to_perm:
294 for p in repo_info.users_group_to_perm:
295 defaults.update({'g_perm_%s' % p.users_group.users_group_name:
295 defaults.update({'g_perm_%s' % p.users_group.users_group_name:
296 p.permission.permission_name})
296 p.permission.permission_name})
297
297
298 return defaults
298 return defaults
299
299
300 def update(self, org_repo_name, **kwargs):
300 def update(self, org_repo_name, **kwargs):
301 try:
301 try:
302 cur_repo = self.get_by_repo_name(org_repo_name, cache=False)
302 cur_repo = self.get_by_repo_name(org_repo_name, cache=False)
303
303
304 if 'user' in kwargs:
304 if 'user' in kwargs:
305 cur_repo.user = User.get_by_username(kwargs['user'])
305 cur_repo.user = User.get_by_username(kwargs['user'])
306
306
307 if 'repo_group' in kwargs:
307 if 'repo_group' in kwargs:
308 cur_repo.group = RepoGroup.get(kwargs['repo_group'])
308 cur_repo.group = RepoGroup.get(kwargs['repo_group'])
309
309
310 for strip, k in [(0, 'repo_type'), (1, 'repo_enable_downloads'),
310 for strip, k in [(1, 'repo_enable_downloads'),
311 (1, 'repo_description'), (1, 'repo_enable_locking'),
311 (1, 'repo_description'), (1, 'repo_enable_locking'),
312 (1, 'repo_landing_rev'), (0, 'clone_uri'),
312 (1, 'repo_landing_rev'), (0, 'clone_uri'),
313 (1, 'repo_private'), (1, 'repo_enable_statistics')]:
313 (1, 'repo_private'), (1, 'repo_enable_statistics')]:
314 if k in kwargs:
314 if k in kwargs:
315 val = kwargs[k]
315 val = kwargs[k]
316 if strip:
316 if strip:
317 k = remove_prefix(k, 'repo_')
317 k = remove_prefix(k, 'repo_')
318 setattr(cur_repo, k, val)
318 setattr(cur_repo, k, val)
319
319
320 new_name = cur_repo.get_new_name(kwargs['repo_name'])
320 new_name = cur_repo.get_new_name(kwargs['repo_name'])
321 cur_repo.repo_name = new_name
321 cur_repo.repo_name = new_name
322 #if private flag is set, reset default permission to NONE
322 #if private flag is set, reset default permission to NONE
323
323
324 if kwargs.get('repo_private'):
324 if kwargs.get('repo_private'):
325 EMPTY_PERM = 'repository.none'
325 EMPTY_PERM = 'repository.none'
326 RepoModel().grant_user_permission(
326 RepoModel().grant_user_permission(
327 repo=cur_repo, user='default', perm=EMPTY_PERM
327 repo=cur_repo, user='default', perm=EMPTY_PERM
328 )
328 )
329 #handle extra fields
329 #handle extra fields
330 for field in filter(lambda k: k.startswith(RepositoryField.PREFIX), kwargs):
330 for field in filter(lambda k: k.startswith(RepositoryField.PREFIX), kwargs):
331 k = RepositoryField.un_prefix_key(field)
331 k = RepositoryField.un_prefix_key(field)
332 ex_field = RepositoryField.get_by_key_name(key=k, repo=cur_repo)
332 ex_field = RepositoryField.get_by_key_name(key=k, repo=cur_repo)
333 if ex_field:
333 if ex_field:
334 ex_field.field_value = kwargs[field]
334 ex_field.field_value = kwargs[field]
335 self.sa.add(ex_field)
335 self.sa.add(ex_field)
336 self.sa.add(cur_repo)
336 self.sa.add(cur_repo)
337
337
338 if org_repo_name != new_name:
338 if org_repo_name != new_name:
339 # rename repository
339 # rename repository
340 self.__rename_repo(old=org_repo_name, new=new_name)
340 self.__rename_repo(old=org_repo_name, new=new_name)
341
341
342 return cur_repo
342 return cur_repo
343 except Exception:
343 except Exception:
344 log.error(traceback.format_exc())
344 log.error(traceback.format_exc())
345 raise
345 raise
346
346
347 def create_repo(self, repo_name, repo_type, description, owner,
347 def create_repo(self, repo_name, repo_type, description, owner,
348 private=False, clone_uri=None, repos_group=None,
348 private=False, clone_uri=None, repos_group=None,
349 landing_rev='tip', just_db=False, fork_of=None,
349 landing_rev='tip', just_db=False, fork_of=None,
350 copy_fork_permissions=False, enable_statistics=False,
350 copy_fork_permissions=False, enable_statistics=False,
351 enable_locking=False, enable_downloads=False):
351 enable_locking=False, enable_downloads=False):
352 """
352 """
353 Create repository
353 Create repository
354
354
355 """
355 """
356 from rhodecode.model.scm import ScmModel
356 from rhodecode.model.scm import ScmModel
357
357
358 owner = self._get_user(owner)
358 owner = self._get_user(owner)
359 fork_of = self._get_repo(fork_of)
359 fork_of = self._get_repo(fork_of)
360 repos_group = self._get_repo_group(repos_group)
360 repos_group = self._get_repo_group(repos_group)
361 try:
361 try:
362
362
363 # repo name is just a name of repository
363 # repo name is just a name of repository
364 # while repo_name_full is a full qualified name that is combined
364 # while repo_name_full is a full qualified name that is combined
365 # with name and path of group
365 # with name and path of group
366 repo_name_full = repo_name
366 repo_name_full = repo_name
367 repo_name = repo_name.split(self.URL_SEPARATOR)[-1]
367 repo_name = repo_name.split(self.URL_SEPARATOR)[-1]
368
368
369 new_repo = Repository()
369 new_repo = Repository()
370 new_repo.enable_statistics = False
370 new_repo.enable_statistics = False
371 new_repo.repo_name = repo_name_full
371 new_repo.repo_name = repo_name_full
372 new_repo.repo_type = repo_type
372 new_repo.repo_type = repo_type
373 new_repo.user = owner
373 new_repo.user = owner
374 new_repo.group = repos_group
374 new_repo.group = repos_group
375 new_repo.description = description or repo_name
375 new_repo.description = description or repo_name
376 new_repo.private = private
376 new_repo.private = private
377 new_repo.clone_uri = clone_uri
377 new_repo.clone_uri = clone_uri
378 new_repo.landing_rev = landing_rev
378 new_repo.landing_rev = landing_rev
379
379
380 new_repo.enable_statistics = enable_statistics
380 new_repo.enable_statistics = enable_statistics
381 new_repo.enable_locking = enable_locking
381 new_repo.enable_locking = enable_locking
382 new_repo.enable_downloads = enable_downloads
382 new_repo.enable_downloads = enable_downloads
383
383
384 if repos_group:
384 if repos_group:
385 new_repo.enable_locking = repos_group.enable_locking
385 new_repo.enable_locking = repos_group.enable_locking
386
386
387 if fork_of:
387 if fork_of:
388 parent_repo = fork_of
388 parent_repo = fork_of
389 new_repo.fork = parent_repo
389 new_repo.fork = parent_repo
390
390
391 self.sa.add(new_repo)
391 self.sa.add(new_repo)
392
392
393 if fork_of:
393 if fork_of:
394 if copy_fork_permissions:
394 if copy_fork_permissions:
395 repo = fork_of
395 repo = fork_of
396 user_perms = UserRepoToPerm.query()\
396 user_perms = UserRepoToPerm.query()\
397 .filter(UserRepoToPerm.repository == repo).all()
397 .filter(UserRepoToPerm.repository == repo).all()
398 group_perms = UserGroupRepoToPerm.query()\
398 group_perms = UserGroupRepoToPerm.query()\
399 .filter(UserGroupRepoToPerm.repository == repo).all()
399 .filter(UserGroupRepoToPerm.repository == repo).all()
400
400
401 for perm in user_perms:
401 for perm in user_perms:
402 UserRepoToPerm.create(perm.user, new_repo,
402 UserRepoToPerm.create(perm.user, new_repo,
403 perm.permission)
403 perm.permission)
404
404
405 for perm in group_perms:
405 for perm in group_perms:
406 UserGroupRepoToPerm.create(perm.users_group, new_repo,
406 UserGroupRepoToPerm.create(perm.users_group, new_repo,
407 perm.permission)
407 perm.permission)
408 else:
408 else:
409 perm_obj = self._create_default_perms(new_repo, private)
409 perm_obj = self._create_default_perms(new_repo, private)
410 self.sa.add(perm_obj)
410 self.sa.add(perm_obj)
411 else:
411 else:
412 perm_obj = self._create_default_perms(new_repo, private)
412 perm_obj = self._create_default_perms(new_repo, private)
413 self.sa.add(perm_obj)
413 self.sa.add(perm_obj)
414
414
415 if not just_db:
415 if not just_db:
416 self.__create_repo(repo_name, repo_type,
416 self.__create_repo(repo_name, repo_type,
417 repos_group,
417 repos_group,
418 clone_uri)
418 clone_uri)
419 log_create_repository(new_repo.get_dict(),
419 log_create_repository(new_repo.get_dict(),
420 created_by=owner.username)
420 created_by=owner.username)
421
421
422 # now automatically start following this repository as owner
422 # now automatically start following this repository as owner
423 ScmModel(self.sa).toggle_following_repo(new_repo.repo_id,
423 ScmModel(self.sa).toggle_following_repo(new_repo.repo_id,
424 owner.user_id)
424 owner.user_id)
425 return new_repo
425 return new_repo
426 except Exception:
426 except Exception:
427 log.error(traceback.format_exc())
427 log.error(traceback.format_exc())
428 raise
428 raise
429
429
430 def create(self, form_data, cur_user, just_db=False, fork=None):
430 def create(self, form_data, cur_user, just_db=False, fork=None):
431 """
431 """
432 Backward compatibility function, just a wrapper on top of create_repo
432 Backward compatibility function, just a wrapper on top of create_repo
433
433
434 :param form_data:
434 :param form_data:
435 :param cur_user:
435 :param cur_user:
436 :param just_db:
436 :param just_db:
437 :param fork:
437 :param fork:
438 """
438 """
439 owner = cur_user
439 owner = cur_user
440 repo_name = form_data['repo_name_full']
440 repo_name = form_data['repo_name_full']
441 repo_type = form_data['repo_type']
441 repo_type = form_data['repo_type']
442 description = form_data['repo_description']
442 description = form_data['repo_description']
443 private = form_data['repo_private']
443 private = form_data['repo_private']
444 clone_uri = form_data.get('clone_uri')
444 clone_uri = form_data.get('clone_uri')
445 repos_group = form_data['repo_group']
445 repos_group = form_data['repo_group']
446 landing_rev = form_data['repo_landing_rev']
446 landing_rev = form_data['repo_landing_rev']
447 copy_fork_permissions = form_data.get('copy_permissions')
447 copy_fork_permissions = form_data.get('copy_permissions')
448 fork_of = form_data.get('fork_parent_id')
448 fork_of = form_data.get('fork_parent_id')
449
449
450 ## repo creation defaults, private and repo_type are filled in form
450 ## repo creation defaults, private and repo_type are filled in form
451 defs = RhodeCodeSetting.get_default_repo_settings(strip_prefix=True)
451 defs = RhodeCodeSetting.get_default_repo_settings(strip_prefix=True)
452 enable_statistics = defs.get('repo_enable_statistics')
452 enable_statistics = defs.get('repo_enable_statistics')
453 enable_locking = defs.get('repo_enable_locking')
453 enable_locking = defs.get('repo_enable_locking')
454 enable_downloads = defs.get('repo_enable_downloads')
454 enable_downloads = defs.get('repo_enable_downloads')
455
455
456 return self.create_repo(
456 return self.create_repo(
457 repo_name, repo_type, description, owner, private, clone_uri,
457 repo_name, repo_type, description, owner, private, clone_uri,
458 repos_group, landing_rev, just_db, fork_of, copy_fork_permissions,
458 repos_group, landing_rev, just_db, fork_of, copy_fork_permissions,
459 enable_statistics, enable_locking, enable_downloads
459 enable_statistics, enable_locking, enable_downloads
460 )
460 )
461
461
462 def _update_permissions(self, repo, perms_new=None, perms_updates=None,
462 def _update_permissions(self, repo, perms_new=None, perms_updates=None,
463 check_perms=True):
463 check_perms=True):
464 if not perms_new:
464 if not perms_new:
465 perms_new = []
465 perms_new = []
466 if not perms_updates:
466 if not perms_updates:
467 perms_updates = []
467 perms_updates = []
468
468
469 # update permissions
469 # update permissions
470 for member, perm, member_type in perms_updates:
470 for member, perm, member_type in perms_updates:
471 if member_type == 'user':
471 if member_type == 'user':
472 # this updates existing one
472 # this updates existing one
473 self.grant_user_permission(
473 self.grant_user_permission(
474 repo=repo, user=member, perm=perm
474 repo=repo, user=member, perm=perm
475 )
475 )
476 else:
476 else:
477 #check if we have permissions to alter this usergroup
477 #check if we have permissions to alter this usergroup
478 req_perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin')
478 req_perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin')
479 if not check_perms or HasUserGroupPermissionAny(*req_perms)(member):
479 if not check_perms or HasUserGroupPermissionAny(*req_perms)(member):
480 self.grant_users_group_permission(
480 self.grant_users_group_permission(
481 repo=repo, group_name=member, perm=perm
481 repo=repo, group_name=member, perm=perm
482 )
482 )
483 # set new permissions
483 # set new permissions
484 for member, perm, member_type in perms_new:
484 for member, perm, member_type in perms_new:
485 if member_type == 'user':
485 if member_type == 'user':
486 self.grant_user_permission(
486 self.grant_user_permission(
487 repo=repo, user=member, perm=perm
487 repo=repo, user=member, perm=perm
488 )
488 )
489 else:
489 else:
490 #check if we have permissions to alter this usergroup
490 #check if we have permissions to alter this usergroup
491 req_perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin')
491 req_perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin')
492 if not check_perms or HasUserGroupPermissionAny(*req_perms)(member):
492 if not check_perms or HasUserGroupPermissionAny(*req_perms)(member):
493 self.grant_users_group_permission(
493 self.grant_users_group_permission(
494 repo=repo, group_name=member, perm=perm
494 repo=repo, group_name=member, perm=perm
495 )
495 )
496
496
497 def create_fork(self, form_data, cur_user):
497 def create_fork(self, form_data, cur_user):
498 """
498 """
499 Simple wrapper into executing celery task for fork creation
499 Simple wrapper into executing celery task for fork creation
500
500
501 :param form_data:
501 :param form_data:
502 :param cur_user:
502 :param cur_user:
503 """
503 """
504 from rhodecode.lib.celerylib import tasks, run_task
504 from rhodecode.lib.celerylib import tasks, run_task
505 run_task(tasks.create_repo_fork, form_data, cur_user)
505 run_task(tasks.create_repo_fork, form_data, cur_user)
506
506
507 def delete(self, repo, forks=None, fs_remove=True):
507 def delete(self, repo, forks=None, fs_remove=True):
508 """
508 """
509 Delete given repository, forks parameter defines what do do with
509 Delete given repository, forks parameter defines what do do with
510 attached forks. Throws AttachedForksError if deleted repo has attached
510 attached forks. Throws AttachedForksError if deleted repo has attached
511 forks
511 forks
512
512
513 :param repo:
513 :param repo:
514 :param forks: str 'delete' or 'detach'
514 :param forks: str 'delete' or 'detach'
515 :param fs_remove: remove(archive) repo from filesystem
515 :param fs_remove: remove(archive) repo from filesystem
516 """
516 """
517 repo = self._get_repo(repo)
517 repo = self._get_repo(repo)
518 if repo:
518 if repo:
519 if forks == 'detach':
519 if forks == 'detach':
520 for r in repo.forks:
520 for r in repo.forks:
521 r.fork = None
521 r.fork = None
522 self.sa.add(r)
522 self.sa.add(r)
523 elif forks == 'delete':
523 elif forks == 'delete':
524 for r in repo.forks:
524 for r in repo.forks:
525 self.delete(r, forks='delete')
525 self.delete(r, forks='delete')
526 elif [f for f in repo.forks]:
526 elif [f for f in repo.forks]:
527 raise AttachedForksError()
527 raise AttachedForksError()
528
528
529 old_repo_dict = repo.get_dict()
529 old_repo_dict = repo.get_dict()
530 owner = repo.user
530 owner = repo.user
531 try:
531 try:
532 self.sa.delete(repo)
532 self.sa.delete(repo)
533 if fs_remove:
533 if fs_remove:
534 self.__delete_repo(repo)
534 self.__delete_repo(repo)
535 else:
535 else:
536 log.debug('skipping removal from filesystem')
536 log.debug('skipping removal from filesystem')
537 log_delete_repository(old_repo_dict,
537 log_delete_repository(old_repo_dict,
538 deleted_by=owner.username)
538 deleted_by=owner.username)
539 except Exception:
539 except Exception:
540 log.error(traceback.format_exc())
540 log.error(traceback.format_exc())
541 raise
541 raise
542
542
543 def grant_user_permission(self, repo, user, perm):
543 def grant_user_permission(self, repo, user, perm):
544 """
544 """
545 Grant permission for user on given repository, or update existing one
545 Grant permission for user on given repository, or update existing one
546 if found
546 if found
547
547
548 :param repo: Instance of Repository, repository_id, or repository name
548 :param repo: Instance of Repository, repository_id, or repository name
549 :param user: Instance of User, user_id or username
549 :param user: Instance of User, user_id or username
550 :param perm: Instance of Permission, or permission_name
550 :param perm: Instance of Permission, or permission_name
551 """
551 """
552 user = self._get_user(user)
552 user = self._get_user(user)
553 repo = self._get_repo(repo)
553 repo = self._get_repo(repo)
554 permission = self._get_perm(perm)
554 permission = self._get_perm(perm)
555
555
556 # check if we have that permission already
556 # check if we have that permission already
557 obj = self.sa.query(UserRepoToPerm)\
557 obj = self.sa.query(UserRepoToPerm)\
558 .filter(UserRepoToPerm.user == user)\
558 .filter(UserRepoToPerm.user == user)\
559 .filter(UserRepoToPerm.repository == repo)\
559 .filter(UserRepoToPerm.repository == repo)\
560 .scalar()
560 .scalar()
561 if obj is None:
561 if obj is None:
562 # create new !
562 # create new !
563 obj = UserRepoToPerm()
563 obj = UserRepoToPerm()
564 obj.repository = repo
564 obj.repository = repo
565 obj.user = user
565 obj.user = user
566 obj.permission = permission
566 obj.permission = permission
567 self.sa.add(obj)
567 self.sa.add(obj)
568 log.debug('Granted perm %s to %s on %s' % (perm, user, repo))
568 log.debug('Granted perm %s to %s on %s' % (perm, user, repo))
569
569
570 def revoke_user_permission(self, repo, user):
570 def revoke_user_permission(self, repo, user):
571 """
571 """
572 Revoke permission for user on given repository
572 Revoke permission for user on given repository
573
573
574 :param repo: Instance of Repository, repository_id, or repository name
574 :param repo: Instance of Repository, repository_id, or repository name
575 :param user: Instance of User, user_id or username
575 :param user: Instance of User, user_id or username
576 """
576 """
577
577
578 user = self._get_user(user)
578 user = self._get_user(user)
579 repo = self._get_repo(repo)
579 repo = self._get_repo(repo)
580
580
581 obj = self.sa.query(UserRepoToPerm)\
581 obj = self.sa.query(UserRepoToPerm)\
582 .filter(UserRepoToPerm.repository == repo)\
582 .filter(UserRepoToPerm.repository == repo)\
583 .filter(UserRepoToPerm.user == user)\
583 .filter(UserRepoToPerm.user == user)\
584 .scalar()
584 .scalar()
585 if obj:
585 if obj:
586 self.sa.delete(obj)
586 self.sa.delete(obj)
587 log.debug('Revoked perm on %s on %s' % (repo, user))
587 log.debug('Revoked perm on %s on %s' % (repo, user))
588
588
589 def grant_users_group_permission(self, repo, group_name, perm):
589 def grant_users_group_permission(self, repo, group_name, perm):
590 """
590 """
591 Grant permission for user group on given repository, or update
591 Grant permission for user group on given repository, or update
592 existing one if found
592 existing one if found
593
593
594 :param repo: Instance of Repository, repository_id, or repository name
594 :param repo: Instance of Repository, repository_id, or repository name
595 :param group_name: Instance of UserGroup, users_group_id,
595 :param group_name: Instance of UserGroup, users_group_id,
596 or user group name
596 or user group name
597 :param perm: Instance of Permission, or permission_name
597 :param perm: Instance of Permission, or permission_name
598 """
598 """
599 repo = self._get_repo(repo)
599 repo = self._get_repo(repo)
600 group_name = self._get_user_group(group_name)
600 group_name = self._get_user_group(group_name)
601 permission = self._get_perm(perm)
601 permission = self._get_perm(perm)
602
602
603 # check if we have that permission already
603 # check if we have that permission already
604 obj = self.sa.query(UserGroupRepoToPerm)\
604 obj = self.sa.query(UserGroupRepoToPerm)\
605 .filter(UserGroupRepoToPerm.users_group == group_name)\
605 .filter(UserGroupRepoToPerm.users_group == group_name)\
606 .filter(UserGroupRepoToPerm.repository == repo)\
606 .filter(UserGroupRepoToPerm.repository == repo)\
607 .scalar()
607 .scalar()
608
608
609 if obj is None:
609 if obj is None:
610 # create new
610 # create new
611 obj = UserGroupRepoToPerm()
611 obj = UserGroupRepoToPerm()
612
612
613 obj.repository = repo
613 obj.repository = repo
614 obj.users_group = group_name
614 obj.users_group = group_name
615 obj.permission = permission
615 obj.permission = permission
616 self.sa.add(obj)
616 self.sa.add(obj)
617 log.debug('Granted perm %s to %s on %s' % (perm, group_name, repo))
617 log.debug('Granted perm %s to %s on %s' % (perm, group_name, repo))
618
618
619 def revoke_users_group_permission(self, repo, group_name):
619 def revoke_users_group_permission(self, repo, group_name):
620 """
620 """
621 Revoke permission for user group on given repository
621 Revoke permission for user group on given repository
622
622
623 :param repo: Instance of Repository, repository_id, or repository name
623 :param repo: Instance of Repository, repository_id, or repository name
624 :param group_name: Instance of UserGroup, users_group_id,
624 :param group_name: Instance of UserGroup, users_group_id,
625 or user group name
625 or user group name
626 """
626 """
627 repo = self._get_repo(repo)
627 repo = self._get_repo(repo)
628 group_name = self._get_user_group(group_name)
628 group_name = self._get_user_group(group_name)
629
629
630 obj = self.sa.query(UserGroupRepoToPerm)\
630 obj = self.sa.query(UserGroupRepoToPerm)\
631 .filter(UserGroupRepoToPerm.repository == repo)\
631 .filter(UserGroupRepoToPerm.repository == repo)\
632 .filter(UserGroupRepoToPerm.users_group == group_name)\
632 .filter(UserGroupRepoToPerm.users_group == group_name)\
633 .scalar()
633 .scalar()
634 if obj:
634 if obj:
635 self.sa.delete(obj)
635 self.sa.delete(obj)
636 log.debug('Revoked perm to %s on %s' % (repo, group_name))
636 log.debug('Revoked perm to %s on %s' % (repo, group_name))
637
637
638 def delete_stats(self, repo_name):
638 def delete_stats(self, repo_name):
639 """
639 """
640 removes stats for given repo
640 removes stats for given repo
641
641
642 :param repo_name:
642 :param repo_name:
643 """
643 """
644 repo = self._get_repo(repo_name)
644 repo = self._get_repo(repo_name)
645 try:
645 try:
646 obj = self.sa.query(Statistics)\
646 obj = self.sa.query(Statistics)\
647 .filter(Statistics.repository == repo).scalar()
647 .filter(Statistics.repository == repo).scalar()
648 if obj:
648 if obj:
649 self.sa.delete(obj)
649 self.sa.delete(obj)
650 except Exception:
650 except Exception:
651 log.error(traceback.format_exc())
651 log.error(traceback.format_exc())
652 raise
652 raise
653
653
654 def _create_repo(self, repo_name, alias, parent, clone_uri=False,
654 def _create_repo(self, repo_name, alias, parent, clone_uri=False,
655 repo_store_location=None):
655 repo_store_location=None):
656 return self.__create_repo(repo_name, alias, parent, clone_uri,
656 return self.__create_repo(repo_name, alias, parent, clone_uri,
657 repo_store_location)
657 repo_store_location)
658
658
659 def __create_repo(self, repo_name, alias, parent, clone_uri=False,
659 def __create_repo(self, repo_name, alias, parent, clone_uri=False,
660 repo_store_location=None):
660 repo_store_location=None):
661 """
661 """
662 makes repository on filesystem. It's group aware means it'll create
662 makes repository on filesystem. It's group aware means it'll create
663 a repository within a group, and alter the paths accordingly of
663 a repository within a group, and alter the paths accordingly of
664 group location
664 group location
665
665
666 :param repo_name:
666 :param repo_name:
667 :param alias:
667 :param alias:
668 :param parent_id:
668 :param parent_id:
669 :param clone_uri:
669 :param clone_uri:
670 :param repo_path:
670 :param repo_path:
671 """
671 """
672 from rhodecode.lib.utils import is_valid_repo, is_valid_repos_group
672 from rhodecode.lib.utils import is_valid_repo, is_valid_repos_group
673 from rhodecode.model.scm import ScmModel
673 from rhodecode.model.scm import ScmModel
674
674
675 if parent:
675 if parent:
676 new_parent_path = os.sep.join(parent.full_path_splitted)
676 new_parent_path = os.sep.join(parent.full_path_splitted)
677 else:
677 else:
678 new_parent_path = ''
678 new_parent_path = ''
679 if repo_store_location:
679 if repo_store_location:
680 _paths = [repo_store_location]
680 _paths = [repo_store_location]
681 else:
681 else:
682 _paths = [self.repos_path, new_parent_path, repo_name]
682 _paths = [self.repos_path, new_parent_path, repo_name]
683 # we need to make it str for mercurial
683 # we need to make it str for mercurial
684 repo_path = os.path.join(*map(lambda x: safe_str(x), _paths))
684 repo_path = os.path.join(*map(lambda x: safe_str(x), _paths))
685
685
686 # check if this path is not a repository
686 # check if this path is not a repository
687 if is_valid_repo(repo_path, self.repos_path):
687 if is_valid_repo(repo_path, self.repos_path):
688 raise Exception('This path %s is a valid repository' % repo_path)
688 raise Exception('This path %s is a valid repository' % repo_path)
689
689
690 # check if this path is a group
690 # check if this path is a group
691 if is_valid_repos_group(repo_path, self.repos_path):
691 if is_valid_repos_group(repo_path, self.repos_path):
692 raise Exception('This path %s is a valid group' % repo_path)
692 raise Exception('This path %s is a valid group' % repo_path)
693
693
694 log.info('creating repo %s in %s @ %s' % (
694 log.info('creating repo %s in %s @ %s' % (
695 repo_name, safe_unicode(repo_path),
695 repo_name, safe_unicode(repo_path),
696 obfuscate_url_pw(clone_uri)
696 obfuscate_url_pw(clone_uri)
697 )
697 )
698 )
698 )
699 backend = get_backend(alias)
699 backend = get_backend(alias)
700 if alias == 'hg':
700 if alias == 'hg':
701 repo = backend(repo_path, create=True, src_url=clone_uri)
701 repo = backend(repo_path, create=True, src_url=clone_uri)
702 elif alias == 'git':
702 elif alias == 'git':
703 repo = backend(repo_path, create=True, src_url=clone_uri, bare=True)
703 repo = backend(repo_path, create=True, src_url=clone_uri, bare=True)
704 # add rhodecode hook into this repo
704 # add rhodecode hook into this repo
705 ScmModel().install_git_hook(repo=repo)
705 ScmModel().install_git_hook(repo=repo)
706 else:
706 else:
707 raise Exception('Undefined alias %s' % alias)
707 raise Exception('Undefined alias %s' % alias)
708 return repo
708 return repo
709
709
710 def __rename_repo(self, old, new):
710 def __rename_repo(self, old, new):
711 """
711 """
712 renames repository on filesystem
712 renames repository on filesystem
713
713
714 :param old: old name
714 :param old: old name
715 :param new: new name
715 :param new: new name
716 """
716 """
717 log.info('renaming repo from %s to %s' % (old, new))
717 log.info('renaming repo from %s to %s' % (old, new))
718
718
719 old_path = os.path.join(self.repos_path, old)
719 old_path = os.path.join(self.repos_path, old)
720 new_path = os.path.join(self.repos_path, new)
720 new_path = os.path.join(self.repos_path, new)
721 if os.path.isdir(new_path):
721 if os.path.isdir(new_path):
722 raise Exception(
722 raise Exception(
723 'Was trying to rename to already existing dir %s' % new_path
723 'Was trying to rename to already existing dir %s' % new_path
724 )
724 )
725 shutil.move(old_path, new_path)
725 shutil.move(old_path, new_path)
726
726
727 def __delete_repo(self, repo):
727 def __delete_repo(self, repo):
728 """
728 """
729 removes repo from filesystem, the removal is acctually made by
729 removes repo from filesystem, the removal is acctually made by
730 added rm__ prefix into dir, and rename internat .hg/.git dirs so this
730 added rm__ prefix into dir, and rename internat .hg/.git dirs so this
731 repository is no longer valid for rhodecode, can be undeleted later on
731 repository is no longer valid for rhodecode, can be undeleted later on
732 by reverting the renames on this repository
732 by reverting the renames on this repository
733
733
734 :param repo: repo object
734 :param repo: repo object
735 """
735 """
736 rm_path = os.path.join(self.repos_path, repo.repo_name)
736 rm_path = os.path.join(self.repos_path, repo.repo_name)
737 log.info("Removing %s" % (rm_path))
737 log.info("Removing %s" % (rm_path))
738 # disable hg/git internal that it doesn't get detected as repo
738 # disable hg/git internal that it doesn't get detected as repo
739 alias = repo.repo_type
739 alias = repo.repo_type
740
740
741 bare = getattr(repo.scm_instance, 'bare', False)
741 bare = getattr(repo.scm_instance, 'bare', False)
742
742
743 if not bare:
743 if not bare:
744 # skip this for bare git repos
744 # skip this for bare git repos
745 shutil.move(os.path.join(rm_path, '.%s' % alias),
745 shutil.move(os.path.join(rm_path, '.%s' % alias),
746 os.path.join(rm_path, 'rm__.%s' % alias))
746 os.path.join(rm_path, 'rm__.%s' % alias))
747 # disable repo
747 # disable repo
748 _now = datetime.now()
748 _now = datetime.now()
749 _ms = str(_now.microsecond).rjust(6, '0')
749 _ms = str(_now.microsecond).rjust(6, '0')
750 _d = 'rm__%s__%s' % (_now.strftime('%Y%m%d_%H%M%S_' + _ms),
750 _d = 'rm__%s__%s' % (_now.strftime('%Y%m%d_%H%M%S_' + _ms),
751 repo.just_name)
751 repo.just_name)
752 if repo.group:
752 if repo.group:
753 args = repo.group.full_path_splitted + [_d]
753 args = repo.group.full_path_splitted + [_d]
754 _d = os.path.join(*args)
754 _d = os.path.join(*args)
755 shutil.move(rm_path, os.path.join(self.repos_path, _d))
755 shutil.move(rm_path, os.path.join(self.repos_path, _d))
@@ -1,395 +1,387 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 ##
2 ##
3 ## See also repo_settings.html
3 ## See also repo_settings.html
4 ##
4 ##
5 <%inherit file="/base/base.html"/>
5 <%inherit file="/base/base.html"/>
6
6
7 <%def name="title()">
7 <%def name="title()">
8 ${_('Edit repository')} ${c.repo_info.repo_name} &middot; ${c.rhodecode_name}
8 ${_('Edit repository')} ${c.repo_info.repo_name} &middot; ${c.rhodecode_name}
9 </%def>
9 </%def>
10
10
11 <%def name="breadcrumbs_links()">
11 <%def name="breadcrumbs_links()">
12 ${_('Settings')}
12 ${_('Settings')}
13 </%def>
13 </%def>
14
14
15 <%def name="page_nav()">
15 <%def name="page_nav()">
16 ${self.menu('admin')}
16 ${self.menu('admin')}
17 </%def>
17 </%def>
18
18
19 <%def name="main()">
19 <%def name="main()">
20 ${self.context_bar('options')}
20 ${self.context_bar('options')}
21 <div class="box box-left">
21 <div class="box box-left">
22 <!-- box / title -->
22 <!-- box / title -->
23 <div class="title">
23 <div class="title">
24 ${self.breadcrumbs()}
24 ${self.breadcrumbs()}
25 </div>
25 </div>
26 ${h.form(url('repo', repo_name=c.repo_info.repo_name),method='put')}
26 ${h.form(url('repo', repo_name=c.repo_info.repo_name),method='put')}
27 <div class="form">
27 <div class="form">
28 <!-- fields -->
28 <!-- fields -->
29 <div class="fields">
29 <div class="fields">
30 <div class="field">
30 <div class="field">
31 <div class="label">
31 <div class="label">
32 <label for="repo_name">${_('Name')}:</label>
32 <label for="repo_name">${_('Name')}:</label>
33 </div>
33 </div>
34 <div class="input">
34 <div class="input">
35 ${h.text('repo_name',class_="medium")}
35 ${h.text('repo_name',class_="medium")}
36 </div>
36 </div>
37 </div>
37 </div>
38 <div class="field">
38 <div class="field">
39 <div class="label">
39 <div class="label">
40 <label for="clone_uri">${_('Clone uri')}:</label>
40 <label for="clone_uri">${_('Clone uri')}:</label>
41 </div>
41 </div>
42 <div class="input">
42 <div class="input">
43 ${h.text('clone_uri',class_="medium")}
43 ${h.text('clone_uri',class_="medium")}
44 <span class="help-block">${_('Optional http[s] url from which repository should be cloned.')}</span>
44 <span class="help-block">${_('Optional http[s] url from which repository should be cloned.')}</span>
45 </div>
45 </div>
46 </div>
46 </div>
47 <div class="field">
47 <div class="field">
48 <div class="label">
48 <div class="label">
49 <label for="repo_group">${_('Repository group')}:</label>
49 <label for="repo_group">${_('Repository group')}:</label>
50 </div>
50 </div>
51 <div class="input">
51 <div class="input">
52 ${h.select('repo_group','',c.repo_groups,class_="medium")}
52 ${h.select('repo_group','',c.repo_groups,class_="medium")}
53 <span class="help-block">${_('Optional select a group to put this repository into.')}</span>
53 <span class="help-block">${_('Optional select a group to put this repository into.')}</span>
54 </div>
54 </div>
55 </div>
55 </div>
56 <div class="field">
56 <div class="field">
57 <div class="label">
57 <div class="label">
58 <label for="repo_type">${_('Type')}:</label>
59 </div>
60 <div class="input">
61 ${h.select('repo_type','hg',c.backends,class_="medium")}
62 </div>
63 </div>
64 <div class="field">
65 <div class="label">
66 <label for="repo_landing_rev">${_('Landing revision')}:</label>
58 <label for="repo_landing_rev">${_('Landing revision')}:</label>
67 </div>
59 </div>
68 <div class="input">
60 <div class="input">
69 ${h.select('repo_landing_rev','',c.landing_revs,class_="medium")}
61 ${h.select('repo_landing_rev','',c.landing_revs,class_="medium")}
70 <span class="help-block">${_('Default revision for files page, downloads, whoosh and readme')}</span>
62 <span class="help-block">${_('Default revision for files page, downloads, whoosh and readme')}</span>
71 </div>
63 </div>
72 </div>
64 </div>
73 <div class="field">
65 <div class="field">
74 <div class="label label-textarea">
66 <div class="label label-textarea">
75 <label for="repo_description">${_('Description')}:</label>
67 <label for="repo_description">${_('Description')}:</label>
76 </div>
68 </div>
77 <div class="textarea text-area editor">
69 <div class="textarea text-area editor">
78 ${h.textarea('repo_description')}
70 ${h.textarea('repo_description')}
79 <span class="help-block">${_('Keep it short and to the point. Use a README file for longer descriptions.')}</span>
71 <span class="help-block">${_('Keep it short and to the point. Use a README file for longer descriptions.')}</span>
80 </div>
72 </div>
81 </div>
73 </div>
82
74
83 <div class="field">
75 <div class="field">
84 <div class="label label-checkbox">
76 <div class="label label-checkbox">
85 <label for="repo_private">${_('Private repository')}:</label>
77 <label for="repo_private">${_('Private repository')}:</label>
86 </div>
78 </div>
87 <div class="checkboxes">
79 <div class="checkboxes">
88 ${h.checkbox('repo_private',value="True")}
80 ${h.checkbox('repo_private',value="True")}
89 <span class="help-block">${_('Private repositories are only visible to people explicitly added as collaborators.')}</span>
81 <span class="help-block">${_('Private repositories are only visible to people explicitly added as collaborators.')}</span>
90 </div>
82 </div>
91 </div>
83 </div>
92 <div class="field">
84 <div class="field">
93 <div class="label label-checkbox">
85 <div class="label label-checkbox">
94 <label for="repo_enable_statistics">${_('Enable statistics')}:</label>
86 <label for="repo_enable_statistics">${_('Enable statistics')}:</label>
95 </div>
87 </div>
96 <div class="checkboxes">
88 <div class="checkboxes">
97 ${h.checkbox('repo_enable_statistics',value="True")}
89 ${h.checkbox('repo_enable_statistics',value="True")}
98 <span class="help-block">${_('Enable statistics window on summary page.')}</span>
90 <span class="help-block">${_('Enable statistics window on summary page.')}</span>
99 </div>
91 </div>
100 </div>
92 </div>
101 <div class="field">
93 <div class="field">
102 <div class="label label-checkbox">
94 <div class="label label-checkbox">
103 <label for="repo_enable_downloads">${_('Enable downloads')}:</label>
95 <label for="repo_enable_downloads">${_('Enable downloads')}:</label>
104 </div>
96 </div>
105 <div class="checkboxes">
97 <div class="checkboxes">
106 ${h.checkbox('repo_enable_downloads',value="True")}
98 ${h.checkbox('repo_enable_downloads',value="True")}
107 <span class="help-block">${_('Enable download menu on summary page.')}</span>
99 <span class="help-block">${_('Enable download menu on summary page.')}</span>
108 </div>
100 </div>
109 </div>
101 </div>
110 <div class="field">
102 <div class="field">
111 <div class="label label-checkbox">
103 <div class="label label-checkbox">
112 <label for="repo_enable_locking">${_('Enable locking')}:</label>
104 <label for="repo_enable_locking">${_('Enable locking')}:</label>
113 </div>
105 </div>
114 <div class="checkboxes">
106 <div class="checkboxes">
115 ${h.checkbox('repo_enable_locking',value="True")}
107 ${h.checkbox('repo_enable_locking',value="True")}
116 <span class="help-block">${_('Enable lock-by-pulling on repository.')}</span>
108 <span class="help-block">${_('Enable lock-by-pulling on repository.')}</span>
117 </div>
109 </div>
118 </div>
110 </div>
119 <div class="field">
111 <div class="field">
120 <div class="label">
112 <div class="label">
121 <label for="user">${_('Owner')}:</label>
113 <label for="user">${_('Owner')}:</label>
122 </div>
114 </div>
123 <div class="input input-medium ac">
115 <div class="input input-medium ac">
124 <div class="perm_ac">
116 <div class="perm_ac">
125 ${h.text('user',class_='yui-ac-input')}
117 ${h.text('user',class_='yui-ac-input')}
126 <span class="help-block">${_('Change owner of this repository.')}</span>
118 <span class="help-block">${_('Change owner of this repository.')}</span>
127 <div id="owner_container"></div>
119 <div id="owner_container"></div>
128 </div>
120 </div>
129 </div>
121 </div>
130 </div>
122 </div>
131 %if c.visual.repository_fields:
123 %if c.visual.repository_fields:
132 ## EXTRA FIELDS
124 ## EXTRA FIELDS
133 %for field in c.repo_fields:
125 %for field in c.repo_fields:
134 <div class="field">
126 <div class="field">
135 <div class="label">
127 <div class="label">
136 <label for="${field.field_key_prefixed}">${field.field_label} (${field.field_key}):</label>
128 <label for="${field.field_key_prefixed}">${field.field_label} (${field.field_key}):</label>
137 </div>
129 </div>
138 <div class="input input-medium">
130 <div class="input input-medium">
139 ${h.text(field.field_key_prefixed, field.field_value, class_='medium')}
131 ${h.text(field.field_key_prefixed, field.field_value, class_='medium')}
140 %if field.field_desc:
132 %if field.field_desc:
141 <span class="help-block">${field.field_desc}</span>
133 <span class="help-block">${field.field_desc}</span>
142 %endif
134 %endif
143 </div>
135 </div>
144 </div>
136 </div>
145 %endfor
137 %endfor
146 %endif
138 %endif
147 <div class="buttons">
139 <div class="buttons">
148 ${h.submit('save',_('Save'),class_="ui-btn large")}
140 ${h.submit('save',_('Save'),class_="ui-btn large")}
149 ${h.reset('reset',_('Reset'),class_="ui-btn large")}
141 ${h.reset('reset',_('Reset'),class_="ui-btn large")}
150 </div>
142 </div>
151 </div>
143 </div>
152 </div>
144 </div>
153 ${h.end_form()}
145 ${h.end_form()}
154 </div>
146 </div>
155
147
156 <div class="box box-right">
148 <div class="box box-right">
157 <div class="title">
149 <div class="title">
158 <h5>${_('Permissions')}</h5>
150 <h5>${_('Permissions')}</h5>
159 </div>
151 </div>
160 ${h.form(url('set_repo_perm_member', repo_name=c.repo_info.repo_name),method='post')}
152 ${h.form(url('set_repo_perm_member', repo_name=c.repo_info.repo_name),method='post')}
161 <div class="form">
153 <div class="form">
162 <div class="fields">
154 <div class="fields">
163 <div class="field">
155 <div class="field">
164 <div class="label">
156 <div class="label">
165 <label for="input">${_('Permissions')}:</label>
157 <label for="input">${_('Permissions')}:</label>
166 </div>
158 </div>
167 <div class="input">
159 <div class="input">
168 ${h.hidden('repo_private')}
160 ${h.hidden('repo_private')}
169 <%include file="repo_edit_perms.html"/>
161 <%include file="repo_edit_perms.html"/>
170 </div>
162 </div>
171 </div>
163 </div>
172 <div class="buttons">
164 <div class="buttons">
173 ${h.submit('save',_('Save'),class_="ui-btn large")}
165 ${h.submit('save',_('Save'),class_="ui-btn large")}
174 ${h.reset('reset',_('Reset'),class_="ui-btn large")}
166 ${h.reset('reset',_('Reset'),class_="ui-btn large")}
175 </div>
167 </div>
176 </div>
168 </div>
177 </div>
169 </div>
178 ${h.end_form()}
170 ${h.end_form()}
179 </div>
171 </div>
180
172
181
173
182 <div class="box box-right" style="clear:right">
174 <div class="box box-right" style="clear:right">
183 <div class="title">
175 <div class="title">
184 <h5>${_('Advanced settings')}</h5>
176 <h5>${_('Advanced settings')}</h5>
185 </div>
177 </div>
186
178
187 <h3>${_('Statistics')}</h3>
179 <h3>${_('Statistics')}</h3>
188 ${h.form(url('repo_stats', repo_name=c.repo_info.repo_name),method='delete')}
180 ${h.form(url('repo_stats', repo_name=c.repo_info.repo_name),method='delete')}
189 <div class="form">
181 <div class="form">
190 <div class="fields">
182 <div class="fields">
191 ${h.submit('reset_stats_%s' % c.repo_info.repo_name,_('Reset current statistics'),class_="ui-btn",onclick="return confirm('"+_('Confirm to remove current statistics')+"');")}
183 ${h.submit('reset_stats_%s' % c.repo_info.repo_name,_('Reset current statistics'),class_="ui-btn",onclick="return confirm('"+_('Confirm to remove current statistics')+"');")}
192 <div class="field" style="border:none;color:#888">
184 <div class="field" style="border:none;color:#888">
193 <ul>
185 <ul>
194 <li>${_('Fetched to rev')}: ${c.stats_revision}/${c.repo_last_rev}</li>
186 <li>${_('Fetched to rev')}: ${c.stats_revision}/${c.repo_last_rev}</li>
195 <li>${_('Stats gathered')}: ${c.stats_percentage}%</li>
187 <li>${_('Stats gathered')}: ${c.stats_percentage}%</li>
196 </ul>
188 </ul>
197 </div>
189 </div>
198 </div>
190 </div>
199 </div>
191 </div>
200 ${h.end_form()}
192 ${h.end_form()}
201
193
202 %if c.repo_info.clone_uri:
194 %if c.repo_info.clone_uri:
203 <h3>${_('Remote')}</h3>
195 <h3>${_('Remote')}</h3>
204 ${h.form(url('repo_pull', repo_name=c.repo_info.repo_name),method='put')}
196 ${h.form(url('repo_pull', repo_name=c.repo_info.repo_name),method='put')}
205 <div class="form">
197 <div class="form">
206 <div class="fields">
198 <div class="fields">
207 ${h.submit('remote_pull_%s' % c.repo_info.repo_name,_('Pull changes from remote location'),class_="ui-btn",onclick="return confirm('"+_('Confirm to pull changes from remote side')+"');")}
199 ${h.submit('remote_pull_%s' % c.repo_info.repo_name,_('Pull changes from remote location'),class_="ui-btn",onclick="return confirm('"+_('Confirm to pull changes from remote side')+"');")}
208 <div class="field" style="border:none">
200 <div class="field" style="border:none">
209 <ul>
201 <ul>
210 <li><a href="${c.repo_info.clone_uri}">${c.repo_info.clone_uri}</a></li>
202 <li><a href="${c.repo_info.clone_uri}">${c.repo_info.clone_uri}</a></li>
211 </ul>
203 </ul>
212 </div>
204 </div>
213 </div>
205 </div>
214 </div>
206 </div>
215 ${h.end_form()}
207 ${h.end_form()}
216 %endif
208 %endif
217
209
218 <h3>${_('Cache')}</h3>
210 <h3>${_('Cache')}</h3>
219 ${h.form(url('repo_cache', repo_name=c.repo_info.repo_name),method='delete')}
211 ${h.form(url('repo_cache', repo_name=c.repo_info.repo_name),method='delete')}
220 <div class="form">
212 <div class="form">
221 <div class="fields">
213 <div class="fields">
222 ${h.submit('reset_cache_%s' % c.repo_info.repo_name,_('Invalidate repository cache'),class_="ui-btn",onclick="return confirm('"+_('Confirm to invalidate repository cache')+"');")}
214 ${h.submit('reset_cache_%s' % c.repo_info.repo_name,_('Invalidate repository cache'),class_="ui-btn",onclick="return confirm('"+_('Confirm to invalidate repository cache')+"');")}
223 <div class="field" style="border:none;color:#888">
215 <div class="field" style="border:none;color:#888">
224 <ul>
216 <ul>
225 <li>${_('Manually invalidate cache for this repository. On first access repository will be cached again')}
217 <li>${_('Manually invalidate cache for this repository. On first access repository will be cached again')}
226 </li>
218 </li>
227 </ul>
219 </ul>
228 </div>
220 </div>
229 <div class="field" style="border:none;">
221 <div class="field" style="border:none;">
230 ${_('List of cached values')}
222 ${_('List of cached values')}
231 <table>
223 <table>
232 <tr>
224 <tr>
233 <th>${_('Prefix')}</th>
225 <th>${_('Prefix')}</th>
234 <th>${_('Key')}</th>
226 <th>${_('Key')}</th>
235 <th>${_('Active')}</th>
227 <th>${_('Active')}</th>
236 </tr>
228 </tr>
237 %for cache in c.repo_info.cache_keys:
229 %for cache in c.repo_info.cache_keys:
238 <tr>
230 <tr>
239 <td>${cache.get_prefix() or '-'}</td>
231 <td>${cache.get_prefix() or '-'}</td>
240 <td>${cache.cache_key}</td>
232 <td>${cache.cache_key}</td>
241 <td>${h.boolicon(cache.cache_active)}</td>
233 <td>${h.boolicon(cache.cache_active)}</td>
242 </tr>
234 </tr>
243 %endfor
235 %endfor
244 </table>
236 </table>
245 </div>
237 </div>
246 </div>
238 </div>
247 </div>
239 </div>
248 ${h.end_form()}
240 ${h.end_form()}
249
241
250 <h3>${_('Public journal')}</h3>
242 <h3>${_('Public journal')}</h3>
251 ${h.form(url('repo_public_journal', repo_name=c.repo_info.repo_name),method='put')}
243 ${h.form(url('repo_public_journal', repo_name=c.repo_info.repo_name),method='put')}
252 <div class="form">
244 <div class="form">
253 ${h.hidden('auth_token',str(h.get_token()))}
245 ${h.hidden('auth_token',str(h.get_token()))}
254 <div class="field">
246 <div class="field">
255 %if c.in_public_journal:
247 %if c.in_public_journal:
256 ${h.submit('set_public_%s' % c.repo_info.repo_name,_('Remove from public journal'),class_="ui-btn")}
248 ${h.submit('set_public_%s' % c.repo_info.repo_name,_('Remove from public journal'),class_="ui-btn")}
257 %else:
249 %else:
258 ${h.submit('set_public_%s' % c.repo_info.repo_name,_('Add to public journal'),class_="ui-btn")}
250 ${h.submit('set_public_%s' % c.repo_info.repo_name,_('Add to public journal'),class_="ui-btn")}
259 %endif
251 %endif
260 </div>
252 </div>
261 <div class="field" style="border:none;color:#888">
253 <div class="field" style="border:none;color:#888">
262 <ul>
254 <ul>
263 <li>${_('All actions made on this repository will be accessible to everyone in public journal')}
255 <li>${_('All actions made on this repository will be accessible to everyone in public journal')}
264 </li>
256 </li>
265 </ul>
257 </ul>
266 </div>
258 </div>
267 </div>
259 </div>
268 ${h.end_form()}
260 ${h.end_form()}
269
261
270 <h3>${_('Locking')}</h3>
262 <h3>${_('Locking')}</h3>
271 ${h.form(url('repo_locking', repo_name=c.repo_info.repo_name),method='put')}
263 ${h.form(url('repo_locking', repo_name=c.repo_info.repo_name),method='put')}
272 <div class="form">
264 <div class="form">
273 <div class="fields">
265 <div class="fields">
274 %if c.repo_info.locked[0]:
266 %if c.repo_info.locked[0]:
275 ${h.submit('set_unlock' ,_('Unlock locked repo'),class_="ui-btn",onclick="return confirm('"+_('Confirm to unlock repository')+"');")}
267 ${h.submit('set_unlock' ,_('Unlock locked repo'),class_="ui-btn",onclick="return confirm('"+_('Confirm to unlock repository')+"');")}
276 ${'Locked by %s on %s' % (h.person_by_id(c.repo_info.locked[0]),h.fmt_date(h.time_to_datetime(c.repo_info.locked[1])))}
268 ${'Locked by %s on %s' % (h.person_by_id(c.repo_info.locked[0]),h.fmt_date(h.time_to_datetime(c.repo_info.locked[1])))}
277 %else:
269 %else:
278 ${h.submit('set_lock',_('Lock repo'),class_="ui-btn",onclick="return confirm('"+_('Confirm to lock repository')+"');")}
270 ${h.submit('set_lock',_('Lock repo'),class_="ui-btn",onclick="return confirm('"+_('Confirm to lock repository')+"');")}
279 ${_('Repository is not locked')}
271 ${_('Repository is not locked')}
280 %endif
272 %endif
281 </div>
273 </div>
282 <div class="field" style="border:none;color:#888">
274 <div class="field" style="border:none;color:#888">
283 <ul>
275 <ul>
284 <li>${_('Force locking on repository. Works only when anonymous access is disabled')}
276 <li>${_('Force locking on repository. Works only when anonymous access is disabled')}
285 </li>
277 </li>
286 </ul>
278 </ul>
287 </div>
279 </div>
288 </div>
280 </div>
289 ${h.end_form()}
281 ${h.end_form()}
290
282
291 <h3>${_('Set as fork of')}</h3>
283 <h3>${_('Set as fork of')}</h3>
292 ${h.form(url('repo_as_fork', repo_name=c.repo_info.repo_name),method='put')}
284 ${h.form(url('repo_as_fork', repo_name=c.repo_info.repo_name),method='put')}
293 <div class="form">
285 <div class="form">
294 <div class="fields">
286 <div class="fields">
295 ${h.select('id_fork_of','',c.repos_list,class_="medium")}
287 ${h.select('id_fork_of','',c.repos_list,class_="medium")}
296 ${h.submit('set_as_fork_%s' % c.repo_info.repo_name,_('Set'),class_="ui-btn",)}
288 ${h.submit('set_as_fork_%s' % c.repo_info.repo_name,_('Set'),class_="ui-btn",)}
297 </div>
289 </div>
298 <div class="field" style="border:none;color:#888">
290 <div class="field" style="border:none;color:#888">
299 <ul>
291 <ul>
300 <li>${_('''Manually set this repository as a fork of another from the list''')}</li>
292 <li>${_('''Manually set this repository as a fork of another from the list''')}</li>
301 </ul>
293 </ul>
302 </div>
294 </div>
303 </div>
295 </div>
304 ${h.end_form()}
296 ${h.end_form()}
305
297
306 <h3>${_('Delete')}</h3>
298 <h3>${_('Delete')}</h3>
307 ${h.form(url('repo', repo_name=c.repo_info.repo_name),method='delete')}
299 ${h.form(url('repo', repo_name=c.repo_info.repo_name),method='delete')}
308 <div class="form">
300 <div class="form">
309 <div class="fields">
301 <div class="fields">
310 <div class="field" style="border:none;color:#888">
302 <div class="field" style="border:none;color:#888">
311 ## <div class="label">
303 ## <div class="label">
312 ## <label for="">${_('Remove repository')}:</label>
304 ## <label for="">${_('Remove repository')}:</label>
313 ## </div>
305 ## </div>
314 <div class="checkboxes">
306 <div class="checkboxes">
315 ${h.submit('remove_%s' % c.repo_info.repo_name,_('Remove this repository'),class_="ui-btn red",onclick="return confirm('"+_('Confirm to delete this repository')+"');")}
307 ${h.submit('remove_%s' % c.repo_info.repo_name,_('Remove this repository'),class_="ui-btn red",onclick="return confirm('"+_('Confirm to delete this repository')+"');")}
316 %if c.repo_info.forks.count():
308 %if c.repo_info.forks.count():
317 - ${ungettext('this repository has %s fork', 'this repository has %s forks', c.repo_info.forks.count()) % c.repo_info.forks.count()}
309 - ${ungettext('this repository has %s fork', 'this repository has %s forks', c.repo_info.forks.count()) % c.repo_info.forks.count()}
318 <input type="radio" name="forks" value="detach_forks" checked="checked"/> <label for="forks">${_('Detach forks')}</label>
310 <input type="radio" name="forks" value="detach_forks" checked="checked"/> <label for="forks">${_('Detach forks')}</label>
319 <input type="radio" name="forks" value="delete_forks" /> <label for="forks">${_('Delete forks')}</label>
311 <input type="radio" name="forks" value="delete_forks" /> <label for="forks">${_('Delete forks')}</label>
320 %endif
312 %endif
321 <ul>
313 <ul>
322 <li>${_('This repository will be renamed in a special way in order to be unaccesible for RhodeCode and VCS systems. If you need to fully delete it from file system please do it manually')}</li>
314 <li>${_('This repository will be renamed in a special way in order to be unaccesible for RhodeCode and VCS systems. If you need to fully delete it from file system please do it manually')}</li>
323 </ul>
315 </ul>
324 </div>
316 </div>
325 </div>
317 </div>
326 </div>
318 </div>
327 </div>
319 </div>
328 ${h.end_form()}
320 ${h.end_form()}
329 </div>
321 </div>
330
322
331 ##TODO: this should be controlled by the VISUAL setting
323 ##TODO: this should be controlled by the VISUAL setting
332 %if c.visual.repository_fields:
324 %if c.visual.repository_fields:
333 <div class="box box-left" style="clear:left">
325 <div class="box box-left" style="clear:left">
334 <!-- box / title -->
326 <!-- box / title -->
335 <div class="title">
327 <div class="title">
336 <h5>${_('Extra fields')}</h5>
328 <h5>${_('Extra fields')}</h5>
337 </div>
329 </div>
338
330
339 <div class="emails_wrap">
331 <div class="emails_wrap">
340 <table class="noborder">
332 <table class="noborder">
341 %for field in c.repo_fields:
333 %for field in c.repo_fields:
342 <tr>
334 <tr>
343 <td>${field.field_label} (${field.field_key})</td>
335 <td>${field.field_label} (${field.field_key})</td>
344 <td>${field.field_type}</td>
336 <td>${field.field_type}</td>
345 <td>
337 <td>
346 ${h.form(url('delete_repo_fields', repo_name=c.repo_info.repo_name, field_id=field.repo_field_id),method='delete')}
338 ${h.form(url('delete_repo_fields', repo_name=c.repo_info.repo_name, field_id=field.repo_field_id),method='delete')}
347 ${h.submit('remove_%s' % field.repo_field_id, _('delete'), id="remove_field_%s" % field.repo_field_id,
339 ${h.submit('remove_%s' % field.repo_field_id, _('delete'), id="remove_field_%s" % field.repo_field_id,
348 class_="delete_icon action_button", onclick="return confirm('"+_('Confirm to delete this field: %s') % field.field_key+"');")}
340 class_="delete_icon action_button", onclick="return confirm('"+_('Confirm to delete this field: %s') % field.field_key+"');")}
349 ${h.end_form()}
341 ${h.end_form()}
350 </td>
342 </td>
351 </tr>
343 </tr>
352 %endfor
344 %endfor
353 </table>
345 </table>
354 </div>
346 </div>
355
347
356 ${h.form(url('create_repo_fields', repo_name=c.repo_info.repo_name),method='put')}
348 ${h.form(url('create_repo_fields', repo_name=c.repo_info.repo_name),method='put')}
357 <div class="form">
349 <div class="form">
358 <!-- fields -->
350 <!-- fields -->
359 <div class="fields">
351 <div class="fields">
360 <div class="field">
352 <div class="field">
361 <div class="label">
353 <div class="label">
362 <label for="new_field_key">${_('New field key')}:</label>
354 <label for="new_field_key">${_('New field key')}:</label>
363 </div>
355 </div>
364 <div class="input">
356 <div class="input">
365 ${h.text('new_field_key', class_='small')}
357 ${h.text('new_field_key', class_='small')}
366 </div>
358 </div>
367 </div>
359 </div>
368 <div class="field">
360 <div class="field">
369 <div class="label">
361 <div class="label">
370 <label for="new_field_label">${_('New field label')}:</label>
362 <label for="new_field_label">${_('New field label')}:</label>
371 </div>
363 </div>
372 <div class="input">
364 <div class="input">
373 ${h.text('new_field_label', class_='small', placeholder=_('Enter short label'))}
365 ${h.text('new_field_label', class_='small', placeholder=_('Enter short label'))}
374 </div>
366 </div>
375 </div>
367 </div>
376
368
377 <div class="field">
369 <div class="field">
378 <div class="label">
370 <div class="label">
379 <label for="new_field_desc">${_('New field description')}:</label>
371 <label for="new_field_desc">${_('New field description')}:</label>
380 </div>
372 </div>
381 <div class="input">
373 <div class="input">
382 ${h.text('new_field_desc', class_='small', placeholder=_('Enter description of a field'))}
374 ${h.text('new_field_desc', class_='small', placeholder=_('Enter description of a field'))}
383 </div>
375 </div>
384 </div>
376 </div>
385
377
386 <div class="buttons">
378 <div class="buttons">
387 ${h.submit('save',_('Add'),class_="ui-btn large")}
379 ${h.submit('save',_('Add'),class_="ui-btn large")}
388 ${h.reset('reset',_('Reset'),class_="ui-btn large")}
380 ${h.reset('reset',_('Reset'),class_="ui-btn large")}
389 </div>
381 </div>
390 </div>
382 </div>
391 </div>
383 </div>
392 ${h.end_form()}
384 ${h.end_form()}
393 </div>
385 </div>
394 %endif
386 %endif
395 </%def>
387 </%def>
General Comments 0
You need to be logged in to leave comments. Login now