Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial qiita_pet commit #31

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions qiita_pet/analysis_handlers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#!/usr/bin/env python

__author__ = "Joshua Shorenstein"
__copyright__ = "Copyright 2013, The QiiTa-pet Project"
__credits__ = ["Joshua Shorenstein", "Antonio Gonzalez",
"Jose Antonio Navas Molina"]
__license__ = "BSD"
__version__ = "0.2.0-dev"
__maintainer__ = "Joshua Shorenstein"
__email__ = "[email protected]"
__status__ = "Development"

from tornado.web import authenticated, HTTPError

from .webserver import BaseHandler
from qiita_core.qiita_settings import DATATYPES, FUNCTIONS


class WaitingHandler(BaseHandler):
"""Waiting Page"""
@authenticated
def get(self, analysis):
pass

@authenticated
#This post function takes care of actual job submission
def post(self, page):
pass


class RunningHandler(BaseHandler):
"""Currently running jobs list handler"""
@authenticated
def get(self):
pass


class ShowAnalysisHandler(BaseHandler):
"""Completed analysis page"""
@authenticated
def get(self, analysis):
pass

@authenticated
def post(self, page):
pass


class DeleteAnalysisHandler(BaseHandler):
@authenticated
def post(self):
pass


#ANALYSES and COMBINED lists are set in settings.py
class QiitaAnalysisHandler(BaseHandler):
#@authenticated
def get(self, page):
if page != "1":
HTTPError("405", "Request page >1 of QiitaAnalysisHandler")
else:
#global variable that is wiped when you start a new analysis
self.render("meta1.html", user=self.get_current_user(), error="",
metadata=["meta1", "meta2", "meta3"], datatypes=DATATYPES)

@authenticated
def post(self, page):
if page == "1":
HTTPError("405", "Post to page 1 of QiitaAnalysisHandler")
elif page == "2":
raise NotImplementedError("MetaAnalysis Page %s missing!" % page)
else:
raise NotImplementedError("MetaAnalysis Page %s missing!" % page)
82 changes: 82 additions & 0 deletions qiita_pet/auth_handlers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#!/usr/bin/env python

__author__ = "Joshua Shorenstein"
__copyright__ = "Copyright 2013, The QiiTa-pet Project"
__credits__ = ["Joshua Shorenstein"]
__license__ = "BSD"
__version__ = "0.2.0-dev"
__maintainer__ = "Joshua Shorenstein"
__email__ = "[email protected]"
__status__ = "Development"

from hashlib import sha512

from tornado.escape import url_escape, json_encode

from .webserver import BaseHandler
from ..qiita_ware.api.user_manager import create_user, check_password
from ..qiita_core.exceptions import QiitaUserError


class AuthCreateHandler(BaseHandler):
'''User Creation'''
def get(self):
try:
error_message = self.get_argument("error")
# Tornado can raise an Exception directly, not a defined type
except Exception, e:
error_message = str(e)
self.render("create.html", user=self.get_current_user(),
errormessage=url_escape(error_message))

def post(self):
username = self.get_argument("username", "")
passwd = sha512(self.get_argument("password", "")).hexdigest()
try:
create_user(username, passwd)
except QiitaUserError, e:
error_msg = u"?error=" + url_escape(str(e))
self.redirect(u"/auth/create/" + error_msg)
return
self.redirect(u"/auth/login/?error=User+created")


class AuthLoginHandler(BaseHandler):
'''Login Page'''
def get(self):
try:
error_message = self.get_argument("error")
# Tornado can raise an Exception directly, not a defined type
except Exception:
error_message = ""

self.render("login.html", user=self.get_current_user(),
errormessage=error_message)

def post(self):
username = self.get_argument("username", "")
passwd = sha512(self.get_argument("password", "")).hexdigest()
auth = check_password(username, passwd)
if auth:
self.set_current_user(username)
self.redirect(self.get_argument("next", u"/"))
else:
error_msg = u"?error=%s" % url_escape("Login incorrect")
self.redirect(u"/auth/login/" + error_msg)

def set_current_user(self, user):
"""Sets current user or, if already set, clears current user
Input:
user: username to set
"""
if user:
self.set_secure_cookie("user", json_encode(user))
else:
self.clear_cookie("user")


class AuthLogoutHandler(BaseHandler):
'''Logout handler, no page necessary'''
def get(self):
self.clear_cookie("user")
self.redirect("/")
19 changes: 19 additions & 0 deletions qiita_pet/connections.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/usr/bin/env python

__author__ = "Joshua Shorenstein"
__copyright__ = "Copyright 2013, The QiiTa-pet Project"
__credits__ = ["Joshua Shorenstein", "Jose Antonio Navas Molina"]
__license__ = "BSD"
__version__ = "0.2.0-dev"
__maintainer__ = "Joshua Shorenstein"
__email__ = "[email protected]"
__status__ = "Development"

from redis import Redis
from redis.exceptions import RedisError

# Set up Redis connection
try:
r_server = Redis()
except RedisError, e:
raise RuntimeError("Unable to connect to the REDIS database: %s" % e)
176 changes: 176 additions & 0 deletions qiita_pet/push.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
#!/usr/bin/env python

