##// END OF EJS Templates
repositories: ported repo_creating checks to pyramid....
marcink -
r1985:f5a73a5e default
parent child Browse files
Show More
@@ -0,0 +1,110 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
4 #
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
7 # (only), as published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
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/>.
16 #
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
21 import logging
22
23 from pyramid.view import view_config
24 from pyramid.httpexceptions import HTTPFound, HTTPNotFound
25
26 from rhodecode.apps._base import BaseAppView
27 from rhodecode.lib import helpers as h
28 from rhodecode.lib.auth import (NotAnonymous, HasRepoPermissionAny)
29 from rhodecode.model.db import Repository
30
31 log = logging.getLogger(__name__)
32
33
34 class RepoChecksView(BaseAppView):
35 def load_default_context(self):
36 c = self._get_local_tmpl_context()
37 self._register_global_c(c)
38 return c
39
40 @NotAnonymous()
41 @view_config(
42 route_name='repo_creating', request_method='GET',
43 renderer='rhodecode:templates/admin/repos/repo_creating.mako')
44 def repo_creating(self):
45 c = self.load_default_context()
46
47 repo_name = self.request.matchdict['repo_name']
48 db_repo = Repository.get_by_repo_name(repo_name)
49 if not db_repo:
50 raise HTTPNotFound()
51
52 # check if maybe repo is already created
53 if db_repo.repo_state in [Repository.STATE_CREATED]:
54 # re-check permissions before redirecting to prevent resource
55 # discovery by checking the 302 code
56 perm_set = ['repository.read', 'repository.write', 'repository.admin']
57 has_perm = HasRepoPermissionAny(*perm_set)(
58 db_repo.repo_name, 'Repo Creating check')
59 if not has_perm:
60 raise HTTPNotFound()
61
62 raise HTTPFound(h.route_path(
63 'repo_summary', repo_name=db_repo.repo_name))
64
65 c.task_id = self.request.GET.get('task_id')
66 c.repo_name = repo_name
67
68 return self._get_template_context(c)
69
70 @NotAnonymous()
71 @view_config(
72 route_name='repo_creating_check', request_method='GET',
73 renderer='json_ext')
74 def repo_creating_check(self):
75 _ = self.request.translate
76 task_id = self.request.GET.get('task_id')
77 self.load_default_context()
78
79 repo_name = self.request.matchdict['repo_name']
80
81 if task_id and task_id not in ['None']:
82 import rhodecode
83 from celery.result import AsyncResult
84 if rhodecode.CELERY_ENABLED:
85 task = AsyncResult(task_id)
86 if task.failed():
87 msg = self._log_creation_exception(task.result, repo_name)
88 h.flash(msg, category='error')
89 raise HTTPFound(h.route_path('home'), code=501)
90
91 db_repo = Repository.get_by_repo_name(repo_name)
92 if db_repo and db_repo.repo_state == Repository.STATE_CREATED:
93 if db_repo.clone_uri:
94 clone_uri = db_repo.clone_uri_hidden
95 h.flash(_('Created repository %s from %s')
96 % (db_repo.repo_name, clone_uri), category='success')
97 else:
98 repo_url = h.link_to(
99 db_repo.repo_name,
100 h.route_path('repo_summary', repo_name=db_repo.repo_name))
101 fork = db_repo.fork
102 if fork:
103 fork_name = fork.repo_name
104 h.flash(h.literal(_('Forked repository %s as %s')
105 % (fork_name, repo_url)), category='success')
106 else:
107 h.flash(h.literal(_('Created repository %s') % repo_url),
108 category='success')
109 return {'result': True}
110 return {'result': False}
@@ -362,14 +362,22 b' class RepoRoutePredicate(object):'
362 repo_model = repo.RepoModel()
362 repo_model = repo.RepoModel()
363 by_name_match = repo_model.get_by_repo_name(repo_name, cache=True)
363 by_name_match = repo_model.get_by_repo_name(repo_name, cache=True)
364
364
365 def redirect_if_creating(db_repo):
366 if db_repo.repo_state in [repo.Repository.STATE_PENDING]:
367 raise HTTPFound(
368 request.route_path('repo_creating',
369 repo_name=db_repo.repo_name))
370
365 if by_name_match:
371 if by_name_match:
366 # register this as request object we can re-use later
372 # register this as request object we can re-use later
367 request.db_repo = by_name_match
373 request.db_repo = by_name_match
374 redirect_if_creating(by_name_match)
368 return True
375 return True
369
376
370 by_id_match = repo_model.get_repo_by_id(repo_name)
377 by_id_match = repo_model.get_repo_by_id(repo_name)
371 if by_id_match:
378 if by_id_match:
372 request.db_repo = by_id_match
379 request.db_repo = by_id_match
380 redirect_if_creating(by_id_match)
373 return True
381 return True
374
382
375 return False
383 return False
@@ -22,6 +22,15 b' from rhodecode.apps._base import add_rou'
22
22
23 def includeme(config):
23 def includeme(config):
24
24
25 # repo creating checks, special cases that aren't repo routes
26 config.add_route(
27 name='repo_creating',
28 pattern='/{repo_name:.*?[^/]}/repo_creating')
29
30 config.add_route(
31 name='repo_creating_check',
32 pattern='/{repo_name:.*?[^/]}/repo_creating_check')
33
25 # Summary
34 # Summary
26 # NOTE(marcink): one additional route is defined in very bottom, catch
35 # NOTE(marcink): one additional route is defined in very bottom, catch
27 # all pattern
36 # all pattern
@@ -47,8 +47,8 b' def route_path(name, params=None, **kwar'
47 'repo_summary': '/{repo_name}',
47 'repo_summary': '/{repo_name}',
48 'repo_stats': '/{repo_name}/repo_stats/{commit_id}',
48 'repo_stats': '/{repo_name}/repo_stats/{commit_id}',
49 'repo_refs_data': '/{repo_name}/refs-data',
49 'repo_refs_data': '/{repo_name}/refs-data',
50 'repo_refs_changelog_data': '/{repo_name}/refs-data-changelog'
50 'repo_refs_changelog_data': '/{repo_name}/refs-data-changelog',
51
51 'repo_creating_check': '/{repo_name}/repo_creating_check',
52 }[name].format(**kwargs)
52 }[name].format(**kwargs)
53
53
54 if params:
54 if params:
@@ -416,13 +416,6 b' def make_map(config):'
416 # REPOSITORY ROUTES
416 # REPOSITORY ROUTES
417 #==========================================================================
417 #==========================================================================
418
418
419 rmap.connect('repo_creating_home', '/{repo_name}/repo_creating',
420 controller='admin/repos', action='repo_creating',
421 requirements=URL_NAME_REQUIREMENTS)
422 rmap.connect('repo_check_home', '/{repo_name}/crepo_check',
423 controller='admin/repos', action='repo_check',
424 requirements=URL_NAME_REQUIREMENTS)
425
426 # repo edit options
419 # repo edit options
427 rmap.connect('edit_repo_fields', '/{repo_name}/settings/fields',
420 rmap.connect('edit_repo_fields', '/{repo_name}/settings/fields',
428 controller='admin/repos', action='edit_fields',
421 controller='admin/repos', action='edit_fields',
@@ -31,8 +31,9 b' 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, HTTPBadRequest
35
35
36 from pyramid.httpexceptions import HTTPFound
36 import rhodecode
37 import rhodecode
37 from rhodecode.lib import auth, helpers as h
38 from rhodecode.lib import auth, helpers as h
38 from rhodecode.lib.auth import (
39 from rhodecode.lib.auth import (
@@ -183,9 +184,10 b' class ReposController(BaseRepoController'
183 h.flash(msg, category='error')
184 h.flash(msg, category='error')
184 return redirect(h.route_path('home'))
185 return redirect(h.route_path('home'))
185
186
186 return redirect(h.url('repo_creating_home',
187 raise HTTPFound(
187 repo_name=form_result['repo_name_full'],
188 h.route_path('repo_creating',
188 task_id=task_id))
189 repo_name=form_result['repo_name_full'],
190 _query=dict(task_id=task_id)))
189
191
190 # perms check inside
192 # perms check inside
191 @NotAnonymous()
193 @NotAnonymous()
@@ -239,51 +241,6 b' class ReposController(BaseRepoController'
239 force_defaults=False
241 force_defaults=False
240 )
242 )
241
243
242 @NotAnonymous()
243 def repo_creating(self, repo_name):
244 c.repo = repo_name
245 c.task_id = request.GET.get('task_id')
246 if not c.repo:
247 raise HTTPNotFound()
248 return render('admin/repos/repo_creating.mako')
249
250 @NotAnonymous()
251 @jsonify
252 def repo_check(self, repo_name):
253 c.repo = repo_name
254 task_id = request.GET.get('task_id')
255
256 if task_id and task_id not in ['None']:
257 import rhodecode
258 from celery.result import AsyncResult
259 if rhodecode.CELERY_ENABLED:
260 task = AsyncResult(task_id)
261 if task.failed():
262 msg = self._log_creation_exception(task.result, c.repo)
263 h.flash(msg, category='error')
264 return redirect(h.route_path('home'), code=501)
265
266 repo = Repository.get_by_repo_name(repo_name)
267 if repo and repo.repo_state == Repository.STATE_CREATED:
268 if repo.clone_uri:
269 clone_uri = repo.clone_uri_hidden
270 h.flash(_('Created repository %s from %s')
271 % (repo.repo_name, clone_uri), category='success')
272 else:
273 repo_url = h.link_to(
274 repo.repo_name,
275 h.route_path('repo_summary',repo_name=repo.repo_name))
276 fork = repo.fork
277 if fork:
278 fork_name = fork.repo_name
279 h.flash(h.literal(_('Forked repository %s as %s')
280 % (fork_name, repo_url)), category='success')
281 else:
282 h.flash(h.literal(_('Created repository %s') % repo_url),
283 category='success')
284 return {'result': True}
285 return {'result': False}
286
287 @HasPermissionAllDecorator('hg.admin')
244 @HasPermissionAllDecorator('hg.admin')
288 def show(self, repo_name, format='html'):
245 def show(self, repo_name, format='html'):
289 """GET /repos/repo_name: Show a specific item"""
246 """GET /repos/repo_name: Show a specific item"""
@@ -30,6 +30,7 b' from pylons import tmpl_context as c, re'
30 from pylons.controllers.util import redirect
30 from pylons.controllers.util import redirect
31 from pylons.i18n.translation import _
31 from pylons.i18n.translation import _
32
32
33 from pyramid.httpexceptions import HTTPFound
33 import rhodecode.lib.helpers as h
34 import rhodecode.lib.helpers as h
34
35
35 from rhodecode.lib import auth
36 from rhodecode.lib import auth
@@ -191,6 +192,7 b' class ForksController(BaseRepoController'
191 (repo_name, ))
192 (repo_name, ))
192 h.flash(msg, category='error')
193 h.flash(msg, category='error')
193
194
194 return redirect(h.url('repo_creating_home',
195 raise HTTPFound(
195 repo_name=form_result['repo_name_full'],
196 h.route_path('repo_creating',
196 task_id=task_id))
197 repo_name=form_result['repo_name_full'],
198 _query=dict(task_id=task_id)))
@@ -1833,6 +1833,11 b' BIN_FILENODE = 7'
1833 }
1833 }
1834 }
1834 }
1835
1835
1836
1837 .creation_in_progress {
1838 color: @grey4
1839 }
1840
1836 .status_box_menu {
1841 .status_box_menu {
1837 margin: 0;
1842 margin: 0;
1838 }
1843 }
@@ -96,6 +96,8 b' function registerRCRoutes() {'
96 pyroutes.register('journal_public_rss', '/_admin/public_journal/rss', []);
96 pyroutes.register('journal_public_rss', '/_admin/public_journal/rss', []);
97 pyroutes.register('journal_public_rss_old', '/_admin/public_journal_rss', []);
97 pyroutes.register('journal_public_rss_old', '/_admin/public_journal_rss', []);
98 pyroutes.register('toggle_following', '/_admin/toggle_following', []);
98 pyroutes.register('toggle_following', '/_admin/toggle_following', []);
99 pyroutes.register('repo_creating', '/%(repo_name)s/repo_creating', ['repo_name']);
100 pyroutes.register('repo_creating_check', '/%(repo_name)s/repo_creating_check', ['repo_name']);
99 pyroutes.register('repo_summary_explicit', '/%(repo_name)s/summary', ['repo_name']);
101 pyroutes.register('repo_summary_explicit', '/%(repo_name)s/summary', ['repo_name']);
100 pyroutes.register('repo_summary_commits', '/%(repo_name)s/summary-commits', ['repo_name']);
102 pyroutes.register('repo_summary_commits', '/%(repo_name)s/summary-commits', ['repo_name']);
101 pyroutes.register('repo_commit', '/%(repo_name)s/changeset/%(commit_id)s', ['repo_name', 'commit_id']);
103 pyroutes.register('repo_commit', '/%(repo_name)s/changeset/%(commit_id)s', ['repo_name', 'commit_id']);
@@ -2,14 +2,14 b''
2 <%inherit file="/base/base.mako"/>
2 <%inherit file="/base/base.mako"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${_('%s Creating repository') % c.repo_name}
5 ${_('{} Creating repository').format(c.repo_name)}
6 %if c.rhodecode_name:
6 %if c.rhodecode_name:
7 &middot; ${h.branding(c.rhodecode_name)}
7 &middot; ${h.branding(c.rhodecode_name)}
8 %endif
8 %endif
9 </%def>
9 </%def>
10
10
11 <%def name="breadcrumbs_links()">
11 <%def name="breadcrumbs_links()">
12 ${_('Creating repository')} ${c.repo}
12 ${_('Creating repository')} ${c.repo_name}
13 </%def>
13 </%def>
14
14
15 <%def name="menu_bar_nav()">
15 <%def name="menu_bar_nav()">
@@ -38,7 +38,7 b''
38 <script>
38 <script>
39 (function worker() {
39 (function worker() {
40 var skipCheck = false;
40 var skipCheck = false;
41 var url = "${h.url('repo_check_home', repo_name=c.repo_name, repo=c.repo, task_id=c.task_id)}";
41 var url = "${h.route_path('repo_creating_check', repo_name=c.repo_name, _query=dict(task_id=c.task_id))}";
42 $.ajax({
42 $.ajax({
43 url: url,
43 url: url,
44 complete: function(resp) {
44 complete: function(resp) {
@@ -48,12 +48,12 b''
48 if (jsonResponse === undefined) {
48 if (jsonResponse === undefined) {
49 setTimeout(function () {
49 setTimeout(function () {
50 // we might have a backend problem, try dashboard again
50 // we might have a backend problem, try dashboard again
51 window.location = "${h.route_path('repo_summary', repo_name = c.repo)}";
51 window.location = "${h.route_path('repo_summary', repo_name = c.repo_name)}";
52 }, 3000);
52 }, 3000);
53 } else {
53 } else {
54 if (skipCheck || jsonResponse.result === true) {
54 if (skipCheck || jsonResponse.result === true) {
55 // success, means go to dashboard
55 // success, means go to dashboard
56 window.location = "${h.route_path('repo_summary', repo_name = c.repo)}";
56 window.location = "${h.route_path('repo_summary', repo_name = c.repo_name)}";
57 } else {
57 } else {
58 // Schedule the next request when the current one's complete
58 // Schedule the next request when the current one's complete
59 setTimeout(worker, 1000);
59 setTimeout(worker, 1000);
@@ -61,10 +61,17 b''
61 }
61 }
62 }
62 }
63 else {
63 else {
64 window.location = "${h.route_path('home')}";
64 var payload = {
65 message: {
66 message: _gettext('Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.').format(resp.status, resp.statusText),
67 level: 'error',
68 force: true
69 }
70 };
71 $.Topic('/notifications').publish(payload);
65 }
72 }
66 }
73 }
67 });
74 });
68 })();
75 })();
69 </script>
76 </script>
70 </%def> No newline at end of file
77 </%def>
@@ -67,7 +67,9 b''
67 <a href="${h.route_path('repo_summary',repo_name=fork_of.repo_name)}"><i class="icon-code-fork"></i></a>
67 <a href="${h.route_path('repo_summary',repo_name=fork_of.repo_name)}"><i class="icon-code-fork"></i></a>
68 %endif
68 %endif
69 %if rstate == 'repo_state_pending':
69 %if rstate == 'repo_state_pending':
70 <i class="icon-cogs" title="${_('Repository creating in progress...')}"></i>
70 <span class="creation_in_progress tooltip" title="${_('This repository is being created in a background task')}">
71 (${_('creating...')})
72 </span>
71 %endif
73 %endif
72 </div>
74 </div>
73 </%def>
75 </%def>
@@ -122,8 +122,6 b' class _BaseTest(TestController):'
122 csrf_token=self.csrf_token))
122 csrf_token=self.csrf_token))
123
123
124 # run the check page that triggers the flash message
124 # run the check page that triggers the flash message
125 # response = self.app.get(url('repo_check_home', repo_name=repo_name))
126 # assert response.json == {u'result': True}
127 repo_gr_url = h.route_path(
125 repo_gr_url = h.route_path(
128 'repo_group_home', repo_group_name=repo_group_name)
126 'repo_group_home', repo_group_name=repo_group_name)
129
127
@@ -35,14 +35,26 b' from rhodecode.model.settings import Set'
35 from rhodecode.model.user import UserModel
35 from rhodecode.model.user import UserModel
36 from rhodecode.tests import (
36 from rhodecode.tests import (
37 login_user_session, url, assert_session_flash, TEST_USER_ADMIN_LOGIN,
37 login_user_session, url, assert_session_flash, TEST_USER_ADMIN_LOGIN,
38 TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS, HG_REPO, GIT_REPO,
38 TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS, logout_user_session)
39 logout_user_session)
40 from rhodecode.tests.fixture import Fixture, error_function
39 from rhodecode.tests.fixture import Fixture, error_function
41 from rhodecode.tests.utils import AssertResponse, repo_on_filesystem
40 from rhodecode.tests.utils import AssertResponse, repo_on_filesystem
42
41
43 fixture = Fixture()
42 fixture = Fixture()
44
43
45
44
45 def route_path(name, params=None, **kwargs):
46 import urllib
47
48 base_url = {
49 'repo_summary': '/{repo_name}',
50 'repo_creating_check': '/{repo_name}/repo_creating_check',
51 }[name].format(**kwargs)
52
53 if params:
54 base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
55 return base_url
56
57
46 @pytest.mark.usefixtures("app")
58 @pytest.mark.usefixtures("app")
47 class TestAdminRepos(object):
59 class TestAdminRepos(object):
48
60
@@ -461,7 +473,8 b' class TestAdminRepos(object):'
461 repo_name_utf8 = safe_str(repo_name)
473 repo_name_utf8 = safe_str(repo_name)
462
474
463 # run the check page that triggers the flash message
475 # run the check page that triggers the flash message
464 response = self.app.get(url('repo_check_home', repo_name=repo_name))
476 response = self.app.get(
477 route_path('repo_creating_check', repo_name=safe_str(repo_name)))
465 assert response.json == {u'result': True}
478 assert response.json == {u'result': True}
466
479
467 flash_msg = u'Created repository <a href="/{}">{}</a>'.format(
480 flash_msg = u'Created repository <a href="/{}">{}</a>'.format(
@@ -475,7 +488,8 b' class TestAdminRepos(object):'
475 assert new_repo.description == description
488 assert new_repo.description == description
476
489
477 # test if the repository is visible in the list ?
490 # test if the repository is visible in the list ?
478 response = self.app.get(h.route_path('repo_summary', repo_name=repo_name))
491 response = self.app.get(
492 h.route_path('repo_summary', repo_name=safe_str(repo_name)))
479 response.mustcontain(repo_name)
493 response.mustcontain(repo_name)
480 response.mustcontain(backend.alias)
494 response.mustcontain(backend.alias)
481
495
@@ -32,6 +32,19 b' from rhodecode.model.meta import Session'
32 fixture = Fixture()
32 fixture = Fixture()
33
33
34
34
35 def route_path(name, params=None, **kwargs):
36 import urllib
37
38 base_url = {
39 'repo_summary': '/{repo_name}',
40 'repo_creating_check': '/{repo_name}/repo_creating_check',
41 }[name].format(**kwargs)
42
43 if params:
44 base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
45 return base_url
46
47
35 class _BaseTest(TestController):
48 class _BaseTest(TestController):
36
49
37 REPO = None
50 REPO = None
@@ -134,7 +147,8 b' class _BaseTest(TestController):'
134 assert repo.fork.repo_name == self.REPO
147 assert repo.fork.repo_name == self.REPO
135
148
136 # run the check page that triggers the flash message
149 # run the check page that triggers the flash message
137 response = self.app.get(url('repo_check_home', repo_name=fork_name_full))
150 response = self.app.get(
151 route_path('repo_creating_check', repo_name=fork_name_full))
138 # test if we have a message that fork is ok
152 # test if we have a message that fork is ok
139 assert_session_flash(response,
153 assert_session_flash(response,
140 'Forked repository %s as <a href="/%s">%s</a>'
154 'Forked repository %s as <a href="/%s">%s</a>'
@@ -180,7 +194,8 b' class _BaseTest(TestController):'
180 assert repo.fork.repo_name == self.REPO
194 assert repo.fork.repo_name == self.REPO
181
195
182 # run the check page that triggers the flash message
196 # run the check page that triggers the flash message
183 response = self.app.get(url('repo_check_home', repo_name=fork_name))
197 response = self.app.get(
198 route_path('repo_creating_check', repo_name=fork_name))
184 # test if we have a message that fork is ok
199 # test if we have a message that fork is ok
185 assert_session_flash(response,
200 assert_session_flash(response,
186 'Forked repository %s as <a href="/%s">%s</a>'
201 'Forked repository %s as <a href="/%s">%s</a>'
General Comments 0
You need to be logged in to leave comments. Login now