Skip to content

Commit

Permalink
Merge d626a9a into 2a4e108
Browse files Browse the repository at this point in the history
  • Loading branch information
squirrelo committed Jun 20, 2014
2 parents 2a4e108 + d626a9a commit 8159321
Show file tree
Hide file tree
Showing 10 changed files with 199 additions and 67 deletions.
5 changes: 1 addition & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,8 @@ install:
- pip install .
script:
- qiita_env make_test_env
- nosetests --with-doctest
- nosetests --with-doctest --with-coverage --cover-package=coveralls
- pep8 qiita_db qiita_core qiita_pet setup.py
# we need to run the test suite from setup.py for coveralls to grab the info
- coverage run setup.py test
- coverage report -m
services:
- redis-server
after_success:
Expand Down
70 changes: 70 additions & 0 deletions qiita_pet/handlers/analysis_handlers.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
r"""
Qitta analysis handlers for the Tornado webserver.
"""
# -----------------------------------------------------------------------------
# Copyright (c) 2014--, The Qiita Development Team.
#
# Distributed under the terms of the BSD 3-clause License.
#
# The full license is in the file LICENSE, distributed with this software.
# -----------------------------------------------------------------------------
from __future__ import division

from tornado.web import authenticated
from collections import defaultdict

Expand All @@ -7,6 +20,7 @@
from qiita_db.study import Study
from qiita_db.data import ProcessedData
from qiita_db.metadata_template import SampleTemplate
from qiita_db.job import Job
# login code modified from https://gist.github.com/guillaumevincent/4771570


Expand Down Expand Up @@ -78,3 +92,59 @@ def post(self):
samples = [(processed_data[data_type], sid) for sid in
sample_ids]
analysis.add_samples(samples)


class AnalysisWaitHandler(BaseHandler):
@authenticated
def get(self, analysis_id):
analysis = Analysis(analysis_id)
commands = []
for job in analysis.jobs:
jobject = Job(job)
commands.append("%s:%s" % (jobject.datatype, jobject.command[0]))

self.render("analysis_waiting.html", user=self.get_current_user(),
aid=analysis_id, aname=analysis.name,
commands=commands)

@authenticated
def post(self, analysis_id):
command_args = self.get_arguments("commands")
split = [x.split("#") for x in command_args]
analysis = Analysis(analysis_id)

commands = []
for data_type, command in split:
Job.create(data_type, command, {}, analysis)
commands.append("%s:%s" % (data_type, command))

self.render("analysis_waiting.html", user=self.get_current_user(),
aid=analysis_id, aname=analysis.name,
commands=commands)
# fire off analysis run here


class AnalysisResultsHandler(BaseHandler):
@authenticated
def get(self, aid):
analysis = Analysis(aid)
jobres = defaultdict(list)
for job in analysis.jobs:
jobject = Job(job)
jobres[jobject.datatype].append((jobject.command[0],
jobject.results))

self.render("analysis_results.html", user=self.get_current_user(),
jobres=jobres, aname=analysis.name)


class ShowAnalysesHandler(BaseHandler):
"""Shows the user's analyses"""
def get(self):
user_id = self.get_current_user()
user = User(user_id)

analyses = [Analysis(a) for a in user.private_analyses]
analyses.extend([Analysis(a) for a in user.shared_analyses])

self.render("show_analyses.html", user=user_id, analyses=analyses)
40 changes: 13 additions & 27 deletions qiita_pet/handlers/websocket_handlers.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,22 @@
# adapted from
# https://github.com/leporo/tornado-redis/blob/master/demos/websockets
from time import sleep

from redis import Redis
from tornadoredis import Client
from tornado.websocket import WebSocketHandler
import tornado.gen
from tornado.gen import engine, Task
from json import loads

# all messages are in json format. They must have the following format:
# 'job': jobname
# 'analysis': analysis_id
# 'msg': message to print
# 'analysis': what analysis this is from in format datatype:analysis
# 'results': list of files created if any
# 'command': what command this is from in format datatype#command


