Handle user events Redis not working in tutorial
Also does some basic restyling Fixes #1586
This commit is contained in:
parent
073b643aab
commit
310ecd11cc
6 changed files with 169 additions and 162 deletions
|
@ -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):
|
||||
|
|
|
@ -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")
|
||||
|
|
147
static/css/directives/ui/angular-tour-ui.css
Normal file
147
static/css/directives/ui/angular-tour-ui.css
Normal 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;
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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() {
|
||||
|
|
Reference in a new issue