Copybara | 854996b | 2021-09-07 19:36:02 +0000 | [diff] [blame] | 1 | # Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 | # Use of this source code is governed by a BSD-style |
| 3 | # license that can be found in the LICENSE file or at |
| 4 | # https://developers.google.com/open-source/licenses/bsd |
| 5 | |
| 6 | """Helper functions used by the Monorail servlet base class.""" |
| 7 | from __future__ import print_function |
| 8 | from __future__ import division |
| 9 | from __future__ import absolute_import |
| 10 | |
| 11 | import calendar |
| 12 | import datetime |
| 13 | import logging |
| 14 | import urllib |
| 15 | |
| 16 | from framework import framework_bizobj |
| 17 | from framework import framework_helpers |
| 18 | from framework import permissions |
| 19 | from framework import template_helpers |
| 20 | from framework import urls |
| 21 | from framework import xsrf |
| 22 | |
| 23 | _ZERO = datetime.timedelta(0) |
| 24 | |
| 25 | class _UTCTimeZone(datetime.tzinfo): |
| 26 | """UTC""" |
| 27 | def utcoffset(self, _dt): |
| 28 | return _ZERO |
| 29 | def tzname(self, _dt): |
| 30 | return "UTC" |
| 31 | def dst(self, _dt): |
| 32 | return _ZERO |
| 33 | |
| 34 | _UTC = _UTCTimeZone() |
| 35 | |
| 36 | |
| 37 | def GetBannerTime(timestamp): |
| 38 | """Converts a timestamp into EZT-ready data so it can appear in the banner. |
| 39 | |
| 40 | Args: |
| 41 | timestamp: timestamp expressed in the following format: |
| 42 | [year,month,day,hour,minute,second] |
| 43 | e.g. [2009,3,20,21,45,50] represents March 20 2009 9:45:50 PM |
| 44 | |
| 45 | Returns: |
| 46 | EZT-ready data used to display the time inside the banner message. |
| 47 | """ |
| 48 | if timestamp is None: |
| 49 | return None |
| 50 | |
| 51 | ts = datetime.datetime(*timestamp, tzinfo=_UTC) |
| 52 | return calendar.timegm(ts.timetuple()) |
| 53 | |
| 54 | |
| 55 | def AssertBasePermissionForUser(user, user_view): |
| 56 | """Verify user permissions and state. |
| 57 | |
| 58 | Args: |
| 59 | user: user_pb2.User protocol buffer for the user |
| 60 | user_view: framework.views.UserView for the user |
| 61 | """ |
| 62 | if permissions.IsBanned(user, user_view): |
| 63 | raise permissions.BannedUserException( |
| 64 | 'You have been banned from using this site') |
| 65 | |
| 66 | |
| 67 | def AssertBasePermission(mr): |
| 68 | """Make sure that the logged in user can view the requested page. |
| 69 | |
| 70 | Args: |
| 71 | mr: common information parsed from the HTTP request. |
| 72 | |
| 73 | Returns: |
| 74 | Nothing |
| 75 | |
| 76 | Raises: |
| 77 | BannedUserException: If the user is banned. |
| 78 | PermissionException: If the user does not have permisssion to view. |
| 79 | """ |
| 80 | AssertBasePermissionForUser(mr.auth.user_pb, mr.auth.user_view) |
| 81 | |
| 82 | if mr.project_name and not CheckPerm(mr, permissions.VIEW): |
| 83 | logging.info('your perms are %r', mr.perms) |
| 84 | raise permissions.PermissionException( |
| 85 | 'User is not allowed to view this project') |
| 86 | |
| 87 | |
| 88 | def CheckPerm(mr, perm, art=None, granted_perms=None): |
| 89 | """Convenience method that makes permission checks easier. |
| 90 | |
| 91 | Args: |
| 92 | mr: common information parsed from the HTTP request. |
| 93 | perm: A permission constant, defined in module framework.permissions |
| 94 | art: Optional artifact pb |
| 95 | granted_perms: optional set of perms granted specifically in that artifact. |
| 96 | |
| 97 | Returns: |
| 98 | A boolean, whether the request can be satisfied, given the permission. |
| 99 | """ |
| 100 | return mr.perms.CanUsePerm( |
| 101 | perm, mr.auth.effective_ids, mr.project, |
| 102 | permissions.GetRestrictions(art), granted_perms=granted_perms) |
| 103 | |
| 104 | |
| 105 | def CheckPermForProject(mr, perm, project, art=None): |
| 106 | """Convenience method that makes permission checks for projects easier. |
| 107 | |
| 108 | Args: |
| 109 | mr: common information parsed from the HTTP request. |
| 110 | perm: A permission constant, defined in module framework.permissions |
| 111 | project: The project to enforce permissions for. |
| 112 | art: Optional artifact pb |
| 113 | |
| 114 | Returns: |
| 115 | A boolean, whether the request can be satisfied, given the permission. |
| 116 | """ |
| 117 | perms = permissions.GetPermissions( |
| 118 | mr.auth.user_pb, mr.auth.effective_ids, project) |
| 119 | return perms.CanUsePerm( |
| 120 | perm, mr.auth.effective_ids, project, permissions.GetRestrictions(art)) |
| 121 | |
| 122 | |
| 123 | def ComputeIssueEntryURL(mr, config): |
| 124 | """Compute the URL to use for the "New issue" subtab. |
| 125 | |
| 126 | Args: |
| 127 | mr: commonly used info parsed from the request. |
| 128 | config: ProjectIssueConfig for the current project. |
| 129 | |
| 130 | Returns: |
| 131 | A URL string to use. It will be simply "entry" in the non-customized |
| 132 | case. Otherewise it will be a fully qualified URL that includes some |
| 133 | query string parameters. |
| 134 | """ |
| 135 | if not config.custom_issue_entry_url: |
| 136 | return '/p/%s/issues/entry' % (mr.project_name) |
| 137 | |
| 138 | base_url = config.custom_issue_entry_url |
| 139 | sep = '&' if '?' in base_url else '?' |
| 140 | token = xsrf.GenerateToken( |
| 141 | mr.auth.user_id, '/p/%s%s%s' % (mr.project_name, urls.ISSUE_ENTRY, '.do')) |
| 142 | role_name = framework_helpers.GetRoleName(mr.auth.effective_ids, mr.project) |
| 143 | |
| 144 | continue_url = urllib.quote(framework_helpers.FormatAbsoluteURL( |
| 145 | mr, urls.ISSUE_ENTRY + '.do')) |
| 146 | |
| 147 | return '%s%stoken=%s&role=%s&continue=%s' % ( |
| 148 | base_url, sep, urllib.quote(token), |
| 149 | urllib.quote(role_name or ''), continue_url) |
| 150 | |
| 151 | |
| 152 | def IssueListURL(mr, config, query_string=None): |
| 153 | """Make an issue list URL for non-members or members.""" |
| 154 | url = '/p/%s%s' % (mr.project_name, urls.ISSUE_LIST) |
| 155 | if query_string: |
| 156 | url += '?' + query_string |
| 157 | elif framework_bizobj.UserIsInProject(mr.project, mr.auth.effective_ids): |
| 158 | if config and config.member_default_query: |
| 159 | url += '?q=' + urllib.quote_plus(config.member_default_query) |
| 160 | return url |