class MessageHandler(WebSocketHandler):
def __init__(self, *args, **kwargs):
super(MessageHandler, self).__init__(*args, **kwargs)
self.r_server = Redis()
self.redis = Client()
self.redis.connect()
# self.redis = Client()
# self.redis.connect()

def get_current_user(self):
user = self.get_secure_cookie("user")
Expand All @@ -32,33 +29,22 @@ def on_message(self, msg):
msginfo = loads(msg)
# listens for handshake from page
if "user:" in msginfo['msg']:
self.channel = msginfo['msg'].split(':')[1]
self.aid = msginfo['msg'].split()[0]
self.channel = msginfo['msg'].split()[1].split(':')[1]
# need to split the rest off to new func so it can be asynchronous
self.listen()

# decorator turns the function into an asynchronous generator object
@tornado.gen.engine
@engine
def listen(self):
# runs task given, with the yield required to get returned value
# equivalent of callback/wait pairing from tornado.gen
yield tornado.gen.Task(self.redis.subscribe, self.channel)
if not self.redis.subscribed:
self.write_message('ERROR IN SUBSCRIPTION')
# listen from tornadoredis makes the listen object asynchronous
# if using standard redis lib, it blocks while listening
self.redis.listen(self.callback)
# fight race condition by loading from redis after listen started
# need to use std redis lib because tornadoredis is in subscribed state
oldmessages = self.r_server.lrange(self.channel + ':messages', 0, -1)
if oldmessages is not None:
for message in oldmessages:
self.write_message(message)
sleep(5)
self.write_message({"analysis": self.aid, "msg": "allcomplete"})

def callback(self, msg):
if msg.kind == 'message':
self.write_message(str(msg.body))

@tornado.gen.engine
@engine
def on_close(self):
yield tornado.gen.Task(self.redis.unsubscribe, self.channel)
yield Task(self.redis.unsubscribe, self.channel)
self.redis.disconnect()
1 change: 1 addition & 0 deletions qiita_pet/static/css/style.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#template-content{
padding: 20px;
height: 100%;
}

40 changes: 40 additions & 0 deletions qiita_pet/templates/analysis_results.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{% extends sitebase.html%}

{%block head%}


{%end%}

{%block content%}
<div class="container">
<div class="row">
<h1>Analysis {{aname}}</h1>
</div>
<div class="row">
<div class="col-md-2">
<div class="panel-group" id="accordion">
{% for data_type, jobs in jobres.items() %}
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title"><a data-toggle="collapse" data-parent="#accordion" href="#{{data_type}}">{{data_type}}</a></h3>
</div>
<div id="{{data_type}}" class="panel-collapse collapse">
{% for job, results in jobs%}
<div class="panel-body">
{{job}}<br />
{%for result in results%}
<a href="/results/{{result}}" target="resframe">{{result}}</a><br />
{% end %}
</div>
{% end %}
</div>
</div>
{% end %}
</div>
</div>
<div class="col-md-10">
<iframe id="resframe" name="resframe" width="100%" height="900" frameBorder=0></iframe>
</div>
</div>
</div>
{%end%}
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@
noerror = true;

websocket.onopen = function() {
websocket.send(JSON.stringify({'msg': 'user:{{user}}'}));
console.log(JSON.stringify({'msg': 'user:{{user}}'}));
websocket.send(JSON.stringify({'msg': '{{aid}} user:{{user}}'}));
console.log(JSON.stringify({'msg':'{{aid}} user:{{user}}'}));
};
websocket.onmessage = function(evt) {
console.log(evt.data);
message = JSON.parse(evt.data);
if(message.job == '{{job}}') {
if(message.analysis == '{{aid}}') {
if(noerror && message.msg == 'allcomplete') {
window.location.replace("/completed/{{job}}");
window.location.replace("/analysis/results/{{aid}}");
}
list = document.getElementById(message.analysis);
if(message.msg.indexOf("ERROR") != -1) {
Expand All @@ -30,11 +30,7 @@
else {
list.style.color="Blue";
}
list.innerHTML = message.msg + '<br />';
for(var i=0; i<message.results.length; i++) {
list.innerHTML += '<a class="link" target="_blank" href="../' +
message.results[i] + '">Plot ' + (i+1) + '</a><br />';
}
list.innerHTML = message.msg;
}
};
websocket.onerror = function(evt) { };
Expand All @@ -52,24 +48,12 @@
{% end %}

{% block content %}
<table width='100%'>
<tr>
<td width=180 valign='top'>
1) Choose studies<br />
2) Select analyses<br />
3) Set analysis options<br />
4) Review analysis<br />
<b>5) Running analysis</b><br />
6) Analysis results<br />
</td>
<td>
<h1>Analysis {{job}}</h1>
{% for analysis in analyses %}
<h1>Analysis {{aname}}</h1>
{% for command in commands%}
<p>
{{analysis}}: <span id='{{analysis}}'>Queued</span>
{{command}}: <span id='{{command}}'>Queued</span>
</p>
{% end %}
</td></tr></table>
<div id='error'></div>

