##// 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 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 import time
22 22 import logging
23 23 from pylons import tmpl_context as c
24 24 from pyramid.httpexceptions import HTTPFound
25 25
26 26 from rhodecode.lib import helpers as h
27 27 from rhodecode.lib.utils2 import StrictAttributeDict, safe_int
28 from rhodecode.lib.vcs.exceptions import RepositoryRequirementError
28 29 from rhodecode.model import repo
29 30 from rhodecode.model.db import User
30 31 from rhodecode.model.scm import ScmModel
31 32
32 33 log = logging.getLogger(__name__)
33 34
34 35
35 36 ADMIN_PREFIX = '/_admin'
36 37 STATIC_FILE_PREFIX = '/_static'
37 38
38 39
39 40 class TemplateArgs(StrictAttributeDict):
40 41 pass
41 42
42 43
43 44 class BaseAppView(object):
44 45
45 46 def __init__(self, context, request):
46 47 self.request = request
47 48 self.context = context
48 49 self.session = request.session
49 50 self._rhodecode_user = request.user # auth user
50 51 self._rhodecode_db_user = self._rhodecode_user.get_instance()
51 52 self._maybe_needs_password_change(
52 53 request.matched_route.name, self._rhodecode_db_user)
53 54
54 55 def _maybe_needs_password_change(self, view_name, user_obj):
55 56 log.debug('Checking if user %s needs password change on view %s',
56 57 user_obj, view_name)
57 58 skip_user_views = [
58 59 'logout', 'login',
59 60 'my_account_password', 'my_account_password_update'
60 61 ]
61 62
62 63 if not user_obj:
63 64 return
64 65
65 66 if user_obj.username == User.DEFAULT_USER:
66 67 return
67 68
68 69 now = time.time()
69 70 should_change = user_obj.user_data.get('force_password_change')
70 71 change_after = safe_int(should_change) or 0
71 72 if should_change and now > change_after:
72 73 log.debug('User %s requires password change', user_obj)
73 74 h.flash('You are required to change your password', 'warning',
74 75 ignore_duplicate=True)
75 76
76 77 if view_name not in skip_user_views:
77 78 raise HTTPFound(
78 79 self.request.route_path('my_account_password'))
79 80
80 81 def _get_local_tmpl_context(self):
81 82 c = TemplateArgs()
82 83 c.auth_user = self.request.user
83 84 return c
84 85
85 86 def _register_global_c(self, tmpl_args):
86 87 """
87 88 Registers attributes to pylons global `c`
88 89 """
89 90 # TODO(marcink): remove once pyramid migration is finished
90 91 for k, v in tmpl_args.items():
91 92 setattr(c, k, v)
92 93
93 94 def _get_template_context(self, tmpl_args):
94 95 self._register_global_c(tmpl_args)
95 96
96 97 local_tmpl_args = {
97 98 'defaults': {},
98 99 'errors': {},
99 100 }
100 101 local_tmpl_args.update(tmpl_args)
101 102 return local_tmpl_args
102 103
103 104 def load_default_context(self):
104 105 """
105 106 example:
106 107
107 108 def load_default_context(self):
108 109 c = self._get_local_tmpl_context()
109 110 c.custom_var = 'foobar'
110 111 self._register_global_c(c)
111 112 return c
112 113 """
113 114 raise NotImplementedError('Needs implementation in view class')
114 115
115 116
116 117 class RepoAppView(BaseAppView):
117 118
118 119 def __init__(self, context, request):
119 120 super(RepoAppView, self).__init__(context, request)
120 121 self.db_repo = request.db_repo
121 122 self.db_repo_name = self.db_repo.repo_name
122 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 130 def _get_local_tmpl_context(self):
125 131 c = super(RepoAppView, self)._get_local_tmpl_context()
126 132 # register common vars for this type of view
127 133 c.rhodecode_db_repo = self.db_repo
128 134 c.repo_name = self.db_repo_name
129 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 144 return c
131 145
132 146
133 147 class DataGridAppView(object):
134 148 """
135 149 Common class to have re-usable grid rendering components
136 150 """
137 151
138 152 def _extract_ordering(self, request, column_map=None):
139 153 column_map = column_map or {}
140 154 column_index = safe_int(request.GET.get('order[0][column]'))
141 155 order_dir = request.GET.get(
142 156 'order[0][dir]', 'desc')
143 157 order_by = request.GET.get(
144 158 'columns[%s][data][sort]' % column_index, 'name_raw')
145 159
146 160 # translate datatable to DB columns
147 161 order_by = column_map.get(order_by) or order_by
148 162
149 163 search_q = request.GET.get('search[value]')
150 164 return search_q, order_by, order_dir
151 165
152 166 def _extract_chunk(self, request):
153 167 start = safe_int(request.GET.get('start'), 0)
154 168 length = safe_int(request.GET.get('length'), 25)
155 169 draw = safe_int(request.GET.get('draw'))
156 170 return draw, start, length
157 171
158 172
159 173 class RepoRoutePredicate(object):
160 174 def __init__(self, val, config):
161 175 self.val = val
162 176
163 177 def text(self):
164 178 return 'repo_route = %s' % self.val
165 179
166 180 phash = text
167 181
168 182 def __call__(self, info, request):
169 183 repo_name = info['match']['repo_name']
170 184 repo_model = repo.RepoModel()
171 185 by_name_match = repo_model.get_by_repo_name(repo_name, cache=True)
172 186 # if we match quickly from database, short circuit the operation,
173 187 # and validate repo based on the type.
174 188 if by_name_match:
175 189 # register this as request object we can re-use later
176 190 request.db_repo = by_name_match
177 191 return True
178 192
179 193 by_id_match = repo_model.get_repo_by_id(repo_name)
180 194 if by_id_match:
181 195 request.db_repo = by_id_match
182 196 return True
183 197
184 198 return False
185 199
186 200
187 201 def includeme(config):
188 202 config.add_route_predicate(
189 203 'repo_route', RepoRoutePredicate)
General Comments 0
You need to be logged in to leave comments. Login now