Show More
@@ -0,0 +1,76 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.httpexceptions import HTTPFound | |||
|
24 | from pyramid.view import view_config | |||
|
25 | ||||
|
26 | from rhodecode.apps._base import RepoAppView | |||
|
27 | from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator | |||
|
28 | from rhodecode.lib import helpers as h | |||
|
29 | from rhodecode.model.meta import Session | |||
|
30 | from rhodecode.model.scm import ScmModel | |||
|
31 | ||||
|
32 | log = logging.getLogger(__name__) | |||
|
33 | ||||
|
34 | ||||
|
35 | class RepoCachesView(RepoAppView): | |||
|
36 | def load_default_context(self): | |||
|
37 | c = self._get_local_tmpl_context() | |||
|
38 | ||||
|
39 | # TODO(marcink): remove repo_info and use c.rhodecode_db_repo instead | |||
|
40 | c.repo_info = self.db_repo | |||
|
41 | ||||
|
42 | self._register_global_c(c) | |||
|
43 | return c | |||
|
44 | ||||
|
45 | @LoginRequired() | |||
|
46 | @HasRepoPermissionAnyDecorator('repository.admin') | |||
|
47 | @view_config( | |||
|
48 | route_name='edit_repo_caches', request_method='GET', | |||
|
49 | renderer='rhodecode:templates/admin/repos/repo_edit.mako') | |||
|
50 | def repo_caches(self): | |||
|
51 | c = self.load_default_context() | |||
|
52 | c.active = 'caches' | |||
|
53 | ||||
|
54 | return self._get_template_context(c) | |||
|
55 | ||||
|
56 | @LoginRequired() | |||
|
57 | @HasRepoPermissionAnyDecorator('repository.admin') | |||
|
58 | @view_config( | |||
|
59 | route_name='edit_repo_caches', request_method='POST') | |||
|
60 | def repo_caches_purge(self): | |||
|
61 | _ = self.request.translate | |||
|
62 | c = self.load_default_context() | |||
|
63 | c.active = 'caches' | |||
|
64 | ||||
|
65 | try: | |||
|
66 | ScmModel().mark_for_invalidation(self.db_repo_name, delete=True) | |||
|
67 | Session().commit() | |||
|
68 | h.flash(_('Cache invalidation successful'), | |||
|
69 | category='success') | |||
|
70 | except Exception: | |||
|
71 | log.exception("Exception during cache invalidation") | |||
|
72 | h.flash(_('An error occurred during cache invalidation'), | |||
|
73 | category='error') | |||
|
74 | ||||
|
75 | raise HTTPFound(h.route_path( | |||
|
76 | 'edit_repo_caches', repo_name=self.db_repo_name)) No newline at end of file |
@@ -26,6 +26,12 b' def includeme(config):' | |||||
26 | name='edit_repo', |
|
26 | name='edit_repo', | |
27 | pattern='/{repo_name:.*?[^/]}/settings', repo_route=True) |
|
27 | pattern='/{repo_name:.*?[^/]}/settings', repo_route=True) | |
28 |
|
28 | |||
|
29 | # Caches | |||
|
30 | config.add_route( | |||
|
31 | name='edit_repo_caches', | |||
|
32 | pattern='/{repo_name:.*?[^/]}/settings/caches', repo_route=True) | |||
|
33 | ||||
|
34 | # Maintenance | |||
29 | config.add_route( |
|
35 | config.add_route( | |
30 | name='repo_maintenance', |
|
36 | name='repo_maintenance', | |
31 | pattern='/{repo_name:.*?[^/]}/maintenance', repo_route=True) |
|
37 | pattern='/{repo_name:.*?[^/]}/maintenance', repo_route=True) |
@@ -38,6 +38,7 b' def route_path(name, params=None, **kwar' | |||||
38 |
|
38 | |||
39 | base_url = { |
|
39 | base_url = { | |
40 | 'edit_repo': '/{repo_name}/settings', |
|
40 | 'edit_repo': '/{repo_name}/settings', | |
|
41 | 'edit_repo_caches': '/{repo_name}/settings/caches', | |||
41 | }[name].format(**kwargs) |
|
42 | }[name].format(**kwargs) | |
42 |
|
43 | |||
43 | if params: |
|
44 | if params: | |
@@ -58,6 +59,7 b' def _get_permission_for_user(user, repo)' | |||||
58 | class TestAdminRepoSettings(object): |
|
59 | class TestAdminRepoSettings(object): | |
59 | @pytest.mark.parametrize('urlname', [ |
|
60 | @pytest.mark.parametrize('urlname', [ | |
60 | 'edit_repo', |
|
61 | 'edit_repo', | |
|
62 | 'edit_repo_caches' | |||
61 | ]) |
|
63 | ]) | |
62 | def test_show_page(self, urlname, app, backend): |
|
64 | def test_show_page(self, urlname, app, backend): | |
63 | app.get(route_path(urlname, repo_name=backend.repo_name), status=200) |
|
65 | app.get(route_path(urlname, repo_name=backend.repo_name), status=200) | |
@@ -75,7 +77,6 b' class TestAdminRepoSettings(object):' | |||||
75 | 'repo_vcs_settings', |
|
77 | 'repo_vcs_settings', | |
76 | 'edit_repo_fields', |
|
78 | 'edit_repo_fields', | |
77 | 'repo_settings_issuetracker', |
|
79 | 'repo_settings_issuetracker', | |
78 | 'edit_repo_caches', |
|
|||
79 | 'edit_repo_remote', |
|
80 | 'edit_repo_remote', | |
80 | 'edit_repo_statistics', |
|
81 | 'edit_repo_statistics', | |
81 | ]) |
|
82 | ]) |
@@ -708,15 +708,6 b' def make_map(config):' | |||||
708 | conditions={'method': ['PUT'], 'function': check_repo}, |
|
708 | conditions={'method': ['PUT'], 'function': check_repo}, | |
709 | requirements=URL_NAME_REQUIREMENTS) |
|
709 | requirements=URL_NAME_REQUIREMENTS) | |
710 |
|
710 | |||
711 | rmap.connect('edit_repo_caches', '/{repo_name}/settings/caches', |
|
|||
712 | controller='admin/repos', action='edit_caches_form', |
|
|||
713 | conditions={'method': ['GET'], 'function': check_repo}, |
|
|||
714 | requirements=URL_NAME_REQUIREMENTS) |
|
|||
715 | rmap.connect('edit_repo_caches', '/{repo_name}/settings/caches', |
|
|||
716 | controller='admin/repos', action='edit_caches', |
|
|||
717 | conditions={'method': ['PUT'], 'function': check_repo}, |
|
|||
718 | requirements=URL_NAME_REQUIREMENTS) |
|
|||
719 |
|
||||
720 | rmap.connect('edit_repo_remote', '/{repo_name}/settings/remote', |
|
711 | rmap.connect('edit_repo_remote', '/{repo_name}/settings/remote', | |
721 | controller='admin/repos', action='edit_remote_form', |
|
712 | controller='admin/repos', action='edit_remote_form', | |
722 | conditions={'method': ['GET'], 'function': check_repo}, |
|
713 | conditions={'method': ['GET'], 'function': check_repo}, |
@@ -541,30 +541,6 b' class ReposController(BaseRepoController' | |||||
541 |
|
541 | |||
542 | @HasRepoPermissionAllDecorator('repository.admin') |
|
542 | @HasRepoPermissionAllDecorator('repository.admin') | |
543 | @auth.CSRFRequired() |
|
543 | @auth.CSRFRequired() | |
544 | def edit_caches(self, repo_name): |
|
|||
545 | """PUT /{repo_name}/settings/caches: invalidate the repo caches.""" |
|
|||
546 | try: |
|
|||
547 | ScmModel().mark_for_invalidation(repo_name, delete=True) |
|
|||
548 | Session().commit() |
|
|||
549 | h.flash(_('Cache invalidation successful'), |
|
|||
550 | category='success') |
|
|||
551 | except Exception: |
|
|||
552 | log.exception("Exception during cache invalidation") |
|
|||
553 | h.flash(_('An error occurred during cache invalidation'), |
|
|||
554 | category='error') |
|
|||
555 |
|
||||
556 | return redirect(url('edit_repo_caches', repo_name=c.repo_name)) |
|
|||
557 |
|
||||
558 | @HasRepoPermissionAllDecorator('repository.admin') |
|
|||
559 | def edit_caches_form(self, repo_name): |
|
|||
560 | """GET /repo_name/settings: Form to edit an existing item""" |
|
|||
561 | c.repo_info = self._load_repo(repo_name) |
|
|||
562 | c.active = 'caches' |
|
|||
563 |
|
||||
564 | return render('admin/repos/repo_edit.mako') |
|
|||
565 |
|
||||
566 | @HasRepoPermissionAllDecorator('repository.admin') |
|
|||
567 | @auth.CSRFRequired() |
|
|||
568 | def edit_remote(self, repo_name): |
|
544 | def edit_remote(self, repo_name): | |
569 | """PUT /{repo_name}/settings/remote: edit the repo remote.""" |
|
545 | """PUT /{repo_name}/settings/remote: edit the repo remote.""" | |
570 | try: |
|
546 | try: |
@@ -98,6 +98,7 b' function registerRCRoutes() {' | |||||
98 | pyroutes.register('repo_list_data', '/_repos', []); |
|
98 | pyroutes.register('repo_list_data', '/_repos', []); | |
99 | pyroutes.register('goto_switcher_data', '/_goto_data', []); |
|
99 | pyroutes.register('goto_switcher_data', '/_goto_data', []); | |
100 | pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']); |
|
100 | pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']); | |
|
101 | pyroutes.register('edit_repo_caches', '/%(repo_name)s/settings/caches', ['repo_name']); | |||
101 | pyroutes.register('repo_maintenance', '/%(repo_name)s/maintenance', ['repo_name']); |
|
102 | pyroutes.register('repo_maintenance', '/%(repo_name)s/maintenance', ['repo_name']); | |
102 | pyroutes.register('repo_maintenance_execute', '/%(repo_name)s/maintenance/execute', ['repo_name']); |
|
103 | pyroutes.register('repo_maintenance_execute', '/%(repo_name)s/maintenance/execute', ['repo_name']); | |
103 | pyroutes.register('strip', '/%(repo_name)s/strip', ['repo_name']); |
|
104 | pyroutes.register('strip', '/%(repo_name)s/strip', ['repo_name']); |
@@ -58,7 +58,7 b'' | |||||
58 | <a href="${h.url('repo_settings_issuetracker', repo_name=c.repo_name)}">${_('Issue Tracker')}</a> |
|
58 | <a href="${h.url('repo_settings_issuetracker', repo_name=c.repo_name)}">${_('Issue Tracker')}</a> | |
59 | </li> |
|
59 | </li> | |
60 | <li class="${'active' if c.active=='caches' else ''}"> |
|
60 | <li class="${'active' if c.active=='caches' else ''}"> | |
61 |
<a href="${h. |
|
61 | <a href="${h.route_path('edit_repo_caches', repo_name=c.repo_name)}">${_('Caches')}</a> | |
62 | </li> |
|
62 | </li> | |
63 | %if c.repo_info.repo_type != 'svn': |
|
63 | %if c.repo_info.repo_type != 'svn': | |
64 | <li class="${'active' if c.active=='remote' else ''}"> |
|
64 | <li class="${'active' if c.active=='remote' else ''}"> |
@@ -3,21 +3,25 b'' | |||||
3 | <h3 class="panel-title">${_('Invalidate Cache for Repository')}</h3> |
|
3 | <h3 class="panel-title">${_('Invalidate Cache for Repository')}</h3> | |
4 | </div> |
|
4 | </div> | |
5 | <div class="panel-body"> |
|
5 | <div class="panel-body"> | |
6 | ${h.secure_form(url('edit_repo_caches', repo_name=c.repo_name), method='put')} |
|
6 | ||
7 | <div> |
|
7 | <h4>${_('Manually invalidate the repository cache. On the next access a repository cache will be recreated.')}</h4> | |
8 | <div class="fields"> |
|
8 | ||
9 |
|
|
9 | <p> | |
10 | ${h.submit('reset_cache_%s' % c.repo_info.repo_name,_('Invalidate repository cache'),class_="btn btn-small",onclick="return confirm('"+_('Confirm to invalidate repository cache')+"');")} |
|
10 | ${_('Cache purge can be automated by such api call called periodically (in crontab etc)')} | |
|
11 | <br/> | |||
|
12 | <code> | |||
|
13 | curl ${h.route_url('apiv2')} -X POST -H 'content-type:text/plain' --data-binary '{"id":1, "auth_token":"SECRET", "method":"invalidate_cache", "args":{"repoid":"${c.repo_info.repo_name}"}}' | |||
|
14 | </code> | |||
11 |
|
|
15 | </p> | |
12 | <div class="field" > |
|
|||
13 | <span class="help-block"> |
|
|||
14 | ${_('Manually invalidate the repository cache. On the next access a repository cache will be recreated.')} |
|
|||
15 | </span> |
|
|||
16 | </div> |
|
|||
17 |
|
16 | |||
|
17 | ${h.secure_form(h.route_path('edit_repo_caches', repo_name=c.repo_name), method='POST')} | |||
|
18 | <div class="form"> | |||
|
19 | <div class="fields"> | |||
|
20 | ${h.submit('reset_cache_%s' % c.repo_info.repo_name,_('Invalidate repository cache'),class_="btn btn-small",onclick="return confirm('"+_('Confirm to invalidate repository cache')+"');")} | |||
18 | </div> |
|
21 | </div> | |
19 | </div> |
|
22 | </div> | |
20 | ${h.end_form()} |
|
23 | ${h.end_form()} | |
|
24 | ||||
21 | </div> |
|
25 | </div> | |
22 | </div> |
|
26 | </div> | |
23 |
|
27 | |||
@@ -25,7 +29,7 b'' | |||||
25 | <div class="panel panel-default"> |
|
29 | <div class="panel panel-default"> | |
26 | <div class="panel-heading"> |
|
30 | <div class="panel-heading"> | |
27 | <h3 class="panel-title"> |
|
31 | <h3 class="panel-title"> | |
28 | ${(ungettext('List of repository caches (%(count)s entry)', 'List of repository caches (%(count)s entries)' ,len(c.repo_info.cache_keys)) % {'count': len(c.repo_info.cache_keys)})} |
|
32 | ${(_ungettext('List of repository caches (%(count)s entry)', 'List of repository caches (%(count)s entries)' ,len(c.repo_info.cache_keys)) % {'count': len(c.repo_info.cache_keys)})} | |
29 | </h3> |
|
33 | </h3> | |
30 | </div> |
|
34 | </div> | |
31 | <div class="panel-body"> |
|
35 | <div class="panel-body"> |
General Comments 0
You need to be logged in to leave comments.
Login now