##// END OF EJS Templates
repo-view: handle empty repo or missing requirements in base view for repositories.
marcink -
r1714:01c11e23 default
parent child Browse files
Show More
@@ -1,189 +1,203 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2017 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 from pylons import tmpl_context as c
23 from pylons import tmpl_context as c
24 from pyramid.httpexceptions import HTTPFound
24 from pyramid.httpexceptions import HTTPFound
25
25
26 from rhodecode.lib import helpers as h
26 from rhodecode.lib import helpers as h
27 from rhodecode.lib.utils2 import StrictAttributeDict, safe_int
27 from rhodecode.lib.utils2 import StrictAttributeDict, safe_int
28 from rhodecode.lib.vcs.exceptions import RepositoryRequirementError
28 from rhodecode.model import repo
29 from rhodecode.model import repo
29 from rhodecode.model.db import User
30 from rhodecode.model.db import User
30 from rhodecode.model.scm import ScmModel
31 from rhodecode.model.scm import ScmModel
31
32
32 log = logging.getLogger(__name__)
33 log = logging.getLogger(__name__)
33
34
34
35
35 ADMIN_PREFIX = '/_admin'
36 ADMIN_PREFIX = '/_admin'
36 STATIC_FILE_PREFIX = '/_static'
37 STATIC_FILE_PREFIX = '/_static'
37
38
38
39
39 class TemplateArgs(StrictAttributeDict):
40 class TemplateArgs(StrictAttributeDict):
40 pass
41 pass
41
42
42
43
43 class BaseAppView(object):
44 class BaseAppView(object):
44
45
45 def __init__(self, context, request):
46 def __init__(self, context, request):
46 self.request = request
47 self.request = request
47 self.context = context
48 self.context = context
48 self.session = request.session
49 self.session = request.session
49 self._rhodecode_user = request.user # auth user
50 self._rhodecode_user = request.user # auth user
50 self._rhodecode_db_user = self._rhodecode_user.get_instance()
51 self._rhodecode_db_user = self._rhodecode_user.get_instance()
51 self._maybe_needs_password_change(
52 self._maybe_needs_password_change(
52 request.matched_route.name, self._rhodecode_db_user)
53 request.matched_route.name, self._rhodecode_db_user)
53
54
54 def _maybe_needs_password_change(self, view_name, user_obj):
55 def _maybe_needs_password_change(self, view_name, user_obj):
55 log.debug('Checking if user %s needs password change on view %s',
56 log.debug('Checking if user %s needs password change on view %s',
56 user_obj, view_name)
57 user_obj, view_name)
57 skip_user_views = [
58 skip_user_views = [
58 'logout', 'login',
59 'logout', 'login',
59 'my_account_password', 'my_account_password_update'
60 'my_account_password', 'my_account_password_update'
60 ]
61 ]
61
62
62 if not user_obj:
63 if not user_obj:
63 return
64 return
64
65
65 if user_obj.username == User.DEFAULT_USER:
66 if user_obj.username == User.DEFAULT_USER:
66 return
67 return
67
68
68 now = time.time()
69 now = time.time()
69 should_change = user_obj.user_data.get('force_password_change')
70 should_change = user_obj.user_data.get('force_password_change')
70 change_after = safe_int(should_change) or 0
71 change_after = safe_int(should_change) or 0
71 if should_change and now > change_after:
72 if should_change and now > change_after:
72 log.debug('User %s requires password change', user_obj)
73 log.debug('User %s requires password change', user_obj)
73 h.flash('You are required to change your password', 'warning',
74 h.flash('You are required to change your password', 'warning',
74 ignore_duplicate=True)
75 ignore_duplicate=True)
75
76
76 if view_name not in skip_user_views:
77 if view_name not in skip_user_views:
77 raise HTTPFound(
78 raise HTTPFound(
78 self.request.route_path('my_account_password'))
79 self.request.route_path('my_account_password'))
79
80
80 def _get_local_tmpl_context(self):
81 def _get_local_tmpl_context(self):
81 c = TemplateArgs()
82 c = TemplateArgs()
82 c.auth_user = self.request.user
83 c.auth_user = self.request.user
83 return c
84 return c
84
85
85 def _register_global_c(self, tmpl_args):
86 def _register_global_c(self, tmpl_args):
86 """
87 """
87 Registers attributes to pylons global `c`
88 Registers attributes to pylons global `c`
88 """
89 """
89 # TODO(marcink): remove once pyramid migration is finished
90 # TODO(marcink): remove once pyramid migration is finished
90 for k, v in tmpl_args.items():
91 for k, v in tmpl_args.items():
91 setattr(c, k, v)
92 setattr(c, k, v)
92
93
93 def _get_template_context(self, tmpl_args):
94 def _get_template_context(self, tmpl_args):
94 self._register_global_c(tmpl_args)
95 self._register_global_c(tmpl_args)
95
96
96 local_tmpl_args = {
97 local_tmpl_args = {
97 'defaults': {},
98 'defaults': {},
98 'errors': {},
99 'errors': {},
99 }
100 }
100 local_tmpl_args.update(tmpl_args)
101 local_tmpl_args.update(tmpl_args)
101 return local_tmpl_args
102 return local_tmpl_args
102
103
103 def load_default_context(self):
104 def load_default_context(self):
104 """
105 """
105 example:
106 example:
106
107
107 def load_default_context(self):
108 def load_default_context(self):
108 c = self._get_local_tmpl_context()
109 c = self._get_local_tmpl_context()
109 c.custom_var = 'foobar'
110 c.custom_var = 'foobar'
110 self._register_global_c(c)
111 self._register_global_c(c)
111 return c
112 return c
112 """
113 """
113 raise NotImplementedError('Needs implementation in view class')
114 raise NotImplementedError('Needs implementation in view class')
114
115
115
116
116 class RepoAppView(BaseAppView):
117 class RepoAppView(BaseAppView):
117
118
118 def __init__(self, context, request):
119 def __init__(self, context, request):
119 super(RepoAppView, self).__init__(context, request)
120 super(RepoAppView, self).__init__(context, request)
120 self.db_repo = request.db_repo
121 self.db_repo = request.db_repo
121 self.db_repo_name = self.db_repo.repo_name
122 self.db_repo_name = self.db_repo.repo_name
122 self.db_repo_pull_requests = ScmModel().get_pull_requests(self.db_repo)
123 self.db_repo_pull_requests = ScmModel().get_pull_requests(self.db_repo)
123
124
125 def _handle_missing_requirements(self, error):
126 log.error(
127 'Requirements are missing for repository %s: %s',
128 self.db_repo_name, error.message)
129
124 def _get_local_tmpl_context(self):
130 def _get_local_tmpl_context(self):
125 c = super(RepoAppView, self)._get_local_tmpl_context()
131 c = super(RepoAppView, self)._get_local_tmpl_context()
126 # register common vars for this type of view
132 # register common vars for this type of view
127 c.rhodecode_db_repo = self.db_repo
133 c.rhodecode_db_repo = self.db_repo
128 c.repo_name = self.db_repo_name
134 c.repo_name = self.db_repo_name
129 c.repository_pull_requests = self.db_repo_pull_requests
135 c.repository_pull_requests = self.db_repo_pull_requests
136
137 c.repository_requirements_missing = False
138 try:
139 self.rhodecode_vcs_repo = self.db_repo.scm_instance()
140 except RepositoryRequirementError as e:
141 c.repository_requirements_missing = True
142 self._handle_missing_requirements(e)
143
130 return c
144 return c
131
145
132
146
133 class DataGridAppView(object):
147 class DataGridAppView(object):
134 """
148 """
135 Common class to have re-usable grid rendering components
149 Common class to have re-usable grid rendering components
136 """
150 """
137
151
138 def _extract_ordering(self, request, column_map=None):
152 def _extract_ordering(self, request, column_map=None):
139 column_map = column_map or {}
153 column_map = column_map or {}
140 column_index = safe_int(request.GET.get('order[0][column]'))
154 column_index = safe_int(request.GET.get('order[0][column]'))
141 order_dir = request.GET.get(
155 order_dir = request.GET.get(
142 'order[0][dir]', 'desc')
156 'order[0][dir]', 'desc')
143 order_by = request.GET.get(
157 order_by = request.GET.get(
144 'columns[%s][data][sort]' % column_index, 'name_raw')
158 'columns[%s][data][sort]' % column_index, 'name_raw')
145
159
146 # translate datatable to DB columns
160 # translate datatable to DB columns
147 order_by = column_map.get(order_by) or order_by
161 order_by = column_map.get(order_by) or order_by
148
162
149 search_q = request.GET.get('search[value]')
163 search_q = request.GET.get('search[value]')
150 return search_q, order_by, order_dir
164 return search_q, order_by, order_dir
151
165
152 def _extract_chunk(self, request):
166 def _extract_chunk(self, request):
153 start = safe_int(request.GET.get('start'), 0)
167 start = safe_int(request.GET.get('start'), 0)
154 length = safe_int(request.GET.get('length'), 25)
168 length = safe_int(request.GET.get('length'), 25)
155 draw = safe_int(request.GET.get('draw'))
169 draw = safe_int(request.GET.get('draw'))
156 return draw, start, length
170 return draw, start, length
157
171
158
172
159 class RepoRoutePredicate(object):
173 class RepoRoutePredicate(object):
160 def __init__(self, val, config):
174 def __init__(self, val, config):
161 self.val = val
175 self.val = val
162
176
163 def text(self):
177 def text(self):
164 return 'repo_route = %s' % self.val
178 return 'repo_route = %s' % self.val
165
179
166 phash = text
180 phash = text
167
181
168 def __call__(self, info, request):
182 def __call__(self, info, request):
169 repo_name = info['match']['repo_name']
183 repo_name = info['match']['repo_name']
170 repo_model = repo.RepoModel()
184 repo_model = repo.RepoModel()
171 by_name_match = repo_model.get_by_repo_name(repo_name, cache=True)
185 by_name_match = repo_model.get_by_repo_name(repo_name, cache=True)
172 # if we match quickly from database, short circuit the operation,
186 # if we match quickly from database, short circuit the operation,
173 # and validate repo based on the type.
187 # and validate repo based on the type.
174 if by_name_match:
188 if by_name_match:
175 # register this as request object we can re-use later
189 # register this as request object we can re-use later
176 request.db_repo = by_name_match
190 request.db_repo = by_name_match
177 return True
191 return True
178
192
179 by_id_match = repo_model.get_repo_by_id(repo_name)
193 by_id_match = repo_model.get_repo_by_id(repo_name)
180 if by_id_match:
194 if by_id_match:
181 request.db_repo = by_id_match
195 request.db_repo = by_id_match
182 return True
196 return True
183
197
184 return False
198 return False
185
199
186
200
187 def includeme(config):
201 def includeme(config):
188 config.add_route_predicate(
202 config.add_route_predicate(
189 'repo_route', RepoRoutePredicate)
203 'repo_route', RepoRoutePredicate)
General Comments 0
You need to be logged in to leave comments. Login now