OLD | NEW |
1 # Copyright 2014 The Chromium Authors. All rights reserved. | 1 # Copyright 2014 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 import calendar | 5 import calendar |
6 from datetime import datetime | 6 from datetime import datetime |
| 7 import functools |
7 import hashlib | 8 import hashlib |
8 import json | 9 import json |
9 import logging | 10 import logging |
| 11 import os |
10 | 12 |
11 from google.appengine.api import memcache | 13 from google.appengine.api import memcache |
12 from google.appengine.api import users | 14 from google.appengine.api import users |
| 15 from google.appengine.api import app_identity |
13 | 16 |
14 from shared.config import VALID_EMAIL_RE | 17 from shared.config import HOST_ACLS |
15 | 18 |
16 compressed_separators = (',', ':') | 19 compressed_separators = (',', ':') |
17 minutes_per_day = 24 * 60 | |
18 | 20 |
19 def cronjob(cronjob_handler): | 21 def cronjob(cronjob_handler): |
20 def checked_cronjob_handler(self, *args): | 22 def checked_cronjob_handler(self, *args): |
21 assert (self.request.headers.get('X-AppEngine-Cron') or # pragma: no cover | 23 assert (self.request.headers.get('X-AppEngine-Cron') or # pragma: no cover |
22 users.is_current_user_admin()) | 24 users.is_current_user_admin()) |
23 cronjob_handler(self, *args) # pragma: no cover | 25 cronjob_handler(self, *args) # pragma: no cover |
24 return checked_cronjob_handler | 26 return checked_cronjob_handler |
25 | 27 |
26 def cross_origin_json(handler): | 28 def cross_origin_json(handler): |
| 29 @functools.wraps(handler) |
27 def headered_json_handler(self, *args): | 30 def headered_json_handler(self, *args): |
28 self.response.headers.add_header("Access-Control-Allow-Origin", "*") | 31 self.response.headers.add_header("Access-Control-Allow-Origin", "*") |
29 result = handler(self, *args) | 32 result = handler(self, *args) |
30 if result is not None: | 33 if result is not None: |
31 self.response.headers.add_header('Content-Type', 'application/json') | 34 self.response.headers.add_header('Content-Type', 'application/json') |
32 self.response.write(compressed_json_dumps(result)) | 35 self.response.write(compressed_json_dumps(result)) |
33 return headered_json_handler | 36 return headered_json_handler |
34 | 37 |
35 def filter_dict(d, keys): | 38 def filter_dict(d, keys): |
36 return {key: d[key] for key in d if key in keys} | 39 return {key: d[key] for key in d if key in keys} |
37 | 40 |
38 def is_valid_user(): | 41 |
| 42 def get_host_permissions(kind): |
| 43 """Returns compiled regex of allowed user email or True if everyone is |
| 44 allowed.""" |
| 45 assert kind in ('read', 'write') |
| 46 if os.environ.get('SERVER_SOFTWARE', '').startswith('Development'): |
| 47 host = 'Development' |
| 48 else: |
| 49 host = app_identity.get_default_version_hostname() |
| 50 return HOST_ACLS[host][kind] |
| 51 |
| 52 def has_permission(kind): |
39 if users.is_current_user_admin(): | 53 if users.is_current_user_admin(): |
| 54 logging.info('user is admin') |
| 55 return True |
| 56 email_pattern = get_host_permissions(kind) |
| 57 if email_pattern == 'everyone': |
40 return True | 58 return True |
41 user = users.get_current_user() | 59 user = users.get_current_user() |
42 return user and VALID_EMAIL_RE.match(user.email()) | 60 logging.info('user: %s %s', user, 'xx' if not user else user.email()) |
| 61 return user and bool(email_pattern.match(user.email())) |
| 62 |
| 63 |
| 64 def read_access(handler): |
| 65 """Decorator ensuring current user has read access to this host.""" |
| 66 @functools.wraps(handler) |
| 67 def ensure(self, *args, **kwargs): |
| 68 if not has_permission('read'): |
| 69 self.redirect(users.create_login_url(self.request.url)) |
| 70 return |
| 71 return handler(self, *args, **kwargs) |
| 72 return ensure |
| 73 |
| 74 |
| 75 def get_friendly_hostname(): |
| 76 host = app_identity.get_default_version_hostname() |
| 77 # For a typical host 'xyz-cq-status.appspot.com', return 'Xyz'. |
| 78 return host.split('-')[0].capitalize() if host else '(Development)' |
| 79 |
43 | 80 |
44 def memcachize(cache_check): | 81 def memcachize(cache_check): |
45 def decorator(f): | 82 def decorator(f): |
46 def memcachized(**kwargs): | 83 def memcachized(**kwargs): |
47 key = '%s.%s(%s)' % ( | 84 key = '%s.%s(%s)' % ( |
48 f.__module__, | 85 f.__module__, |
49 f.__name__, | 86 f.__name__, |
50 ', '.join('%s=%r' % i for i in sorted(kwargs.items())), | 87 ', '.join('%s=%r' % i for i in sorted(kwargs.items())), |
51 ) | 88 ) |
52 cache = memcache.get(key) | 89 cache = memcache.get(key) |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
103 | 140 |
104 | 141 |
105 def get_full_patchset_url(codereview_hostname, issue, patchset): | 142 def get_full_patchset_url(codereview_hostname, issue, patchset): |
106 if codereview_hostname.split('.')[0].split('-')[-1] == 'review': | 143 if codereview_hostname.split('.')[0].split('-')[-1] == 'review': |
107 # This is Gerrit, which has host-review.googlesource.com. | 144 # This is Gerrit, which has host-review.googlesource.com. |
108 templ = 'https://%s/#/c/%s/%s' | 145 templ = 'https://%s/#/c/%s/%s' |
109 else: | 146 else: |
110 # Rietveld. | 147 # Rietveld. |
111 templ = 'https://%s/%s/#ps%s' | 148 templ = 'https://%s/%s/#ps%s' |
112 return templ % (codereview_hostname, issue, patchset) | 149 return templ % (codereview_hostname, issue, patchset) |
OLD | NEW |