##// END OF EJS Templates
implemented #689 Deleting Repositories with Forks Should Be Easier...
marcink -
r3391:f282c81f beta
parent child Browse files
Show More
@@ -1,522 +1,536 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.admin.repos
3 rhodecode.controllers.admin.repos
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Repositories controller for RhodeCode
6 Repositories controller for RhodeCode
7
7
8 :created_on: Apr 7, 2010
8 :created_on: Apr 7, 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
25
26 import logging
26 import logging
27 import traceback
27 import traceback
28 import formencode
28 import formencode
29 from formencode import htmlfill
29 from formencode import htmlfill
30
30
31 from webob.exc import HTTPInternalServerError, HTTPForbidden
31 from webob.exc import HTTPInternalServerError, HTTPForbidden
32 from pylons import request, session, tmpl_context as c, url
32 from pylons import request, session, tmpl_context as c, url
33 from pylons.controllers.util import redirect
33 from pylons.controllers.util import redirect
34 from pylons.i18n.translation import _
34 from pylons.i18n.translation import _
35 from sqlalchemy.exc import IntegrityError
35 from sqlalchemy.exc import IntegrityError
36
36
37 import rhodecode
37 import rhodecode
38 from rhodecode.lib import helpers as h
38 from rhodecode.lib import helpers as h
39 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
39 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
40 HasPermissionAnyDecorator, HasRepoPermissionAllDecorator, NotAnonymous,\
40 HasPermissionAnyDecorator, HasRepoPermissionAllDecorator, NotAnonymous,\
41 HasPermissionAny, HasReposGroupPermissionAny
41 HasPermissionAny, HasReposGroupPermissionAny
42 from rhodecode.lib.base import BaseRepoController, render
42 from rhodecode.lib.base import BaseRepoController, render
43 from rhodecode.lib.utils import invalidate_cache, action_logger, repo_name_slug
43 from rhodecode.lib.utils import invalidate_cache, action_logger, repo_name_slug
44 from rhodecode.lib.helpers import get_token
44 from rhodecode.lib.helpers import get_token
45 from rhodecode.model.meta import Session
45 from rhodecode.model.meta import Session
46 from rhodecode.model.db import User, Repository, UserFollowing, RepoGroup,\
46 from rhodecode.model.db import User, Repository, UserFollowing, RepoGroup,\
47 RhodeCodeSetting, RepositoryField
47 RhodeCodeSetting, RepositoryField
48 from rhodecode.model.forms import RepoForm, RepoFieldForm
48 from rhodecode.model.forms import RepoForm, RepoFieldForm
49 from rhodecode.model.scm import ScmModel, GroupList
49 from rhodecode.model.scm import ScmModel, GroupList
50 from rhodecode.model.repo import RepoModel
50 from rhodecode.model.repo import RepoModel
51 from rhodecode.lib.compat import json
51 from rhodecode.lib.compat import json
52 from sqlalchemy.sql.expression import func
52 from sqlalchemy.sql.expression import func
53
53
54 log = logging.getLogger(__name__)
54 log = logging.getLogger(__name__)
55
55
56
56
57 class ReposController(BaseRepoController):
57 class ReposController(BaseRepoController):
58 """
58 """
59 REST Controller styled on the Atom Publishing Protocol"""
59 REST Controller styled on the Atom Publishing Protocol"""
60 # To properly map this controller, ensure your config/routing.py
60 # To properly map this controller, ensure your config/routing.py
61 # file has a resource setup:
61 # file has a resource setup:
62 # map.resource('repo', 'repos')
62 # map.resource('repo', 'repos')
63
63
64 @LoginRequired()
64 @LoginRequired()
65 def __before__(self):
65 def __before__(self):
66 c.admin_user = session.get('admin_user')
66 c.admin_user = session.get('admin_user')
67 c.admin_username = session.get('admin_username')
67 c.admin_username = session.get('admin_username')
68 super(ReposController, self).__before__()
68 super(ReposController, self).__before__()
69
69
70 def __load_defaults(self):
70 def __load_defaults(self):
71 acl_groups = GroupList(RepoGroup.query().all(),
71 acl_groups = GroupList(RepoGroup.query().all(),
72 perm_set=['group.write', 'group.admin'])
72 perm_set=['group.write', 'group.admin'])
73 c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
73 c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
74 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
74 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
75
75
76 repo_model = RepoModel()
76 repo_model = RepoModel()
77 c.users_array = repo_model.get_users_js()
77 c.users_array = repo_model.get_users_js()
78 c.users_groups_array = repo_model.get_users_groups_js()
78 c.users_groups_array = repo_model.get_users_groups_js()
79 choices, c.landing_revs = ScmModel().get_repo_landing_revs()
79 choices, c.landing_revs = ScmModel().get_repo_landing_revs()
80 c.landing_revs_choices = choices
80 c.landing_revs_choices = choices
81
81
82 def __load_data(self, repo_name=None):
82 def __load_data(self, repo_name=None):
83 """
83 """
84 Load defaults settings for edit, and update
84 Load defaults settings for edit, and update
85
85
86 :param repo_name:
86 :param repo_name:
87 """
87 """
88 self.__load_defaults()
88 self.__load_defaults()
89
89
90 c.repo_info = db_repo = Repository.get_by_repo_name(repo_name)
90 c.repo_info = db_repo = Repository.get_by_repo_name(repo_name)
91 repo = db_repo.scm_instance
91 repo = db_repo.scm_instance
92
92
93 if c.repo_info is None:
93 if c.repo_info is None:
94 h.not_mapped_error(repo_name)
94 h.not_mapped_error(repo_name)
95 return redirect(url('repos'))
95 return redirect(url('repos'))
96
96
97 ##override defaults for exact repo info here git/hg etc
97 ##override defaults for exact repo info here git/hg etc
98 choices, c.landing_revs = ScmModel().get_repo_landing_revs(c.repo_info)
98 choices, c.landing_revs = ScmModel().get_repo_landing_revs(c.repo_info)
99 c.landing_revs_choices = choices
99 c.landing_revs_choices = choices
100
100
101 c.default_user_id = User.get_by_username('default').user_id
101 c.default_user_id = User.get_by_username('default').user_id
102 c.in_public_journal = UserFollowing.query()\
102 c.in_public_journal = UserFollowing.query()\
103 .filter(UserFollowing.user_id == c.default_user_id)\
103 .filter(UserFollowing.user_id == c.default_user_id)\
104 .filter(UserFollowing.follows_repository == c.repo_info).scalar()
104 .filter(UserFollowing.follows_repository == c.repo_info).scalar()
105
105
106 if c.repo_info.stats:
106 if c.repo_info.stats:
107 # this is on what revision we ended up so we add +1 for count
107 # this is on what revision we ended up so we add +1 for count
108 last_rev = c.repo_info.stats.stat_on_revision + 1
108 last_rev = c.repo_info.stats.stat_on_revision + 1
109 else:
109 else:
110 last_rev = 0
110 last_rev = 0
111 c.stats_revision = last_rev
111 c.stats_revision = last_rev
112
112
113 c.repo_last_rev = repo.count() if repo.revisions else 0
113 c.repo_last_rev = repo.count() if repo.revisions else 0
114
114
115 if last_rev == 0 or c.repo_last_rev == 0:
115 if last_rev == 0 or c.repo_last_rev == 0:
116 c.stats_percentage = 0
116 c.stats_percentage = 0
117 else:
117 else:
118 c.stats_percentage = '%.2f' % ((float((last_rev)) /
118 c.stats_percentage = '%.2f' % ((float((last_rev)) /
119 c.repo_last_rev) * 100)
119 c.repo_last_rev) * 100)
120
120
121 c.repo_fields = RepositoryField.query()\
121 c.repo_fields = RepositoryField.query()\
122 .filter(RepositoryField.repository == db_repo).all()
122 .filter(RepositoryField.repository == db_repo).all()
123
123
124 defaults = RepoModel()._get_defaults(repo_name)
124 defaults = RepoModel()._get_defaults(repo_name)
125
125
126 c.repos_list = [('', _('--REMOVE FORK--'))]
126 c.repos_list = [('', _('--REMOVE FORK--'))]
127 c.repos_list += [(x.repo_id, x.repo_name) for x in
127 c.repos_list += [(x.repo_id, x.repo_name) for x in
128 Repository.query().order_by(Repository.repo_name).all()
128 Repository.query().order_by(Repository.repo_name).all()
129 if x.repo_id != c.repo_info.repo_id]
129 if x.repo_id != c.repo_info.repo_id]
130
130
131 defaults['id_fork_of'] = db_repo.fork.repo_id if db_repo.fork else ''
131 defaults['id_fork_of'] = db_repo.fork.repo_id if db_repo.fork else ''
132 return defaults
132 return defaults
133
133
134 @HasPermissionAllDecorator('hg.admin')
134 @HasPermissionAllDecorator('hg.admin')
135 def index(self, format='html'):
135 def index(self, format='html'):
136 """GET /repos: All items in the collection"""
136 """GET /repos: All items in the collection"""
137 # url('repos')
137 # url('repos')
138
138
139 c.repos_list = Repository.query()\
139 c.repos_list = Repository.query()\
140 .order_by(func.lower(Repository.repo_name))\
140 .order_by(func.lower(Repository.repo_name))\
141 .all()
141 .all()
142
142
143 repos_data = RepoModel().get_repos_as_dict(repos_list=c.repos_list,
143 repos_data = RepoModel().get_repos_as_dict(repos_list=c.repos_list,
144 admin=True,
144 admin=True,
145 super_user_actions=True)
145 super_user_actions=True)
146 #json used to render the grid
146 #json used to render the grid
147 c.data = json.dumps(repos_data)
147 c.data = json.dumps(repos_data)
148
148
149 return render('admin/repos/repos.html')
149 return render('admin/repos/repos.html')
150
150
151 @NotAnonymous()
151 @NotAnonymous()
152 def create(self):
152 def create(self):
153 """
153 """
154 POST /repos: Create a new item"""
154 POST /repos: Create a new item"""
155 # url('repos')
155 # url('repos')
156
156
157 self.__load_defaults()
157 self.__load_defaults()
158 form_result = {}
158 form_result = {}
159 try:
159 try:
160 form_result = RepoForm(repo_groups=c.repo_groups_choices,
160 form_result = RepoForm(repo_groups=c.repo_groups_choices,
161 landing_revs=c.landing_revs_choices)()\
161 landing_revs=c.landing_revs_choices)()\
162 .to_python(dict(request.POST))
162 .to_python(dict(request.POST))
163
163
164 new_repo = RepoModel().create(form_result,
164 new_repo = RepoModel().create(form_result,
165 self.rhodecode_user.user_id)
165 self.rhodecode_user.user_id)
166 if form_result['clone_uri']:
166 if form_result['clone_uri']:
167 h.flash(_('created repository %s from %s') \
167 h.flash(_('created repository %s from %s') \
168 % (form_result['repo_name'], form_result['clone_uri']),
168 % (form_result['repo_name'], form_result['clone_uri']),
169 category='success')
169 category='success')
170 else:
170 else:
171 h.flash(_('created repository %s') % form_result['repo_name'],
171 h.flash(_('created repository %s') % form_result['repo_name'],
172 category='success')
172 category='success')
173
173
174 if request.POST.get('user_created'):
174 if request.POST.get('user_created'):
175 # created by regular non admin user
175 # created by regular non admin user
176 action_logger(self.rhodecode_user, 'user_created_repo',
176 action_logger(self.rhodecode_user, 'user_created_repo',
177 form_result['repo_name_full'], self.ip_addr,
177 form_result['repo_name_full'], self.ip_addr,
178 self.sa)
178 self.sa)
179 else:
179 else:
180 action_logger(self.rhodecode_user, 'admin_created_repo',
180 action_logger(self.rhodecode_user, 'admin_created_repo',
181 form_result['repo_name_full'], self.ip_addr,
181 form_result['repo_name_full'], self.ip_addr,
182 self.sa)
182 self.sa)
183 Session().commit()
183 Session().commit()
184 except formencode.Invalid, errors:
184 except formencode.Invalid, errors:
185 return htmlfill.render(
185 return htmlfill.render(
186 render('admin/repos/repo_add.html'),
186 render('admin/repos/repo_add.html'),
187 defaults=errors.value,
187 defaults=errors.value,
188 errors=errors.error_dict or {},
188 errors=errors.error_dict or {},
189 prefix_error=False,
189 prefix_error=False,
190 encoding="UTF-8")
190 encoding="UTF-8")
191
191
192 except Exception:
192 except Exception:
193 log.error(traceback.format_exc())
193 log.error(traceback.format_exc())
194 msg = _('error occurred during creation of repository %s') \
194 msg = _('error occurred during creation of repository %s') \
195 % form_result.get('repo_name')
195 % form_result.get('repo_name')
196 h.flash(msg, category='error')
196 h.flash(msg, category='error')
197 if c.rhodecode_user.is_admin:
197 if c.rhodecode_user.is_admin:
198 return redirect(url('repos'))
198 return redirect(url('repos'))
199 return redirect(url('home'))
199 return redirect(url('home'))
200 #redirect to our new repo !
200 #redirect to our new repo !
201 return redirect(url('summary_home', repo_name=new_repo.repo_name))
201 return redirect(url('summary_home', repo_name=new_repo.repo_name))
202
202
203 @HasPermissionAllDecorator('hg.admin')
203 @HasPermissionAllDecorator('hg.admin')
204 def new(self, format='html'):
204 def new(self, format='html'):
205 """
205 """
206 WARNING: this function is depracated see settings.create_repo !!
206 WARNING: this function is depracated see settings.create_repo !!
207
207
208 GET /repos/new: Form to create a new item
208 GET /repos/new: Form to create a new item
209 """
209 """
210
210
211 parent_group = request.GET.get('parent_group')
211 parent_group = request.GET.get('parent_group')
212 self.__load_defaults()
212 self.__load_defaults()
213 ## apply the defaults from defaults page
213 ## apply the defaults from defaults page
214 defaults = RhodeCodeSetting.get_default_repo_settings(strip_prefix=True)
214 defaults = RhodeCodeSetting.get_default_repo_settings(strip_prefix=True)
215 if parent_group:
215 if parent_group:
216 defaults.update({'repo_group': parent_group})
216 defaults.update({'repo_group': parent_group})
217
217
218 return htmlfill.render(
218 return htmlfill.render(
219 render('admin/repos/repo_add.html'),
219 render('admin/repos/repo_add.html'),
220 defaults=defaults,
220 defaults=defaults,
221 errors={},
221 errors={},
222 prefix_error=False,
222 prefix_error=False,
223 encoding="UTF-8"
223 encoding="UTF-8"
224 )
224 )
225
225
226 @HasPermissionAllDecorator('hg.admin')
226 @HasPermissionAllDecorator('hg.admin')
227 def update(self, repo_name):
227 def update(self, repo_name):
228 """
228 """
229 PUT /repos/repo_name: Update an existing item"""
229 PUT /repos/repo_name: Update an existing item"""
230 # Forms posted to this method should contain a hidden field:
230 # Forms posted to this method should contain a hidden field:
231 # <input type="hidden" name="_method" value="PUT" />
231 # <input type="hidden" name="_method" value="PUT" />
232 # Or using helpers:
232 # Or using helpers:
233 # h.form(url('repo', repo_name=ID),
233 # h.form(url('repo', repo_name=ID),
234 # method='put')
234 # method='put')
235 # url('repo', repo_name=ID)
235 # url('repo', repo_name=ID)
236 self.__load_defaults()
236 self.__load_defaults()
237 repo_model = RepoModel()
237 repo_model = RepoModel()
238 changed_name = repo_name
238 changed_name = repo_name
239 #override the choices with extracted revisions !
239 #override the choices with extracted revisions !
240 choices, c.landing_revs = ScmModel().get_repo_landing_revs(repo_name)
240 choices, c.landing_revs = ScmModel().get_repo_landing_revs(repo_name)
241 c.landing_revs_choices = choices
241 c.landing_revs_choices = choices
242
242
243 _form = RepoForm(edit=True, old_data={'repo_name': repo_name},
243 _form = RepoForm(edit=True, old_data={'repo_name': repo_name},
244 repo_groups=c.repo_groups_choices,
244 repo_groups=c.repo_groups_choices,
245 landing_revs=c.landing_revs_choices)()
245 landing_revs=c.landing_revs_choices)()
246 try:
246 try:
247 form_result = _form.to_python(dict(request.POST))
247 form_result = _form.to_python(dict(request.POST))
248 repo = repo_model.update(repo_name, **form_result)
248 repo = repo_model.update(repo_name, **form_result)
249 invalidate_cache('get_repo_cached_%s' % repo_name)
249 invalidate_cache('get_repo_cached_%s' % repo_name)
250 h.flash(_('Repository %s updated successfully') % repo_name,
250 h.flash(_('Repository %s updated successfully') % repo_name,
251 category='success')
251 category='success')
252 changed_name = repo.repo_name
252 changed_name = repo.repo_name
253 action_logger(self.rhodecode_user, 'admin_updated_repo',
253 action_logger(self.rhodecode_user, 'admin_updated_repo',
254 changed_name, self.ip_addr, self.sa)
254 changed_name, self.ip_addr, self.sa)
255 Session().commit()
255 Session().commit()
256 except formencode.Invalid, errors:
256 except formencode.Invalid, errors:
257 defaults = self.__load_data(repo_name)
257 defaults = self.__load_data(repo_name)
258 defaults.update(errors.value)
258 defaults.update(errors.value)
259 return htmlfill.render(
259 return htmlfill.render(
260 render('admin/repos/repo_edit.html'),
260 render('admin/repos/repo_edit.html'),
261 defaults=defaults,
261 defaults=defaults,
262 errors=errors.error_dict or {},
262 errors=errors.error_dict or {},
263 prefix_error=False,
263 prefix_error=False,
264 encoding="UTF-8")
264 encoding="UTF-8")
265
265
266 except Exception:
266 except Exception:
267 log.error(traceback.format_exc())
267 log.error(traceback.format_exc())
268 h.flash(_('error occurred during update of repository %s') \
268 h.flash(_('error occurred during update of repository %s') \
269 % repo_name, category='error')
269 % repo_name, category='error')
270 return redirect(url('edit_repo', repo_name=changed_name))
270 return redirect(url('edit_repo', repo_name=changed_name))
271
271
272 @HasPermissionAllDecorator('hg.admin')
272 @HasPermissionAllDecorator('hg.admin')
273 def delete(self, repo_name):
273 def delete(self, repo_name):
274 """
274 """
275 DELETE /repos/repo_name: Delete an existing item"""
275 DELETE /repos/repo_name: Delete an existing item"""
276 # Forms posted to this method should contain a hidden field:
276 # Forms posted to this method should contain a hidden field:
277 # <input type="hidden" name="_method" value="DELETE" />
277 # <input type="hidden" name="_method" value="DELETE" />
278 # Or using helpers:
278 # Or using helpers:
279 # h.form(url('repo', repo_name=ID),
279 # h.form(url('repo', repo_name=ID),
280 # method='delete')
280 # method='delete')
281 # url('repo', repo_name=ID)
281 # url('repo', repo_name=ID)
282
282
283 repo_model = RepoModel()
283 repo_model = RepoModel()
284 repo = repo_model.get_by_repo_name(repo_name)
284 repo = repo_model.get_by_repo_name(repo_name)
285 if not repo:
285 if not repo:
286 h.not_mapped_error(repo_name)
286 h.not_mapped_error(repo_name)
287 return redirect(url('repos'))
287 return redirect(url('repos'))
288 try:
288 try:
289 _forks = repo.forks.count()
290 if _forks and request.POST.get('forks'):
291 do = request.POST['forks']
292 if do == 'detach_forks':
293 for r in repo.forks:
294 log.debug('Detaching fork %s from repo %s' % (r, repo))
295 r.fork = None
296 Session().add(r)
297 h.flash(_('detached %s forks') % _forks, category='success')
298 elif do == 'delete_forks':
299 for r in repo.forks:
300 log.debug('Deleting fork %s of repo %s' % (r, repo))
301 repo_model.delete(r)
302 h.flash(_('deleted %s forks') % _forks, category='success')
289 action_logger(self.rhodecode_user, 'admin_deleted_repo',
303 action_logger(self.rhodecode_user, 'admin_deleted_repo',
290 repo_name, self.ip_addr, self.sa)
304 repo_name, self.ip_addr, self.sa)
291 repo_model.delete(repo)
305 repo_model.delete(repo)
292 invalidate_cache('get_repo_cached_%s' % repo_name)
306 invalidate_cache('get_repo_cached_%s' % repo_name)
293 h.flash(_('deleted repository %s') % repo_name, category='success')
307 h.flash(_('deleted repository %s') % repo_name, category='success')
294 Session().commit()
308 Session().commit()
295 except IntegrityError, e:
309 except IntegrityError, e:
296 if e.message.find('repositories_fork_id_fkey') != -1:
310 if e.message.find('repositories_fork_id_fkey') != -1:
297 log.error(traceback.format_exc())
311 log.error(traceback.format_exc())
298 h.flash(_('Cannot delete %s it still contains attached '
312 h.flash(_('Cannot delete %s it still contains attached '
299 'forks') % repo_name,
313 'forks') % repo_name,
300 category='warning')
314 category='warning')
301 else:
315 else:
302 log.error(traceback.format_exc())
316 log.error(traceback.format_exc())
303 h.flash(_('An error occurred during '
317 h.flash(_('An error occurred during '
304 'deletion of %s') % repo_name,
318 'deletion of %s') % repo_name,
305 category='error')
319 category='error')
306
320
307 except Exception, e:
321 except Exception, e:
308 log.error(traceback.format_exc())
322 log.error(traceback.format_exc())
309 h.flash(_('An error occurred during deletion of %s') % repo_name,
323 h.flash(_('An error occurred during deletion of %s') % repo_name,
310 category='error')
324 category='error')
311
325
312 return redirect(url('repos'))
326 return redirect(url('repos'))
313
327
314 @HasRepoPermissionAllDecorator('repository.admin')
328 @HasRepoPermissionAllDecorator('repository.admin')
315 def delete_perm_user(self, repo_name):
329 def delete_perm_user(self, repo_name):
316 """
330 """
317 DELETE an existing repository permission user
331 DELETE an existing repository permission user
318
332
319 :param repo_name:
333 :param repo_name:
320 """
334 """
321 try:
335 try:
322 RepoModel().revoke_user_permission(repo=repo_name,
336 RepoModel().revoke_user_permission(repo=repo_name,
323 user=request.POST['user_id'])
337 user=request.POST['user_id'])
324 Session().commit()
338 Session().commit()
325 except Exception:
339 except Exception:
326 log.error(traceback.format_exc())
340 log.error(traceback.format_exc())
327 h.flash(_('An error occurred during deletion of repository user'),
341 h.flash(_('An error occurred during deletion of repository user'),
328 category='error')
342 category='error')
329 raise HTTPInternalServerError()
343 raise HTTPInternalServerError()
330
344
331 @HasRepoPermissionAllDecorator('repository.admin')
345 @HasRepoPermissionAllDecorator('repository.admin')
332 def delete_perm_users_group(self, repo_name):
346 def delete_perm_users_group(self, repo_name):
333 """
347 """
334 DELETE an existing repository permission users group
348 DELETE an existing repository permission users group
335
349
336 :param repo_name:
350 :param repo_name:
337 """
351 """
338
352
339 try:
353 try:
340 RepoModel().revoke_users_group_permission(
354 RepoModel().revoke_users_group_permission(
341 repo=repo_name, group_name=request.POST['users_group_id']
355 repo=repo_name, group_name=request.POST['users_group_id']
342 )
356 )
343 Session().commit()
357 Session().commit()
344 except Exception:
358 except Exception:
345 log.error(traceback.format_exc())
359 log.error(traceback.format_exc())
346 h.flash(_('An error occurred during deletion of repository'
360 h.flash(_('An error occurred during deletion of repository'
347 ' users groups'),
361 ' users groups'),
348 category='error')
362 category='error')
349 raise HTTPInternalServerError()
363 raise HTTPInternalServerError()
350
364
351 @HasPermissionAllDecorator('hg.admin')
365 @HasPermissionAllDecorator('hg.admin')
352 def repo_stats(self, repo_name):
366 def repo_stats(self, repo_name):
353 """
367 """
354 DELETE an existing repository statistics
368 DELETE an existing repository statistics
355
369
356 :param repo_name:
370 :param repo_name:
357 """
371 """
358
372
359 try:
373 try:
360 RepoModel().delete_stats(repo_name)
374 RepoModel().delete_stats(repo_name)
361 Session().commit()
375 Session().commit()
362 except Exception, e:
376 except Exception, e:
363 log.error(traceback.format_exc())
377 log.error(traceback.format_exc())
364 h.flash(_('An error occurred during deletion of repository stats'),
378 h.flash(_('An error occurred during deletion of repository stats'),
365 category='error')
379 category='error')
366 return redirect(url('edit_repo', repo_name=repo_name))
380 return redirect(url('edit_repo', repo_name=repo_name))
367
381
368 @HasPermissionAllDecorator('hg.admin')
382 @HasPermissionAllDecorator('hg.admin')
369 def repo_cache(self, repo_name):
383 def repo_cache(self, repo_name):
370 """
384 """
371 INVALIDATE existing repository cache
385 INVALIDATE existing repository cache
372
386
373 :param repo_name:
387 :param repo_name:
374 """
388 """
375
389
376 try:
390 try:
377 ScmModel().mark_for_invalidation(repo_name)
391 ScmModel().mark_for_invalidation(repo_name)
378 Session().commit()
392 Session().commit()
379 except Exception, e:
393 except Exception, e:
380 log.error(traceback.format_exc())
394 log.error(traceback.format_exc())
381 h.flash(_('An error occurred during cache invalidation'),
395 h.flash(_('An error occurred during cache invalidation'),
382 category='error')
396 category='error')
383 return redirect(url('edit_repo', repo_name=repo_name))
397 return redirect(url('edit_repo', repo_name=repo_name))
384
398
385 @HasPermissionAllDecorator('hg.admin')
399 @HasPermissionAllDecorator('hg.admin')
386 def repo_locking(self, repo_name):
400 def repo_locking(self, repo_name):
387 """
401 """
388 Unlock repository when it is locked !
402 Unlock repository when it is locked !
389
403
390 :param repo_name:
404 :param repo_name:
391 """
405 """
392
406
393 try:
407 try:
394 repo = Repository.get_by_repo_name(repo_name)
408 repo = Repository.get_by_repo_name(repo_name)
395 if request.POST.get('set_lock'):
409 if request.POST.get('set_lock'):
396 Repository.lock(repo, c.rhodecode_user.user_id)
410 Repository.lock(repo, c.rhodecode_user.user_id)
397 elif request.POST.get('set_unlock'):
411 elif request.POST.get('set_unlock'):
398 Repository.unlock(repo)
412 Repository.unlock(repo)
399 except Exception, e:
413 except Exception, e:
400 log.error(traceback.format_exc())
414 log.error(traceback.format_exc())
401 h.flash(_('An error occurred during unlocking'),
415 h.flash(_('An error occurred during unlocking'),
402 category='error')
416 category='error')
403 return redirect(url('edit_repo', repo_name=repo_name))
417 return redirect(url('edit_repo', repo_name=repo_name))
404
418
405 @HasPermissionAllDecorator('hg.admin')
419 @HasPermissionAllDecorator('hg.admin')
406 def repo_public_journal(self, repo_name):
420 def repo_public_journal(self, repo_name):
407 """
421 """
408 Set's this repository to be visible in public journal,
422 Set's this repository to be visible in public journal,
409 in other words assing default user to follow this repo
423 in other words assing default user to follow this repo
410
424
411 :param repo_name:
425 :param repo_name:
412 """
426 """
413
427
414 cur_token = request.POST.get('auth_token')
428 cur_token = request.POST.get('auth_token')
415 token = get_token()
429 token = get_token()
416 if cur_token == token:
430 if cur_token == token:
417 try:
431 try:
418 repo_id = Repository.get_by_repo_name(repo_name).repo_id
432 repo_id = Repository.get_by_repo_name(repo_name).repo_id
419 user_id = User.get_by_username('default').user_id
433 user_id = User.get_by_username('default').user_id
420 self.scm_model.toggle_following_repo(repo_id, user_id)
434 self.scm_model.toggle_following_repo(repo_id, user_id)
421 h.flash(_('Updated repository visibility in public journal'),
435 h.flash(_('Updated repository visibility in public journal'),
422 category='success')
436 category='success')
423 Session().commit()
437 Session().commit()
424 except:
438 except:
425 h.flash(_('An error occurred during setting this'
439 h.flash(_('An error occurred during setting this'
426 ' repository in public journal'),
440 ' repository in public journal'),
427 category='error')
441 category='error')
428
442
429 else:
443 else:
430 h.flash(_('Token mismatch'), category='error')
444 h.flash(_('Token mismatch'), category='error')
431 return redirect(url('edit_repo', repo_name=repo_name))
445 return redirect(url('edit_repo', repo_name=repo_name))
432
446
433 @HasPermissionAllDecorator('hg.admin')
447 @HasPermissionAllDecorator('hg.admin')
434 def repo_pull(self, repo_name):
448 def repo_pull(self, repo_name):
435 """
449 """
436 Runs task to update given repository with remote changes,
450 Runs task to update given repository with remote changes,
437 ie. make pull on remote location
451 ie. make pull on remote location
438
452
439 :param repo_name:
453 :param repo_name:
440 """
454 """
441 try:
455 try:
442 ScmModel().pull_changes(repo_name, self.rhodecode_user.username)
456 ScmModel().pull_changes(repo_name, self.rhodecode_user.username)
443 h.flash(_('Pulled from remote location'), category='success')
457 h.flash(_('Pulled from remote location'), category='success')
444 except Exception, e:
458 except Exception, e:
445 h.flash(_('An error occurred during pull from remote location'),
459 h.flash(_('An error occurred during pull from remote location'),
446 category='error')
460 category='error')
447
461
448 return redirect(url('edit_repo', repo_name=repo_name))
462 return redirect(url('edit_repo', repo_name=repo_name))
449
463
450 @HasPermissionAllDecorator('hg.admin')
464 @HasPermissionAllDecorator('hg.admin')
451 def repo_as_fork(self, repo_name):
465 def repo_as_fork(self, repo_name):
452 """
466 """
453 Mark given repository as a fork of another
467 Mark given repository as a fork of another
454
468
455 :param repo_name:
469 :param repo_name:
456 """
470 """
457 try:
471 try:
458 fork_id = request.POST.get('id_fork_of')
472 fork_id = request.POST.get('id_fork_of')
459 repo = ScmModel().mark_as_fork(repo_name, fork_id,
473 repo = ScmModel().mark_as_fork(repo_name, fork_id,
460 self.rhodecode_user.username)
474 self.rhodecode_user.username)
461 fork = repo.fork.repo_name if repo.fork else _('Nothing')
475 fork = repo.fork.repo_name if repo.fork else _('Nothing')
462 Session().commit()
476 Session().commit()
463 h.flash(_('Marked repo %s as fork of %s') % (repo_name, fork),
477 h.flash(_('Marked repo %s as fork of %s') % (repo_name, fork),
464 category='success')
478 category='success')
465 except Exception, e:
479 except Exception, e:
466 log.error(traceback.format_exc())
480 log.error(traceback.format_exc())
467 h.flash(_('An error occurred during this operation'),
481 h.flash(_('An error occurred during this operation'),
468 category='error')
482 category='error')
469
483
470 return redirect(url('edit_repo', repo_name=repo_name))
484 return redirect(url('edit_repo', repo_name=repo_name))
471
485
472 @HasPermissionAllDecorator('hg.admin')
486 @HasPermissionAllDecorator('hg.admin')
473 def show(self, repo_name, format='html'):
487 def show(self, repo_name, format='html'):
474 """GET /repos/repo_name: Show a specific item"""
488 """GET /repos/repo_name: Show a specific item"""
475 # url('repo', repo_name=ID)
489 # url('repo', repo_name=ID)
476
490
477 @HasPermissionAllDecorator('hg.admin')
491 @HasPermissionAllDecorator('hg.admin')
478 def edit(self, repo_name, format='html'):
492 def edit(self, repo_name, format='html'):
479 """GET /repos/repo_name/edit: Form to edit an existing item"""
493 """GET /repos/repo_name/edit: Form to edit an existing item"""
480 # url('edit_repo', repo_name=ID)
494 # url('edit_repo', repo_name=ID)
481 defaults = self.__load_data(repo_name)
495 defaults = self.__load_data(repo_name)
482
496
483 return htmlfill.render(
497 return htmlfill.render(
484 render('admin/repos/repo_edit.html'),
498 render('admin/repos/repo_edit.html'),
485 defaults=defaults,
499 defaults=defaults,
486 encoding="UTF-8",
500 encoding="UTF-8",
487 force_defaults=False
501 force_defaults=False
488 )
502 )
489
503
490 @HasPermissionAllDecorator('hg.admin')
504 @HasPermissionAllDecorator('hg.admin')
491 def create_repo_field(self, repo_name):
505 def create_repo_field(self, repo_name):
492 try:
506 try:
493 form_result = RepoFieldForm()().to_python(dict(request.POST))
507 form_result = RepoFieldForm()().to_python(dict(request.POST))
494 new_field = RepositoryField()
508 new_field = RepositoryField()
495 new_field.repository = Repository.get_by_repo_name(repo_name)
509 new_field.repository = Repository.get_by_repo_name(repo_name)
496 new_field.field_key = form_result['new_field_key']
510 new_field.field_key = form_result['new_field_key']
497 new_field.field_type = form_result['new_field_type'] # python type
511 new_field.field_type = form_result['new_field_type'] # python type
498 new_field.field_value = form_result['new_field_value'] # set initial blank value
512 new_field.field_value = form_result['new_field_value'] # set initial blank value
499 new_field.field_desc = form_result['new_field_desc']
513 new_field.field_desc = form_result['new_field_desc']
500 new_field.field_label = form_result['new_field_label']
514 new_field.field_label = form_result['new_field_label']
501 Session().add(new_field)
515 Session().add(new_field)
502 Session().commit()
516 Session().commit()
503
517
504 except Exception, e:
518 except Exception, e:
505 log.error(traceback.format_exc())
519 log.error(traceback.format_exc())
506 msg = _('An error occurred during creation of field')
520 msg = _('An error occurred during creation of field')
507 if isinstance(e, formencode.Invalid):
521 if isinstance(e, formencode.Invalid):
508 msg += ". " + e.msg
522 msg += ". " + e.msg
509 h.flash(msg, category='error')
523 h.flash(msg, category='error')
510 return redirect(url('edit_repo', repo_name=repo_name))
524 return redirect(url('edit_repo', repo_name=repo_name))
511
525
512 @HasPermissionAllDecorator('hg.admin')
526 @HasPermissionAllDecorator('hg.admin')
513 def delete_repo_field(self, repo_name, field_id):
527 def delete_repo_field(self, repo_name, field_id):
514 field = RepositoryField.get_or_404(field_id)
528 field = RepositoryField.get_or_404(field_id)
515 try:
529 try:
516 Session().delete(field)
530 Session().delete(field)
517 Session().commit()
531 Session().commit()
518 except Exception, e:
532 except Exception, e:
519 log.error(traceback.format_exc())
533 log.error(traceback.format_exc())
520 msg = _('An error occurred during removal of field')
534 msg = _('An error occurred during removal of field')
521 h.flash(msg, category='error')
535 h.flash(msg, category='error')
522 return redirect(url('edit_repo', repo_name=repo_name))
536 return redirect(url('edit_repo', repo_name=repo_name))
@@ -1,368 +1,373 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
2 <%inherit file="/base/base.html"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${_('Edit repository')} ${c.repo_info.repo_name} - ${c.rhodecode_name}
5 ${_('Edit repository')} ${c.repo_info.repo_name} - ${c.rhodecode_name}
6 </%def>
6 </%def>
7
7
8 <%def name="breadcrumbs_links()">
8 <%def name="breadcrumbs_links()">
9 ${h.link_to(_(u'Home'),h.url('/'))}
9 ${h.link_to(_(u'Home'),h.url('/'))}
10 &raquo;
10 &raquo;
11 ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
11 ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
12 &raquo;
12 &raquo;
13 ${_('edit')}
13 ${_('edit')}
14 </%def>
14 </%def>
15
15
16 <%def name="page_nav()">
16 <%def name="page_nav()">
17 ${self.menu('options')}
17 ${self.menu('options')}
18 </%def>
18 </%def>
19
19
20 <%def name="main()">
20 <%def name="main()">
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>
58 <label for="repo_type">${_('Type')}:</label>
59 </div>
59 </div>
60 <div class="input">
60 <div class="input">
61 ${h.select('repo_type','hg',c.backends,class_="medium")}
61 ${h.select('repo_type','hg',c.backends,class_="medium")}
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_landing_rev">${_('Landing revision')}:</label>
66 <label for="repo_landing_rev">${_('Landing revision')}:</label>
67 </div>
67 </div>
68 <div class="input">
68 <div class="input">
69 ${h.select('repo_landing_rev','',c.landing_revs,class_="medium")}
69 ${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>
70 <span class="help-block">${_('Default revision for files page, downloads, whoosh and readme')}</span>
71 </div>
71 </div>
72 </div>
72 </div>
73 <div class="field">
73 <div class="field">
74 <div class="label label-textarea">
74 <div class="label label-textarea">
75 <label for="repo_description">${_('Description')}:</label>
75 <label for="repo_description">${_('Description')}:</label>
76 </div>
76 </div>
77 <div class="textarea text-area editor">
77 <div class="textarea text-area editor">
78 ${h.textarea('repo_description')}
78 ${h.textarea('repo_description')}
79 <span class="help-block">${_('Keep it short and to the point. Use a README file for longer descriptions.')}</span>
79 <span class="help-block">${_('Keep it short and to the point. Use a README file for longer descriptions.')}</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="repo_private">${_('Private repository')}:</label>
85 <label for="repo_private">${_('Private repository')}:</label>
86 </div>
86 </div>
87 <div class="checkboxes">
87 <div class="checkboxes">
88 ${h.checkbox('repo_private',value="True")}
88 ${h.checkbox('repo_private',value="True")}
89 <span class="help-block">${_('Private repositories are only visible to people explicitly added as collaborators.')}</span>
89 <span class="help-block">${_('Private repositories are only visible to people explicitly added as collaborators.')}</span>
90 </div>
90 </div>
91 </div>
91 </div>
92 <div class="field">
92 <div class="field">
93 <div class="label label-checkbox">
93 <div class="label label-checkbox">
94 <label for="repo_enable_statistics">${_('Enable statistics')}:</label>
94 <label for="repo_enable_statistics">${_('Enable statistics')}:</label>
95 </div>
95 </div>
96 <div class="checkboxes">
96 <div class="checkboxes">
97 ${h.checkbox('repo_enable_statistics',value="True")}
97 ${h.checkbox('repo_enable_statistics',value="True")}
98 <span class="help-block">${_('Enable statistics window on summary page.')}</span>
98 <span class="help-block">${_('Enable statistics window on summary page.')}</span>
99 </div>
99 </div>
100 </div>
100 </div>
101 <div class="field">
101 <div class="field">
102 <div class="label label-checkbox">
102 <div class="label label-checkbox">
103 <label for="repo_enable_downloads">${_('Enable downloads')}:</label>
103 <label for="repo_enable_downloads">${_('Enable downloads')}:</label>
104 </div>
104 </div>
105 <div class="checkboxes">
105 <div class="checkboxes">
106 ${h.checkbox('repo_enable_downloads',value="True")}
106 ${h.checkbox('repo_enable_downloads',value="True")}
107 <span class="help-block">${_('Enable download menu on summary page.')}</span>
107 <span class="help-block">${_('Enable download menu on summary page.')}</span>
108 </div>
108 </div>
109 </div>
109 </div>
110 <div class="field">
110 <div class="field">
111 <div class="label label-checkbox">
111 <div class="label label-checkbox">
112 <label for="repo_enable_locking">${_('Enable locking')}:</label>
112 <label for="repo_enable_locking">${_('Enable locking')}:</label>
113 </div>
113 </div>
114 <div class="checkboxes">
114 <div class="checkboxes">
115 ${h.checkbox('repo_enable_locking',value="True")}
115 ${h.checkbox('repo_enable_locking',value="True")}
116 <span class="help-block">${_('Enable lock-by-pulling on repository.')}</span>
116 <span class="help-block">${_('Enable lock-by-pulling on repository.')}</span>
117 </div>
117 </div>
118 </div>
118 </div>
119 <div class="field">
119 <div class="field">
120 <div class="label">
120 <div class="label">
121 <label for="user">${_('Owner')}:</label>
121 <label for="user">${_('Owner')}:</label>
122 </div>
122 </div>
123 <div class="input input-medium ac">
123 <div class="input input-medium ac">
124 <div class="perm_ac">
124 <div class="perm_ac">
125 ${h.text('user',class_='yui-ac-input')}
125 ${h.text('user',class_='yui-ac-input')}
126 <span class="help-block">${_('Change owner of this repository.')}</span>
126 <span class="help-block">${_('Change owner of this repository.')}</span>
127 <div id="owner_container"></div>
127 <div id="owner_container"></div>
128 </div>
128 </div>
129 </div>
129 </div>
130 </div>
130 </div>
131 %if c.visual.repository_fields:
131 %if c.visual.repository_fields:
132 ## EXTRA FIELDS
132 ## EXTRA FIELDS
133 %for field in c.repo_fields:
133 %for field in c.repo_fields:
134 <div class="field">
134 <div class="field">
135 <div class="label">
135 <div class="label">
136 <label for="${field.field_key_prefixed}">${field.field_label} (${field.field_key}):</label>
136 <label for="${field.field_key_prefixed}">${field.field_label} (${field.field_key}):</label>
137 </div>
137 </div>
138 <div class="input input-medium">
138 <div class="input input-medium">
139 ${h.text(field.field_key_prefixed, field.field_value, class_='medium')}
139 ${h.text(field.field_key_prefixed, field.field_value, class_='medium')}
140 %if field.field_desc:
140 %if field.field_desc:
141 <span class="help-block">${field.field_desc}</span>
141 <span class="help-block">${field.field_desc}</span>
142 %endif
142 %endif
143 </div>
143 </div>
144 </div>
144 </div>
145 %endfor
145 %endfor
146 %endif
146 %endif
147 <div class="field">
147 <div class="field">
148 <div class="label">
148 <div class="label">
149 <label for="input">${_('Permissions')}:</label>
149 <label for="input">${_('Permissions')}:</label>
150 </div>
150 </div>
151 <div class="input">
151 <div class="input">
152 <%include file="repo_edit_perms.html"/>
152 <%include file="repo_edit_perms.html"/>
153 </div>
153 </div>
154
154
155 <div class="buttons">
155 <div class="buttons">
156 ${h.submit('save',_('Save'),class_="ui-btn large")}
156 ${h.submit('save',_('Save'),class_="ui-btn large")}
157 ${h.reset('reset',_('Reset'),class_="ui-btn large")}
157 ${h.reset('reset',_('Reset'),class_="ui-btn large")}
158 </div>
158 </div>
159 </div>
159 </div>
160 </div>
160 </div>
161 </div>
161 </div>
162 ${h.end_form()}
162 ${h.end_form()}
163 </div>
163 </div>
164
164
165 <div class="box box-right">
165 <div class="box box-right">
166 <div class="title">
166 <div class="title">
167 <h5>${_('Administration')}</h5>
167 <h5>${_('Administration')}</h5>
168 </div>
168 </div>
169
169
170 <h3>${_('Statistics')}</h3>
170 <h3>${_('Statistics')}</h3>
171 ${h.form(url('repo_stats', repo_name=c.repo_info.repo_name),method='delete')}
171 ${h.form(url('repo_stats', repo_name=c.repo_info.repo_name),method='delete')}
172 <div class="form">
172 <div class="form">
173 <div class="fields">
173 <div class="fields">
174 ${h.submit('reset_stats_%s' % c.repo_info.repo_name,_('Reset current statistics'),class_="ui-btn",onclick="return confirm('"+_('Confirm to remove current statistics')+"');")}
174 ${h.submit('reset_stats_%s' % c.repo_info.repo_name,_('Reset current statistics'),class_="ui-btn",onclick="return confirm('"+_('Confirm to remove current statistics')+"');")}
175 <div class="field" style="border:none;color:#888">
175 <div class="field" style="border:none;color:#888">
176 <ul>
176 <ul>
177 <li>${_('Fetched to rev')}: ${c.stats_revision}/${c.repo_last_rev}</li>
177 <li>${_('Fetched to rev')}: ${c.stats_revision}/${c.repo_last_rev}</li>
178 <li>${_('Stats gathered')}: ${c.stats_percentage}%</li>
178 <li>${_('Stats gathered')}: ${c.stats_percentage}%</li>
179 </ul>
179 </ul>
180 </div>
180 </div>
181 </div>
181 </div>
182 </div>
182 </div>
183 ${h.end_form()}
183 ${h.end_form()}
184
184
185 %if c.repo_info.clone_uri:
185 %if c.repo_info.clone_uri:
186 <h3>${_('Remote')}</h3>
186 <h3>${_('Remote')}</h3>
187 ${h.form(url('repo_pull', repo_name=c.repo_info.repo_name),method='put')}
187 ${h.form(url('repo_pull', repo_name=c.repo_info.repo_name),method='put')}
188 <div class="form">
188 <div class="form">
189 <div class="fields">
189 <div class="fields">
190 ${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')+"');")}
190 ${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')+"');")}
191 <div class="field" style="border:none">
191 <div class="field" style="border:none">
192 <ul>
192 <ul>
193 <li><a href="${c.repo_info.clone_uri}">${c.repo_info.clone_uri}</a></li>
193 <li><a href="${c.repo_info.clone_uri}">${c.repo_info.clone_uri}</a></li>
194 </ul>
194 </ul>
195 </div>
195 </div>
196 </div>
196 </div>
197 </div>
197 </div>
198 ${h.end_form()}
198 ${h.end_form()}
199 %endif
199 %endif
200
200
201 <h3>${_('Cache')}</h3>
201 <h3>${_('Cache')}</h3>
202 ${h.form(url('repo_cache', repo_name=c.repo_info.repo_name),method='delete')}
202 ${h.form(url('repo_cache', repo_name=c.repo_info.repo_name),method='delete')}
203 <div class="form">
203 <div class="form">
204 <div class="fields">
204 <div class="fields">
205 ${h.submit('reset_cache_%s' % c.repo_info.repo_name,_('Invalidate repository cache'),class_="ui-btn",onclick="return confirm('"+_('Confirm to invalidate repository cache')+"');")}
205 ${h.submit('reset_cache_%s' % c.repo_info.repo_name,_('Invalidate repository cache'),class_="ui-btn",onclick="return confirm('"+_('Confirm to invalidate repository cache')+"');")}
206 <div class="field" style="border:none;color:#888">
206 <div class="field" style="border:none;color:#888">
207 <ul>
207 <ul>
208 <li>${_('Manually invalidate cache for this repository. On first access repository will be cached again')}
208 <li>${_('Manually invalidate cache for this repository. On first access repository will be cached again')}
209 </li>
209 </li>
210 </ul>
210 </ul>
211 </div>
211 </div>
212 <div class="field" style="border:none;">
212 <div class="field" style="border:none;">
213 ${_('List of cached values')}
213 ${_('List of cached values')}
214 <table>
214 <table>
215 <tr>
215 <tr>
216 <th>${_('Prefix')}</th>
216 <th>${_('Prefix')}</th>
217 <th>${_('Key')}</th>
217 <th>${_('Key')}</th>
218 <th>${_('Active')}</th>
218 <th>${_('Active')}</th>
219 </tr>
219 </tr>
220 %for cache in c.repo_info.cache_keys:
220 %for cache in c.repo_info.cache_keys:
221 <tr>
221 <tr>
222 <td>${cache.prefix or '-'}</td>
222 <td>${cache.prefix or '-'}</td>
223 <td>${cache.cache_key}</td>
223 <td>${cache.cache_key}</td>
224 <td>${h.bool2icon(cache.cache_active)}</td>
224 <td>${h.bool2icon(cache.cache_active)}</td>
225 </tr>
225 </tr>
226 %endfor
226 %endfor
227 </table>
227 </table>
228 </div>
228 </div>
229 </div>
229 </div>
230 </div>
230 </div>
231 ${h.end_form()}
231 ${h.end_form()}
232
232
233 <h3>${_('Public journal')}</h3>
233 <h3>${_('Public journal')}</h3>
234 ${h.form(url('repo_public_journal', repo_name=c.repo_info.repo_name),method='put')}
234 ${h.form(url('repo_public_journal', repo_name=c.repo_info.repo_name),method='put')}
235 <div class="form">
235 <div class="form">
236 ${h.hidden('auth_token',str(h.get_token()))}
236 ${h.hidden('auth_token',str(h.get_token()))}
237 <div class="field">
237 <div class="field">
238 %if c.in_public_journal:
238 %if c.in_public_journal:
239 ${h.submit('set_public_%s' % c.repo_info.repo_name,_('Remove from public journal'),class_="ui-btn")}
239 ${h.submit('set_public_%s' % c.repo_info.repo_name,_('Remove from public journal'),class_="ui-btn")}
240 %else:
240 %else:
241 ${h.submit('set_public_%s' % c.repo_info.repo_name,_('Add to public journal'),class_="ui-btn")}
241 ${h.submit('set_public_%s' % c.repo_info.repo_name,_('Add to public journal'),class_="ui-btn")}
242 %endif
242 %endif
243 </div>
243 </div>
244 <div class="field" style="border:none;color:#888">
244 <div class="field" style="border:none;color:#888">
245 <ul>
245 <ul>
246 <li>${_('All actions made on this repository will be accessible to everyone in public journal')}
246 <li>${_('All actions made on this repository will be accessible to everyone in public journal')}
247 </li>
247 </li>
248 </ul>
248 </ul>
249 </div>
249 </div>
250 </div>
250 </div>
251 ${h.end_form()}
251 ${h.end_form()}
252
252
253 <h3>${_('Locking')}</h3>
253 <h3>${_('Locking')}</h3>
254 ${h.form(url('repo_locking', repo_name=c.repo_info.repo_name),method='put')}
254 ${h.form(url('repo_locking', repo_name=c.repo_info.repo_name),method='put')}
255 <div class="form">
255 <div class="form">
256 <div class="fields">
256 <div class="fields">
257 %if c.repo_info.locked[0]:
257 %if c.repo_info.locked[0]:
258 ${h.submit('set_unlock' ,_('Unlock locked repo'),class_="ui-btn",onclick="return confirm('"+_('Confirm to unlock repository')+"');")}
258 ${h.submit('set_unlock' ,_('Unlock locked repo'),class_="ui-btn",onclick="return confirm('"+_('Confirm to unlock repository')+"');")}
259 ${'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])))}
259 ${'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])))}
260 %else:
260 %else:
261 ${h.submit('set_lock',_('lock repo'),class_="ui-btn",onclick="return confirm('"+_('Confirm to lock repository')+"');")}
261 ${h.submit('set_lock',_('lock repo'),class_="ui-btn",onclick="return confirm('"+_('Confirm to lock repository')+"');")}
262 ${_('Repository is not locked')}
262 ${_('Repository is not locked')}
263 %endif
263 %endif
264 </div>
264 </div>
265 <div class="field" style="border:none;color:#888">
265 <div class="field" style="border:none;color:#888">
266 <ul>
266 <ul>
267 <li>${_('Force locking on repository. Works only when anonymous access is disabled')}
267 <li>${_('Force locking on repository. Works only when anonymous access is disabled')}
268 </li>
268 </li>
269 </ul>
269 </ul>
270 </div>
270 </div>
271 </div>
271 </div>
272 ${h.end_form()}
272 ${h.end_form()}
273
273
274 <h3>${_('Set as fork of')}</h3>
274 <h3>${_('Set as fork of')}</h3>
275 ${h.form(url('repo_as_fork', repo_name=c.repo_info.repo_name),method='put')}
275 ${h.form(url('repo_as_fork', repo_name=c.repo_info.repo_name),method='put')}
276 <div class="form">
276 <div class="form">
277 <div class="fields">
277 <div class="fields">
278 ${h.select('id_fork_of','',c.repos_list,class_="medium")}
278 ${h.select('id_fork_of','',c.repos_list,class_="medium")}
279 ${h.submit('set_as_fork_%s' % c.repo_info.repo_name,_('set'),class_="ui-btn",)}
279 ${h.submit('set_as_fork_%s' % c.repo_info.repo_name,_('set'),class_="ui-btn",)}
280 </div>
280 </div>
281 <div class="field" style="border:none;color:#888">
281 <div class="field" style="border:none;color:#888">
282 <ul>
282 <ul>
283 <li>${_('''Manually set this repository as a fork of another from the list''')}</li>
283 <li>${_('''Manually set this repository as a fork of another from the list''')}</li>
284 </ul>
284 </ul>
285 </div>
285 </div>
286 </div>
286 </div>
287 ${h.end_form()}
287 ${h.end_form()}
288
288
289 <h3>${_('Delete')}</h3>
289 <h3>${_('Delete')}</h3>
290 ${h.form(url('repo', repo_name=c.repo_info.repo_name),method='delete')}
290 ${h.form(url('repo', repo_name=c.repo_info.repo_name),method='delete')}
291 <div class="form">
291 <div class="form">
292 <div class="fields">
292 <div class="fields">
293 ${h.submit('remove_%s' % c.repo_info.repo_name,_('Remove this repository'),class_="ui-btn red",onclick="return confirm('"+_('Confirm to delete this repository')+"');")}
293 ${h.submit('remove_%s' % c.repo_info.repo_name,_('Remove this repository'),class_="ui-btn red",onclick="return confirm('"+_('Confirm to delete this repository')+"');")}
294 %if c.repo_info.forks.count():
295 - ${ungettext('this repository has %s fork', 'this repository has %s forks', c.repo_info.forks.count()) % c.repo_info.forks.count()}
296 <input type="radio" name="forks" value="detach_forks" checked="checked"/> <label for="forks">${_('Detach forks')}</label>
297 <input type="radio" name="forks" value="delete_forks" /> <label for="forks">${_('Delete forks')}</label>
298 %endif
294 </div>
299 </div>
295 <div class="field" style="border:none;color:#888">
300 <div class="field" style="border:none;color:#888">
296 <ul>
301 <ul>
297 <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>
302 <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>
298 </ul>
303 </ul>
299 </div>
304 </div>
300 </div>
305 </div>
301 ${h.end_form()}
306 ${h.end_form()}
302 </div>
307 </div>
303
308
304 ##TODO: this should be controlled by the VISUAL setting
309 ##TODO: this should be controlled by the VISUAL setting
305 %if c.visual.repository_fields:
310 %if c.visual.repository_fields:
306 <div class="box box-left" style="clear:left">
311 <div class="box box-left" style="clear:left">
307 <!-- box / title -->
312 <!-- box / title -->
308 <div class="title">
313 <div class="title">
309 <h5>${_('Extra fields')}</h5>
314 <h5>${_('Extra fields')}</h5>
310 </div>
315 </div>
311
316
312 <div class="emails_wrap">
317 <div class="emails_wrap">
313 <table class="noborder">
318 <table class="noborder">
314 %for field in c.repo_fields:
319 %for field in c.repo_fields:
315 <tr>
320 <tr>
316 <td>${field.field_label} (${field.field_key})</td>
321 <td>${field.field_label} (${field.field_key})</td>
317 <td>${field.field_type}</td>
322 <td>${field.field_type}</td>
318 <td>
323 <td>
319 ${h.form(url('delete_repo_fields', repo_name=c.repo_info.repo_name, field_id=field.repo_field_id),method='delete')}
324 ${h.form(url('delete_repo_fields', repo_name=c.repo_info.repo_name, field_id=field.repo_field_id),method='delete')}
320 ${h.submit('remove_%s' % field.repo_field_id, _('delete'), id="remove_field_%s" % field.repo_field_id,
325 ${h.submit('remove_%s' % field.repo_field_id, _('delete'), id="remove_field_%s" % field.repo_field_id,
321 class_="delete_icon action_button", onclick="return confirm('"+_('Confirm to delete this field: %s') % field.field_key+"');")}
326 class_="delete_icon action_button", onclick="return confirm('"+_('Confirm to delete this field: %s') % field.field_key+"');")}
322 ${h.end_form()}
327 ${h.end_form()}
323 </td>
328 </td>
324 </tr>
329 </tr>
325 %endfor
330 %endfor
326 </table>
331 </table>
327 </div>
332 </div>
328
333
329 ${h.form(url('create_repo_fields', repo_name=c.repo_info.repo_name),method='put')}
334 ${h.form(url('create_repo_fields', repo_name=c.repo_info.repo_name),method='put')}
330 <div class="form">
335 <div class="form">
331 <!-- fields -->
336 <!-- fields -->
332 <div class="fields">
337 <div class="fields">
333 <div class="field">
338 <div class="field">
334 <div class="label">
339 <div class="label">
335 <label for="new_field_key">${_('New field key')}:</label>
340 <label for="new_field_key">${_('New field key')}:</label>
336 </div>
341 </div>
337 <div class="input">
342 <div class="input">
338 ${h.text('new_field_key', class_='small')}
343 ${h.text('new_field_key', class_='small')}
339 </div>
344 </div>
340 </div>
345 </div>
341 <div class="field">
346 <div class="field">
342 <div class="label">
347 <div class="label">
343 <label for="new_field_label">${_('New field label')}:</label>
348 <label for="new_field_label">${_('New field label')}:</label>
344 </div>
349 </div>
345 <div class="input">
350 <div class="input">
346 ${h.text('new_field_label', class_='small', placeholder=_('Enter short label'))}
351 ${h.text('new_field_label', class_='small', placeholder=_('Enter short label'))}
347 </div>
352 </div>
348 </div>
353 </div>
349
354
350 <div class="field">
355 <div class="field">
351 <div class="label">
356 <div class="label">
352 <label for="new_field_desc">${_('New field description')}:</label>
357 <label for="new_field_desc">${_('New field description')}:</label>
353 </div>
358 </div>
354 <div class="input">
359 <div class="input">
355 ${h.text('new_field_desc', class_='small', placeholder=_('Enter description of a field'))}
360 ${h.text('new_field_desc', class_='small', placeholder=_('Enter description of a field'))}
356 </div>
361 </div>
357 </div>
362 </div>
358
363
359 <div class="buttons">
364 <div class="buttons">
360 ${h.submit('save',_('Add'),class_="ui-btn large")}
365 ${h.submit('save',_('Add'),class_="ui-btn large")}
361 ${h.reset('reset',_('Reset'),class_="ui-btn large")}
366 ${h.reset('reset',_('Reset'),class_="ui-btn large")}
362 </div>
367 </div>
363 </div>
368 </div>
364 </div>
369 </div>
365 ${h.end_form()}
370 ${h.end_form()}
366 </div>
371 </div>
367 %endif
372 %endif
368 </%def>
373 </%def>
General Comments 0
You need to be logged in to leave comments. Login now