##// END OF EJS Templates
better path extraction method....
marcink -
r2490:7a5eeafb beta
parent child Browse files
Show More
@@ -1,228 +1,236 b''
1 1 """The base Controller API
2 2
3 3 Provides the BaseController class for subclassing.
4 4 """
5 5 import logging
6 6 import time
7 7 import traceback
8 8
9 9 from paste.auth.basic import AuthBasicAuthenticator
10 10 from paste.httpexceptions import HTTPUnauthorized, HTTPForbidden
11 11 from paste.httpheaders import WWW_AUTHENTICATE
12 12
13 13 from pylons import config, tmpl_context as c, request, session, url
14 14 from pylons.controllers import WSGIController
15 15 from pylons.controllers.util import redirect
16 16 from pylons.templating import render_mako as render
17 17
18 18 from rhodecode import __version__, BACKENDS
19 19
20 20 from rhodecode.lib.utils2 import str2bool, safe_unicode
21 21 from rhodecode.lib.auth import AuthUser, get_container_username, authfunc,\
22 22 HasPermissionAnyMiddleware, CookieStoreWrapper
23 23 from rhodecode.lib.utils import get_repo_slug, invalidate_cache
24 24 from rhodecode.model import meta
25 25
26 26 from rhodecode.model.db import Repository
27 27 from rhodecode.model.notification import NotificationModel
28 28 from rhodecode.model.scm import ScmModel
29 29
30 30 log = logging.getLogger(__name__)
31 31
32 32
33 33 def _get_ip_addr(environ):
34 34 proxy_key = 'HTTP_X_REAL_IP'
35 35 proxy_key2 = 'HTTP_X_FORWARDED_FOR'
36 36 def_key = 'REMOTE_ADDR'
37 37
38 38 ip = environ.get(proxy_key2)
39 39 if ip:
40 40 return ip
41 41
42 42 ip = environ.get(proxy_key)
43 43
44 44 if ip:
45 45 return ip
46 46
47 47 ip = environ.get(def_key, '0.0.0.0')
48 48 return ip
49 49
50 50
51 def _get_access_path(environ):
52 path = environ.get('PATH_INFO')
53 org_req = environ.get('pylons.original_request')
54 if org_req:
55 path = org_req.environ.get('PATH_INFO')
56 return path
57
58
51 59 class BasicAuth(AuthBasicAuthenticator):
52 60
53 61 def __init__(self, realm, authfunc, auth_http_code=None):
54 62 self.realm = realm
55 63 self.authfunc = authfunc
56 64 self._rc_auth_http_code = auth_http_code
57 65
58 66 def build_authentication(self):
59 67 head = WWW_AUTHENTICATE.tuples('Basic realm="%s"' % self.realm)
60 68 if self._rc_auth_http_code and self._rc_auth_http_code == '403':
61 69 # return 403 if alternative http return code is specified in
62 70 # RhodeCode config
63 71 return HTTPForbidden(headers=head)
64 72 return HTTPUnauthorized(headers=head)
65 73
66 74
67 75 class BaseVCSController(object):
68 76
69 77 def __init__(self, application, config):
70 78 self.application = application
71 79 self.config = config
72 80 # base path of repo locations
73 81 self.basepath = self.config['base_path']
74 82 #authenticate this mercurial request using authfunc
75 83 self.authenticate = BasicAuth('', authfunc,
76 84 config.get('auth_ret_code'))
77 85 self.ipaddr = '0.0.0.0'
78 86
79 87 def _handle_request(self, environ, start_response):
80 88 raise NotImplementedError()
81 89
82 90 def _get_by_id(self, repo_name):
83 91 """
84 92 Get's a special pattern _<ID> from clone url and tries to replace it
85 93 with a repository_name for support of _<ID> non changable urls
86 94
87 95 :param repo_name:
88 96 """
89 97 try:
90 98 data = repo_name.split('/')
91 99 if len(data) >= 2:
92 100 by_id = data[1].split('_')
93 101 if len(by_id) == 2 and by_id[1].isdigit():
94 102 _repo_name = Repository.get(by_id[1]).repo_name
95 103 data[1] = _repo_name
96 104 except:
97 105 log.debug('Failed to extract repo_name from id %s' % (
98 106 traceback.format_exc()
99 107 )
100 108 )
101 109
102 110 return '/'.join(data)
103 111
104 112 def _invalidate_cache(self, repo_name):
105 113 """
106 114 Set's cache for this repository for invalidation on next access
107 115
108 116 :param repo_name: full repo name, also a cache key
109 117 """
110 118 invalidate_cache('get_repo_cached_%s' % repo_name)
111 119
112 120 def _check_permission(self, action, user, repo_name):
113 121 """
114 122 Checks permissions using action (push/pull) user and repository
115 123 name
116 124
117 125 :param action: push or pull action
118 126 :param user: user instance
119 127 :param repo_name: repository name
120 128 """
121 129 if action == 'push':
122 130 if not HasPermissionAnyMiddleware('repository.write',
123 131 'repository.admin')(user,
124 132 repo_name):
125 133 return False
126 134
127 135 else:
128 136 #any other action need at least read permission
129 137 if not HasPermissionAnyMiddleware('repository.read',
130 138 'repository.write',
131 139 'repository.admin')(user,
132 140 repo_name):
133 141 return False
134 142
135 143 return True
136 144
137 145 def _get_ip_addr(self, environ):
138 146 return _get_ip_addr(environ)
139 147
140 148 def __call__(self, environ, start_response):
141 149 start = time.time()
142 150 try:
143 151 return self._handle_request(environ, start_response)
144 152 finally:
145 153 log = logging.getLogger('rhodecode.' + self.__class__.__name__)
146 154 log.debug('Request time: %.3fs' % (time.time() - start))
147 155 meta.Session.remove()
148 156
149 157
150 158 class BaseController(WSGIController):
151 159
152 160 def __before__(self):
153 161 c.rhodecode_version = __version__
154 162 c.rhodecode_instanceid = config.get('instance_id')
155 163 c.rhodecode_name = config.get('rhodecode_title')
156 164 c.use_gravatar = str2bool(config.get('use_gravatar'))
157 165 c.ga_code = config.get('rhodecode_ga_code')
158 166 c.repo_name = get_repo_slug(request)
159 167 c.backends = BACKENDS.keys()
160 168 c.unread_notifications = NotificationModel()\
161 169 .get_unread_cnt_for_user(c.rhodecode_user.user_id)
162 170 self.cut_off_limit = int(config.get('cut_off_limit'))
163 171
164 172 self.sa = meta.Session
165 173 self.scm_model = ScmModel(self.sa)
166 174 self.ip_addr = ''
167 175
168 176 def __call__(self, environ, start_response):
169 177 """Invoke the Controller"""
170 178 # WSGIController.__call__ dispatches to the Controller method
171 179 # the request is routed to. This routing information is
172 180 # available in environ['pylons.routes_dict']
173 181 start = time.time()
174 182 try:
175 183 self.ip_addr = _get_ip_addr(environ)
176 184 # make sure that we update permissions each time we call controller
177 185 api_key = request.GET.get('api_key')
178 186 cookie_store = CookieStoreWrapper(session.get('rhodecode_user'))
179 187 user_id = cookie_store.get('user_id', None)
180 188 username = get_container_username(environ, config)
181 189 auth_user = AuthUser(user_id, api_key, username)
182 190 request.user = auth_user
183 191 self.rhodecode_user = c.rhodecode_user = auth_user
184 192 if not self.rhodecode_user.is_authenticated and \
185 193 self.rhodecode_user.user_id is not None:
186 194 self.rhodecode_user.set_authenticated(
187 195 cookie_store.get('is_authenticated')
188 196 )
189 197 log.info('IP: %s User: %s accessed %s' % (
190 self.ip_addr, auth_user, safe_unicode(environ.get('PATH_INFO')))
198 self.ip_addr, auth_user, safe_unicode(_get_access_path(environ)))
191 199 )
192 200 return WSGIController.__call__(self, environ, start_response)
193 201 finally:
194 202 log.info('IP: %s Request to %s time: %.3fs' % (
195 203 _get_ip_addr(environ),
196 safe_unicode(environ.get('PATH_INFO')), time.time() - start)
204 safe_unicode(_get_access_path(environ)), time.time() - start)
197 205 )
198 206 meta.Session.remove()
199 207
200 208
201 209 class BaseRepoController(BaseController):
202 210 """
203 211 Base class for controllers responsible for loading all needed data for
204 212 repository loaded items are
205 213
206 214 c.rhodecode_repo: instance of scm repository
207 215 c.rhodecode_db_repo: instance of db
208 216 c.repository_followers: number of followers
209 217 c.repository_forks: number of forks
210 218 """
211 219
212 220 def __before__(self):
213 221 super(BaseRepoController, self).__before__()
214 222 if c.repo_name:
215 223
216 224 dbr = c.rhodecode_db_repo = Repository.get_by_repo_name(c.repo_name)
217 225 c.rhodecode_repo = c.rhodecode_db_repo.scm_instance
218 226
219 227 if c.rhodecode_repo is None:
220 228 log.error('%s this repository is present in database but it '
221 229 'cannot be created as an scm instance', c.repo_name)
222 230
223 231 redirect(url('home'))
224 232
225 233 # some globals counter for menu
226 234 c.repository_followers = self.scm_model.get_followers(dbr)
227 235 c.repository_forks = self.scm_model.get_forks(dbr)
228 236 c.repository_pull_requests = self.scm_model.get_pull_requests(dbr)
@@ -1,53 +1,55 b''
1 1 ## -*- coding: utf-8 -*-
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
2 <!DOCTYPE html>
3 3 <html xmlns="http://www.w3.org/1999/xhtml">
4 4 <head>
5 5 <title>Error - ${c.error_message}</title>
6 6 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
7 <meta name="robots" content="index, nofollow"/>
8 <link rel="icon" href="${h.url('/images/icons/database_gear.png')}" type="image/png" />
9
10 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
7 11 %if c.redirect_time:
8 12 <meta http-equiv="refresh" content="${c.redirect_time}; url=${c.url_redirect}"/>
9 13 %endif
10 <link rel="icon" href="${h.url("/images/hgicon.png")}" type="image/png" />
11 <meta name="robots" content="index, nofollow"/>
12 14
13 15 <!-- stylesheets -->
14 16 <link rel="stylesheet" type="text/css" href="${h.url('/css/style.css')}" media="screen" />
15 17 <style type="text/css">
16 18 #main_div{
17 19 border: 0px solid #000;
18 20 width: 500px;
19 21 margin: auto;
20 22 text-align: center;
21 23 margin-top: 200px;
22 24 font-size: 1.6em;
23 25 }
24 26 .error_message{
25 27 text-align: center;
26 28 color:#003367;
27 29 font-size: 1.6em;
28 30 margin:10px;
29 31 }
30 32 </style>
31 33
32 34 </head>
33 35 <body>
34 36
35 37 <div id="login">
36 38 <div class="table">
37 39 <div id="main_div">
38 40 <div style="font-size:2.0em;margin: 10px">${c.rhodecode_name}</div>
39 41 <h1 class="error_message">${c.error_message}</h1>
40 42
41 43 <p>${c.error_explanation}</p>
42 44
43 45 %if c.redirect_time:
44 46 <p>${_('You will be redirected to %s in %s seconds') % (c.redirect_module,c.redirect_time)}</p>
45 47 %endif
46 48
47 49 </div>
48 50 </div>
49 51 <!-- end login -->
50 52 </div>
51 53 </body>
52 54
53 55 </html>
General Comments 0
You need to be logged in to leave comments. Login now