##// END OF EJS Templates
repository-groups: improved detection of repository groups parent....
marcink -
r1188:8732a902 default
parent child Browse files
Show More
@@ -1,878 +1,888 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2013-2016 RhodeCode GmbH
3 # Copyright (C) 2013-2016 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21
21
22 """
22 """
23 Repositories controller for RhodeCode
23 Repositories controller for RhodeCode
24 """
24 """
25
25
26 import logging
26 import logging
27 import traceback
27 import traceback
28
28
29 import formencode
29 import formencode
30 from formencode import htmlfill
30 from formencode import htmlfill
31 from pylons import request, tmpl_context as c, url
31 from pylons import request, tmpl_context as c, url
32 from pylons.controllers.util import redirect
32 from pylons.controllers.util import redirect
33 from pylons.i18n.translation import _
33 from pylons.i18n.translation import _
34 from webob.exc import HTTPForbidden, HTTPNotFound, HTTPBadRequest
34 from webob.exc import HTTPForbidden, HTTPNotFound, HTTPBadRequest
35
35
36 import rhodecode
36 import rhodecode
37 from rhodecode.lib import auth, helpers as h
37 from rhodecode.lib import auth, helpers as h
38 from rhodecode.lib.auth import (
38 from rhodecode.lib.auth import (
39 LoginRequired, HasPermissionAllDecorator,
39 LoginRequired, HasPermissionAllDecorator,
40 HasRepoPermissionAllDecorator, NotAnonymous, HasPermissionAny,
40 HasRepoPermissionAllDecorator, NotAnonymous, HasPermissionAny,
41 HasRepoGroupPermissionAny, HasRepoPermissionAnyDecorator)
41 HasRepoGroupPermissionAny, HasRepoPermissionAnyDecorator)
42 from rhodecode.lib.base import BaseRepoController, render
42 from rhodecode.lib.base import BaseRepoController, render
43 from rhodecode.lib.ext_json import json
43 from rhodecode.lib.ext_json import json
44 from rhodecode.lib.exceptions import AttachedForksError
44 from rhodecode.lib.exceptions import AttachedForksError
45 from rhodecode.lib.utils import action_logger, repo_name_slug, jsonify
45 from rhodecode.lib.utils import action_logger, repo_name_slug, jsonify
46 from rhodecode.lib.utils2 import safe_int, str2bool
46 from rhodecode.lib.utils2 import safe_int, str2bool
47 from rhodecode.lib.vcs import RepositoryError
47 from rhodecode.lib.vcs import RepositoryError
48 from rhodecode.model.db import (
48 from rhodecode.model.db import (
49 User, Repository, UserFollowing, RepoGroup, RepositoryField)
49 User, Repository, UserFollowing, RepoGroup, RepositoryField)
50 from rhodecode.model.forms import (
50 from rhodecode.model.forms import (
51 RepoForm, RepoFieldForm, RepoPermsForm, RepoVcsSettingsForm,
51 RepoForm, RepoFieldForm, RepoPermsForm, RepoVcsSettingsForm,
52 IssueTrackerPatternsForm)
52 IssueTrackerPatternsForm)
53 from rhodecode.model.meta import Session
53 from rhodecode.model.meta import Session
54 from rhodecode.model.repo import RepoModel
54 from rhodecode.model.repo import RepoModel
55 from rhodecode.model.scm import ScmModel, RepoGroupList, RepoList
55 from rhodecode.model.scm import ScmModel, RepoGroupList, RepoList
56 from rhodecode.model.settings import (
56 from rhodecode.model.settings import (
57 SettingsModel, IssueTrackerSettingsModel, VcsSettingsModel,
57 SettingsModel, IssueTrackerSettingsModel, VcsSettingsModel,
58 SettingNotFound)
58 SettingNotFound)
59
59
60 log = logging.getLogger(__name__)
60 log = logging.getLogger(__name__)
61
61
62
62
63 class ReposController(BaseRepoController):
63 class ReposController(BaseRepoController):
64 """
64 """
65 REST Controller styled on the Atom Publishing Protocol"""
65 REST Controller styled on the Atom Publishing Protocol"""
66 # To properly map this controller, ensure your config/routing.py
66 # To properly map this controller, ensure your config/routing.py
67 # file has a resource setup:
67 # file has a resource setup:
68 # map.resource('repo', 'repos')
68 # map.resource('repo', 'repos')
69
69
70 @LoginRequired()
70 @LoginRequired()
71 def __before__(self):
71 def __before__(self):
72 super(ReposController, self).__before__()
72 super(ReposController, self).__before__()
73
73
74 def _load_repo(self, repo_name):
74 def _load_repo(self, repo_name):
75 repo_obj = Repository.get_by_repo_name(repo_name)
75 repo_obj = Repository.get_by_repo_name(repo_name)
76
76
77 if repo_obj is None:
77 if repo_obj is None:
78 h.not_mapped_error(repo_name)
78 h.not_mapped_error(repo_name)
79 return redirect(url('repos'))
79 return redirect(url('repos'))
80
80
81 return repo_obj
81 return repo_obj
82
82
83 def __load_defaults(self, repo=None):
83 def __load_defaults(self, repo=None):
84 acl_groups = RepoGroupList(RepoGroup.query().all(),
84 acl_groups = RepoGroupList(RepoGroup.query().all(),
85 perm_set=['group.write', 'group.admin'])
85 perm_set=['group.write', 'group.admin'])
86 c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
86 c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
87 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
87 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
88
88
89 # in case someone no longer have a group.write access to a repository
89 # in case someone no longer have a group.write access to a repository
90 # pre fill the list with this entry, we don't care if this is the same
90 # pre fill the list with this entry, we don't care if this is the same
91 # but it will allow saving repo data properly.
91 # but it will allow saving repo data properly.
92
92
93 repo_group = None
93 repo_group = None
94 if repo:
94 if repo:
95 repo_group = repo.group
95 repo_group = repo.group
96 if repo_group and unicode(repo_group.group_id) not in c.repo_groups_choices:
96 if repo_group and unicode(repo_group.group_id) not in c.repo_groups_choices:
97 c.repo_groups_choices.append(unicode(repo_group.group_id))
97 c.repo_groups_choices.append(unicode(repo_group.group_id))
98 c.repo_groups.append(RepoGroup._generate_choice(repo_group))
98 c.repo_groups.append(RepoGroup._generate_choice(repo_group))
99
99
100 choices, c.landing_revs = ScmModel().get_repo_landing_revs()
100 choices, c.landing_revs = ScmModel().get_repo_landing_revs()
101 c.landing_revs_choices = choices
101 c.landing_revs_choices = choices
102
102
103 def __load_data(self, repo_name=None):
103 def __load_data(self, repo_name=None):
104 """
104 """
105 Load defaults settings for edit, and update
105 Load defaults settings for edit, and update
106
106
107 :param repo_name:
107 :param repo_name:
108 """
108 """
109 c.repo_info = self._load_repo(repo_name)
109 c.repo_info = self._load_repo(repo_name)
110 self.__load_defaults(c.repo_info)
110 self.__load_defaults(c.repo_info)
111
111
112 # override defaults for exact repo info here git/hg etc
112 # override defaults for exact repo info here git/hg etc
113 if not c.repository_requirements_missing:
113 if not c.repository_requirements_missing:
114 choices, c.landing_revs = ScmModel().get_repo_landing_revs(
114 choices, c.landing_revs = ScmModel().get_repo_landing_revs(
115 c.repo_info)
115 c.repo_info)
116 c.landing_revs_choices = choices
116 c.landing_revs_choices = choices
117 defaults = RepoModel()._get_defaults(repo_name)
117 defaults = RepoModel()._get_defaults(repo_name)
118
118
119 return defaults
119 return defaults
120
120
121 def _log_creation_exception(self, e, repo_name):
121 def _log_creation_exception(self, e, repo_name):
122 reason = None
122 reason = None
123 if len(e.args) == 2:
123 if len(e.args) == 2:
124 reason = e.args[1]
124 reason = e.args[1]
125
125
126 if reason == 'INVALID_CERTIFICATE':
126 if reason == 'INVALID_CERTIFICATE':
127 log.exception(
127 log.exception(
128 'Exception creating a repository: invalid certificate')
128 'Exception creating a repository: invalid certificate')
129 msg = (_('Error creating repository %s: invalid certificate')
129 msg = (_('Error creating repository %s: invalid certificate')
130 % repo_name)
130 % repo_name)
131 else:
131 else:
132 log.exception("Exception creating a repository")
132 log.exception("Exception creating a repository")
133 msg = (_('Error creating repository %s')
133 msg = (_('Error creating repository %s')
134 % repo_name)
134 % repo_name)
135
135
136 return msg
136 return msg
137
137
138 @NotAnonymous()
138 @NotAnonymous()
139 def index(self, format='html'):
139 def index(self, format='html'):
140 """GET /repos: All items in the collection"""
140 """GET /repos: All items in the collection"""
141 # url('repos')
141 # url('repos')
142
142
143 repo_list = Repository.get_all_repos()
143 repo_list = Repository.get_all_repos()
144 c.repo_list = RepoList(repo_list, perm_set=['repository.admin'])
144 c.repo_list = RepoList(repo_list, perm_set=['repository.admin'])
145 repos_data = RepoModel().get_repos_as_dict(
145 repos_data = RepoModel().get_repos_as_dict(
146 repo_list=c.repo_list, admin=True, super_user_actions=True)
146 repo_list=c.repo_list, admin=True, super_user_actions=True)
147 # json used to render the grid
147 # json used to render the grid
148 c.data = json.dumps(repos_data)
148 c.data = json.dumps(repos_data)
149
149
150 return render('admin/repos/repos.html')
150 return render('admin/repos/repos.html')
151
151
152 # perms check inside
152 # perms check inside
153 @NotAnonymous()
153 @NotAnonymous()
154 @auth.CSRFRequired()
154 @auth.CSRFRequired()
155 def create(self):
155 def create(self):
156 """
156 """
157 POST /repos: Create a new item"""
157 POST /repos: Create a new item"""
158 # url('repos')
158 # url('repos')
159
159
160 self.__load_defaults()
160 self.__load_defaults()
161 form_result = {}
161 form_result = {}
162 task_id = None
162 task_id = None
163 c.personal_repo_group = c.rhodecode_user.personal_repo_group
163 c.personal_repo_group = c.rhodecode_user.personal_repo_group
164 try:
164 try:
165 # CanWriteToGroup validators checks permissions of this POST
165 # CanWriteToGroup validators checks permissions of this POST
166 form_result = RepoForm(repo_groups=c.repo_groups_choices,
166 form_result = RepoForm(repo_groups=c.repo_groups_choices,
167 landing_revs=c.landing_revs_choices)()\
167 landing_revs=c.landing_revs_choices)()\
168 .to_python(dict(request.POST))
168 .to_python(dict(request.POST))
169
169
170 # create is done sometimes async on celery, db transaction
170 # create is done sometimes async on celery, db transaction
171 # management is handled there.
171 # management is handled there.
172 task = RepoModel().create(form_result, c.rhodecode_user.user_id)
172 task = RepoModel().create(form_result, c.rhodecode_user.user_id)
173 from celery.result import BaseAsyncResult
173 from celery.result import BaseAsyncResult
174 if isinstance(task, BaseAsyncResult):
174 if isinstance(task, BaseAsyncResult):
175 task_id = task.task_id
175 task_id = task.task_id
176 except formencode.Invalid as errors:
176 except formencode.Invalid as errors:
177 return htmlfill.render(
177 return htmlfill.render(
178 render('admin/repos/repo_add.html'),
178 render('admin/repos/repo_add.html'),
179 defaults=errors.value,
179 defaults=errors.value,
180 errors=errors.error_dict or {},
180 errors=errors.error_dict or {},
181 prefix_error=False,
181 prefix_error=False,
182 encoding="UTF-8",
182 encoding="UTF-8",
183 force_defaults=False)
183 force_defaults=False)
184
184
185 except Exception as e:
185 except Exception as e:
186 msg = self._log_creation_exception(e, form_result.get('repo_name'))
186 msg = self._log_creation_exception(e, form_result.get('repo_name'))
187 h.flash(msg, category='error')
187 h.flash(msg, category='error')
188 return redirect(url('home'))
188 return redirect(url('home'))
189
189
190 return redirect(h.url('repo_creating_home',
190 return redirect(h.url('repo_creating_home',
191 repo_name=form_result['repo_name_full'],
191 repo_name=form_result['repo_name_full'],
192 task_id=task_id))
192 task_id=task_id))
193
193
194 # perms check inside
194 # perms check inside
195 @NotAnonymous()
195 @NotAnonymous()
196 def create_repository(self):
196 def create_repository(self):
197 """GET /_admin/create_repository: Form to create a new item"""
197 """GET /_admin/create_repository: Form to create a new item"""
198 new_repo = request.GET.get('repo', '')
198 new_repo = request.GET.get('repo', '')
199 parent_group = request.GET.get('parent_group')
199 parent_group = safe_int(request.GET.get('parent_group'))
200 _gr = RepoGroup.get(parent_group)
201
200 if not HasPermissionAny('hg.admin', 'hg.create.repository')():
202 if not HasPermissionAny('hg.admin', 'hg.create.repository')():
201 # you're not super admin nor have global create permissions,
203 # you're not super admin nor have global create permissions,
202 # but maybe you have at least write permission to a parent group ?
204 # but maybe you have at least write permission to a parent group ?
203 _gr = RepoGroup.get(parent_group)
205
204 gr_name = _gr.group_name if _gr else None
206 gr_name = _gr.group_name if _gr else None
205 # create repositories with write permission on group is set to true
207 # create repositories with write permission on group is set to true
206 create_on_write = HasPermissionAny('hg.create.write_on_repogroup.true')()
208 create_on_write = HasPermissionAny('hg.create.write_on_repogroup.true')()
207 group_admin = HasRepoGroupPermissionAny('group.admin')(group_name=gr_name)
209 group_admin = HasRepoGroupPermissionAny('group.admin')(group_name=gr_name)
208 group_write = HasRepoGroupPermissionAny('group.write')(group_name=gr_name)
210 group_write = HasRepoGroupPermissionAny('group.write')(group_name=gr_name)
209 if not (group_admin or (group_write and create_on_write)):
211 if not (group_admin or (group_write and create_on_write)):
210 raise HTTPForbidden
212 raise HTTPForbidden
211
213
212 acl_groups = RepoGroupList(RepoGroup.query().all(),
214 acl_groups = RepoGroupList(RepoGroup.query().all(),
213 perm_set=['group.write', 'group.admin'])
215 perm_set=['group.write', 'group.admin'])
214 c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
216 c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
215 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
217 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
216 choices, c.landing_revs = ScmModel().get_repo_landing_revs()
218 choices, c.landing_revs = ScmModel().get_repo_landing_revs()
217 c.personal_repo_group = c.rhodecode_user.personal_repo_group
219 c.personal_repo_group = c.rhodecode_user.personal_repo_group
218 c.new_repo = repo_name_slug(new_repo)
220 c.new_repo = repo_name_slug(new_repo)
219
221
220 ## apply the defaults from defaults page
222 # apply the defaults from defaults page
221 defaults = SettingsModel().get_default_repo_settings(strip_prefix=True)
223 defaults = SettingsModel().get_default_repo_settings(strip_prefix=True)
222 # set checkbox to autochecked
224 # set checkbox to autochecked
223 defaults['repo_copy_permissions'] = True
225 defaults['repo_copy_permissions'] = True
224 if parent_group:
226
225 defaults.update({'repo_group': parent_group})
227 parent_group_choice = '-1'
228 if not c.rhodecode_user.is_admin and c.rhodecode_user.personal_repo_group:
229 parent_group_choice = c.rhodecode_user.personal_repo_group
230
231 if parent_group and _gr:
232 if parent_group in [x[0] for x in c.repo_groups]:
233 parent_group_choice = unicode(parent_group)
234
235 defaults.update({'repo_group': parent_group_choice})
226
236
227 return htmlfill.render(
237 return htmlfill.render(
228 render('admin/repos/repo_add.html'),
238 render('admin/repos/repo_add.html'),
229 defaults=defaults,
239 defaults=defaults,
230 errors={},
240 errors={},
231 prefix_error=False,
241 prefix_error=False,
232 encoding="UTF-8",
242 encoding="UTF-8",
233 force_defaults=False
243 force_defaults=False
234 )
244 )
235
245
236 @NotAnonymous()
246 @NotAnonymous()
237 def repo_creating(self, repo_name):
247 def repo_creating(self, repo_name):
238 c.repo = repo_name
248 c.repo = repo_name
239 c.task_id = request.GET.get('task_id')
249 c.task_id = request.GET.get('task_id')
240 if not c.repo:
250 if not c.repo:
241 raise HTTPNotFound()
251 raise HTTPNotFound()
242 return render('admin/repos/repo_creating.html')
252 return render('admin/repos/repo_creating.html')
243
253
244 @NotAnonymous()
254 @NotAnonymous()
245 @jsonify
255 @jsonify
246 def repo_check(self, repo_name):
256 def repo_check(self, repo_name):
247 c.repo = repo_name
257 c.repo = repo_name
248 task_id = request.GET.get('task_id')
258 task_id = request.GET.get('task_id')
249
259
250 if task_id and task_id not in ['None']:
260 if task_id and task_id not in ['None']:
251 import rhodecode
261 import rhodecode
252 from celery.result import AsyncResult
262 from celery.result import AsyncResult
253 if rhodecode.CELERY_ENABLED:
263 if rhodecode.CELERY_ENABLED:
254 task = AsyncResult(task_id)
264 task = AsyncResult(task_id)
255 if task.failed():
265 if task.failed():
256 msg = self._log_creation_exception(task.result, c.repo)
266 msg = self._log_creation_exception(task.result, c.repo)
257 h.flash(msg, category='error')
267 h.flash(msg, category='error')
258 return redirect(url('home'), code=501)
268 return redirect(url('home'), code=501)
259
269
260 repo = Repository.get_by_repo_name(repo_name)
270 repo = Repository.get_by_repo_name(repo_name)
261 if repo and repo.repo_state == Repository.STATE_CREATED:
271 if repo and repo.repo_state == Repository.STATE_CREATED:
262 if repo.clone_uri:
272 if repo.clone_uri:
263 clone_uri = repo.clone_uri_hidden
273 clone_uri = repo.clone_uri_hidden
264 h.flash(_('Created repository %s from %s')
274 h.flash(_('Created repository %s from %s')
265 % (repo.repo_name, clone_uri), category='success')
275 % (repo.repo_name, clone_uri), category='success')
266 else:
276 else:
267 repo_url = h.link_to(repo.repo_name,
277 repo_url = h.link_to(repo.repo_name,
268 h.url('summary_home',
278 h.url('summary_home',
269 repo_name=repo.repo_name))
279 repo_name=repo.repo_name))
270 fork = repo.fork
280 fork = repo.fork
271 if fork:
281 if fork:
272 fork_name = fork.repo_name
282 fork_name = fork.repo_name
273 h.flash(h.literal(_('Forked repository %s as %s')
283 h.flash(h.literal(_('Forked repository %s as %s')
274 % (fork_name, repo_url)), category='success')
284 % (fork_name, repo_url)), category='success')
275 else:
285 else:
276 h.flash(h.literal(_('Created repository %s') % repo_url),
286 h.flash(h.literal(_('Created repository %s') % repo_url),
277 category='success')
287 category='success')
278 return {'result': True}
288 return {'result': True}
279 return {'result': False}
289 return {'result': False}
280
290
281 @HasRepoPermissionAllDecorator('repository.admin')
291 @HasRepoPermissionAllDecorator('repository.admin')
282 @auth.CSRFRequired()
292 @auth.CSRFRequired()
283 def update(self, repo_name):
293 def update(self, repo_name):
284 """
294 """
285 PUT /repos/repo_name: Update an existing item"""
295 PUT /repos/repo_name: Update an existing item"""
286 # Forms posted to this method should contain a hidden field:
296 # Forms posted to this method should contain a hidden field:
287 # <input type="hidden" name="_method" value="PUT" />
297 # <input type="hidden" name="_method" value="PUT" />
288 # Or using helpers:
298 # Or using helpers:
289 # h.form(url('repo', repo_name=ID),
299 # h.form(url('repo', repo_name=ID),
290 # method='put')
300 # method='put')
291 # url('repo', repo_name=ID)
301 # url('repo', repo_name=ID)
292
302
293 self.__load_data(repo_name)
303 self.__load_data(repo_name)
294 c.active = 'settings'
304 c.active = 'settings'
295 c.repo_fields = RepositoryField.query()\
305 c.repo_fields = RepositoryField.query()\
296 .filter(RepositoryField.repository == c.repo_info).all()
306 .filter(RepositoryField.repository == c.repo_info).all()
297
307
298 repo_model = RepoModel()
308 repo_model = RepoModel()
299 changed_name = repo_name
309 changed_name = repo_name
300
310
301 c.personal_repo_group = c.rhodecode_user.personal_repo_group
311 c.personal_repo_group = c.rhodecode_user.personal_repo_group
302 # override the choices with extracted revisions !
312 # override the choices with extracted revisions !
303 repo = Repository.get_by_repo_name(repo_name)
313 repo = Repository.get_by_repo_name(repo_name)
304 old_data = {
314 old_data = {
305 'repo_name': repo_name,
315 'repo_name': repo_name,
306 'repo_group': repo.group.get_dict() if repo.group else {},
316 'repo_group': repo.group.get_dict() if repo.group else {},
307 'repo_type': repo.repo_type,
317 'repo_type': repo.repo_type,
308 }
318 }
309 _form = RepoForm(
319 _form = RepoForm(
310 edit=True, old_data=old_data, repo_groups=c.repo_groups_choices,
320 edit=True, old_data=old_data, repo_groups=c.repo_groups_choices,
311 landing_revs=c.landing_revs_choices, allow_disabled=True)()
321 landing_revs=c.landing_revs_choices, allow_disabled=True)()
312
322
313 try:
323 try:
314 form_result = _form.to_python(dict(request.POST))
324 form_result = _form.to_python(dict(request.POST))
315 repo = repo_model.update(repo_name, **form_result)
325 repo = repo_model.update(repo_name, **form_result)
316 ScmModel().mark_for_invalidation(repo_name)
326 ScmModel().mark_for_invalidation(repo_name)
317 h.flash(_('Repository %s updated successfully') % repo_name,
327 h.flash(_('Repository %s updated successfully') % repo_name,
318 category='success')
328 category='success')
319 changed_name = repo.repo_name
329 changed_name = repo.repo_name
320 action_logger(c.rhodecode_user, 'admin_updated_repo',
330 action_logger(c.rhodecode_user, 'admin_updated_repo',
321 changed_name, self.ip_addr, self.sa)
331 changed_name, self.ip_addr, self.sa)
322 Session().commit()
332 Session().commit()
323 except formencode.Invalid as errors:
333 except formencode.Invalid as errors:
324 defaults = self.__load_data(repo_name)
334 defaults = self.__load_data(repo_name)
325 defaults.update(errors.value)
335 defaults.update(errors.value)
326 return htmlfill.render(
336 return htmlfill.render(
327 render('admin/repos/repo_edit.html'),
337 render('admin/repos/repo_edit.html'),
328 defaults=defaults,
338 defaults=defaults,
329 errors=errors.error_dict or {},
339 errors=errors.error_dict or {},
330 prefix_error=False,
340 prefix_error=False,
331 encoding="UTF-8",
341 encoding="UTF-8",
332 force_defaults=False)
342 force_defaults=False)
333
343
334 except Exception:
344 except Exception:
335 log.exception("Exception during update of repository")
345 log.exception("Exception during update of repository")
336 h.flash(_('Error occurred during update of repository %s') \
346 h.flash(_('Error occurred during update of repository %s') \
337 % repo_name, category='error')
347 % repo_name, category='error')
338 return redirect(url('edit_repo', repo_name=changed_name))
348 return redirect(url('edit_repo', repo_name=changed_name))
339
349
340 @HasRepoPermissionAllDecorator('repository.admin')
350 @HasRepoPermissionAllDecorator('repository.admin')
341 @auth.CSRFRequired()
351 @auth.CSRFRequired()
342 def delete(self, repo_name):
352 def delete(self, repo_name):
343 """
353 """
344 DELETE /repos/repo_name: Delete an existing item"""
354 DELETE /repos/repo_name: Delete an existing item"""
345 # Forms posted to this method should contain a hidden field:
355 # Forms posted to this method should contain a hidden field:
346 # <input type="hidden" name="_method" value="DELETE" />
356 # <input type="hidden" name="_method" value="DELETE" />
347 # Or using helpers:
357 # Or using helpers:
348 # h.form(url('repo', repo_name=ID),
358 # h.form(url('repo', repo_name=ID),
349 # method='delete')
359 # method='delete')
350 # url('repo', repo_name=ID)
360 # url('repo', repo_name=ID)
351
361
352 repo_model = RepoModel()
362 repo_model = RepoModel()
353 repo = repo_model.get_by_repo_name(repo_name)
363 repo = repo_model.get_by_repo_name(repo_name)
354 if not repo:
364 if not repo:
355 h.not_mapped_error(repo_name)
365 h.not_mapped_error(repo_name)
356 return redirect(url('repos'))
366 return redirect(url('repos'))
357 try:
367 try:
358 _forks = repo.forks.count()
368 _forks = repo.forks.count()
359 handle_forks = None
369 handle_forks = None
360 if _forks and request.POST.get('forks'):
370 if _forks and request.POST.get('forks'):
361 do = request.POST['forks']
371 do = request.POST['forks']
362 if do == 'detach_forks':
372 if do == 'detach_forks':
363 handle_forks = 'detach'
373 handle_forks = 'detach'
364 h.flash(_('Detached %s forks') % _forks, category='success')
374 h.flash(_('Detached %s forks') % _forks, category='success')
365 elif do == 'delete_forks':
375 elif do == 'delete_forks':
366 handle_forks = 'delete'
376 handle_forks = 'delete'
367 h.flash(_('Deleted %s forks') % _forks, category='success')
377 h.flash(_('Deleted %s forks') % _forks, category='success')
368 repo_model.delete(repo, forks=handle_forks)
378 repo_model.delete(repo, forks=handle_forks)
369 action_logger(c.rhodecode_user, 'admin_deleted_repo',
379 action_logger(c.rhodecode_user, 'admin_deleted_repo',
370 repo_name, self.ip_addr, self.sa)
380 repo_name, self.ip_addr, self.sa)
371 ScmModel().mark_for_invalidation(repo_name)
381 ScmModel().mark_for_invalidation(repo_name)
372 h.flash(_('Deleted repository %s') % repo_name, category='success')
382 h.flash(_('Deleted repository %s') % repo_name, category='success')
373 Session().commit()
383 Session().commit()
374 except AttachedForksError:
384 except AttachedForksError:
375 h.flash(_('Cannot delete %s it still contains attached forks')
385 h.flash(_('Cannot delete %s it still contains attached forks')
376 % repo_name, category='warning')
386 % repo_name, category='warning')
377
387
378 except Exception:
388 except Exception:
379 log.exception("Exception during deletion of repository")
389 log.exception("Exception during deletion of repository")
380 h.flash(_('An error occurred during deletion of %s') % repo_name,
390 h.flash(_('An error occurred during deletion of %s') % repo_name,
381 category='error')
391 category='error')
382
392
383 return redirect(url('repos'))
393 return redirect(url('repos'))
384
394
385 @HasPermissionAllDecorator('hg.admin')
395 @HasPermissionAllDecorator('hg.admin')
386 def show(self, repo_name, format='html'):
396 def show(self, repo_name, format='html'):
387 """GET /repos/repo_name: Show a specific item"""
397 """GET /repos/repo_name: Show a specific item"""
388 # url('repo', repo_name=ID)
398 # url('repo', repo_name=ID)
389
399
390 @HasRepoPermissionAllDecorator('repository.admin')
400 @HasRepoPermissionAllDecorator('repository.admin')
391 def edit(self, repo_name):
401 def edit(self, repo_name):
392 """GET /repo_name/settings: Form to edit an existing item"""
402 """GET /repo_name/settings: Form to edit an existing item"""
393 # url('edit_repo', repo_name=ID)
403 # url('edit_repo', repo_name=ID)
394 defaults = self.__load_data(repo_name)
404 defaults = self.__load_data(repo_name)
395 if 'clone_uri' in defaults:
405 if 'clone_uri' in defaults:
396 del defaults['clone_uri']
406 del defaults['clone_uri']
397
407
398 c.repo_fields = RepositoryField.query()\
408 c.repo_fields = RepositoryField.query()\
399 .filter(RepositoryField.repository == c.repo_info).all()
409 .filter(RepositoryField.repository == c.repo_info).all()
400 c.personal_repo_group = c.rhodecode_user.personal_repo_group
410 c.personal_repo_group = c.rhodecode_user.personal_repo_group
401 c.active = 'settings'
411 c.active = 'settings'
402 return htmlfill.render(
412 return htmlfill.render(
403 render('admin/repos/repo_edit.html'),
413 render('admin/repos/repo_edit.html'),
404 defaults=defaults,
414 defaults=defaults,
405 encoding="UTF-8",
415 encoding="UTF-8",
406 force_defaults=False)
416 force_defaults=False)
407
417
408 @HasRepoPermissionAllDecorator('repository.admin')
418 @HasRepoPermissionAllDecorator('repository.admin')
409 def edit_permissions(self, repo_name):
419 def edit_permissions(self, repo_name):
410 """GET /repo_name/settings: Form to edit an existing item"""
420 """GET /repo_name/settings: Form to edit an existing item"""
411 # url('edit_repo', repo_name=ID)
421 # url('edit_repo', repo_name=ID)
412 c.repo_info = self._load_repo(repo_name)
422 c.repo_info = self._load_repo(repo_name)
413 c.active = 'permissions'
423 c.active = 'permissions'
414 defaults = RepoModel()._get_defaults(repo_name)
424 defaults = RepoModel()._get_defaults(repo_name)
415
425
416 return htmlfill.render(
426 return htmlfill.render(
417 render('admin/repos/repo_edit.html'),
427 render('admin/repos/repo_edit.html'),
418 defaults=defaults,
428 defaults=defaults,
419 encoding="UTF-8",
429 encoding="UTF-8",
420 force_defaults=False)
430 force_defaults=False)
421
431
422 @HasRepoPermissionAllDecorator('repository.admin')
432 @HasRepoPermissionAllDecorator('repository.admin')
423 @auth.CSRFRequired()
433 @auth.CSRFRequired()
424 def edit_permissions_update(self, repo_name):
434 def edit_permissions_update(self, repo_name):
425 form = RepoPermsForm()().to_python(request.POST)
435 form = RepoPermsForm()().to_python(request.POST)
426 RepoModel().update_permissions(repo_name,
436 RepoModel().update_permissions(repo_name,
427 form['perm_additions'], form['perm_updates'], form['perm_deletions'])
437 form['perm_additions'], form['perm_updates'], form['perm_deletions'])
428
438
429 #TODO: implement this
439 #TODO: implement this
430 #action_logger(c.rhodecode_user, 'admin_changed_repo_permissions',
440 #action_logger(c.rhodecode_user, 'admin_changed_repo_permissions',
431 # repo_name, self.ip_addr, self.sa)
441 # repo_name, self.ip_addr, self.sa)
432 Session().commit()
442 Session().commit()
433 h.flash(_('Repository permissions updated'), category='success')
443 h.flash(_('Repository permissions updated'), category='success')
434 return redirect(url('edit_repo_perms', repo_name=repo_name))
444 return redirect(url('edit_repo_perms', repo_name=repo_name))
435
445
436 @HasRepoPermissionAllDecorator('repository.admin')
446 @HasRepoPermissionAllDecorator('repository.admin')
437 def edit_fields(self, repo_name):
447 def edit_fields(self, repo_name):
438 """GET /repo_name/settings: Form to edit an existing item"""
448 """GET /repo_name/settings: Form to edit an existing item"""
439 # url('edit_repo', repo_name=ID)
449 # url('edit_repo', repo_name=ID)
440 c.repo_info = self._load_repo(repo_name)
450 c.repo_info = self._load_repo(repo_name)
441 c.repo_fields = RepositoryField.query()\
451 c.repo_fields = RepositoryField.query()\
442 .filter(RepositoryField.repository == c.repo_info).all()
452 .filter(RepositoryField.repository == c.repo_info).all()
443 c.active = 'fields'
453 c.active = 'fields'
444 if request.POST:
454 if request.POST:
445
455
446 return redirect(url('repo_edit_fields'))
456 return redirect(url('repo_edit_fields'))
447 return render('admin/repos/repo_edit.html')
457 return render('admin/repos/repo_edit.html')
448
458
449 @HasRepoPermissionAllDecorator('repository.admin')
459 @HasRepoPermissionAllDecorator('repository.admin')
450 @auth.CSRFRequired()
460 @auth.CSRFRequired()
451 def create_repo_field(self, repo_name):
461 def create_repo_field(self, repo_name):
452 try:
462 try:
453 form_result = RepoFieldForm()().to_python(dict(request.POST))
463 form_result = RepoFieldForm()().to_python(dict(request.POST))
454 RepoModel().add_repo_field(
464 RepoModel().add_repo_field(
455 repo_name, form_result['new_field_key'],
465 repo_name, form_result['new_field_key'],
456 field_type=form_result['new_field_type'],
466 field_type=form_result['new_field_type'],
457 field_value=form_result['new_field_value'],
467 field_value=form_result['new_field_value'],
458 field_label=form_result['new_field_label'],
468 field_label=form_result['new_field_label'],
459 field_desc=form_result['new_field_desc'])
469 field_desc=form_result['new_field_desc'])
460
470
461 Session().commit()
471 Session().commit()
462 except Exception as e:
472 except Exception as e:
463 log.exception("Exception creating field")
473 log.exception("Exception creating field")
464 msg = _('An error occurred during creation of field')
474 msg = _('An error occurred during creation of field')
465 if isinstance(e, formencode.Invalid):
475 if isinstance(e, formencode.Invalid):
466 msg += ". " + e.msg
476 msg += ". " + e.msg
467 h.flash(msg, category='error')
477 h.flash(msg, category='error')
468 return redirect(url('edit_repo_fields', repo_name=repo_name))
478 return redirect(url('edit_repo_fields', repo_name=repo_name))
469
479
470 @HasRepoPermissionAllDecorator('repository.admin')
480 @HasRepoPermissionAllDecorator('repository.admin')
471 @auth.CSRFRequired()
481 @auth.CSRFRequired()
472 def delete_repo_field(self, repo_name, field_id):
482 def delete_repo_field(self, repo_name, field_id):
473 field = RepositoryField.get_or_404(field_id)
483 field = RepositoryField.get_or_404(field_id)
474 try:
484 try:
475 RepoModel().delete_repo_field(repo_name, field.field_key)
485 RepoModel().delete_repo_field(repo_name, field.field_key)
476 Session().commit()
486 Session().commit()
477 except Exception as e:
487 except Exception as e:
478 log.exception("Exception during removal of field")
488 log.exception("Exception during removal of field")
479 msg = _('An error occurred during removal of field')
489 msg = _('An error occurred during removal of field')
480 h.flash(msg, category='error')
490 h.flash(msg, category='error')
481 return redirect(url('edit_repo_fields', repo_name=repo_name))
491 return redirect(url('edit_repo_fields', repo_name=repo_name))
482
492
483 @HasRepoPermissionAllDecorator('repository.admin')
493 @HasRepoPermissionAllDecorator('repository.admin')
484 def edit_advanced(self, repo_name):
494 def edit_advanced(self, repo_name):
485 """GET /repo_name/settings: Form to edit an existing item"""
495 """GET /repo_name/settings: Form to edit an existing item"""
486 # url('edit_repo', repo_name=ID)
496 # url('edit_repo', repo_name=ID)
487 c.repo_info = self._load_repo(repo_name)
497 c.repo_info = self._load_repo(repo_name)
488 c.default_user_id = User.get_default_user().user_id
498 c.default_user_id = User.get_default_user().user_id
489 c.in_public_journal = UserFollowing.query()\
499 c.in_public_journal = UserFollowing.query()\
490 .filter(UserFollowing.user_id == c.default_user_id)\
500 .filter(UserFollowing.user_id == c.default_user_id)\
491 .filter(UserFollowing.follows_repository == c.repo_info).scalar()
501 .filter(UserFollowing.follows_repository == c.repo_info).scalar()
492
502
493 c.active = 'advanced'
503 c.active = 'advanced'
494 c.has_origin_repo_read_perm = False
504 c.has_origin_repo_read_perm = False
495 if c.repo_info.fork:
505 if c.repo_info.fork:
496 c.has_origin_repo_read_perm = h.HasRepoPermissionAny(
506 c.has_origin_repo_read_perm = h.HasRepoPermissionAny(
497 'repository.write', 'repository.read', 'repository.admin')(
507 'repository.write', 'repository.read', 'repository.admin')(
498 c.repo_info.fork.repo_name, 'repo set as fork page')
508 c.repo_info.fork.repo_name, 'repo set as fork page')
499
509
500 if request.POST:
510 if request.POST:
501 return redirect(url('repo_edit_advanced'))
511 return redirect(url('repo_edit_advanced'))
502 return render('admin/repos/repo_edit.html')
512 return render('admin/repos/repo_edit.html')
503
513
504 @HasRepoPermissionAllDecorator('repository.admin')
514 @HasRepoPermissionAllDecorator('repository.admin')
505 @auth.CSRFRequired()
515 @auth.CSRFRequired()
506 def edit_advanced_journal(self, repo_name):
516 def edit_advanced_journal(self, repo_name):
507 """
517 """
508 Set's this repository to be visible in public journal,
518 Set's this repository to be visible in public journal,
509 in other words assing default user to follow this repo
519 in other words assing default user to follow this repo
510
520
511 :param repo_name:
521 :param repo_name:
512 """
522 """
513
523
514 try:
524 try:
515 repo_id = Repository.get_by_repo_name(repo_name).repo_id
525 repo_id = Repository.get_by_repo_name(repo_name).repo_id
516 user_id = User.get_default_user().user_id
526 user_id = User.get_default_user().user_id
517 self.scm_model.toggle_following_repo(repo_id, user_id)
527 self.scm_model.toggle_following_repo(repo_id, user_id)
518 h.flash(_('Updated repository visibility in public journal'),
528 h.flash(_('Updated repository visibility in public journal'),
519 category='success')
529 category='success')
520 Session().commit()
530 Session().commit()
521 except Exception:
531 except Exception:
522 h.flash(_('An error occurred during setting this'
532 h.flash(_('An error occurred during setting this'
523 ' repository in public journal'),
533 ' repository in public journal'),
524 category='error')
534 category='error')
525
535
526 return redirect(url('edit_repo_advanced', repo_name=repo_name))
536 return redirect(url('edit_repo_advanced', repo_name=repo_name))
527
537
528 @HasRepoPermissionAllDecorator('repository.admin')
538 @HasRepoPermissionAllDecorator('repository.admin')
529 @auth.CSRFRequired()
539 @auth.CSRFRequired()
530 def edit_advanced_fork(self, repo_name):
540 def edit_advanced_fork(self, repo_name):
531 """
541 """
532 Mark given repository as a fork of another
542 Mark given repository as a fork of another
533
543
534 :param repo_name:
544 :param repo_name:
535 """
545 """
536
546
537 new_fork_id = request.POST.get('id_fork_of')
547 new_fork_id = request.POST.get('id_fork_of')
538 try:
548 try:
539
549
540 if new_fork_id and not new_fork_id.isdigit():
550 if new_fork_id and not new_fork_id.isdigit():
541 log.error('Given fork id %s is not an INT', new_fork_id)
551 log.error('Given fork id %s is not an INT', new_fork_id)
542
552
543 fork_id = safe_int(new_fork_id)
553 fork_id = safe_int(new_fork_id)
544 repo = ScmModel().mark_as_fork(repo_name, fork_id,
554 repo = ScmModel().mark_as_fork(repo_name, fork_id,
545 c.rhodecode_user.username)
555 c.rhodecode_user.username)
546 fork = repo.fork.repo_name if repo.fork else _('Nothing')
556 fork = repo.fork.repo_name if repo.fork else _('Nothing')
547 Session().commit()
557 Session().commit()
548 h.flash(_('Marked repo %s as fork of %s') % (repo_name, fork),
558 h.flash(_('Marked repo %s as fork of %s') % (repo_name, fork),
549 category='success')
559 category='success')
550 except RepositoryError as e:
560 except RepositoryError as e:
551 log.exception("Repository Error occurred")
561 log.exception("Repository Error occurred")
552 h.flash(str(e), category='error')
562 h.flash(str(e), category='error')
553 except Exception as e:
563 except Exception as e:
554 log.exception("Exception while editing fork")
564 log.exception("Exception while editing fork")
555 h.flash(_('An error occurred during this operation'),
565 h.flash(_('An error occurred during this operation'),
556 category='error')
566 category='error')
557
567
558 return redirect(url('edit_repo_advanced', repo_name=repo_name))
568 return redirect(url('edit_repo_advanced', repo_name=repo_name))
559
569
560 @HasRepoPermissionAllDecorator('repository.admin')
570 @HasRepoPermissionAllDecorator('repository.admin')
561 @auth.CSRFRequired()
571 @auth.CSRFRequired()
562 def edit_advanced_locking(self, repo_name):
572 def edit_advanced_locking(self, repo_name):
563 """
573 """
564 Unlock repository when it is locked !
574 Unlock repository when it is locked !
565
575
566 :param repo_name:
576 :param repo_name:
567 """
577 """
568 try:
578 try:
569 repo = Repository.get_by_repo_name(repo_name)
579 repo = Repository.get_by_repo_name(repo_name)
570 if request.POST.get('set_lock'):
580 if request.POST.get('set_lock'):
571 Repository.lock(repo, c.rhodecode_user.user_id,
581 Repository.lock(repo, c.rhodecode_user.user_id,
572 lock_reason=Repository.LOCK_WEB)
582 lock_reason=Repository.LOCK_WEB)
573 h.flash(_('Locked repository'), category='success')
583 h.flash(_('Locked repository'), category='success')
574 elif request.POST.get('set_unlock'):
584 elif request.POST.get('set_unlock'):
575 Repository.unlock(repo)
585 Repository.unlock(repo)
576 h.flash(_('Unlocked repository'), category='success')
586 h.flash(_('Unlocked repository'), category='success')
577 except Exception as e:
587 except Exception as e:
578 log.exception("Exception during unlocking")
588 log.exception("Exception during unlocking")
579 h.flash(_('An error occurred during unlocking'),
589 h.flash(_('An error occurred during unlocking'),
580 category='error')
590 category='error')
581 return redirect(url('edit_repo_advanced', repo_name=repo_name))
591 return redirect(url('edit_repo_advanced', repo_name=repo_name))
582
592
583 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
593 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
584 @auth.CSRFRequired()
594 @auth.CSRFRequired()
585 def toggle_locking(self, repo_name):
595 def toggle_locking(self, repo_name):
586 """
596 """
587 Toggle locking of repository by simple GET call to url
597 Toggle locking of repository by simple GET call to url
588
598
589 :param repo_name:
599 :param repo_name:
590 """
600 """
591
601
592 try:
602 try:
593 repo = Repository.get_by_repo_name(repo_name)
603 repo = Repository.get_by_repo_name(repo_name)
594
604
595 if repo.enable_locking:
605 if repo.enable_locking:
596 if repo.locked[0]:
606 if repo.locked[0]:
597 Repository.unlock(repo)
607 Repository.unlock(repo)
598 action = _('Unlocked')
608 action = _('Unlocked')
599 else:
609 else:
600 Repository.lock(repo, c.rhodecode_user.user_id,
610 Repository.lock(repo, c.rhodecode_user.user_id,
601 lock_reason=Repository.LOCK_WEB)
611 lock_reason=Repository.LOCK_WEB)
602 action = _('Locked')
612 action = _('Locked')
603
613
604 h.flash(_('Repository has been %s') % action,
614 h.flash(_('Repository has been %s') % action,
605 category='success')
615 category='success')
606 except Exception:
616 except Exception:
607 log.exception("Exception during unlocking")
617 log.exception("Exception during unlocking")
608 h.flash(_('An error occurred during unlocking'),
618 h.flash(_('An error occurred during unlocking'),
609 category='error')
619 category='error')
610 return redirect(url('summary_home', repo_name=repo_name))
620 return redirect(url('summary_home', repo_name=repo_name))
611
621
612 @HasRepoPermissionAllDecorator('repository.admin')
622 @HasRepoPermissionAllDecorator('repository.admin')
613 @auth.CSRFRequired()
623 @auth.CSRFRequired()
614 def edit_caches(self, repo_name):
624 def edit_caches(self, repo_name):
615 """PUT /{repo_name}/settings/caches: invalidate the repo caches."""
625 """PUT /{repo_name}/settings/caches: invalidate the repo caches."""
616 try:
626 try:
617 ScmModel().mark_for_invalidation(repo_name, delete=True)
627 ScmModel().mark_for_invalidation(repo_name, delete=True)
618 Session().commit()
628 Session().commit()
619 h.flash(_('Cache invalidation successful'),
629 h.flash(_('Cache invalidation successful'),
620 category='success')
630 category='success')
621 except Exception:
631 except Exception:
622 log.exception("Exception during cache invalidation")
632 log.exception("Exception during cache invalidation")
623 h.flash(_('An error occurred during cache invalidation'),
633 h.flash(_('An error occurred during cache invalidation'),
624 category='error')
634 category='error')
625
635
626 return redirect(url('edit_repo_caches', repo_name=c.repo_name))
636 return redirect(url('edit_repo_caches', repo_name=c.repo_name))
627
637
628 @HasRepoPermissionAllDecorator('repository.admin')
638 @HasRepoPermissionAllDecorator('repository.admin')
629 def edit_caches_form(self, repo_name):
639 def edit_caches_form(self, repo_name):
630 """GET /repo_name/settings: Form to edit an existing item"""
640 """GET /repo_name/settings: Form to edit an existing item"""
631 # url('edit_repo', repo_name=ID)
641 # url('edit_repo', repo_name=ID)
632 c.repo_info = self._load_repo(repo_name)
642 c.repo_info = self._load_repo(repo_name)
633 c.active = 'caches'
643 c.active = 'caches'
634
644
635 return render('admin/repos/repo_edit.html')
645 return render('admin/repos/repo_edit.html')
636
646
637 @HasRepoPermissionAllDecorator('repository.admin')
647 @HasRepoPermissionAllDecorator('repository.admin')
638 @auth.CSRFRequired()
648 @auth.CSRFRequired()
639 def edit_remote(self, repo_name):
649 def edit_remote(self, repo_name):
640 """PUT /{repo_name}/settings/remote: edit the repo remote."""
650 """PUT /{repo_name}/settings/remote: edit the repo remote."""
641 try:
651 try:
642 ScmModel().pull_changes(repo_name, c.rhodecode_user.username)
652 ScmModel().pull_changes(repo_name, c.rhodecode_user.username)
643 h.flash(_('Pulled from remote location'), category='success')
653 h.flash(_('Pulled from remote location'), category='success')
644 except Exception:
654 except Exception:
645 log.exception("Exception during pull from remote")
655 log.exception("Exception during pull from remote")
646 h.flash(_('An error occurred during pull from remote location'),
656 h.flash(_('An error occurred during pull from remote location'),
647 category='error')
657 category='error')
648 return redirect(url('edit_repo_remote', repo_name=c.repo_name))
658 return redirect(url('edit_repo_remote', repo_name=c.repo_name))
649
659
650 @HasRepoPermissionAllDecorator('repository.admin')
660 @HasRepoPermissionAllDecorator('repository.admin')
651 def edit_remote_form(self, repo_name):
661 def edit_remote_form(self, repo_name):
652 """GET /repo_name/settings: Form to edit an existing item"""
662 """GET /repo_name/settings: Form to edit an existing item"""
653 # url('edit_repo', repo_name=ID)
663 # url('edit_repo', repo_name=ID)
654 c.repo_info = self._load_repo(repo_name)
664 c.repo_info = self._load_repo(repo_name)
655 c.active = 'remote'
665 c.active = 'remote'
656
666
657 return render('admin/repos/repo_edit.html')
667 return render('admin/repos/repo_edit.html')
658
668
659 @HasRepoPermissionAllDecorator('repository.admin')
669 @HasRepoPermissionAllDecorator('repository.admin')
660 @auth.CSRFRequired()
670 @auth.CSRFRequired()
661 def edit_statistics(self, repo_name):
671 def edit_statistics(self, repo_name):
662 """PUT /{repo_name}/settings/statistics: reset the repo statistics."""
672 """PUT /{repo_name}/settings/statistics: reset the repo statistics."""
663 try:
673 try:
664 RepoModel().delete_stats(repo_name)
674 RepoModel().delete_stats(repo_name)
665 Session().commit()
675 Session().commit()
666 except Exception as e:
676 except Exception as e:
667 log.error(traceback.format_exc())
677 log.error(traceback.format_exc())
668 h.flash(_('An error occurred during deletion of repository stats'),
678 h.flash(_('An error occurred during deletion of repository stats'),
669 category='error')
679 category='error')
670 return redirect(url('edit_repo_statistics', repo_name=c.repo_name))
680 return redirect(url('edit_repo_statistics', repo_name=c.repo_name))
671
681
672 @HasRepoPermissionAllDecorator('repository.admin')
682 @HasRepoPermissionAllDecorator('repository.admin')
673 def edit_statistics_form(self, repo_name):
683 def edit_statistics_form(self, repo_name):
674 """GET /repo_name/settings: Form to edit an existing item"""
684 """GET /repo_name/settings: Form to edit an existing item"""
675 # url('edit_repo', repo_name=ID)
685 # url('edit_repo', repo_name=ID)
676 c.repo_info = self._load_repo(repo_name)
686 c.repo_info = self._load_repo(repo_name)
677 repo = c.repo_info.scm_instance()
687 repo = c.repo_info.scm_instance()
678
688
679 if c.repo_info.stats:
689 if c.repo_info.stats:
680 # this is on what revision we ended up so we add +1 for count
690 # this is on what revision we ended up so we add +1 for count
681 last_rev = c.repo_info.stats.stat_on_revision + 1
691 last_rev = c.repo_info.stats.stat_on_revision + 1
682 else:
692 else:
683 last_rev = 0
693 last_rev = 0
684 c.stats_revision = last_rev
694 c.stats_revision = last_rev
685
695
686 c.repo_last_rev = repo.count()
696 c.repo_last_rev = repo.count()
687
697
688 if last_rev == 0 or c.repo_last_rev == 0:
698 if last_rev == 0 or c.repo_last_rev == 0:
689 c.stats_percentage = 0
699 c.stats_percentage = 0
690 else:
700 else:
691 c.stats_percentage = '%.2f' % ((float((last_rev)) / c.repo_last_rev) * 100)
701 c.stats_percentage = '%.2f' % ((float((last_rev)) / c.repo_last_rev) * 100)
692
702
693 c.active = 'statistics'
703 c.active = 'statistics'
694
704
695 return render('admin/repos/repo_edit.html')
705 return render('admin/repos/repo_edit.html')
696
706
697 @HasRepoPermissionAllDecorator('repository.admin')
707 @HasRepoPermissionAllDecorator('repository.admin')
698 @auth.CSRFRequired()
708 @auth.CSRFRequired()
699 def repo_issuetracker_test(self, repo_name):
709 def repo_issuetracker_test(self, repo_name):
700 if request.is_xhr:
710 if request.is_xhr:
701 return h.urlify_commit_message(
711 return h.urlify_commit_message(
702 request.POST.get('test_text', ''),
712 request.POST.get('test_text', ''),
703 repo_name)
713 repo_name)
704 else:
714 else:
705 raise HTTPBadRequest()
715 raise HTTPBadRequest()
706
716
707 @HasRepoPermissionAllDecorator('repository.admin')
717 @HasRepoPermissionAllDecorator('repository.admin')
708 @auth.CSRFRequired()
718 @auth.CSRFRequired()
709 def repo_issuetracker_delete(self, repo_name):
719 def repo_issuetracker_delete(self, repo_name):
710 uid = request.POST.get('uid')
720 uid = request.POST.get('uid')
711 repo_settings = IssueTrackerSettingsModel(repo=repo_name)
721 repo_settings = IssueTrackerSettingsModel(repo=repo_name)
712 try:
722 try:
713 repo_settings.delete_entries(uid)
723 repo_settings.delete_entries(uid)
714 except Exception:
724 except Exception:
715 h.flash(_('Error occurred during deleting issue tracker entry'),
725 h.flash(_('Error occurred during deleting issue tracker entry'),
716 category='error')
726 category='error')
717 else:
727 else:
718 h.flash(_('Removed issue tracker entry'), category='success')
728 h.flash(_('Removed issue tracker entry'), category='success')
719 return redirect(url('repo_settings_issuetracker',
729 return redirect(url('repo_settings_issuetracker',
720 repo_name=repo_name))
730 repo_name=repo_name))
721
731
722 def _update_patterns(self, form, repo_settings):
732 def _update_patterns(self, form, repo_settings):
723 for uid in form['delete_patterns']:
733 for uid in form['delete_patterns']:
724 repo_settings.delete_entries(uid)
734 repo_settings.delete_entries(uid)
725
735
726 for pattern in form['patterns']:
736 for pattern in form['patterns']:
727 for setting, value, type_ in pattern:
737 for setting, value, type_ in pattern:
728 sett = repo_settings.create_or_update_setting(
738 sett = repo_settings.create_or_update_setting(
729 setting, value, type_)
739 setting, value, type_)
730 Session().add(sett)
740 Session().add(sett)
731
741
732 Session().commit()
742 Session().commit()
733
743
734 @HasRepoPermissionAllDecorator('repository.admin')
744 @HasRepoPermissionAllDecorator('repository.admin')
735 @auth.CSRFRequired()
745 @auth.CSRFRequired()
736 def repo_issuetracker_save(self, repo_name):
746 def repo_issuetracker_save(self, repo_name):
737 # Save inheritance
747 # Save inheritance
738 repo_settings = IssueTrackerSettingsModel(repo=repo_name)
748 repo_settings = IssueTrackerSettingsModel(repo=repo_name)
739 inherited = (request.POST.get('inherit_global_issuetracker')
749 inherited = (request.POST.get('inherit_global_issuetracker')
740 == "inherited")
750 == "inherited")
741 repo_settings.inherit_global_settings = inherited
751 repo_settings.inherit_global_settings = inherited
742 Session().commit()
752 Session().commit()
743
753
744 form = IssueTrackerPatternsForm()().to_python(request.POST)
754 form = IssueTrackerPatternsForm()().to_python(request.POST)
745 if form:
755 if form:
746 self._update_patterns(form, repo_settings)
756 self._update_patterns(form, repo_settings)
747
757
748 h.flash(_('Updated issue tracker entries'), category='success')
758 h.flash(_('Updated issue tracker entries'), category='success')
749 return redirect(url('repo_settings_issuetracker',
759 return redirect(url('repo_settings_issuetracker',
750 repo_name=repo_name))
760 repo_name=repo_name))
751
761
752 @HasRepoPermissionAllDecorator('repository.admin')
762 @HasRepoPermissionAllDecorator('repository.admin')
753 def repo_issuetracker(self, repo_name):
763 def repo_issuetracker(self, repo_name):
754 """GET /admin/settings/issue-tracker: All items in the collection"""
764 """GET /admin/settings/issue-tracker: All items in the collection"""
755 c.active = 'issuetracker'
765 c.active = 'issuetracker'
756 c.data = 'data'
766 c.data = 'data'
757 c.repo_info = self._load_repo(repo_name)
767 c.repo_info = self._load_repo(repo_name)
758
768
759 repo = Repository.get_by_repo_name(repo_name)
769 repo = Repository.get_by_repo_name(repo_name)
760 c.settings_model = IssueTrackerSettingsModel(repo=repo)
770 c.settings_model = IssueTrackerSettingsModel(repo=repo)
761 c.global_patterns = c.settings_model.get_global_settings()
771 c.global_patterns = c.settings_model.get_global_settings()
762 c.repo_patterns = c.settings_model.get_repo_settings()
772 c.repo_patterns = c.settings_model.get_repo_settings()
763
773
764 return render('admin/repos/repo_edit.html')
774 return render('admin/repos/repo_edit.html')
765
775
766 @HasRepoPermissionAllDecorator('repository.admin')
776 @HasRepoPermissionAllDecorator('repository.admin')
767 def repo_settings_vcs(self, repo_name):
777 def repo_settings_vcs(self, repo_name):
768 """GET /{repo_name}/settings/vcs/: All items in the collection"""
778 """GET /{repo_name}/settings/vcs/: All items in the collection"""
769
779
770 model = VcsSettingsModel(repo=repo_name)
780 model = VcsSettingsModel(repo=repo_name)
771
781
772 c.active = 'vcs'
782 c.active = 'vcs'
773 c.global_svn_branch_patterns = model.get_global_svn_branch_patterns()
783 c.global_svn_branch_patterns = model.get_global_svn_branch_patterns()
774 c.global_svn_tag_patterns = model.get_global_svn_tag_patterns()
784 c.global_svn_tag_patterns = model.get_global_svn_tag_patterns()
775 c.svn_branch_patterns = model.get_repo_svn_branch_patterns()
785 c.svn_branch_patterns = model.get_repo_svn_branch_patterns()
776 c.svn_tag_patterns = model.get_repo_svn_tag_patterns()
786 c.svn_tag_patterns = model.get_repo_svn_tag_patterns()
777 c.repo_info = self._load_repo(repo_name)
787 c.repo_info = self._load_repo(repo_name)
778 defaults = self._vcs_form_defaults(repo_name)
788 defaults = self._vcs_form_defaults(repo_name)
779 c.inherit_global_settings = defaults['inherit_global_settings']
789 c.inherit_global_settings = defaults['inherit_global_settings']
780 c.labs_active = str2bool(
790 c.labs_active = str2bool(
781 rhodecode.CONFIG.get('labs_settings_active', 'true'))
791 rhodecode.CONFIG.get('labs_settings_active', 'true'))
782
792
783 return htmlfill.render(
793 return htmlfill.render(
784 render('admin/repos/repo_edit.html'),
794 render('admin/repos/repo_edit.html'),
785 defaults=defaults,
795 defaults=defaults,
786 encoding="UTF-8",
796 encoding="UTF-8",
787 force_defaults=False)
797 force_defaults=False)
788
798
789 @HasRepoPermissionAllDecorator('repository.admin')
799 @HasRepoPermissionAllDecorator('repository.admin')
790 @auth.CSRFRequired()
800 @auth.CSRFRequired()
791 def repo_settings_vcs_update(self, repo_name):
801 def repo_settings_vcs_update(self, repo_name):
792 """POST /{repo_name}/settings/vcs/: All items in the collection"""
802 """POST /{repo_name}/settings/vcs/: All items in the collection"""
793 c.active = 'vcs'
803 c.active = 'vcs'
794
804
795 model = VcsSettingsModel(repo=repo_name)
805 model = VcsSettingsModel(repo=repo_name)
796 c.global_svn_branch_patterns = model.get_global_svn_branch_patterns()
806 c.global_svn_branch_patterns = model.get_global_svn_branch_patterns()
797 c.global_svn_tag_patterns = model.get_global_svn_tag_patterns()
807 c.global_svn_tag_patterns = model.get_global_svn_tag_patterns()
798 c.svn_branch_patterns = model.get_repo_svn_branch_patterns()
808 c.svn_branch_patterns = model.get_repo_svn_branch_patterns()
799 c.svn_tag_patterns = model.get_repo_svn_tag_patterns()
809 c.svn_tag_patterns = model.get_repo_svn_tag_patterns()
800 c.repo_info = self._load_repo(repo_name)
810 c.repo_info = self._load_repo(repo_name)
801 defaults = self._vcs_form_defaults(repo_name)
811 defaults = self._vcs_form_defaults(repo_name)
802 c.inherit_global_settings = defaults['inherit_global_settings']
812 c.inherit_global_settings = defaults['inherit_global_settings']
803
813
804 application_form = RepoVcsSettingsForm(repo_name)()
814 application_form = RepoVcsSettingsForm(repo_name)()
805 try:
815 try:
806 form_result = application_form.to_python(dict(request.POST))
816 form_result = application_form.to_python(dict(request.POST))
807 except formencode.Invalid as errors:
817 except formencode.Invalid as errors:
808 h.flash(
818 h.flash(
809 _("Some form inputs contain invalid data."),
819 _("Some form inputs contain invalid data."),
810 category='error')
820 category='error')
811 return htmlfill.render(
821 return htmlfill.render(
812 render('admin/repos/repo_edit.html'),
822 render('admin/repos/repo_edit.html'),
813 defaults=errors.value,
823 defaults=errors.value,
814 errors=errors.error_dict or {},
824 errors=errors.error_dict or {},
815 prefix_error=False,
825 prefix_error=False,
816 encoding="UTF-8",
826 encoding="UTF-8",
817 force_defaults=False
827 force_defaults=False
818 )
828 )
819
829
820 try:
830 try:
821 inherit_global_settings = form_result['inherit_global_settings']
831 inherit_global_settings = form_result['inherit_global_settings']
822 model.create_or_update_repo_settings(
832 model.create_or_update_repo_settings(
823 form_result, inherit_global_settings=inherit_global_settings)
833 form_result, inherit_global_settings=inherit_global_settings)
824 except Exception:
834 except Exception:
825 log.exception("Exception while updating settings")
835 log.exception("Exception while updating settings")
826 h.flash(
836 h.flash(
827 _('Error occurred during updating repository VCS settings'),
837 _('Error occurred during updating repository VCS settings'),
828 category='error')
838 category='error')
829 else:
839 else:
830 Session().commit()
840 Session().commit()
831 h.flash(_('Updated VCS settings'), category='success')
841 h.flash(_('Updated VCS settings'), category='success')
832 return redirect(url('repo_vcs_settings', repo_name=repo_name))
842 return redirect(url('repo_vcs_settings', repo_name=repo_name))
833
843
834 return htmlfill.render(
844 return htmlfill.render(
835 render('admin/repos/repo_edit.html'),
845 render('admin/repos/repo_edit.html'),
836 defaults=self._vcs_form_defaults(repo_name),
846 defaults=self._vcs_form_defaults(repo_name),
837 encoding="UTF-8",
847 encoding="UTF-8",
838 force_defaults=False)
848 force_defaults=False)
839
849
840 @HasRepoPermissionAllDecorator('repository.admin')
850 @HasRepoPermissionAllDecorator('repository.admin')
841 @auth.CSRFRequired()
851 @auth.CSRFRequired()
842 @jsonify
852 @jsonify
843 def repo_delete_svn_pattern(self, repo_name):
853 def repo_delete_svn_pattern(self, repo_name):
844 if not request.is_xhr:
854 if not request.is_xhr:
845 return False
855 return False
846
856
847 delete_pattern_id = request.POST.get('delete_svn_pattern')
857 delete_pattern_id = request.POST.get('delete_svn_pattern')
848 model = VcsSettingsModel(repo=repo_name)
858 model = VcsSettingsModel(repo=repo_name)
849 try:
859 try:
850 model.delete_repo_svn_pattern(delete_pattern_id)
860 model.delete_repo_svn_pattern(delete_pattern_id)
851 except SettingNotFound:
861 except SettingNotFound:
852 raise HTTPBadRequest()
862 raise HTTPBadRequest()
853
863
854 Session().commit()
864 Session().commit()
855 return True
865 return True
856
866
857 def _vcs_form_defaults(self, repo_name):
867 def _vcs_form_defaults(self, repo_name):
858 model = VcsSettingsModel(repo=repo_name)
868 model = VcsSettingsModel(repo=repo_name)
859 global_defaults = model.get_global_settings()
869 global_defaults = model.get_global_settings()
860
870
861 repo_defaults = {}
871 repo_defaults = {}
862 repo_defaults.update(global_defaults)
872 repo_defaults.update(global_defaults)
863 repo_defaults.update(model.get_repo_settings())
873 repo_defaults.update(model.get_repo_settings())
864
874
865 global_defaults = {
875 global_defaults = {
866 '{}_inherited'.format(k): global_defaults[k]
876 '{}_inherited'.format(k): global_defaults[k]
867 for k in global_defaults}
877 for k in global_defaults}
868
878
869 defaults = {
879 defaults = {
870 'inherit_global_settings': model.inherit_global_settings
880 'inherit_global_settings': model.inherit_global_settings
871 }
881 }
872 defaults.update(global_defaults)
882 defaults.update(global_defaults)
873 defaults.update(repo_defaults)
883 defaults.update(repo_defaults)
874 defaults.update({
884 defaults.update({
875 'new_svn_branch': '',
885 'new_svn_branch': '',
876 'new_svn_tag': '',
886 'new_svn_tag': '',
877 })
887 })
878 return defaults
888 return defaults
General Comments 0
You need to be logged in to leave comments. Login now