##// END OF EJS Templates
apps: base app fixes for python3
super-admin -
r5086:62af941a default
parent child Browse files
Show More
@@ -1,59 +1,88 b''
1 # -*- coding: utf-8 -*-
2
1
3 # Copyright (C) 2010-2020 RhodeCode GmbH
2 # Copyright (C) 2010-2020 RhodeCode GmbH
4 #
3 #
5 # This program is free software: you can redistribute it and/or modify
4 # 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
5 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
6 # (only), as published by the Free Software Foundation.
8 #
7 #
9 # This program is distributed in the hope that it will be useful,
8 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
11 # GNU General Public License for more details.
13 #
12 #
14 # You should have received a copy of the GNU Affero General Public License
13 # 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/>.
14 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
15 #
17 # This program is dual-licensed. If you wish to learn more about the
16 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
17 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
18 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
19
21 import os
20 import os
22 import datetime
21 import datetime
23 import collections
22 import collections
24
23
25 now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")
24 now = datetime.datetime.now()
25 now = now.strftime("%Y-%m-%d %H:%M:%S") + '.' + "{:03d}".format(int(now.microsecond/1000))
26
26
27 print(f'{now} Starting RhodeCode imports...')
27 print(f'{now} Starting RhodeCode imports...')
28
28
29 VERSION = tuple(open(os.path.join(
29 VERSION = tuple(open(os.path.join(
30 os.path.dirname(__file__), 'VERSION')).read().split('.'))
30 os.path.dirname(__file__), 'VERSION')).read().split('.'))
31
31
32 BACKENDS = collections.OrderedDict()
32 BACKENDS = collections.OrderedDict()
33
33
34 BACKENDS['hg'] = 'Mercurial repository'
34 BACKENDS['hg'] = 'Mercurial repository'
35 BACKENDS['git'] = 'Git repository'
35 BACKENDS['git'] = 'Git repository'
36 BACKENDS['svn'] = 'Subversion repository'
36 BACKENDS['svn'] = 'Subversion repository'
37
37
38
38
39 CELERY_ENABLED = False
39 CELERY_ENABLED = False
40 CELERY_EAGER = False
40 CELERY_EAGER = False
41
41
42 # link to config for pyramid
42 # link to config for pyramid
43 CONFIG = {}
43 CONFIG = {}
44
44
45
46 class ConfigGet:
47 NotGiven = object()
48
49 def _get_val_or_missing(self, key, missing):
50 if key not in CONFIG:
51 if missing == self.NotGiven:
52 return missing
53 # we don't get key, we don't get missing value, return nothing similar as config.get(key)
54 return None
55 else:
56 val = CONFIG[key]
57 return val
58
59 def get_str(self, key, missing=NotGiven):
60 from rhodecode.lib.str_utils import safe_str
61 val = self._get_val_or_missing(key, missing)
62 return safe_str(val)
63
64 def get_int(self, key, missing=NotGiven):
65 from rhodecode.lib.str_utils import safe_int
66 val = self._get_val_or_missing(key, missing)
67 return safe_int(val)
68
69 def get_bool(self, key, missing=NotGiven):
70 from rhodecode.lib.type_utils import str2bool
71 val = self._get_val_or_missing(key, missing)
72 return str2bool(val)
73
45 # Populated with the settings dictionary from application init in
74 # Populated with the settings dictionary from application init in
46 # rhodecode.conf.environment.load_pyramid_environment
75 # rhodecode.conf.environment.load_pyramid_environment
47 PYRAMID_SETTINGS = {}
76 PYRAMID_SETTINGS = {}
48
77
49 # Linked module for extensions
78 # Linked module for extensions
50 EXTENSIONS = {}
79 EXTENSIONS = {}
51
80
52 __version__ = ('.'.join((str(each) for each in VERSION[:3])))
81 __version__ = ('.'.join((str(each) for each in VERSION[:3])))
53 __dbversion__ = 114 # defines current db version for migrations
82 __dbversion__ = 114 # defines current db version for migrations
54 __license__ = 'AGPLv3, and Commercial License'
83 __license__ = 'AGPLv3, and Commercial License'
55 __author__ = 'RhodeCode GmbH'
84 __author__ = 'RhodeCode GmbH'
56 __url__ = 'https://code.rhodecode.com'
85 __url__ = 'https://code.rhodecode.com'
57
86
58 is_test = False
87 is_test = False
59 disable_error_handler = False
88 disable_error_handler = False
@@ -1,858 +1,860 b''
1
1
2
2
3 # Copyright (C) 2016-2020 RhodeCode GmbH
3 # Copyright (C) 2016-2020 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 import time
21 import time
22 import logging
22 import logging
23 import operator
23 import operator
24
24
25 from pyramid.httpexceptions import HTTPFound, HTTPForbidden, HTTPBadRequest
25 from pyramid.httpexceptions import HTTPFound, HTTPForbidden, HTTPBadRequest
26
26
27 from rhodecode.lib import helpers as h, diffs, rc_cache
27 from rhodecode.lib import helpers as h, diffs, rc_cache
28 from rhodecode.lib.str_utils import safe_str
28 from rhodecode.lib.utils import repo_name_slug
29 from rhodecode.lib.utils import repo_name_slug
29 from rhodecode.lib.utils2 import (
30 from rhodecode.lib.utils2 import (
30 StrictAttributeDict, str2bool, safe_int, datetime_to_time, safe_unicode)
31 StrictAttributeDict, str2bool, safe_int, datetime_to_time)
31 from rhodecode.lib.markup_renderer import MarkupRenderer, relative_links
32 from rhodecode.lib.markup_renderer import MarkupRenderer, relative_links
32 from rhodecode.lib.vcs.backends.base import EmptyCommit
33 from rhodecode.lib.vcs.backends.base import EmptyCommit
33 from rhodecode.lib.vcs.exceptions import RepositoryRequirementError
34 from rhodecode.lib.vcs.exceptions import RepositoryRequirementError
34 from rhodecode.model import repo
35 from rhodecode.model import repo
35 from rhodecode.model import repo_group
36 from rhodecode.model import repo_group
36 from rhodecode.model import user_group
37 from rhodecode.model import user_group
37 from rhodecode.model import user
38 from rhodecode.model import user
38 from rhodecode.model.db import User
39 from rhodecode.model.db import User
39 from rhodecode.model.scm import ScmModel
40 from rhodecode.model.scm import ScmModel
40 from rhodecode.model.settings import VcsSettingsModel, IssueTrackerSettingsModel
41 from rhodecode.model.settings import VcsSettingsModel, IssueTrackerSettingsModel
41 from rhodecode.model.repo import ReadmeFinder
42 from rhodecode.model.repo import ReadmeFinder
42
43
43 log = logging.getLogger(__name__)
44 log = logging.getLogger(__name__)
44
45
45
46
46 ADMIN_PREFIX = '/_admin'
47 ADMIN_PREFIX = '/_admin'
47 STATIC_FILE_PREFIX = '/_static'
48 STATIC_FILE_PREFIX = '/_static'
48
49
49 URL_NAME_REQUIREMENTS = {
50 URL_NAME_REQUIREMENTS = {
50 # group name can have a slash in them, but they must not end with a slash
51 # group name can have a slash in them, but they must not end with a slash
51 'group_name': r'.*?[^/]',
52 'group_name': r'.*?[^/]',
52 'repo_group_name': r'.*?[^/]',
53 'repo_group_name': r'.*?[^/]',
53 # repo names can have a slash in them, but they must not end with a slash
54 # repo names can have a slash in them, but they must not end with a slash
54 'repo_name': r'.*?[^/]',
55 'repo_name': r'.*?[^/]',
55 # file path eats up everything at the end
56 # file path eats up everything at the end
56 'f_path': r'.*',
57 'f_path': r'.*',
57 # reference types
58 # reference types
58 'source_ref_type': '(branch|book|tag|rev|\%\(source_ref_type\)s)',
59 'source_ref_type': '(branch|book|tag|rev|\%\(source_ref_type\)s)',
59 'target_ref_type': '(branch|book|tag|rev|\%\(target_ref_type\)s)',
60 'target_ref_type': '(branch|book|tag|rev|\%\(target_ref_type\)s)',
60 }
61 }
61
62
62
63
63 def add_route_with_slash(config,name, pattern, **kw):
64 def add_route_with_slash(config,name, pattern, **kw):
64 config.add_route(name, pattern, **kw)
65 config.add_route(name, pattern, **kw)
65 if not pattern.endswith('/'):
66 if not pattern.endswith('/'):
66 config.add_route(name + '_slash', pattern + '/', **kw)
67 config.add_route(name + '_slash', pattern + '/', **kw)
67
68
68
69
69 def add_route_requirements(route_path, requirements=None):
70 def add_route_requirements(route_path, requirements=None):
70 """
71 """
71 Adds regex requirements to pyramid routes using a mapping dict
72 Adds regex requirements to pyramid routes using a mapping dict
72 e.g::
73 e.g::
73 add_route_requirements('{repo_name}/settings')
74 add_route_requirements('{repo_name}/settings')
74 """
75 """
75 requirements = requirements or URL_NAME_REQUIREMENTS
76 requirements = requirements or URL_NAME_REQUIREMENTS
76 for key, regex in requirements.items():
77 for key, regex in list(requirements.items()):
77 route_path = route_path.replace('{%s}' % key, '{%s:%s}' % (key, regex))
78 route_path = route_path.replace('{%s}' % key, '{%s:%s}' % (key, regex))
78 return route_path
79 return route_path
79
80
80
81
81 def get_format_ref_id(repo):
82 def get_format_ref_id(repo):
82 """Returns a `repo` specific reference formatter function"""
83 """Returns a `repo` specific reference formatter function"""
83 if h.is_svn(repo):
84 if h.is_svn(repo):
84 return _format_ref_id_svn
85 return _format_ref_id_svn
85 else:
86 else:
86 return _format_ref_id
87 return _format_ref_id
87
88
88
89
89 def _format_ref_id(name, raw_id):
90 def _format_ref_id(name, raw_id):
90 """Default formatting of a given reference `name`"""
91 """Default formatting of a given reference `name`"""
91 return name
92 return name
92
93
93
94
94 def _format_ref_id_svn(name, raw_id):
95 def _format_ref_id_svn(name, raw_id):
95 """Special way of formatting a reference for Subversion including path"""
96 """Special way of formatting a reference for Subversion including path"""
96 return '%s@%s' % (name, raw_id)
97 return '%s@%s' % (name, raw_id)
97
98
98
99
99 class TemplateArgs(StrictAttributeDict):
100 class TemplateArgs(StrictAttributeDict):
100 pass
101 pass
101
102
102
103
103 class BaseAppView(object):
104 class BaseAppView(object):
104
105
105 def __init__(self, context, request):
106 def __init__(self, context, request):
106 self.request = request
107 self.request = request
107 self.context = context
108 self.context = context
108 self.session = request.session
109 self.session = request.session
109 if not hasattr(request, 'user'):
110 if not hasattr(request, 'user'):
110 # NOTE(marcink): edge case, we ended up in matched route
111 # NOTE(marcink): edge case, we ended up in matched route
111 # but probably of web-app context, e.g API CALL/VCS CALL
112 # but probably of web-app context, e.g API CALL/VCS CALL
112 if hasattr(request, 'vcs_call') or hasattr(request, 'rpc_method'):
113 if hasattr(request, 'vcs_call') or hasattr(request, 'rpc_method'):
113 log.warning('Unable to process request `%s` in this scope', request)
114 log.warning('Unable to process request `%s` in this scope', request)
114 raise HTTPBadRequest()
115 raise HTTPBadRequest()
115
116
116 self._rhodecode_user = request.user # auth user
117 self._rhodecode_user = request.user # auth user
117 self._rhodecode_db_user = self._rhodecode_user.get_instance()
118 self._rhodecode_db_user = self._rhodecode_user.get_instance()
118 self._maybe_needs_password_change(
119 self._maybe_needs_password_change(
119 request.matched_route.name, self._rhodecode_db_user)
120 request.matched_route.name, self._rhodecode_db_user)
120
121
121 def _maybe_needs_password_change(self, view_name, user_obj):
122 def _maybe_needs_password_change(self, view_name, user_obj):
122
123
123 dont_check_views = [
124 dont_check_views = [
124 'channelstream_connect',
125 'channelstream_connect',
125 'ops_ping'
126 'ops_ping'
126 ]
127 ]
127 if view_name in dont_check_views:
128 if view_name in dont_check_views:
128 return
129 return
129
130
130 log.debug('Checking if user %s needs password change on view %s',
131 log.debug('Checking if user %s needs password change on view %s',
131 user_obj, view_name)
132 user_obj, view_name)
132
133
133 skip_user_views = [
134 skip_user_views = [
134 'logout', 'login',
135 'logout', 'login',
135 'my_account_password', 'my_account_password_update'
136 'my_account_password', 'my_account_password_update'
136 ]
137 ]
137
138
138 if not user_obj:
139 if not user_obj:
139 return
140 return
140
141
141 if user_obj.username == User.DEFAULT_USER:
142 if user_obj.username == User.DEFAULT_USER:
142 return
143 return
143
144
144 now = time.time()
145 now = time.time()
145 should_change = user_obj.user_data.get('force_password_change')
146 should_change = user_obj.user_data.get('force_password_change')
146 change_after = safe_int(should_change) or 0
147 change_after = safe_int(should_change) or 0
147 if should_change and now > change_after:
148 if should_change and now > change_after:
148 log.debug('User %s requires password change', user_obj)
149 log.debug('User %s requires password change', user_obj)
149 h.flash('You are required to change your password', 'warning',
150 h.flash('You are required to change your password', 'warning',
150 ignore_duplicate=True)
151 ignore_duplicate=True)
151
152
152 if view_name not in skip_user_views:
153 if view_name not in skip_user_views:
153 raise HTTPFound(
154 raise HTTPFound(
154 self.request.route_path('my_account_password'))
155 self.request.route_path('my_account_password'))
155
156
156 def _log_creation_exception(self, e, repo_name):
157 def _log_creation_exception(self, e, repo_name):
157 _ = self.request.translate
158 _ = self.request.translate
158 reason = None
159 reason = None
159 if len(e.args) == 2:
160 if len(e.args) == 2:
160 reason = e.args[1]
161 reason = e.args[1]
161
162
162 if reason == 'INVALID_CERTIFICATE':
163 if reason == 'INVALID_CERTIFICATE':
163 log.exception(
164 log.exception(
164 'Exception creating a repository: invalid certificate')
165 'Exception creating a repository: invalid certificate')
165 msg = (_('Error creating repository %s: invalid certificate')
166 msg = (_('Error creating repository %s: invalid certificate')
166 % repo_name)
167 % repo_name)
167 else:
168 else:
168 log.exception("Exception creating a repository")
169 log.exception("Exception creating a repository")
169 msg = (_('Error creating repository %s')
170 msg = (_('Error creating repository %s')
170 % repo_name)
171 % repo_name)
171 return msg
172 return msg
172
173
173 def _get_local_tmpl_context(self, include_app_defaults=True):
174 def _get_local_tmpl_context(self, include_app_defaults=True):
174 c = TemplateArgs()
175 c = TemplateArgs()
175 c.auth_user = self.request.user
176 c.auth_user = self.request.user
176 # TODO(marcink): migrate the usage of c.rhodecode_user to c.auth_user
177 # TODO(marcink): migrate the usage of c.rhodecode_user to c.auth_user
177 c.rhodecode_user = self.request.user
178 c.rhodecode_user = self.request.user
178
179
179 if include_app_defaults:
180 if include_app_defaults:
180 from rhodecode.lib.base import attach_context_attributes
181 from rhodecode.lib.base import attach_context_attributes
181 attach_context_attributes(c, self.request, self.request.user.user_id)
182 attach_context_attributes(c, self.request, self.request.user.user_id)
182
183
183 c.is_super_admin = c.auth_user.is_admin
184 c.is_super_admin = c.auth_user.is_admin
184
185
185 c.can_create_repo = c.is_super_admin
186 c.can_create_repo = c.is_super_admin
186 c.can_create_repo_group = c.is_super_admin
187 c.can_create_repo_group = c.is_super_admin
187 c.can_create_user_group = c.is_super_admin
188 c.can_create_user_group = c.is_super_admin
188
189
189 c.is_delegated_admin = False
190 c.is_delegated_admin = False
190
191
191 if not c.auth_user.is_default and not c.is_super_admin:
192 if not c.auth_user.is_default and not c.is_super_admin:
192 c.can_create_repo = h.HasPermissionAny('hg.create.repository')(
193 c.can_create_repo = h.HasPermissionAny('hg.create.repository')(
193 user=self.request.user)
194 user=self.request.user)
194 repositories = c.auth_user.repositories_admin or c.can_create_repo
195 repositories = c.auth_user.repositories_admin or c.can_create_repo
195
196
196 c.can_create_repo_group = h.HasPermissionAny('hg.repogroup.create.true')(
197 c.can_create_repo_group = h.HasPermissionAny('hg.repogroup.create.true')(
197 user=self.request.user)
198 user=self.request.user)
198 repository_groups = c.auth_user.repository_groups_admin or c.can_create_repo_group
199 repository_groups = c.auth_user.repository_groups_admin or c.can_create_repo_group
199
200
200 c.can_create_user_group = h.HasPermissionAny('hg.usergroup.create.true')(
201 c.can_create_user_group = h.HasPermissionAny('hg.usergroup.create.true')(
201 user=self.request.user)
202 user=self.request.user)
202 user_groups = c.auth_user.user_groups_admin or c.can_create_user_group
203 user_groups = c.auth_user.user_groups_admin or c.can_create_user_group
203 # delegated admin can create, or manage some objects
204 # delegated admin can create, or manage some objects
204 c.is_delegated_admin = repositories or repository_groups or user_groups
205 c.is_delegated_admin = repositories or repository_groups or user_groups
205 return c
206 return c
206
207
207 def _get_template_context(self, tmpl_args, **kwargs):
208 def _get_template_context(self, tmpl_args, **kwargs):
208
209
209 local_tmpl_args = {
210 local_tmpl_args = {
210 'defaults': {},
211 'defaults': {},
211 'errors': {},
212 'errors': {},
212 'c': tmpl_args
213 'c': tmpl_args
213 }
214 }
214 local_tmpl_args.update(kwargs)
215 local_tmpl_args.update(kwargs)
215 return local_tmpl_args
216 return local_tmpl_args
216
217
217 def load_default_context(self):
218 def load_default_context(self):
218 """
219 """
219 example:
220 example:
220
221
221 def load_default_context(self):
222 def load_default_context(self):
222 c = self._get_local_tmpl_context()
223 c = self._get_local_tmpl_context()
223 c.custom_var = 'foobar'
224 c.custom_var = 'foobar'
224
225
225 return c
226 return c
226 """
227 """
227 raise NotImplementedError('Needs implementation in view class')
228 raise NotImplementedError('Needs implementation in view class')
228
229
229
230
230 class RepoAppView(BaseAppView):
231 class RepoAppView(BaseAppView):
231
232
232 def __init__(self, context, request):
233 def __init__(self, context, request):
233 super(RepoAppView, self).__init__(context, request)
234 super(RepoAppView, self).__init__(context, request)
234 self.db_repo = request.db_repo
235 self.db_repo = request.db_repo
235 self.db_repo_name = self.db_repo.repo_name
236 self.db_repo_name = self.db_repo.repo_name
236 self.db_repo_pull_requests = ScmModel().get_pull_requests(self.db_repo)
237 self.db_repo_pull_requests = ScmModel().get_pull_requests(self.db_repo)
237 self.db_repo_artifacts = ScmModel().get_artifacts(self.db_repo)
238 self.db_repo_artifacts = ScmModel().get_artifacts(self.db_repo)
238 self.db_repo_patterns = IssueTrackerSettingsModel(repo=self.db_repo)
239 self.db_repo_patterns = IssueTrackerSettingsModel(repo=self.db_repo)
239
240
240 def _handle_missing_requirements(self, error):
241 def _handle_missing_requirements(self, error):
241 log.error(
242 log.error(
242 'Requirements are missing for repository %s: %s',
243 'Requirements are missing for repository %s: %s',
243 self.db_repo_name, safe_unicode(error))
244 self.db_repo_name, safe_str(error))
244
245
245 def _prepare_and_set_clone_url(self, c):
246 def _prepare_and_set_clone_url(self, c):
246 username = ''
247 username = ''
247 if self._rhodecode_user.username != User.DEFAULT_USER:
248 if self._rhodecode_user.username != User.DEFAULT_USER:
248 username = self._rhodecode_user.username
249 username = self._rhodecode_user.username
249
250
250 _def_clone_uri = c.clone_uri_tmpl
251 _def_clone_uri = c.clone_uri_tmpl
251 _def_clone_uri_id = c.clone_uri_id_tmpl
252 _def_clone_uri_id = c.clone_uri_id_tmpl
252 _def_clone_uri_ssh = c.clone_uri_ssh_tmpl
253 _def_clone_uri_ssh = c.clone_uri_ssh_tmpl
253
254
254 c.clone_repo_url = self.db_repo.clone_url(
255 c.clone_repo_url = self.db_repo.clone_url(
255 user=username, uri_tmpl=_def_clone_uri)
256 user=username, uri_tmpl=_def_clone_uri)
256 c.clone_repo_url_id = self.db_repo.clone_url(
257 c.clone_repo_url_id = self.db_repo.clone_url(
257 user=username, uri_tmpl=_def_clone_uri_id)
258 user=username, uri_tmpl=_def_clone_uri_id)
258 c.clone_repo_url_ssh = self.db_repo.clone_url(
259 c.clone_repo_url_ssh = self.db_repo.clone_url(
259 uri_tmpl=_def_clone_uri_ssh, ssh=True)
260 uri_tmpl=_def_clone_uri_ssh, ssh=True)
260
261
261 def _get_local_tmpl_context(self, include_app_defaults=True):
262 def _get_local_tmpl_context(self, include_app_defaults=True):
262 _ = self.request.translate
263 _ = self.request.translate
263 c = super(RepoAppView, self)._get_local_tmpl_context(
264 c = super(RepoAppView, self)._get_local_tmpl_context(
264 include_app_defaults=include_app_defaults)
265 include_app_defaults=include_app_defaults)
265
266
266 # register common vars for this type of view
267 # register common vars for this type of view
267 c.rhodecode_db_repo = self.db_repo
268 c.rhodecode_db_repo = self.db_repo
268 c.repo_name = self.db_repo_name
269 c.repo_name = self.db_repo_name
269 c.repository_pull_requests = self.db_repo_pull_requests
270 c.repository_pull_requests = self.db_repo_pull_requests
270 c.repository_artifacts = self.db_repo_artifacts
271 c.repository_artifacts = self.db_repo_artifacts
271 c.repository_is_user_following = ScmModel().is_following_repo(
272 c.repository_is_user_following = ScmModel().is_following_repo(
272 self.db_repo_name, self._rhodecode_user.user_id)
273 self.db_repo_name, self._rhodecode_user.user_id)
273 self.path_filter = PathFilter(None)
274 self.path_filter = PathFilter(None)
274
275
275 c.repository_requirements_missing = {}
276 c.repository_requirements_missing = {}
276 try:
277 try:
277 self.rhodecode_vcs_repo = self.db_repo.scm_instance()
278 self.rhodecode_vcs_repo = self.db_repo.scm_instance()
278 # NOTE(marcink):
279 # NOTE(marcink):
279 # comparison to None since if it's an object __bool__ is expensive to
280 # comparison to None since if it's an object __bool__ is expensive to
280 # calculate
281 # calculate
281 if self.rhodecode_vcs_repo is not None:
282 if self.rhodecode_vcs_repo is not None:
282 path_perms = self.rhodecode_vcs_repo.get_path_permissions(
283 path_perms = self.rhodecode_vcs_repo.get_path_permissions(
283 c.auth_user.username)
284 c.auth_user.username)
284 self.path_filter = PathFilter(path_perms)
285 self.path_filter = PathFilter(path_perms)
285 except RepositoryRequirementError as e:
286 except RepositoryRequirementError as e:
286 c.repository_requirements_missing = {'error': str(e)}
287 c.repository_requirements_missing = {'error': str(e)}
287 self._handle_missing_requirements(e)
288 self._handle_missing_requirements(e)
288 self.rhodecode_vcs_repo = None
289 self.rhodecode_vcs_repo = None
289
290
290 c.path_filter = self.path_filter # used by atom_feed_entry.mako
291 c.path_filter = self.path_filter # used by atom_feed_entry.mako
291
292
292 if self.rhodecode_vcs_repo is None:
293 if self.rhodecode_vcs_repo is None:
293 # unable to fetch this repo as vcs instance, report back to user
294 # unable to fetch this repo as vcs instance, report back to user
294 log.debug('Repository was not found on filesystem, check if it exists or is not damaged')
295 log.debug('Repository was not found on filesystem, check if it exists or is not damaged')
295 h.flash(_(
296 h.flash(_(
296 "The repository `%(repo_name)s` cannot be loaded in filesystem. "
297 "The repository `%(repo_name)s` cannot be loaded in filesystem. "
297 "Please check if it exist, or is not damaged.") %
298 "Please check if it exist, or is not damaged.") %
298 {'repo_name': c.repo_name},
299 {'repo_name': c.repo_name},
299 category='error', ignore_duplicate=True)
300 category='error', ignore_duplicate=True)
300 if c.repository_requirements_missing:
301 if c.repository_requirements_missing:
301 route = self.request.matched_route.name
302 route = self.request.matched_route.name
302 if route.startswith(('edit_repo', 'repo_summary')):
303 if route.startswith(('edit_repo', 'repo_summary')):
303 # allow summary and edit repo on missing requirements
304 # allow summary and edit repo on missing requirements
304 return c
305 return c
305
306
306 raise HTTPFound(
307 raise HTTPFound(
307 h.route_path('repo_summary', repo_name=self.db_repo_name))
308 h.route_path('repo_summary', repo_name=self.db_repo_name))
308
309
309 else: # redirect if we don't show missing requirements
310 else: # redirect if we don't show missing requirements
310 raise HTTPFound(h.route_path('home'))
311 raise HTTPFound(h.route_path('home'))
311
312
312 c.has_origin_repo_read_perm = False
313 c.has_origin_repo_read_perm = False
313 if self.db_repo.fork:
314 if self.db_repo.fork:
314 c.has_origin_repo_read_perm = h.HasRepoPermissionAny(
315 c.has_origin_repo_read_perm = h.HasRepoPermissionAny(
315 'repository.write', 'repository.read', 'repository.admin')(
316 'repository.write', 'repository.read', 'repository.admin')(
316 self.db_repo.fork.repo_name, 'summary fork link')
317 self.db_repo.fork.repo_name, 'summary fork link')
317
318
318 return c
319 return c
319
320
320 def _get_f_path_unchecked(self, matchdict, default=None):
321 def _get_f_path_unchecked(self, matchdict, default=None):
321 """
322 """
322 Should only be used by redirects, everything else should call _get_f_path
323 Should only be used by redirects, everything else should call _get_f_path
323 """
324 """
324 f_path = matchdict.get('f_path')
325 f_path = matchdict.get('f_path')
325 if f_path:
326 if f_path:
326 # fix for multiple initial slashes that causes errors for GIT
327 # fix for multiple initial slashes that causes errors for GIT
327 return f_path.lstrip('/')
328 return f_path.lstrip('/')
328
329
329 return default
330 return default
330
331
331 def _get_f_path(self, matchdict, default=None):
332 def _get_f_path(self, matchdict, default=None):
332 f_path_match = self._get_f_path_unchecked(matchdict, default)
333 f_path_match = self._get_f_path_unchecked(matchdict, default)
333 return self.path_filter.assert_path_permissions(f_path_match)
334 return self.path_filter.assert_path_permissions(f_path_match)
334
335
335 def _get_general_setting(self, target_repo, settings_key, default=False):
336 def _get_general_setting(self, target_repo, settings_key, default=False):
336 settings_model = VcsSettingsModel(repo=target_repo)
337 settings_model = VcsSettingsModel(repo=target_repo)
337 settings = settings_model.get_general_settings()
338 settings = settings_model.get_general_settings()
338 return settings.get(settings_key, default)
339 return settings.get(settings_key, default)
339
340
340 def _get_repo_setting(self, target_repo, settings_key, default=False):
341 def _get_repo_setting(self, target_repo, settings_key, default=False):
341 settings_model = VcsSettingsModel(repo=target_repo)
342 settings_model = VcsSettingsModel(repo=target_repo)
342 settings = settings_model.get_repo_settings_inherited()
343 settings = settings_model.get_repo_settings_inherited()
343 return settings.get(settings_key, default)
344 return settings.get(settings_key, default)
344
345
345 def _get_readme_data(self, db_repo, renderer_type, commit_id=None, path='/'):
346 def _get_readme_data(self, db_repo, renderer_type, commit_id=None, path='/'):
346 log.debug('Looking for README file at path %s', path)
347 log.debug('Looking for README file at path %s', path)
347 if commit_id:
348 if commit_id:
348 landing_commit_id = commit_id
349 landing_commit_id = commit_id
349 else:
350 else:
350 landing_commit = db_repo.get_landing_commit()
351 landing_commit = db_repo.get_landing_commit()
351 if isinstance(landing_commit, EmptyCommit):
352 if isinstance(landing_commit, EmptyCommit):
352 return None, None
353 return None, None
353 landing_commit_id = landing_commit.raw_id
354 landing_commit_id = landing_commit.raw_id
354
355
355 cache_namespace_uid = 'cache_repo.{}'.format(db_repo.repo_id)
356 cache_namespace_uid = 'repo.{}'.format(db_repo.repo_id)
356 region = rc_cache.get_or_create_region('cache_repo', cache_namespace_uid)
357 region = rc_cache.get_or_create_region('cache_repo', cache_namespace_uid, use_async_runner=True)
357 start = time.time()
358 start = time.time()
358
359
359 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid)
360 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid)
360 def generate_repo_readme(repo_id, _commit_id, _repo_name, _readme_search_path, _renderer_type):
361 def generate_repo_readme(repo_id, _commit_id, _repo_name, _readme_search_path, _renderer_type):
361 readme_data = None
362 readme_data = None
362 readme_filename = None
363 readme_filename = None
363
364
364 commit = db_repo.get_commit(_commit_id)
365 commit = db_repo.get_commit(_commit_id)
365 log.debug("Searching for a README file at commit %s.", _commit_id)
366 log.debug("Searching for a README file at commit %s.", _commit_id)
366 readme_node = ReadmeFinder(_renderer_type).search(commit, path=_readme_search_path)
367 readme_node = ReadmeFinder(_renderer_type).search(commit, path=_readme_search_path)
367
368
368 if readme_node:
369 if readme_node:
369 log.debug('Found README node: %s', readme_node)
370 log.debug('Found README node: %s', readme_node)
370 relative_urls = {
371 relative_urls = {
371 'raw': h.route_path(
372 'raw': h.route_path(
372 'repo_file_raw', repo_name=_repo_name,
373 'repo_file_raw', repo_name=_repo_name,
373 commit_id=commit.raw_id, f_path=readme_node.path),
374 commit_id=commit.raw_id, f_path=readme_node.path),
374 'standard': h.route_path(
375 'standard': h.route_path(
375 'repo_files', repo_name=_repo_name,
376 'repo_files', repo_name=_repo_name,
376 commit_id=commit.raw_id, f_path=readme_node.path),
377 commit_id=commit.raw_id, f_path=readme_node.path),
377 }
378 }
378
379
379 readme_data = self._render_readme_or_none(commit, readme_node, relative_urls)
380 readme_data = self._render_readme_or_none(commit, readme_node, relative_urls)
380 readme_filename = readme_node.unicode_path
381 readme_filename = readme_node.str_path
381
382
382 return readme_data, readme_filename
383 return readme_data, readme_filename
383
384
384 readme_data, readme_filename = generate_repo_readme(
385 readme_data, readme_filename = generate_repo_readme(
385 db_repo.repo_id, landing_commit_id, db_repo.repo_name, path, renderer_type,)
386 db_repo.repo_id, landing_commit_id, db_repo.repo_name, path, renderer_type,)
386
387
387 compute_time = time.time() - start
388 compute_time = time.time() - start
388 log.debug('Repo README for path %s generated and computed in %.4fs',
389 log.debug('Repo README for path %s generated and computed in %.4fs',
389 path, compute_time)
390 path, compute_time)
390 return readme_data, readme_filename
391 return readme_data, readme_filename
391
392
392 def _render_readme_or_none(self, commit, readme_node, relative_urls):
393 def _render_readme_or_none(self, commit, readme_node, relative_urls):
393 log.debug('Found README file `%s` rendering...', readme_node.path)
394 log.debug('Found README file `%s` rendering...', readme_node.path)
394 renderer = MarkupRenderer()
395 renderer = MarkupRenderer()
395 try:
396 try:
396 html_source = renderer.render(
397 html_source = renderer.render(
397 readme_node.content, filename=readme_node.path)
398 readme_node.str_content, filename=readme_node.path)
398 if relative_urls:
399 if relative_urls:
399 return relative_links(html_source, relative_urls)
400 return relative_links(html_source, relative_urls)
400 return html_source
401 return html_source
401 except Exception:
402 except Exception:
402 log.exception(
403 log.exception("Exception while trying to render the README")
403 "Exception while trying to render the README")
404
404
405 def get_recache_flag(self):
405 def get_recache_flag(self):
406 for flag_name in ['force_recache', 'force-recache', 'no-cache']:
406 for flag_name in ['force_recache', 'force-recache', 'no-cache']:
407 flag_val = self.request.GET.get(flag_name)
407 flag_val = self.request.GET.get(flag_name)
408 if str2bool(flag_val):
408 if str2bool(flag_val):
409 return True
409 return True
410 return False
410 return False
411
411
412 def get_commit_preload_attrs(cls):
412 def get_commit_preload_attrs(cls):
413 pre_load = ['author', 'branch', 'date', 'message', 'parents',
413 pre_load = ['author', 'branch', 'date', 'message', 'parents',
414 'obsolete', 'phase', 'hidden']
414 'obsolete', 'phase', 'hidden']
415 return pre_load
415 return pre_load
416
416
417
417
418 class PathFilter(object):
418 class PathFilter(object):
419
419
420 # Expects and instance of BasePathPermissionChecker or None
420 # Expects and instance of BasePathPermissionChecker or None
421 def __init__(self, permission_checker):
421 def __init__(self, permission_checker):
422 self.permission_checker = permission_checker
422 self.permission_checker = permission_checker
423
423
424 def assert_path_permissions(self, path):
424 def assert_path_permissions(self, path):
425 if self.path_access_allowed(path):
425 if self.path_access_allowed(path):
426 return path
426 return path
427 raise HTTPForbidden()
427 raise HTTPForbidden()
428
428
429 def path_access_allowed(self, path):
429 def path_access_allowed(self, path):
430 log.debug('Checking ACL permissions for PathFilter for `%s`', path)
430 log.debug('Checking ACL permissions for PathFilter for `%s`', path)
431 if self.permission_checker:
431 if self.permission_checker:
432 has_access = path and self.permission_checker.has_access(path)
432 has_access = path and self.permission_checker.has_access(path)
433 log.debug('ACL Permissions checker enabled, ACL Check has_access: %s', has_access)
433 log.debug('ACL Permissions checker enabled, ACL Check has_access: %s', has_access)
434 return has_access
434 return has_access
435
435
436 log.debug('ACL permissions checker not enabled, skipping...')
436 log.debug('ACL permissions checker not enabled, skipping...')
437 return True
437 return True
438
438
439 def filter_patchset(self, patchset):
439 def filter_patchset(self, patchset):
440 if not self.permission_checker or not patchset:
440 if not self.permission_checker or not patchset:
441 return patchset, False
441 return patchset, False
442 had_filtered = False
442 had_filtered = False
443 filtered_patchset = []
443 filtered_patchset = []
444 for patch in patchset:
444 for patch in patchset:
445 filename = patch.get('filename', None)
445 filename = patch.get('filename', None)
446 if not filename or self.permission_checker.has_access(filename):
446 if not filename or self.permission_checker.has_access(filename):
447 filtered_patchset.append(patch)
447 filtered_patchset.append(patch)
448 else:
448 else:
449 had_filtered = True
449 had_filtered = True
450 if had_filtered:
450 if had_filtered:
451 if isinstance(patchset, diffs.LimitedDiffContainer):
451 if isinstance(patchset, diffs.LimitedDiffContainer):
452 filtered_patchset = diffs.LimitedDiffContainer(patchset.diff_limit, patchset.cur_diff_size, filtered_patchset)
452 filtered_patchset = diffs.LimitedDiffContainer(patchset.diff_limit, patchset.cur_diff_size, filtered_patchset)
453 return filtered_patchset, True
453 return filtered_patchset, True
454 else:
454 else:
455 return patchset, False
455 return patchset, False
456
456
457 def render_patchset_filtered(self, diffset, patchset, source_ref=None, target_ref=None):
457 def render_patchset_filtered(self, diffset, patchset, source_ref=None, target_ref=None):
458
458 filtered_patchset, has_hidden_changes = self.filter_patchset(patchset)
459 filtered_patchset, has_hidden_changes = self.filter_patchset(patchset)
459 result = diffset.render_patchset(
460 result = diffset.render_patchset(
460 filtered_patchset, source_ref=source_ref, target_ref=target_ref)
461 filtered_patchset, source_ref=source_ref, target_ref=target_ref)
461 result.has_hidden_changes = has_hidden_changes
462 result.has_hidden_changes = has_hidden_changes
462 return result
463 return result
463
464
464 def get_raw_patch(self, diff_processor):
465 def get_raw_patch(self, diff_processor):
465 if self.permission_checker is None:
466 if self.permission_checker is None:
466 return diff_processor.as_raw()
467 return diff_processor.as_raw()
467 elif self.permission_checker.has_full_access:
468 elif self.permission_checker.has_full_access:
468 return diff_processor.as_raw()
469 return diff_processor.as_raw()
469 else:
470 else:
470 return '# Repository has user-specific filters, raw patch generation is disabled.'
471 return '# Repository has user-specific filters, raw patch generation is disabled.'
471
472
472 @property
473 @property
473 def is_enabled(self):
474 def is_enabled(self):
474 return self.permission_checker is not None
475 return self.permission_checker is not None
475
476
476
477
477 class RepoGroupAppView(BaseAppView):
478 class RepoGroupAppView(BaseAppView):
478 def __init__(self, context, request):
479 def __init__(self, context, request):
479 super(RepoGroupAppView, self).__init__(context, request)
480 super(RepoGroupAppView, self).__init__(context, request)
480 self.db_repo_group = request.db_repo_group
481 self.db_repo_group = request.db_repo_group
481 self.db_repo_group_name = self.db_repo_group.group_name
482 self.db_repo_group_name = self.db_repo_group.group_name
482
483
483 def _get_local_tmpl_context(self, include_app_defaults=True):
484 def _get_local_tmpl_context(self, include_app_defaults=True):
484 _ = self.request.translate
485 _ = self.request.translate
485 c = super(RepoGroupAppView, self)._get_local_tmpl_context(
486 c = super(RepoGroupAppView, self)._get_local_tmpl_context(
486 include_app_defaults=include_app_defaults)
487 include_app_defaults=include_app_defaults)
487 c.repo_group = self.db_repo_group
488 c.repo_group = self.db_repo_group
488 return c
489 return c
489
490
490 def _revoke_perms_on_yourself(self, form_result):
491 def _revoke_perms_on_yourself(self, form_result):
491 _updates = filter(lambda u: self._rhodecode_user.user_id == int(u[0]),
492 _updates = [u for u in form_result['perm_updates'] if self._rhodecode_user.user_id == int(u[0])]
492 form_result['perm_updates'])
493 _additions = [u for u in form_result['perm_additions'] if self._rhodecode_user.user_id == int(u[0])]
493 _additions = filter(lambda u: self._rhodecode_user.user_id == int(u[0]),
494 _deletions = [u for u in form_result['perm_deletions'] if self._rhodecode_user.user_id == int(u[0])]
494 form_result['perm_additions'])
495 _deletions = filter(lambda u: self._rhodecode_user.user_id == int(u[0]),
496 form_result['perm_deletions'])
497 admin_perm = 'group.admin'
495 admin_perm = 'group.admin'
498 if _updates and _updates[0][1] != admin_perm or \
496 if _updates and _updates[0][1] != admin_perm or \
499 _additions and _additions[0][1] != admin_perm or \
497 _additions and _additions[0][1] != admin_perm or \
500 _deletions and _deletions[0][1] != admin_perm:
498 _deletions and _deletions[0][1] != admin_perm:
501 return True
499 return True
502 return False
500 return False
503
501
504
502
505 class UserGroupAppView(BaseAppView):
503 class UserGroupAppView(BaseAppView):
506 def __init__(self, context, request):
504 def __init__(self, context, request):
507 super(UserGroupAppView, self).__init__(context, request)
505 super(UserGroupAppView, self).__init__(context, request)
508 self.db_user_group = request.db_user_group
506 self.db_user_group = request.db_user_group
509 self.db_user_group_name = self.db_user_group.users_group_name
507 self.db_user_group_name = self.db_user_group.users_group_name
510
508
511
509
512 class UserAppView(BaseAppView):
510 class UserAppView(BaseAppView):
513 def __init__(self, context, request):
511 def __init__(self, context, request):
514 super(UserAppView, self).__init__(context, request)
512 super(UserAppView, self).__init__(context, request)
515 self.db_user = request.db_user
513 self.db_user = request.db_user
516 self.db_user_id = self.db_user.user_id
514 self.db_user_id = self.db_user.user_id
517
515
518 _ = self.request.translate
516 _ = self.request.translate
519 if not request.db_user_supports_default:
517 if not request.db_user_supports_default:
520 if self.db_user.username == User.DEFAULT_USER:
518 if self.db_user.username == User.DEFAULT_USER:
521 h.flash(_("Editing user `{}` is disabled.".format(
519 h.flash(_("Editing user `{}` is disabled.".format(
522 User.DEFAULT_USER)), category='warning')
520 User.DEFAULT_USER)), category='warning')
523 raise HTTPFound(h.route_path('users'))
521 raise HTTPFound(h.route_path('users'))
524
522
525
523
526 class DataGridAppView(object):
524 class DataGridAppView(object):
527 """
525 """
528 Common class to have re-usable grid rendering components
526 Common class to have re-usable grid rendering components
529 """
527 """
530
528
531 def _extract_ordering(self, request, column_map=None):
529 def _extract_ordering(self, request, column_map=None):
532 column_map = column_map or {}
530 column_map = column_map or {}
533 column_index = safe_int(request.GET.get('order[0][column]'))
531 column_index = safe_int(request.GET.get('order[0][column]'))
534 order_dir = request.GET.get(
532 order_dir = request.GET.get(
535 'order[0][dir]', 'desc')
533 'order[0][dir]', 'desc')
536 order_by = request.GET.get(
534 order_by = request.GET.get(
537 'columns[%s][data][sort]' % column_index, 'name_raw')
535 'columns[%s][data][sort]' % column_index, 'name_raw')
538
536
539 # translate datatable to DB columns
537 # translate datatable to DB columns
540 order_by = column_map.get(order_by) or order_by
538 order_by = column_map.get(order_by) or order_by
541
539
542 search_q = request.GET.get('search[value]')
540 search_q = request.GET.get('search[value]')
543 return search_q, order_by, order_dir
541 return search_q, order_by, order_dir
544
542
545 def _extract_chunk(self, request):
543 def _extract_chunk(self, request):
546 start = safe_int(request.GET.get('start'), 0)
544 start = safe_int(request.GET.get('start'), 0)
547 length = safe_int(request.GET.get('length'), 25)
545 length = safe_int(request.GET.get('length'), 25)
548 draw = safe_int(request.GET.get('draw'))
546 draw = safe_int(request.GET.get('draw'))
549 return draw, start, length
547 return draw, start, length
550
548
551 def _get_order_col(self, order_by, model):
549 def _get_order_col(self, order_by, model):
552 if isinstance(order_by, str):
550 if isinstance(order_by, str):
553 try:
551 try:
554 return operator.attrgetter(order_by)(model)
552 return operator.attrgetter(order_by)(model)
555 except AttributeError:
553 except AttributeError:
556 return None
554 return None
557 else:
555 else:
558 return order_by
556 return order_by
559
557
560
558
561 class BaseReferencesView(RepoAppView):
559 class BaseReferencesView(RepoAppView):
562 """
560 """
563 Base for reference view for branches, tags and bookmarks.
561 Base for reference view for branches, tags and bookmarks.
564 """
562 """
565 def load_default_context(self):
563 def load_default_context(self):
566 c = self._get_local_tmpl_context()
564 c = self._get_local_tmpl_context()
567 return c
565 return c
568
566
569 def load_refs_context(self, ref_items, partials_template):
567 def load_refs_context(self, ref_items, partials_template):
570 _render = self.request.get_partial_renderer(partials_template)
568 _render = self.request.get_partial_renderer(partials_template)
571 pre_load = ["author", "date", "message", "parents"]
569 pre_load = ["author", "date", "message", "parents"]
572
570
573 is_svn = h.is_svn(self.rhodecode_vcs_repo)
571 is_svn = h.is_svn(self.rhodecode_vcs_repo)
574 is_hg = h.is_hg(self.rhodecode_vcs_repo)
572 is_hg = h.is_hg(self.rhodecode_vcs_repo)
575
573
576 format_ref_id = get_format_ref_id(self.rhodecode_vcs_repo)
574 format_ref_id = get_format_ref_id(self.rhodecode_vcs_repo)
577
575
578 closed_refs = {}
576 closed_refs = {}
579 if is_hg:
577 if is_hg:
580 closed_refs = self.rhodecode_vcs_repo.branches_closed
578 closed_refs = self.rhodecode_vcs_repo.branches_closed
581
579
582 data = []
580 data = []
583 for ref_name, commit_id in ref_items:
581 for ref_name, commit_id in ref_items:
584 commit = self.rhodecode_vcs_repo.get_commit(
582 commit = self.rhodecode_vcs_repo.get_commit(
585 commit_id=commit_id, pre_load=pre_load)
583 commit_id=commit_id, pre_load=pre_load)
586 closed = ref_name in closed_refs
584 closed = ref_name in closed_refs
587
585
588 # TODO: johbo: Unify generation of reference links
586 # TODO: johbo: Unify generation of reference links
589 use_commit_id = '/' in ref_name or is_svn
587 use_commit_id = '/' in ref_name or is_svn
590
588
591 if use_commit_id:
589 if use_commit_id:
592 files_url = h.route_path(
590 files_url = h.route_path(
593 'repo_files',
591 'repo_files',
594 repo_name=self.db_repo_name,
592 repo_name=self.db_repo_name,
595 f_path=ref_name if is_svn else '',
593 f_path=ref_name if is_svn else '',
596 commit_id=commit_id,
594 commit_id=commit_id,
597 _query=dict(at=ref_name)
595 _query=dict(at=ref_name)
598 )
596 )
599
597
600 else:
598 else:
601 files_url = h.route_path(
599 files_url = h.route_path(
602 'repo_files',
600 'repo_files',
603 repo_name=self.db_repo_name,
601 repo_name=self.db_repo_name,
604 f_path=ref_name if is_svn else '',
602 f_path=ref_name if is_svn else '',
605 commit_id=ref_name,
603 commit_id=ref_name,
606 _query=dict(at=ref_name)
604 _query=dict(at=ref_name)
607 )
605 )
608
606
609 data.append({
607 data.append({
610 "name": _render('name', ref_name, files_url, closed),
608 "name": _render('name', ref_name, files_url, closed),
611 "name_raw": ref_name,
609 "name_raw": ref_name,
612 "date": _render('date', commit.date),
610 "date": _render('date', commit.date),
613 "date_raw": datetime_to_time(commit.date),
611 "date_raw": datetime_to_time(commit.date),
614 "author": _render('author', commit.author),
612 "author": _render('author', commit.author),
615 "commit": _render(
613 "commit": _render(
616 'commit', commit.message, commit.raw_id, commit.idx),
614 'commit', commit.message, commit.raw_id, commit.idx),
617 "commit_raw": commit.idx,
615 "commit_raw": commit.idx,
618 "compare": _render(
616 "compare": _render(
619 'compare', format_ref_id(ref_name, commit.raw_id)),
617 'compare', format_ref_id(ref_name, commit.raw_id)),
620 })
618 })
621
619
622 return data
620 return data
623
621
624
622
625 class RepoRoutePredicate(object):
623 class RepoRoutePredicate(object):
626 def __init__(self, val, config):
624 def __init__(self, val, config):
627 self.val = val
625 self.val = val
628
626
629 def text(self):
627 def text(self):
630 return 'repo_route = %s' % self.val
628 return f'repo_route = {self.val}'
631
629
632 phash = text
630 phash = text
633
631
634 def __call__(self, info, request):
632 def __call__(self, info, request):
635 if hasattr(request, 'vcs_call'):
633 if hasattr(request, 'vcs_call'):
636 # skip vcs calls
634 # skip vcs calls
637 return
635 return
638
636
639 repo_name = info['match']['repo_name']
637 repo_name = info['match']['repo_name']
640
638
641 repo_name_parts = repo_name.split('/')
639 repo_name_parts = repo_name.split('/')
642 repo_slugs = [x for x in map(lambda x: repo_name_slug(x), repo_name_parts)]
640 repo_slugs = [x for x in (repo_name_slug(x) for x in repo_name_parts)]
643
641
644 if repo_name_parts != repo_slugs:
642 if repo_name_parts != repo_slugs:
645 # short-skip if the repo-name doesn't follow slug rule
643 # short-skip if the repo-name doesn't follow slug rule
646 log.warning('repo_name: %s is different than slug %s', repo_name_parts, repo_slugs)
644 log.warning('repo_name: %s is different than slug %s', repo_name_parts, repo_slugs)
647 return False
645 return False
648
646
649 repo_model = repo.RepoModel()
647 repo_model = repo.RepoModel()
650
648
651 by_name_match = repo_model.get_by_repo_name(repo_name, cache=False)
649 by_name_match = repo_model.get_by_repo_name(repo_name, cache=False)
652
650
653 def redirect_if_creating(route_info, db_repo):
651 def redirect_if_creating(route_info, db_repo):
654 skip_views = ['edit_repo_advanced_delete']
652 skip_views = ['edit_repo_advanced_delete']
655 route = route_info['route']
653 route = route_info['route']
656 # we should skip delete view so we can actually "remove" repositories
654 # we should skip delete view so we can actually "remove" repositories
657 # if they get stuck in creating state.
655 # if they get stuck in creating state.
658 if route.name in skip_views:
656 if route.name in skip_views:
659 return
657 return
660
658
661 if db_repo.repo_state in [repo.Repository.STATE_PENDING]:
659 if db_repo.repo_state in [repo.Repository.STATE_PENDING]:
662 repo_creating_url = request.route_path(
660 repo_creating_url = request.route_path(
663 'repo_creating', repo_name=db_repo.repo_name)
661 'repo_creating', repo_name=db_repo.repo_name)
664 raise HTTPFound(repo_creating_url)
662 raise HTTPFound(repo_creating_url)
665
663
666 if by_name_match:
664 if by_name_match:
667 # register this as request object we can re-use later
665 # register this as request object we can re-use later
668 request.db_repo = by_name_match
666 request.db_repo = by_name_match
667 request.db_repo_name = request.db_repo.repo_name
668
669 redirect_if_creating(info, by_name_match)
669 redirect_if_creating(info, by_name_match)
670 return True
670 return True
671
671
672 by_id_match = repo_model.get_repo_by_id(repo_name)
672 by_id_match = repo_model.get_repo_by_id(repo_name)
673 if by_id_match:
673 if by_id_match:
674 request.db_repo = by_id_match
674 request.db_repo = by_id_match
675 request.db_repo_name = request.db_repo.repo_name
675 redirect_if_creating(info, by_id_match)
676 redirect_if_creating(info, by_id_match)
676 return True
677 return True
677
678
678 return False
679 return False
679
680
680
681
681 class RepoForbidArchivedRoutePredicate(object):
682 class RepoForbidArchivedRoutePredicate(object):
682 def __init__(self, val, config):
683 def __init__(self, val, config):
683 self.val = val
684 self.val = val
684
685
685 def text(self):
686 def text(self):
686 return 'repo_forbid_archived = %s' % self.val
687 return f'repo_forbid_archived = {self.val}'
687
688
688 phash = text
689 phash = text
689
690
690 def __call__(self, info, request):
691 def __call__(self, info, request):
691 _ = request.translate
692 _ = request.translate
692 rhodecode_db_repo = request.db_repo
693 rhodecode_db_repo = request.db_repo
693
694
694 log.debug(
695 log.debug(
695 '%s checking if archived flag for repo for %s',
696 '%s checking if archived flag for repo for %s',
696 self.__class__.__name__, rhodecode_db_repo.repo_name)
697 self.__class__.__name__, rhodecode_db_repo.repo_name)
697
698
698 if rhodecode_db_repo.archived:
699 if rhodecode_db_repo.archived:
699 log.warning('Current view is not supported for archived repo:%s',
700 log.warning('Current view is not supported for archived repo:%s',
700 rhodecode_db_repo.repo_name)
701 rhodecode_db_repo.repo_name)
701
702
702 h.flash(
703 h.flash(
703 h.literal(_('Action not supported for archived repository.')),
704 h.literal(_('Action not supported for archived repository.')),
704 category='warning')
705 category='warning')
705 summary_url = request.route_path(
706 summary_url = request.route_path(
706 'repo_summary', repo_name=rhodecode_db_repo.repo_name)
707 'repo_summary', repo_name=rhodecode_db_repo.repo_name)
707 raise HTTPFound(summary_url)
708 raise HTTPFound(summary_url)
708 return True
709 return True
709
710
710
711
711 class RepoTypeRoutePredicate(object):
712 class RepoTypeRoutePredicate(object):
712 def __init__(self, val, config):
713 def __init__(self, val, config):
713 self.val = val or ['hg', 'git', 'svn']
714 self.val = val or ['hg', 'git', 'svn']
714
715
715 def text(self):
716 def text(self):
716 return 'repo_accepted_type = %s' % self.val
717 return f'repo_accepted_type = {self.val}'
717
718
718 phash = text
719 phash = text
719
720
720 def __call__(self, info, request):
721 def __call__(self, info, request):
721 if hasattr(request, 'vcs_call'):
722 if hasattr(request, 'vcs_call'):
722 # skip vcs calls
723 # skip vcs calls
723 return
724 return
724
725
725 rhodecode_db_repo = request.db_repo
726 rhodecode_db_repo = request.db_repo
726
727
727 log.debug(
728 log.debug(
728 '%s checking repo type for %s in %s',
729 '%s checking repo type for %s in %s',
729 self.__class__.__name__, rhodecode_db_repo.repo_type, self.val)
730 self.__class__.__name__, rhodecode_db_repo.repo_type, self.val)
730
731
731 if rhodecode_db_repo.repo_type in self.val:
732 if rhodecode_db_repo.repo_type in self.val:
732 return True
733 return True
733 else:
734 else:
734 log.warning('Current view is not supported for repo type:%s',
735 log.warning('Current view is not supported for repo type:%s',
735 rhodecode_db_repo.repo_type)
736 rhodecode_db_repo.repo_type)
736 return False
737 return False
737
738
738
739
739 class RepoGroupRoutePredicate(object):
740 class RepoGroupRoutePredicate(object):
740 def __init__(self, val, config):
741 def __init__(self, val, config):
741 self.val = val
742 self.val = val
742
743
743 def text(self):
744 def text(self):
744 return 'repo_group_route = %s' % self.val
745 return f'repo_group_route = {self.val}'
745
746
746 phash = text
747 phash = text
747
748
748 def __call__(self, info, request):
749 def __call__(self, info, request):
749 if hasattr(request, 'vcs_call'):
750 if hasattr(request, 'vcs_call'):
750 # skip vcs calls
751 # skip vcs calls
751 return
752 return
752
753
753 repo_group_name = info['match']['repo_group_name']
754 repo_group_name = info['match']['repo_group_name']
754
755
755 repo_group_name_parts = repo_group_name.split('/')
756 repo_group_name_parts = repo_group_name.split('/')
756 repo_group_slugs = [x for x in map(lambda x: repo_name_slug(x), repo_group_name_parts)]
757 repo_group_slugs = [x for x in [repo_name_slug(x) for x in repo_group_name_parts]]
757 if repo_group_name_parts != repo_group_slugs:
758 if repo_group_name_parts != repo_group_slugs:
758 # short-skip if the repo-name doesn't follow slug rule
759 # short-skip if the repo-name doesn't follow slug rule
759 log.warning('repo_group_name: %s is different than slug %s', repo_group_name_parts, repo_group_slugs)
760 log.warning('repo_group_name: %s is different than slug %s', repo_group_name_parts, repo_group_slugs)
760 return False
761 return False
761
762
762 repo_group_model = repo_group.RepoGroupModel()
763 repo_group_model = repo_group.RepoGroupModel()
763 by_name_match = repo_group_model.get_by_group_name(repo_group_name, cache=False)
764 by_name_match = repo_group_model.get_by_group_name(repo_group_name, cache=False)
764
765
765 if by_name_match:
766 if by_name_match:
766 # register this as request object we can re-use later
767 # register this as request object we can re-use later
767 request.db_repo_group = by_name_match
768 request.db_repo_group = by_name_match
769 request.db_repo_group_name = request.db_repo_group.group_name
768 return True
770 return True
769
771
770 return False
772 return False
771
773
772
774
773 class UserGroupRoutePredicate(object):
775 class UserGroupRoutePredicate(object):
774 def __init__(self, val, config):
776 def __init__(self, val, config):
775 self.val = val
777 self.val = val
776
778
777 def text(self):
779 def text(self):
778 return 'user_group_route = %s' % self.val
780 return f'user_group_route = {self.val}'
779
781
780 phash = text
782 phash = text
781
783
782 def __call__(self, info, request):
784 def __call__(self, info, request):
783 if hasattr(request, 'vcs_call'):
785 if hasattr(request, 'vcs_call'):
784 # skip vcs calls
786 # skip vcs calls
785 return
787 return
786
788
787 user_group_id = info['match']['user_group_id']
789 user_group_id = info['match']['user_group_id']
788 user_group_model = user_group.UserGroup()
790 user_group_model = user_group.UserGroup()
789 by_id_match = user_group_model.get(user_group_id, cache=False)
791 by_id_match = user_group_model.get(user_group_id, cache=False)
790
792
791 if by_id_match:
793 if by_id_match:
792 # register this as request object we can re-use later
794 # register this as request object we can re-use later
793 request.db_user_group = by_id_match
795 request.db_user_group = by_id_match
794 return True
796 return True
795
797
796 return False
798 return False
797
799
798
800
799 class UserRoutePredicateBase(object):
801 class UserRoutePredicateBase(object):
800 supports_default = None
802 supports_default = None
801
803
802 def __init__(self, val, config):
804 def __init__(self, val, config):
803 self.val = val
805 self.val = val
804
806
805 def text(self):
807 def text(self):
806 raise NotImplementedError()
808 raise NotImplementedError()
807
809
808 def __call__(self, info, request):
810 def __call__(self, info, request):
809 if hasattr(request, 'vcs_call'):
811 if hasattr(request, 'vcs_call'):
810 # skip vcs calls
812 # skip vcs calls
811 return
813 return
812
814
813 user_id = info['match']['user_id']
815 user_id = info['match']['user_id']
814 user_model = user.User()
816 user_model = user.User()
815 by_id_match = user_model.get(user_id, cache=False)
817 by_id_match = user_model.get(user_id, cache=False)
816
818
817 if by_id_match:
819 if by_id_match:
818 # register this as request object we can re-use later
820 # register this as request object we can re-use later
819 request.db_user = by_id_match
821 request.db_user = by_id_match
820 request.db_user_supports_default = self.supports_default
822 request.db_user_supports_default = self.supports_default
821 return True
823 return True
822
824
823 return False
825 return False
824
826
825
827
826 class UserRoutePredicate(UserRoutePredicateBase):
828 class UserRoutePredicate(UserRoutePredicateBase):
827 supports_default = False
829 supports_default = False
828
830
829 def text(self):
831 def text(self):
830 return 'user_route = %s' % self.val
832 return f'user_route = {self.val}'
831
833
832 phash = text
834 phash = text
833
835
834
836
835 class UserRouteWithDefaultPredicate(UserRoutePredicateBase):
837 class UserRouteWithDefaultPredicate(UserRoutePredicateBase):
836 supports_default = True
838 supports_default = True
837
839
838 def text(self):
840 def text(self):
839 return 'user_with_default_route = %s' % self.val
841 return f'user_with_default_route = {self.val}'
840
842
841 phash = text
843 phash = text
842
844
843
845
844 def includeme(config):
846 def includeme(config):
845 config.add_route_predicate(
847 config.add_route_predicate(
846 'repo_route', RepoRoutePredicate)
848 'repo_route', RepoRoutePredicate)
847 config.add_route_predicate(
849 config.add_route_predicate(
848 'repo_accepted_types', RepoTypeRoutePredicate)
850 'repo_accepted_types', RepoTypeRoutePredicate)
849 config.add_route_predicate(
851 config.add_route_predicate(
850 'repo_forbid_when_archived', RepoForbidArchivedRoutePredicate)
852 'repo_forbid_when_archived', RepoForbidArchivedRoutePredicate)
851 config.add_route_predicate(
853 config.add_route_predicate(
852 'repo_group_route', RepoGroupRoutePredicate)
854 'repo_group_route', RepoGroupRoutePredicate)
853 config.add_route_predicate(
855 config.add_route_predicate(
854 'user_group_route', UserGroupRoutePredicate)
856 'user_group_route', UserGroupRoutePredicate)
855 config.add_route_predicate(
857 config.add_route_predicate(
856 'user_route_with_default', UserRouteWithDefaultPredicate)
858 'user_route_with_default', UserRouteWithDefaultPredicate)
857 config.add_route_predicate(
859 config.add_route_predicate(
858 'user_route', UserRoutePredicate)
860 'user_route', UserRoutePredicate)
General Comments 0
You need to be logged in to leave comments. Login now