Implement site banner. Set banner for Google Sign-In. (#1304)

* Implement site banner.  Set banner for Google Sign-In.

* Addressed review comments
This commit is contained in:
Jason Robbins 2021-05-04 11:33:29 -07:00 коммит произвёл GitHub
Родитель 27312f6f08
Коммит ca1d31b0ea
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
7 изменённых файлов: 124 добавлений и 8 удалений

Просмотреть файл

@ -32,6 +32,7 @@ import settings
from framework import permissions
from framework import ramcache
from framework import secrets
from framework import utils
from framework import xsrf
from internals import models
@ -277,7 +278,9 @@ class FlaskHandler(BaseHandler):
'APP_TITLE': settings.APP_TITLE,
'current_path': current_path,
'TEMPLATE_CACHE_TIME': settings.TEMPLATE_CACHE_TIME,
}
'banner_message': settings.BANNER_MESSAGE,
'banner_time': utils.get_banner_time(settings.BANNER_TIME),
}
user = self.get_current_user()
if user:

Просмотреть файл

@ -16,6 +16,7 @@
from __future__ import division
from __future__ import print_function
import calendar
import datetime
import flask
import logging
@ -121,3 +122,32 @@ def render_atom_feed(request, title, data):
'Content-Type': 'application/atom+xml;charset=utf-8'}
text = feed.writeString('utf-8')
return text, headers
_ZERO = datetime.timedelta(0)
class _UTCTimeZone(datetime.tzinfo):
"""UTC"""
def utcoffset(self, _dt):
return _ZERO
def tzname(self, _dt):
return "UTC"
def dst(self, _dt):
return _ZERO
_UTC = _UTCTimeZone()
def get_banner_time(timestamp):
"""Converts a timestamp into data so it can appear in the banner.
Args:
timestamp: timestamp expressed in the following format:
[year,month,day,hour,minute,second]
e.g. [2009,3,20,21,45,50] represents March 20 2009 9:45:50 PM
Returns:
EZT-ready data used to display the time inside the banner message.
"""
if timestamp is None:
return None
ts = datetime.datetime(*timestamp, tzinfo=_UTC)
return calendar.timegm(ts.timetuple())

Просмотреть файл

@ -107,3 +107,13 @@ class UtilsFunctionTests(unittest.TestCase):
handlerInstance.handlerMethod('/request/path/')
self.assertIsNone(handlerInstance.handler_called_with)
self.assertEqual('/request/path', handlerInstance.redirected_to)
def test_get_banner_time__None(self):
"""If no time specified, it returns None."""
self.assertIsNone(utils.get_banner_time(None))
def test_get_banner_time__tuple(self):
"""If a time tuple is specified, it returns a timestamp."""
time_tuple = (2019, 6, 13, 18, 30)
actual = utils.get_banner_time(time_tuple)
self.assertEqual(1560450600, actual)

Просмотреть файл

@ -27,6 +27,17 @@ SEND_ALL_EMAIL_TO = 'cr-status-staging-emails+%(user)s+%(domain)s@google.com'
BOUNCE_ESCALATION_ADDR = 'cr-status-bounces@google.com'
# Display a site maintenance banner on every page. Or, an empty string.
BANNER_MESSAGE = ('This site will have a new method of signing in. '
'Users will need to sign in again after ')
# Timestamp used to notify users when the read only mode or other status
# described in the banner message takes effect. Or, None. It is
# expressed as a tuple of ints: (year, month, day[, hour[, minute[, second]]])
# e.g. (2009, 3, 20, 21, 45) represents March 20 2009 9:45PM UTC.
BANNER_TIME = (2021, 3, 11, 20, 00) # May 11, noon pacific
################################################################################
PROD = False

Просмотреть файл

@ -14,6 +14,7 @@ import '@polymer/paper-styles/color.js';
// chromedash components
import './elements/icons';
import './elements/chromedash-accordion';
import './elements/chromedash-banner';
import './elements/chromedash-callout';
import './elements/chromedash-color-status';
import './elements/chromedash-feature';

Просмотреть файл

@ -0,0 +1,59 @@
import {LitElement, css, html} from 'lit-element';
import {nothing} from 'lit-html';
import SHARED_STYLES from '../css/shared.css';
class ChromedashBanner extends LitElement {
static get properties() {
return {
timestamp: {type: Number},
message: {type: String},
};
}
constructor() {
super();
this.timestamp = null; // Unix timestamp: seconds since 1970-01-01.
this.message = '';
}
static get styles() {
return [
SHARED_STYLES,
css`
div {
display: inline-block;
background: var(--warning-background);
color: var(--warning-color);
border-radius: var(--border-radius);
padding: var(--content-padding);
}
`];
}
computeLocalDateString() {
if (!this.timestamp) {
return nothing;
}
const date = new Date(this.timestamp * 1000);
const formatOptions = {
weekday: 'long', year: 'numeric', month: 'long', day: 'numeric',
hour: 'numeric', minute: 'numeric'}; // No seconds
return date.toLocaleString(undefined, formatOptions);
}
render() {
if (!this.message) {
return nothing;
}
return html`
<div>
${this.message}
${this.computeLocalDateString()}
</div>
`;
}
}
customElements.define('chromedash-banner', ChromedashBanner);

Просмотреть файл

@ -96,13 +96,15 @@ limitations under the License.
<div id="content">
<div id="spinner"><img src="/static/img/ring.svg"></div>
<div id="column-container">
<div id="drawer-column">{% block drawer %}{% endblock %}</div>
<div id="content-column">
<div id="horizontal-sub-nav">{% block horizontalsubnav %}{% endblock %}</div>
{% block subheader %}{% endblock %}
{% block content %}{% endblock %}
</div>
</div>
<div id="drawer-column">{% block drawer %}{% endblock %}</div>
<div id="content-column">
<div id="horizontal-sub-nav">{% block horizontalsubnav %}{% endblock %}</div>
<chromedash-banner message="{{banner_message}}"
timestamp="{{banner_time}}"></chromedash-banner>
{% block subheader %}{% endblock %}
{% block content %}{% endblock %}
</div>
</div>
</div>
</app-header-layout>