Handle user events Redis not working in tutorial

Also does some basic restyling

Fixes #1586
This commit is contained in:
Joseph Schorr 2016-06-28 15:35:21 -04:00
parent 073b643aab
commit 310ecd11cc
6 changed files with 169 additions and 162 deletions

View file

@ -5,6 +5,9 @@ import logging
logger = logging.getLogger(__name__)
class CannotReadUserEventsException(Exception):
""" Exception raised if user events cannot be read. """
class UserEventBuilder(object):
"""
Defines a helper class for constructing UserEvent and UserEventListener
@ -87,9 +90,13 @@ class UserEventListener(object):
def __init__(self, redis_config, username, events=set([])):
channels = [self._user_event_key(username, e) for e in events]
self._redis = redis.StrictRedis(socket_connect_timeout=5, **redis_config)
self._pubsub = self._redis.pubsub()
self._pubsub.subscribe(channels)
try:
self._redis = redis.StrictRedis(socket_connect_timeout=5, **redis_config)
self._pubsub = self._redis.pubsub()
self._pubsub.subscribe(channels)
except redis.RedisError as re:
logger.exception('Could not reach user events redis: %s', re)
raise CannotReadUserEventsException
@staticmethod
def _user_event_key(username, event_id):

View file

@ -7,6 +7,7 @@ from auth.auth import require_session_login
from endpoints.common import route_show_if
from app import app, userevents
from auth.permissions import SuperUserPermission
from data.userevent import CannotReadUserEventsException
import features
import psutil
@ -107,5 +108,9 @@ def user_subscribe():
if not events:
abort(404)
listener = userevents.get_listener(current_user.db_user().username, events)
try:
listener = userevents.get_listener(current_user.db_user().username, events)
except CannotReadUserEventsException:
abort(504)
return Response(wrapper(listener), mimetype="text/event-stream")

View file

@ -0,0 +1,147 @@
.angular-tour-ui-element.overlay {
display: block;
position: fixed;
bottom: 50px;
right: 20px;
z-index: 9999999;
background: white;
-webkit-box-shadow: 0 5px 15px rgba(0,0,0,0.5);
box-shadow: 0 5px 15px rgba(0,0,0,0.5);
opacity: 0;
transition: opacity 750ms ease-in-out;
-webkit-transition: opacity 750ms ease-in-out;
min-width: 400px;
}
.angular-tour-ui-element.overlay.touring {
opacity: 1;
}
.angular-tour-ui-element.overlay.nottouring {
pointer-events: none;
position: absolute;
left: -10000px;
width: 0px;
height: 0px;
}
.angular-tour-ui-element.overlay .tour-title {
background-color: #3276b1;
color: white;
padding: 4px;
padding-left: 6px;
padding-right: 6px;
border-radius: 4px;
border-bottom-left-radius: 0px;
border-bottom-right-radius: 0px;
}
.angular-tour-ui-element.overlay .tour-title h4 {
display: inline-block;
font-size: 16px;
margin: 0px;
padding: 2px;
}
.angular-tour-ui-element.overlay .step-title {
font-size: 20px;
}
.angular-tour-ui-element.overlay .step-content {
padding: 10px;
padding-left: 0px;
font-size: 16px;
}
.angular-tour-ui-element.overlay .tour-contents {
padding: 10px;
}
.angular-tour-ui-element.overlay .controls {
text-align: right;
}
.angular-tour-ui-element.overlay .controls .btn {
font-size: 16px;
}
.angular-tour-ui-element.overlay .fa {
display: none;
}
.angular-tour-ui-element.inline .fa-dot-circle-o {
font-size: 34px;
background: #ddd;
border-radius: 50%;
width: 40px;
height: 40px;
text-align: center;
padding-top: 4px;
vertical-align: middle;
margin-right: 10px;
}
.angular-tour-ui-element.inline .tour-title h4 {
font-size: 28px;
padding-bottom: 10px;
margin-bottom: 20px;
border-bottom: 1px solid #eee;
}
.angular-tour-ui-element.inline .tour-title .close {
display: none;
}
.angular-tour-ui-element.inline .step-title {
font-size: 20px;
border-bottom: 1px solid #eee;
padding-bottom: 16px;
margin-bottom: 20px;
}
.angular-tour-ui-element.inline .step-content {
margin-bottom: 10px;
}
.angular-tour-ui-element.inline .controls {
margin-top: 20px;
border-top: 1px solid #eee;
padding-top: 20px;
}
.angular-tour-ui-element p {
margin-bottom: 20px;
}
.angular-tour-ui-element .wait-message {
font-size: 16px;
color: #999;
}
.angular-tour-ui-element .wait-message .quay-spinner {
display: inline-block;
vertical-align: middle;
margin-right: 6px;
}
.angular-tour-ui-element .wait-message .quay-spinner .small-spinner {
border-top-color: #999;
border-left-color: #999;
}
.angular-tour-ui-element .note {
margin: 10px;
padding: 6px;
background: #eee;
border: 1px solid #ddd;
}
.angular-tour-ui-element .skip-message {
display: inline-block;
margin-left: 20px;
}

View file

@ -3019,162 +3019,6 @@ p.editable:hover i {
margin-top: 60px;
}
/*********************************************/
.angular-tour-ui-element.overlay {
display: block;
position: fixed;
bottom: 50px;
right: 20px;
border-radius: 10px;
z-index: 9999999;
background: white;
-webkit-box-shadow: 0 5px 15px rgba(0,0,0,0.5);
box-shadow: 0 5px 15px rgba(0,0,0,0.5);
opacity: 0;
transition: opacity 750ms ease-in-out;
-webkit-transition: opacity 750ms ease-in-out;
min-width: 400px;
}
.angular-tour-ui-element.overlay.touring {
opacity: 1;
}
.angular-tour-ui-element.overlay.nottouring {
pointer-events: none;
position: absolute;
left: -10000px;
width: 0px;
height: 0px;
}
.angular-tour-ui-element.overlay .tour-title {
background-color: #3276b1;
color: white;
padding: 4px;
padding-left: 6px;
padding-right: 6px;
border-radius: 4px;
border-bottom-left-radius: 0px;
border-bottom-right-radius: 0px;
}
.angular-tour-ui-element.overlay .tour-title h4 {
display: inline-block;
font-size: 16px;
margin: 0px;
padding: 2px;
}
.angular-tour-ui-element.overlay .step-title {
font-size: 20px;
}
.angular-tour-ui-element.overlay .step-content {
padding: 10px;
padding-left: 0px;
font-size: 16px;
}
.angular-tour-ui-element.overlay .tour-contents {
padding: 10px;
}
.angular-tour-ui-element.overlay .controls {
text-align: right;
}
.angular-tour-ui-element.overlay .controls .btn {
font-size: 16px;
}
.angular-tour-ui-element.overlay .fa {
display: none;
}
/**************************************************/
.angular-tour-ui-element.inline {
}
.angular-tour-ui-element.inline .fa-dot-circle-o {
font-size: 34px;
background: #ddd;
border-radius: 50%;
width: 40px;
height: 40px;
text-align: center;
padding-top: 4px;
vertical-align: middle;
margin-right: 10px;
}
.angular-tour-ui-element.inline .tour-title h4 {
font-size: 28px;
padding-bottom: 10px;
margin-bottom: 20px;
border-bottom: 1px solid #eee;
}
.angular-tour-ui-element.inline .tour-title .close {
display: none;
}
.angular-tour-ui-element.inline .step-title {
font-size: 20px;
margin-bottom: 20px;
}
.angular-tour-ui-element.inline .step-content {
margin-bottom: 10px;
}
.angular-tour-ui-element.inline .controls {
margin-top: 20px;
border-top: 1px solid #eee;
padding-top: 10px;
}
.angular-tour-ui-element p {
margin-bottom: 20px;
}
.angular-tour-ui-element .wait-message {
font-size: 16px;
color: #999;
}
.angular-tour-ui-element .wait-message .quay-spinner {
display: inline-block;
vertical-align: middle;
margin-right: 6px;
}
.angular-tour-ui-element .wait-message .quay-spinner .small-spinner {
border-top-color: #999;
border-left-color: #999;
}
.angular-tour-ui-element .note {
margin: 10px;
padding: 6px;
background: #eee;
border: 1px solid #ddd;
}
.angular-tour-ui-element .skip-message {
display: inline-block;
margin-left: 20px;
}
pre.command {
padding: 20px;
background: #fff;

View file

@ -15,12 +15,12 @@
</div>
<div class="controls" ng-show="(hasNextStep && !step.signal) || (!hasNextStep && !inline)">
<button class="btn btn-primary" ng-click="next()" ng-show="hasNextStep && !step.signal">Next</button>
<button class="btn btn-primary" ng-click="next()" ng-show="hasNextStep && !step.signal">Continue Tutorial</button>
<button class="btn btn-primary" ng-click="stop()" ng-show="!hasNextStep && !inline">Done</button>
</div>
<div class="wait-message" ng-show="step.waitMessage">
<div class="quay-spinner"></div> {{ step.waitMessage }}
<div class="cor-loader-inline"></div> {{ step.waitMessage }}
<span class="skip-message" ng-show="step.skipTitle"><button class="btn btn-default" ng-click="next()">{{ step.skipTitle }}</button></span>
</div>
</div>

View file

@ -286,6 +286,10 @@ angular.module("angular-tour", [])
checker.$source.onmessage = function(e) {
checker.$message = JSON.parse(e.data);
};
checker.$source.onerror = function(e) {
bootbox.alert('Could not read user events from server due to a Redis issue. ' +
' Please contact support.')
};
};
checker.$teardown = function() {