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