{% end %}
3 changes: 1 addition & 2 deletions qiita_pet/templates/select_commands.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ <h1>Select Commands</h1>
{% end %}
</ul>

<form role="form" action="/analysis/wait/" method="post">
<input type="hidden" name="analysis-id" value="{{aid}}">
<form role="form" action="/analysis/wait/{{aid}}" method="post">
<div class="tab-content" style="height:300px">
{% for data_type in data_types %}
<div class="tab-pane" id="{{ data_type }}">
Expand Down
41 changes: 41 additions & 0 deletions qiita_pet/templates/show_analyses.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{% extends sitebase.html %}
{%block content %}
<table class="table">
<tr>
<th>
Analysis Name
</th><th>
Analysis Description
</th><th>
Status
</th>
</tr>
{% for analysis in analyses %}
{% set status = analysis.status%}
{% if status == "running" %}
<tr class="active">
<td>
<a href="/analysis/waiting/{{analysis.id}}">{{analysis.name}}</a>
{% elif status == "completed" %}
<tr class="success">
<td>
<a href="/analysis/results/{{analysis.id}}">{{analysis.name}}</a>
{% elif status == "error" %}
<tr class="danger">
<td>
<a href="/analysis/results/{{analysis.id}}">{{analysis.name}}</a>
{% else %}
<tr class="active">
<td>
{{analysis.name}}
{% end %}
</td>
<td>
{{analysis.description}}
</td>
<td>
{{status}}
</td>
</tr>
{% end %}
{% end %}
23 changes: 15 additions & 8 deletions qiita_pet/templates/sitebase.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,20 @@

{% block head %}{% end %}
</head>
<body style="padding-top: 65px;">
<body style="padding-top: 65px; height: 100%">
<!-- try/except to check if we have a loginerror variable -->
{% try %}
<!-- if we have a loginerror variable make sure it's not empty -->
{% if loginerror != '' %}
<div class="alert alert-danger alert-dismissable">
<a href="#" class="close" data-dismiss="alert">&times;</a>
<p align="center">
<strong>There's a problem with your credentials: </strong>{{loginerror}}
</p>
</div>
{% end %}
{% except %}
{% end %}
<div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
<div class="container">
<div class="navbar-header">
Expand All @@ -40,8 +53,7 @@
<a href="/analysis/1" data-toggle="dropdown" class="dropdown-toggle">Meta Analysis<b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a data-toggle="modal" data-target="#create-analysis-modal-view">Create Meta Analysis</a></li>
<li><a href="#">See Running Analyses</a></li>
<li><a href="#">See Old Analyses</a>
<li><a href="/analysis/show/">See Previous Analyses</a></li>
</ul>
</li>
{% end %}
Expand All @@ -65,11 +77,6 @@
</ul>
<!-- otherwise show the login form -->
{% else %}
{% try %}
<span style="color: red;">{{loginerror}}</span>
{% except %}
</span>
{% end %}
<form class="navbar-form navbar-right" role="form" action="/auth/login/" method="post">
<div class="form-group">
<input type="text" id="username" name="username" placeholder="Email" class="form-control">
Expand Down
Loading

0 comments on commit 8159321

Please sign in to comment.