__author__ = "Joshua Shorenstein"
__copyright__ = "Copyright 2013, The QiiTa-pet Project"
__credits__ = ["Joshua Shorenstein", "Jose Antonio Navas Molina"]
__license__ = "BSD"
__version__ = "0.2.0-dev"
__maintainer__ = "Joshua Shorenstein"
__email__ = "[email protected]"
__status__ = "Development"

# Adapted from
# https://github.com/leporo/tornado-redis/blob/master/demos/websockets
from json import loads, dumps

from tornadoredis import Client
from tornado.websocket import WebSocketHandler
from tornado.gen import engine, Task
from pyparsing import alphanums, Word, QuotedString, oneOf, Suppress

from ..qiita_core.search import QiitaSearchCriterion, QiitaSearch
from ..qiita_core.exceptions import IncompetentQiitaDeveloperError
from ..qiita_ware.api.analysis_manager import search_analyses
from ..qiita_ware.api.studies_manager import search_studies
from .connections import r_server

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


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

def get_current_user(self):
user = self.get_secure_cookie("user")
if user is None:
return ""
else:
return user.strip("\" '")

def on_message(self, msg):
msginfo = loads(msg)
#listens for handshake from page
if "user:" in msginfo["msg"]:
self.channel = msginfo["msg"].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
@engine
def listen(self):
#runs task given, with the yield required to get returned value
#equivalent of callback/wait pairing from tornado.gen
yield Task(self.redis.subscribe, self.channel)
if not self.redis.subscribed:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure about this but if not subscribed this shouldn't continue, right?

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)
# Try and fight race condition by loading from redis after listen
# started need to use std redis lib because tornadoredis is in
# subscribed state
oldmessages = r_server.lrange(self.channel + ":messages", 0, -1)
if oldmessages is not None:
for message in oldmessages:
self.write_message(message)

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

@engine
def on_close(self):
yield Task(self.redis.unsubscribe, self.channel)
self.redis.disconnect()


class SearchASHandler(WebSocketHandler):

def get_current_user(self):
user = self.get_secure_cookie("user")
if user is None:
return ""
else:
return user.strip("\" '")

def on_message(self, msg):
""" Parses sent search and sends back results

Parameters
----------
msg: json string
contains "query" key with query string and "type" key with return
type, e.g. study, analysis, etc.

Raises
------
IncompetentQiitaDeveloperError
If type is not recognised
"""
user = self.get_current_user()
msginfo = loads(msg)
query, searchstr = self.ParseSearchString(msginfo["query"])
if msginfo["type"] == "analysis":
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My worry about this is to add a new msginfo, you will need to make changes in different parts of the code. What about when defining the possible analysis (datatype:analysis) you can also add the function that will be used for searching and just doing a call to something like msginfo["type"]["search_func"]

res = search_analyses(user, query)
elif msginfo["type"] == "study":
res = search_studies(user, query)
else:
raise IncompetentQiitaDeveloperError("Unrecognised type: %s" %
msginfo["type"])
result = []
for item in res:
result.append((item.name, item.id))
result = dumps({
"results": result,
"query": searchstr
})
self.write_message(result)

def ParseSearchString(string):
""" Parses query and returns string of what query ended up as and
QiitaSearch object of query

Parameters
----------
string: str
query string to parse

Results
--------
search: QiitaSearch object
searchstr: str
New search string with unparsed sections removed
"""
search_string = string.lower()
#define sybols to be used
word = Word(alphanums)
quote_word = QuotedString("\"")
query_type = oneOf("includes startswith endswith < > =")
field_type = oneOf("metadata author year")
col = Suppress(":")
#define chunk of grammar
query_search = field_type + col + (word + query_type +
(word | quote_word) |
(word | quote_word))
search = QiitaSearch()
searchstr = ""
first = 0
for match, start, end in query_search.scanString(search_string):
operator = None
if first > 0:
operator = search_string[first:start-1].split(" ")[-1]
searchstr = " ".join([searchstr, operator])
if len(match) < 4:
#pad out to have full information needed
#add field we are looking at, which equals field_type
#implicit includes, so add it into the match
searchstr = " ".join([searchstr, " ".join(match)])
criterion = QiitaSearchCriterion(match[0], "includes",
match[1])
else:
criterion = QiitaSearchCriterion(match[0], match[1], match[2])
searchstr = " ".join([searchstr, " ".join(match)])
search.add_criterion(criterion)
first = end+1
return search, searchstr

def callback(self, msg):
if msg.kind == "message":
self.write_message(str(msg.body))
31 changes: 31 additions & 0 deletions qiita_pet/render_handlers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#!/usr/bin/env python

__author__ = "Joshua Shorenstein"
__copyright__ = "Copyright 2013, The QiiTa-pet Project"
__credits__ = ["Joshua Shorenstein"]
__license__ = "BSD"
__version__ = "0.2.0-dev"
__maintainer__ = "Joshua Shorenstein"
__email__ = "[email protected]"
__status__ = "Development"

from tornado.web import authenticated

from .webserver import BaseHandler


class MultivisHandler(BaseHandler):
def get(self):
self.render("multivis.html", user=self.get_current_user(), error="")


class MockupHandler(BaseHandler):
def get(self):
self.render("mockup.html", user=self.get_current_user(), error="")


class MinStudyHandler(BaseHandler):
@authenticated
def get(self, study):
self.render("minstudy.html", user=self.get_current_user(), error="",
study=study)
Binary file added qiita_pet/static/.DS_Store
Binary file not shown.
Loading