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