##// END OF EJS Templates
core: revamp of automation/scheduler/artifacts EE functionality
super-admin -
r5137:f3cd5ebe default
parent child Browse files
Show More
@@ -0,0 +1,38 b''
1 # Copyright (C) 2016-2023 RhodeCode GmbH
2 #
3 # This program is free software: you can redistribute it and/or modify
4 # it under the terms of the GNU Affero General Public License, version 3
5 # (only), as published by the Free Software Foundation.
6 #
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
11 #
12 # You should have received a copy of the GNU Affero General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 #
15 # This program is dual-licensed. If you wish to learn more about the
16 # RhodeCode Enterprise Edition, including its added features, Support services,
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
18
19 import logging
20
21 from rhodecode.apps._base import BaseAppView
22 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
23
24 log = logging.getLogger(__name__)
25
26
27 class AdminAutomationView(BaseAppView):
28
29 def load_default_context(self):
30 c = self._get_local_tmpl_context()
31 return c
32
33 @LoginRequired()
34 @HasPermissionAllDecorator('hg.admin')
35 def automation(self):
36 c = self.load_default_context()
37 c.active = 'automation'
38 return self._get_template_context(c)
@@ -0,0 +1,38 b''
1 # Copyright (C) 2016-2023 RhodeCode GmbH
2 #
3 # This program is free software: you can redistribute it and/or modify
4 # it under the terms of the GNU Affero General Public License, version 3
5 # (only), as published by the Free Software Foundation.
6 #
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
11 #
12 # You should have received a copy of the GNU Affero General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 #
15 # This program is dual-licensed. If you wish to learn more about the
16 # RhodeCode Enterprise Edition, including its added features, Support services,
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
18
19 import logging
20
21 from rhodecode.apps._base import BaseAppView
22 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
23
24 log = logging.getLogger(__name__)
25
26
27 class AdminSchedulerView(BaseAppView):
28
29 def load_default_context(self):
30 c = self._get_local_tmpl_context()
31 return c
32
33 @LoginRequired()
34 @HasPermissionAllDecorator('hg.admin')
35 def scheduler(self):
36 c = self.load_default_context()
37 c.active = 'scheduler'
38 return self._get_template_context(c)
@@ -0,0 +1,39 b''
1 <%inherit file="/base/base.mako"/>
2
3 <%def name="title()">
4 ${_('Artifacts Admin')}
5 %if c.rhodecode_name:
6 &middot; ${h.branding(c.rhodecode_name)}
7 %endif
8 </%def>
9
10 <%def name="breadcrumbs_links()"></%def>
11
12 <%def name="menu_bar_nav()">
13 ${self.menu_items(active='admin')}
14 </%def>
15
16 <%def name="menu_bar_subnav()">
17 ${self.admin_menu(active='scheduler')}
18 </%def>
19
20 <%def name="main()">
21
22 <div class="box">
23
24 <div class="panel panel-default">
25 <div class="panel-heading">
26 <h3 class="panel-title">${_('Scheduler Administration.')}</h3>
27 </div>
28 <div class="panel-body">
29 <h4>${_('This feature is available in RhodeCode EE edition only. Contact {sales_email} to obtain a trial license.').format(sales_email='<a href="mailto:sales@rhodecode.com">sales@rhodecode.com</a>')|n}</h4>
30 <p>
31 Scheduler enables management of automation tasks, and defining new custom cron-like actions to be executed within RhodeCode system.
32 </p>
33 </div>
34 </div>
35
36 </div>
37
38
39 </%def>
@@ -0,0 +1,37 b''
1 <%inherit file="/base/base.mako"/>
2
3 <%def name="title()">
4 ${_('Artifacts Admin')}
5 %if c.rhodecode_name:
6 &middot; ${h.branding(c.rhodecode_name)}
7 %endif
8 </%def>
9
10 <%def name="breadcrumbs_links()"></%def>
11
12 <%def name="menu_bar_nav()">
13 ${self.menu_items(active='admin')}
14 </%def>
15
16 <%def name="menu_bar_subnav()">
17 ${self.admin_menu(active='automation')}
18 </%def>
19
20 <%def name="main()">
21
22 <div class="box">
23
24 <div class="panel panel-default">
25 <div class="panel-heading">
26 <h3 class="panel-title">${_('Automation Administration.')}</h3>
27 </div>
28 <div class="panel-body">
29 <h4>${_('This feature is available in RhodeCode EE edition only. Contact {sales_email} to obtain a trial license.').format(sales_email='<a href="mailto:sales@rhodecode.com">sales@rhodecode.com</a>')|n}</h4>
30 <img style="width: 100%; height: 100%" src="${h.asset('images/ee_features/admin_automation.png')}"/>
31 </div>
32 </div>
33
34 </div>
35
36
37 </%def>
@@ -42,8 +42,8 b' from rhodecode.model.repo import ReadmeF'
42 log = logging.getLogger(__name__)
42 log = logging.getLogger(__name__)
43
43
44
44
45 ADMIN_PREFIX = '/_admin'
45 ADMIN_PREFIX: str = '/_admin'
46 STATIC_FILE_PREFIX = '/_static'
46 STATIC_FILE_PREFIX: str = '/_static'
47
47
48 URL_NAME_REQUIREMENTS = {
48 URL_NAME_REQUIREMENTS = {
49 # group name can have a slash in them, but they must not end with a slash
49 # group name can have a slash in them, but they must not end with a slash
@@ -101,8 +101,6 b' class NavigationRegistry(object):'
101 'admin_settings_sessions'),
101 'admin_settings_sessions'),
102 NavEntry('open_source', _('Open Source Licenses'),
102 NavEntry('open_source', _('Open Source Licenses'),
103 'admin_settings_open_source'),
103 'admin_settings_open_source'),
104 NavEntry('automation', _('Automation'),
105 'admin_settings_automation')
106 ]
104 ]
107
105
108 _labs_entry = NavEntry('labs', _('Labs'),
106 _labs_entry = NavEntry('labs', _('Labs'),
@@ -18,6 +18,8 b''
18
18
19
19
20 from rhodecode.apps._base import ADMIN_PREFIX
20 from rhodecode.apps._base import ADMIN_PREFIX
21 from rhodecode.apps._base.navigation import includeme as nav_includeme
22 from rhodecode.apps.admin.views.main_views import AdminMainView
21
23
22
24
23 def admin_routes(config):
25 def admin_routes(config):
@@ -26,9 +28,10 b' def admin_routes(config):'
26 """
28 """
27 from rhodecode.apps.admin.views.audit_logs import AdminAuditLogsView
29 from rhodecode.apps.admin.views.audit_logs import AdminAuditLogsView
28 from rhodecode.apps.admin.views.artifacts import AdminArtifactsView
30 from rhodecode.apps.admin.views.artifacts import AdminArtifactsView
31 from rhodecode.apps.admin.views.automation import AdminAutomationView
32 from rhodecode.apps.admin.views.scheduler import AdminSchedulerView
29 from rhodecode.apps.admin.views.defaults import AdminDefaultSettingsView
33 from rhodecode.apps.admin.views.defaults import AdminDefaultSettingsView
30 from rhodecode.apps.admin.views.exception_tracker import ExceptionsTrackerView
34 from rhodecode.apps.admin.views.exception_tracker import ExceptionsTrackerView
31 from rhodecode.apps.admin.views.main_views import AdminMainView
32 from rhodecode.apps.admin.views.open_source_licenses import OpenSourceLicensesAdminSettingsView
35 from rhodecode.apps.admin.views.open_source_licenses import OpenSourceLicensesAdminSettingsView
33 from rhodecode.apps.admin.views.permissions import AdminPermissionsView
36 from rhodecode.apps.admin.views.permissions import AdminPermissionsView
34 from rhodecode.apps.admin.views.process_management import AdminProcessManagementView
37 from rhodecode.apps.admin.views.process_management import AdminProcessManagementView
@@ -76,6 +79,7 b' def admin_routes(config):'
76 attr='artifacts',
79 attr='artifacts',
77 route_name='admin_artifacts_show_all', request_method='GET',
80 route_name='admin_artifacts_show_all', request_method='GET',
78 renderer='rhodecode:templates/admin/artifacts/artifacts.mako')
81 renderer='rhodecode:templates/admin/artifacts/artifacts.mako')
82
79 # EE views
83 # EE views
80 config.add_route(
84 config.add_route(
81 name='admin_artifacts_show_info',
85 name='admin_artifacts_show_info',
@@ -87,6 +91,26 b' def admin_routes(config):'
87 name='admin_artifacts_update',
91 name='admin_artifacts_update',
88 pattern=ADMIN_PREFIX + '/artifacts/{uid}/update')
92 pattern=ADMIN_PREFIX + '/artifacts/{uid}/update')
89
93
94 # Automation EE feature
95 config.add_route(
96 'admin_automation',
97 pattern=ADMIN_PREFIX + '/automation')
98 config.add_view(
99 AdminAutomationView,
100 attr='automation',
101 route_name='admin_automation', request_method='GET',
102 renderer='rhodecode:templates/admin/automation/automation.mako')
103
104 # Scheduler EE feature
105 config.add_route(
106 'admin_scheduler',
107 pattern=ADMIN_PREFIX + '/scheduler')
108 config.add_view(
109 AdminSchedulerView,
110 attr='scheduler',
111 route_name='admin_scheduler', request_method='GET',
112 renderer='rhodecode:templates/admin/scheduler/scheduler.mako')
113
90 config.add_route(
114 config.add_route(
91 name='admin_settings_open_source',
115 name='admin_settings_open_source',
92 pattern='/settings/open_source')
116 pattern='/settings/open_source')
@@ -440,16 +464,6 b' def admin_routes(config):'
440 route_name='admin_settings_labs_update', request_method='POST',
464 route_name='admin_settings_labs_update', request_method='POST',
441 renderer='rhodecode:templates/admin/settings/settings.mako')
465 renderer='rhodecode:templates/admin/settings/settings.mako')
442
466
443 # Automation EE feature
444 config.add_route(
445 'admin_settings_automation',
446 pattern=ADMIN_PREFIX + '/settings/automation')
447 config.add_view(
448 AdminSettingsView,
449 attr='settings_automation',
450 route_name='admin_settings_automation', request_method='GET',
451 renderer='rhodecode:templates/admin/settings/settings.mako')
452
453 # global permissions
467 # global permissions
454
468
455 config.add_route(
469 config.add_route(
@@ -1039,9 +1053,6 b' def admin_routes(config):'
1039
1053
1040
1054
1041 def includeme(config):
1055 def includeme(config):
1042 from rhodecode.apps._base.navigation import includeme as nav_includeme
1043 from rhodecode.apps.admin.views.main_views import AdminMainView
1044
1045 # Create admin navigation registry and add it to the pyramid registry.
1056 # Create admin navigation registry and add it to the pyramid registry.
1046 nav_includeme(config)
1057 nav_includeme(config)
1047
1058
@@ -248,8 +248,9 b' class AdminSettingsView(BaseAppView):'
248 added, removed = repo2db_mapper(filesystem_repos, rm_obsolete)
248 added, removed = repo2db_mapper(filesystem_repos, rm_obsolete)
249 PermissionModel().trigger_permission_flush()
249 PermissionModel().trigger_permission_flush()
250
250
251 def _repr(l):
251 def _repr(rm_repo):
252 return ', '.join(map(safe_str, l)) or '-'
252 return ', '.join(map(safe_str, rm_repo)) or '-'
253
253 h.flash(_('Repositories successfully '
254 h.flash(_('Repositories successfully '
254 'rescanned added: %s ; removed: %s') %
255 'rescanned added: %s ; removed: %s') %
255 (_repr(added), _repr(removed)),
256 (_repr(added), _repr(removed)),
@@ -623,14 +624,6 b' class AdminSettingsView(BaseAppView):'
623
624
624 @LoginRequired()
625 @LoginRequired()
625 @HasPermissionAllDecorator('hg.admin')
626 @HasPermissionAllDecorator('hg.admin')
626 def settings_automation(self):
627 c = self.load_default_context()
628 c.active = 'automation'
629
630 return self._get_template_context(c)
631
632 @LoginRequired()
633 @HasPermissionAllDecorator('hg.admin')
634 def settings_labs(self):
627 def settings_labs(self):
635 c = self.load_default_context()
628 c = self.load_default_context()
636 if not c.labs_active:
629 if not c.labs_active:
@@ -413,6 +413,7 b' class RepoFilesView(RepoAppView):'
413 archive_cache_disable = self.request.GET.get('no_cache')
413 archive_cache_disable = self.request.GET.get('no_cache')
414
414
415 d_cache = get_archival_cache_store(config=CONFIG)
415 d_cache = get_archival_cache_store(config=CONFIG)
416
416 # NOTE: we get the config to pass to a call to lazy-init the SAME type of cache on vcsserver
417 # NOTE: we get the config to pass to a call to lazy-init the SAME type of cache on vcsserver
417 d_cache_conf = get_archival_config(config=CONFIG)
418 d_cache_conf = get_archival_config(config=CONFIG)
418
419
@@ -30,6 +30,9 b' class PullRequestEvent(RepoEvent):'
30
30
31 :param pullrequest: a :class:`PullRequest` instance
31 :param pullrequest: a :class:`PullRequest` instance
32 """
32 """
33 name = 'pullrequest-event'
34 display_name = lazy_ugettext('pullrequest generic event')
35 description = lazy_ugettext('All events within a context of a pull request')
33
36
34 def __init__(self, pullrequest):
37 def __init__(self, pullrequest):
35 super().__init__(pullrequest.target_repo)
38 super().__init__(pullrequest.target_repo)
@@ -21,7 +21,7 b' import logging'
21 import datetime
21 import datetime
22
22
23 from rhodecode.translation import lazy_ugettext
23 from rhodecode.translation import lazy_ugettext
24 from rhodecode.model.db import User, Repository, Session
24 from rhodecode.model.db import User, Repository
25 from rhodecode.events.base import RhodeCodeIntegrationEvent
25 from rhodecode.events.base import RhodeCodeIntegrationEvent
26 from rhodecode.lib.vcs.exceptions import CommitDoesNotExistError
26 from rhodecode.lib.vcs.exceptions import CommitDoesNotExistError
27
27
@@ -34,7 +34,7 b' def _commits_as_dict(event, commit_ids, '
34
34
35 :param event: class calling this method
35 :param event: class calling this method
36 :param commit_ids: commits to get
36 :param commit_ids: commits to get
37 :param repos: list of repos to check
37 :param repos: a list of repos to check
38 """
38 """
39 from rhodecode.lib.utils2 import extract_mentioned_users
39 from rhodecode.lib.utils2 import extract_mentioned_users
40 from rhodecode.lib.helpers import (
40 from rhodecode.lib.helpers import (
@@ -154,11 +154,12 b' def _issues_as_dict(commits):'
154 class RepoEvent(RhodeCodeIntegrationEvent):
154 class RepoEvent(RhodeCodeIntegrationEvent):
155 """
155 """
156 Base class for events acting on a repository.
156 Base class for events acting on a repository.
157
158 :param repo: a :class:`Repository` instance
159 """
157 """
160
158
161 def __init__(self, repo):
159 def __init__(self, repo):
160 """
161 :param repo: a :class:`Repository` instance
162 """
162 super().__init__()
163 super().__init__()
163 self.repo = repo
164 self.repo = repo
164
165
@@ -299,6 +300,9 b' class RepoVCSEvent(RepoEvent):'
299 """
300 """
300 Base class for events triggered by the VCS
301 Base class for events triggered by the VCS
301 """
302 """
303 name = ''
304 display_name = 'generic_vcs_event'
305
302 def __init__(self, repo_name, extras):
306 def __init__(self, repo_name, extras):
303 self.repo = Repository.get_by_repo_name(repo_name)
307 self.repo = Repository.get_by_repo_name(repo_name)
304 if not self.repo:
308 if not self.repo:
@@ -44,7 +44,7 b' def run_task(task, *args, **kwargs):'
44 import celery
44 import celery
45 log.debug('Got task `%s` for execution, celery mode enabled:%s', task, rhodecode.CELERY_ENABLED)
45 log.debug('Got task `%s` for execution, celery mode enabled:%s', task, rhodecode.CELERY_ENABLED)
46 if task is None:
46 if task is None:
47 raise ValueError('Got non-existing task for execution')
47 raise ValueError(f'Got non-existing task: {task} for execution')
48
48
49 exec_mode = 'sync'
49 exec_mode = 'sync'
50 allow_async = True
50 allow_async = True
@@ -19,9 +19,7 b''
19
19
20 import sqlalchemy
20 import sqlalchemy
21 from sqlalchemy import UnicodeText
21 from sqlalchemy import UnicodeText
22 from sqlalchemy.ext.mutable import Mutable, \
22 from sqlalchemy.ext.mutable import Mutable, MutableList, MutableDict
23 MutableList as MutationList, \
24 MutableDict as MutationDict
25
23
26 from rhodecode.lib import ext_json
24 from rhodecode.lib import ext_json
27
25
@@ -30,7 +28,7 b' class JsonRaw(str):'
30 """
28 """
31 Allows interacting with a JSON types field using a raw string.
29 Allows interacting with a JSON types field using a raw string.
32
30
33 For example::
31 For example:
34 db_instance = JsonTable()
32 db_instance = JsonTable()
35 db_instance.enabled = True
33 db_instance.enabled = True
36 db_instance.json_data = JsonRaw('{"a": 4}')
34 db_instance.json_data = JsonRaw('{"a": 4}')
@@ -100,7 +98,7 b' class MutationObj(Mutable):'
100 return MutationList.coerce(key, value)
98 return MutationList.coerce(key, value)
101 return value
99 return value
102
100
103 def de_coerce(self):
101 def de_coerce(self) -> "MutationObj":
104 return self
102 return self
105
103
106 @classmethod
104 @classmethod
@@ -153,6 +151,16 b' class MutationObj(Mutable):'
153 propagate=True)
151 propagate=True)
154
152
155
153
154 class MutationList(MutableList):
155 def de_coerce(self):
156 return list(self)
157
158
159 class MutationDict(MutableDict):
160 def de_coerce(self):
161 return dict(self)
162
163
156 def JsonType(impl=None, **kwargs):
164 def JsonType(impl=None, **kwargs):
157 """
165 """
158 Helper for using a mutation obj, it allows to use .with_variant easily.
166 Helper for using a mutation obj, it allows to use .with_variant easily.
@@ -5378,14 +5378,14 b' class ScheduleEntry(Base, BaseModel):'
5378 except ValueError:
5378 except ValueError:
5379 return dict()
5379 return dict()
5380
5380
5381 def _as_raw(self, val, indent=None):
5381 def _as_raw(self, val, indent=False):
5382 if hasattr(val, 'de_coerce'):
5382 if hasattr(val, 'de_coerce'):
5383 val = val.de_coerce()
5383 val = val.de_coerce()
5384 if val:
5384 if val:
5385 if indent:
5385 if indent:
5386 ext_json.formatted_json(val)
5386 val = ext_json.formatted_str_json(val)
5387 else:
5387 else:
5388 val = ext_json.json.dumps(val)
5388 val = ext_json.str_json(val)
5389
5389
5390 return val
5390 return val
5391
5391
@@ -5393,10 +5393,10 b' class ScheduleEntry(Base, BaseModel):'
5393 def schedule_definition_raw(self):
5393 def schedule_definition_raw(self):
5394 return self._as_raw(self.schedule_definition)
5394 return self._as_raw(self.schedule_definition)
5395
5395
5396 def args_raw(self, indent=None):
5396 def args_raw(self, indent=False):
5397 return self._as_raw(self.task_args, indent)
5397 return self._as_raw(self.task_args, indent)
5398
5398
5399 def kwargs_raw(self, indent=None):
5399 def kwargs_raw(self, indent=False):
5400 return self._as_raw(self.task_kwargs, indent)
5400 return self._as_raw(self.task_kwargs, indent)
5401
5401
5402 def __repr__(self):
5402 def __repr__(self):
@@ -5610,6 +5610,19 b' class FileStore(Base, BaseModel):'
5610 repo_group = relationship('RepoGroup', lazy='joined')
5610 repo_group = relationship('RepoGroup', lazy='joined')
5611
5611
5612 @classmethod
5612 @classmethod
5613 def get_scope(cls, scope_type, scope_id):
5614 if scope_type == 'repo':
5615 return f'repo:{scope_id}'
5616 elif scope_type == 'repo-group':
5617 return f'repo-group:{scope_id}'
5618 elif scope_type == 'user':
5619 return f'user:{scope_id}'
5620 elif scope_type == 'user-group':
5621 return f'user-group:{scope_id}'
5622 else:
5623 return scope_type
5624
5625 @classmethod
5613 def get_by_store_uid(cls, file_store_uid, safe=False):
5626 def get_by_store_uid(cls, file_store_uid, safe=False):
5614 if safe:
5627 if safe:
5615 return FileStore.query().filter(FileStore.file_uid == file_store_uid).first()
5628 return FileStore.query().filter(FileStore.file_uid == file_store_uid).first()
@@ -25,7 +25,7 b' import colander'
25 from rhodecode.translation import _
25 from rhodecode.translation import _
26 from rhodecode.lib.utils2 import glob2re
26 from rhodecode.lib.utils2 import glob2re
27 from rhodecode.lib.str_utils import safe_str
27 from rhodecode.lib.str_utils import safe_str
28 from rhodecode.lib.ext_json import json
28 from rhodecode.lib.ext_json import json, sjson
29
29
30 log = logging.getLogger(__name__)
30 log = logging.getLogger(__name__)
31
31
@@ -152,8 +152,9 b' def json_validator(node, value):'
152
152
153
153
154 def json_validator_with_exc(node, value):
154 def json_validator_with_exc(node, value):
155
155 try:
156 try:
156 json.loads(value)
157 json.loads(value)
157 except (Exception,) as e:
158 except (Exception,) as e:
158 msg = _(f'Please enter a valid json object: `{e}`')
159 msg = _(f'Please enter a valid json object type={type(value)}: `{e}`')
159 raise colander.Invalid(node, msg)
160 raise colander.Invalid(node, msg)
@@ -20,6 +20,8 b' function registerRCRoutes() {'
20 pyroutes.register('admin_artifacts_update', '/_admin/artifacts/%(uid)s/update', ['uid']);
20 pyroutes.register('admin_artifacts_update', '/_admin/artifacts/%(uid)s/update', ['uid']);
21 pyroutes.register('admin_audit_log_entry', '/_admin/audit_logs/%(audit_log_id)s', ['audit_log_id']);
21 pyroutes.register('admin_audit_log_entry', '/_admin/audit_logs/%(audit_log_id)s', ['audit_log_id']);
22 pyroutes.register('admin_audit_logs', '/_admin/audit_logs', []);
22 pyroutes.register('admin_audit_logs', '/_admin/audit_logs', []);
23 pyroutes.register('admin_automation', '/_admin/automation', []);
24 pyroutes.register('admin_automation_update', '/_admin/automation/%(entry_id)s/update', ['entry_id']);
23 pyroutes.register('admin_defaults_repositories', '/_admin/defaults/repositories', []);
25 pyroutes.register('admin_defaults_repositories', '/_admin/defaults/repositories', []);
24 pyroutes.register('admin_defaults_repositories_update', '/_admin/defaults/repositories/update', []);
26 pyroutes.register('admin_defaults_repositories_update', '/_admin/defaults/repositories/update', []);
25 pyroutes.register('admin_home', '/_admin', []);
27 pyroutes.register('admin_home', '/_admin', []);
@@ -37,9 +39,9 b' function registerRCRoutes() {'
37 pyroutes.register('admin_permissions_ssh_keys', '/_admin/permissions/ssh_keys', []);
39 pyroutes.register('admin_permissions_ssh_keys', '/_admin/permissions/ssh_keys', []);
38 pyroutes.register('admin_permissions_ssh_keys_data', '/_admin/permissions/ssh_keys/data', []);
40 pyroutes.register('admin_permissions_ssh_keys_data', '/_admin/permissions/ssh_keys/data', []);
39 pyroutes.register('admin_permissions_ssh_keys_update', '/_admin/permissions/ssh_keys/update', []);
41 pyroutes.register('admin_permissions_ssh_keys_update', '/_admin/permissions/ssh_keys/update', []);
42 pyroutes.register('admin_scheduler', '/_admin/scheduler', []);
43 pyroutes.register('admin_scheduler_show_tasks', '/_admin/scheduler/_tasks', []);
40 pyroutes.register('admin_settings', '/_admin/settings', []);
44 pyroutes.register('admin_settings', '/_admin/settings', []);
41 pyroutes.register('admin_settings_automation', '/_admin/settings/automation', []);
42 pyroutes.register('admin_settings_automation_update', '/_admin/settings/automation/%(entry_id)s/update', ['entry_id']);
43 pyroutes.register('admin_settings_email', '/_admin/settings/email', []);
45 pyroutes.register('admin_settings_email', '/_admin/settings/email', []);
44 pyroutes.register('admin_settings_email_update', '/_admin/settings/email/update', []);
46 pyroutes.register('admin_settings_email_update', '/_admin/settings/email/update', []);
45 pyroutes.register('admin_settings_exception_tracker', '/_admin/settings/exceptions', []);
47 pyroutes.register('admin_settings_exception_tracker', '/_admin/settings/exceptions', []);
@@ -66,14 +68,12 b' function registerRCRoutes() {'
66 pyroutes.register('admin_settings_process_management_data', '/_admin/settings/process_management/data', []);
68 pyroutes.register('admin_settings_process_management_data', '/_admin/settings/process_management/data', []);
67 pyroutes.register('admin_settings_process_management_master_signal', '/_admin/settings/process_management/master_signal', []);
69 pyroutes.register('admin_settings_process_management_master_signal', '/_admin/settings/process_management/master_signal', []);
68 pyroutes.register('admin_settings_process_management_signal', '/_admin/settings/process_management/signal', []);
70 pyroutes.register('admin_settings_process_management_signal', '/_admin/settings/process_management/signal', []);
69 pyroutes.register('admin_settings_scheduler_create', '/_admin/settings/scheduler/create', []);
71 pyroutes.register('admin_settings_scheduler_create', '/_admin/scheduler/create', []);
70 pyroutes.register('admin_settings_scheduler_delete', '/_admin/settings/scheduler/%(schedule_id)s/delete', ['schedule_id']);
72 pyroutes.register('admin_settings_scheduler_delete', '/_admin/scheduler/%(schedule_id)s/delete', ['schedule_id']);
71 pyroutes.register('admin_settings_scheduler_edit', '/_admin/settings/scheduler/%(schedule_id)s', ['schedule_id']);
73 pyroutes.register('admin_settings_scheduler_edit', '/_admin/scheduler/%(schedule_id)s', ['schedule_id']);
72 pyroutes.register('admin_settings_scheduler_execute', '/_admin/settings/scheduler/%(schedule_id)s/execute', ['schedule_id']);
74 pyroutes.register('admin_settings_scheduler_execute', '/_admin/scheduler/%(schedule_id)s/execute', ['schedule_id']);
73 pyroutes.register('admin_settings_scheduler_new', '/_admin/settings/scheduler/new', []);
75 pyroutes.register('admin_settings_scheduler_new', '/_admin/scheduler/new', []);
74 pyroutes.register('admin_settings_scheduler_show_all', '/_admin/settings/scheduler', []);
76 pyroutes.register('admin_settings_scheduler_update', '/_admin/scheduler/%(schedule_id)s/update', ['schedule_id']);
75 pyroutes.register('admin_settings_scheduler_show_tasks', '/_admin/settings/scheduler/_tasks', []);
76 pyroutes.register('admin_settings_scheduler_update', '/_admin/settings/scheduler/%(schedule_id)s/update', ['schedule_id']);
77 pyroutes.register('admin_settings_search', '/_admin/settings/search', []);
77 pyroutes.register('admin_settings_search', '/_admin/settings/search', []);
78 pyroutes.register('admin_settings_sessions', '/_admin/settings/sessions', []);
78 pyroutes.register('admin_settings_sessions', '/_admin/settings/sessions', []);
79 pyroutes.register('admin_settings_sessions_cleanup', '/_admin/settings/sessions/cleanup', []);
79 pyroutes.register('admin_settings_sessions_cleanup', '/_admin/settings/sessions/cleanup', []);
@@ -308,7 +308,6 b' function registerRCRoutes() {'
308 pyroutes.register('repo_creating', '/%(repo_name)s/repo_creating', ['repo_name']);
308 pyroutes.register('repo_creating', '/%(repo_name)s/repo_creating', ['repo_name']);
309 pyroutes.register('repo_creating_check', '/%(repo_name)s/repo_creating_check', ['repo_name']);
309 pyroutes.register('repo_creating_check', '/%(repo_name)s/repo_creating_check', ['repo_name']);
310 pyroutes.register('repo_default_reviewers_data', '/%(repo_name)s/settings/review/default-reviewers', ['repo_name']);
310 pyroutes.register('repo_default_reviewers_data', '/%(repo_name)s/settings/review/default-reviewers', ['repo_name']);
311 pyroutes.register('repo_edit_toggle_locking', '/%(repo_name)s/settings/toggle_locking', ['repo_name']);
312 pyroutes.register('repo_file_authors', '/%(repo_name)s/authors/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
311 pyroutes.register('repo_file_authors', '/%(repo_name)s/authors/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
313 pyroutes.register('repo_file_download', '/%(repo_name)s/download/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
312 pyroutes.register('repo_file_download', '/%(repo_name)s/download/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
314 pyroutes.register('repo_file_download:legacy', '/%(repo_name)s/rawfile/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
313 pyroutes.register('repo_file_download:legacy', '/%(repo_name)s/rawfile/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
@@ -362,6 +361,7 b' function registerRCRoutes() {'
362 pyroutes.register('repo_reviewers_review_rule_delete', '/%(repo_name)s/settings/review/rules/%(rule_id)s/delete', ['repo_name', 'rule_id']);
361 pyroutes.register('repo_reviewers_review_rule_delete', '/%(repo_name)s/settings/review/rules/%(rule_id)s/delete', ['repo_name', 'rule_id']);
363 pyroutes.register('repo_reviewers_review_rule_edit', '/%(repo_name)s/settings/review/rules/%(rule_id)s', ['repo_name', 'rule_id']);
362 pyroutes.register('repo_reviewers_review_rule_edit', '/%(repo_name)s/settings/review/rules/%(rule_id)s', ['repo_name', 'rule_id']);
364 pyroutes.register('repo_reviewers_review_rule_new', '/%(repo_name)s/settings/review/rules/new', ['repo_name']);
363 pyroutes.register('repo_reviewers_review_rule_new', '/%(repo_name)s/settings/review/rules/new', ['repo_name']);
364 pyroutes.register('repo_settings_quick_actions', '/%(repo_name)s/settings/quick-action', ['repo_name']);
365 pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']);
365 pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']);
366 pyroutes.register('repo_summary', '/%(repo_name)s', ['repo_name']);
366 pyroutes.register('repo_summary', '/%(repo_name)s', ['repo_name']);
367 pyroutes.register('repo_summary_commits', '/%(repo_name)s/summary-commits', ['repo_name']);
367 pyroutes.register('repo_summary_commits', '/%(repo_name)s/summary-commits', ['repo_name']);
@@ -27,7 +27,10 b''
27 </div>
27 </div>
28 <div class="panel-body">
28 <div class="panel-body">
29 <h4>${_('This feature is available in RhodeCode EE edition only. Contact {sales_email} to obtain a trial license.').format(sales_email='<a href="mailto:sales@rhodecode.com">sales@rhodecode.com</a>')|n}</h4>
29 <h4>${_('This feature is available in RhodeCode EE edition only. Contact {sales_email} to obtain a trial license.').format(sales_email='<a href="mailto:sales@rhodecode.com">sales@rhodecode.com</a>')|n}</h4>
30
30 <p>
31 Artifacts are a binary file storage within RhodeCode that allows asset management next to version control system with fine-grained access control.
32 This functionality allows release builds or other types of binary asset to be stored and managed by RhodeCode.
33 </p>
31 </div>
34 </div>
32 </div>
35 </div>
33
36
@@ -1,9 +1,37 b''
1 <div class="panel panel-default">
1 <%inherit file="/base/base.mako"/>
2 <div class="panel-heading">
2
3 <h3 class="panel-title">${_('Admin Automation')}</h3>
3 <%def name="title()">
4 ${_('Artifacts Admin')}
5 %if c.rhodecode_name:
6 &middot; ${h.branding(c.rhodecode_name)}
7 %endif
8 </%def>
9
10 <%def name="breadcrumbs_links()"></%def>
11
12 <%def name="menu_bar_nav()">
13 ${self.menu_items(active='admin')}
14 </%def>
15
16 <%def name="menu_bar_subnav()">
17 ${self.admin_menu(active='automation')}
18 </%def>
19
20 <%def name="main()">
21
22 <div class="box">
23
24 <div class="panel panel-default">
25 <div class="panel-heading">
26 <h3 class="panel-title">${_('Automation Administration.')}</h3>
27 </div>
28 <div class="panel-body">
29 <h4>${_('This feature is available in RhodeCode EE edition only. Contact {sales_email} to obtain a trial license.').format(sales_email='<a href="mailto:sales@rhodecode.com">sales@rhodecode.com</a>')|n}</h4>
30 <img alt="admin-automation" style="width: 100%; height: 100%" src="${h.asset('images/ee_features/admin_automation.png')}"/>
31 </div>
4 </div>
32 </div>
5 <div class="panel-body">
33
6 <h4>${_('This feature is available in RhodeCode EE edition only. Contact {sales_email} to obtain a trial license.').format(sales_email='<a href="mailto:sales@rhodecode.com">sales@rhodecode.com</a>')|n}</h4>
7 <img style="width: 100%; height: 100%" src="${h.asset('images/ee_features/admin_automation.png')}"/>
8 </div>
9 </div>
34 </div>
35
36
37 </%def>
@@ -39,7 +39,7 b''
39 % if c.rhodecode_user.username != h.DEFAULT_USER:
39 % if c.rhodecode_user.username != h.DEFAULT_USER:
40 <div class="pull-right">
40 <div class="pull-right">
41 <a class="btn btn-primary" href="${h.route_path('gists_new')}" >
41 <a class="btn btn-primary" href="${h.route_path('gists_new')}" >
42 ${_(u'Create New Gist')}
42 ${_('Create New Gist')}
43 </a>
43 </a>
44 </div>
44 </div>
45 % endif
45 % endif
@@ -61,7 +61,7 b''
61 create_url = h.route_path('global_integrations_new')
61 create_url = h.route_path('global_integrations_new')
62 %>
62 %>
63 <p class="pull-right">
63 <p class="pull-right">
64 <a href="${create_url}" class="btn btn-small btn-success">${_(u'Create new integration')}</a>
64 <a href="${create_url}" class="btn btn-small btn-success">${_('Create new integration')}</a>
65 </p>
65 </p>
66
66
67 <table class="rctable integrations">
67 <table class="rctable integrations">
@@ -99,7 +99,7 b''
99 %>
99 %>
100 %endif
100 %endif
101
101
102 <a href="${create_url}">${_(u'Create one')}</a>
102 <a href="${create_url}">${_('Create one')}</a>
103 </td>
103 </td>
104 </tr>
104 </tr>
105 %endif
105 %endif
@@ -39,7 +39,7 b''
39 <td class="delegated-admin-repo-groups">${len(c.auth_user.repository_groups_admin)}</td>
39 <td class="delegated-admin-repo-groups">${len(c.auth_user.repository_groups_admin)}</td>
40 <td>
40 <td>
41 % if c.can_create_repo_group:
41 % if c.can_create_repo_group:
42 <a href="${h.route_path('repo_group_new')}" class="">${_(u'Add Repository Group')}</a>
42 <a href="${h.route_path('repo_group_new')}" class="">${_('Add Repository Group')}</a>
43 % endif
43 % endif
44 </td>
44 </td>
45 </tr>
45 </tr>
@@ -48,7 +48,7 b''
48 <td class="delegated-admin-user-groups">${len(c.auth_user.user_groups_admin)}</td>
48 <td class="delegated-admin-user-groups">${len(c.auth_user.user_groups_admin)}</td>
49 <td>
49 <td>
50 % if c.can_create_user_group:
50 % if c.can_create_user_group:
51 <a href="${h.route_path('user_groups_new')}" class="">${_(u'Add User Group')}</a>
51 <a href="${h.route_path('user_groups_new')}" class="">${_('Add User Group')}</a>
52 % endif
52 % endif
53 </td>
53 </td>
54 </tr>
54 </tr>
@@ -27,7 +27,7 b''
27 <ul class="links">
27 <ul class="links">
28 %if c.can_create_repo_group:
28 %if c.can_create_repo_group:
29 <li>
29 <li>
30 <a href="${h.route_path('repo_group_new')}" class="btn btn-small btn-success">${_(u'Add Repository Group')}</a>
30 <a href="${h.route_path('repo_group_new')}" class="btn btn-small btn-success">${_('Add Repository Group')}</a>
31 </li>
31 </li>
32 %endif
32 %endif
33 </ul>
33 </ul>
@@ -27,7 +27,7 b''
27 <ul class="links">
27 <ul class="links">
28 %if c.can_create_repo:
28 %if c.can_create_repo:
29 <li>
29 <li>
30 <a href="${h.route_path('repo_new')}" class="btn btn-small btn-success">${_(u'Add Repository')}</a>
30 <a href="${h.route_path('repo_new')}" class="btn btn-small btn-success">${_('Add Repository')}</a>
31 </li>
31 </li>
32 %endif
32 %endif
33 </ul>
33 </ul>
@@ -27,7 +27,7 b''
27 <ul class="links">
27 <ul class="links">
28 %if c.can_create_user_group:
28 %if c.can_create_user_group:
29 <li>
29 <li>
30 <a href="${h.route_path('user_groups_new')}" class="btn btn-small btn-success">${_(u'Add User Group')}</a>
30 <a href="${h.route_path('user_groups_new')}" class="btn btn-small btn-success">${_('Add User Group')}</a>
31 </li>
31 </li>
32 %endif
32 %endif
33 </ul>
33 </ul>
@@ -27,7 +27,7 b''
27
27
28 <ul class="links">
28 <ul class="links">
29 <li>
29 <li>
30 <a href="${h.route_path('users_new')}" class="btn btn-small btn-success">${_(u'Add User')}</a>
30 <a href="${h.route_path('users_new')}" class="btn btn-small btn-success">${_('Add User')}</a>
31 </li>
31 </li>
32 </ul>
32 </ul>
33 </div>
33 </div>
@@ -107,7 +107,7 b''
107
107
108 <ul id="context-pages" class="navigation horizontal-list">
108 <ul id="context-pages" class="navigation horizontal-list">
109
109
110 ## super-admin case
110 ## super-admin case (Top Menu)
111 % if c.is_super_admin:
111 % if c.is_super_admin:
112 <li class="${h.is_active('audit_logs', active)}"><a href="${h.route_path('admin_audit_logs')}">${_('Admin audit logs')}</a></li>
112 <li class="${h.is_active('audit_logs', active)}"><a href="${h.route_path('admin_audit_logs')}">${_('Admin audit logs')}</a></li>
113 <li class="${h.is_active('repositories', active)}"><a href="${h.route_path('repos')}">${_('Repositories')}</a></li>
113 <li class="${h.is_active('repositories', active)}"><a href="${h.route_path('repos')}">${_('Repositories')}</a></li>
@@ -115,6 +115,8 b''
115 <li class="${h.is_active('users', active)}"><a href="${h.route_path('users')}">${_('Users')}</a></li>
115 <li class="${h.is_active('users', active)}"><a href="${h.route_path('users')}">${_('Users')}</a></li>
116 <li class="${h.is_active('user_groups', active)}"><a href="${h.route_path('user_groups')}">${_('User groups')}</a></li>
116 <li class="${h.is_active('user_groups', active)}"><a href="${h.route_path('user_groups')}">${_('User groups')}</a></li>
117 <li class="${h.is_active('artifacts', active)}"><a href="${h.route_path('admin_artifacts')}">${_('Artifacts')}</a></li>
117 <li class="${h.is_active('artifacts', active)}"><a href="${h.route_path('admin_artifacts')}">${_('Artifacts')}</a></li>
118 <li class="${h.is_active('automation', active)}"><a href="${h.route_path('admin_automation')}">${_('Automation')}</a></li>
119 <li class="${h.is_active('scheduler', active)}"><a href="${h.route_path('admin_scheduler')}">${_('Scheduler')}</a></li>
118 <li class="${h.is_active('permissions', active)}"><a href="${h.route_path('admin_permissions_application')}">${_('Permissions')}</a></li>
120 <li class="${h.is_active('permissions', active)}"><a href="${h.route_path('admin_permissions_application')}">${_('Permissions')}</a></li>
119 <li class="${h.is_active('authentication', active)}"><a href="${h.route_path('auth_home', traverse='')}">${_('Authentication')}</a></li>
121 <li class="${h.is_active('authentication', active)}"><a href="${h.route_path('auth_home', traverse='')}">${_('Authentication')}</a></li>
120 <li class="${h.is_active('integrations', active)}"><a href="${h.route_path('global_integrations_home')}">${_('Integrations')}</a></li>
122 <li class="${h.is_active('integrations', active)}"><a href="${h.route_path('global_integrations_home')}">${_('Integrations')}</a></li>
@@ -540,7 +542,7 b''
540
542
541 % if can_create_repo_groups_in_group:
543 % if can_create_repo_groups_in_group:
542 <li>
544 <li>
543 <a href="${h.route_path('repo_group_new',_query=dict(parent_group=c.repo_group.group_id))}">${_(u'New Repository Group')}</a>
545 <a href="${h.route_path('repo_group_new',_query=dict(parent_group=c.repo_group.group_id))}">${_('New Repository Group')}</a>
544 </li>
546 </li>
545 % endif
547 % endif
546 % endif
548 % endif
@@ -568,12 +570,12 b''
568
570
569 % if can_create_repo_groups:
571 % if can_create_repo_groups:
570 <li>
572 <li>
571 <a href="${h.route_path('repo_group_new')}" >${_(u'New Repository Group')}</a>
573 <a href="${h.route_path('repo_group_new')}" >${_('New Repository Group')}</a>
572 </li>
574 </li>
573 % endif
575 % endif
574
576
575 <li>
577 <li>
576 <a href="${h.route_path('gists_new')}">${_(u'New Gist')}</a>
578 <a href="${h.route_path('gists_new')}">${_('New Gist')}</a>
577 </li>
579 </li>
578
580
579 </ol>
581 </ol>
General Comments 0
You need to be logged in to leave comments. Login now