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__) logger = logging.getLogger(__name__)
class CannotReadUserEventsException(Exception):
""" Exception raised if user events cannot be read. """
class UserEventBuilder(object): class UserEventBuilder(object):
""" """
Defines a helper class for constructing UserEvent and UserEventListener Defines a helper class for constructing UserEvent and UserEventListener
@ -87,9 +90,13 @@ class UserEventListener(object):
def __init__(self, redis_config, username, events=set([])): def __init__(self, redis_config, username, events=set([])):
channels = [self._user_event_key(username, e) for e in events] channels = [self._user_event_key(username, e) for e in events]
self._redis = redis.StrictRedis(socket_connect_timeout=5, **redis_config) try:
self._pubsub = self._redis.pubsub() self._redis = redis.StrictRedis(socket_connect_timeout=5, **redis_config)
self._pubsub.subscribe(channels) 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 @staticmethod
def _user_event_key(username, event_id): 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 endpoints.common import route_show_if
from app import app, userevents from app import app, userevents
from auth.permissions import SuperUserPermission from auth.permissions import SuperUserPermission
from data.userevent import CannotReadUserEventsException
import features import features
import psutil import psutil
@ -107,5 +108,9 @@ def user_subscribe():
if not events: if not events:
abort(404) 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") 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; 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 { pre.command {
padding: 20px; padding: 20px;
background: #fff; background: #fff;

View file

@ -15,12 +15,12 @@
</div> </div>
<div class="controls" ng-show="(hasNextStep && !step.signal) || (!hasNextStep && !inline)"> <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> <button class="btn btn-primary" ng-click="stop()" ng-show="!hasNextStep && !inline">Done</button>
</div> </div>
<div class="wait-message" ng-show="step.waitMessage"> <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> <span class="skip-message" ng-show="step.skipTitle"><button class="btn btn-default" ng-click="next()">{{ step.skipTitle }}</button></span>
</div> </div>
</div> </div>

View file

@ -286,6 +286,10 @@ angular.module("angular-tour", [])
checker.$source.onmessage = function(e) { checker.$source.onmessage = function(e) {
checker.$message = JSON.parse(e.data); 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() { checker.$teardown = function() {