Skip to content
This repository has been archived by the owner on Jul 29, 2020. It is now read-only.

Commit

Permalink
Merge 587c799 into 58b1e81
Browse files Browse the repository at this point in the history
  • Loading branch information
wasade committed Mar 17, 2019
2 parents 58b1e81 + 587c799 commit 1b87de7
Show file tree
Hide file tree
Showing 12 changed files with 362 additions and 7 deletions.
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ install:
- travis_retry conda create --yes -n labadmin python=2.7 pip
- source activate labadmin
- pip install -U pip
- pip install -U click natsort coverage coveralls
- pip install -U click natsort coverage coveralls futures
- pip install git+https://github.com/qiita-spots/qiita_client
- travis_retry pip install -U .[test]
script:
- git clone https://github.com/biocore/american-gut-web.git ~/build/biocore/american-gut-web
Expand All @@ -37,4 +38,3 @@ script:
- flake8 --ignore E722 knimin setup.py scripts
after_success:
- coveralls
- echo "foo"
8 changes: 8 additions & 0 deletions knimin/config.txt.example
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,11 @@ PASSKEY =
USER = test
PASSWORD = test
REGISTRATION = test

[qiita]
QIITA_HOST = test
QIITA_PORT = 21174
QIITA_CLIENT_ID = test
QIITA_CLIENT_SECRET = test
QIITA_CERT = test
QIITA_STUDY_ID = 1
86 changes: 86 additions & 0 deletions knimin/handlers/barcode_util.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,42 @@
#!/usr/bin/env python
from tornado.web import authenticated
from tornado.escape import json_encode
from tornado import gen, concurrent
from knimin.handlers.base import BaseHandler
from datetime import datetime
import requests
import functools
from qiita_client import QiitaClient

from knimin import db
from knimin.lib.constants import survey_type
from knimin.lib.mail import send_email
from knimin.handlers.access_decorators import set_access
from knimin.lib.configuration import config


def get_qiita_client():
if config.debug:
class _mock:
def get(self, *args, **kwargs):
return {'categories': ['a', 'b', 'c']}

def http_patch(self, *args, **kwargs):
return 'okay'

qclient = _mock()
else:
# interface for making HTTP requests against Qiita
qclient = QiitaClient(':'.join([config.qiita_host, config.qiita_port]),
config.qiita_client_id,
config.qiita_client_secret,
config.qiita_certificate)

# we are monkeypatching to use qclient's internal machinery
# and to fix the broken HTTP patch
qclient.http_patch = functools.partial(qclient._request_retry,
requests.patch)
return qclient


class BarcodeUtilHelper(object):
Expand Down Expand Up @@ -172,8 +202,61 @@ def _build_email(self, login_user, barcode, email_type,
return subject, body_message


def align_with_qiita_categories(samples, categories):
# obviously should instead align to the actual sample metadata...
aligned = {}
for s in samples:
aligned[s] = {c: 'LabControl test' for c in categories}
return aligned


@set_access(['Scan Barcodes'])
class PushQiitaHandler(BaseHandler):
executor = concurrent.futures.ThreadPoolExecutor(5)
study_id = config.qiita_study_id
qclient = get_qiita_client()

@concurrent.run_on_executor
def _push_to_qiita(self, study_id, samples):
# TODO: add a mutex or block to ensure a single call process at a time
cats = self.qclient.get('/api/v1/study/%s/samples/info' % study_id)
cats = cats['categories']

samples = align_with_qiita_categories(samples, cats)
data = json_encode(samples)

return self.qclient.http_patch('/api/v1/study/%s/samples' % study_id,
data=data)

@authenticated
def get(self):
barcodes = db.get_unsent_barcodes_from_qiita_buffer()
status = db.get_send_qiita_buffer_status()
dat = {'status': status, "barcodes": barcodes}
self.write(json_encode(dat))
self.finish()

@authenticated
@gen.coroutine
def post(self):
barcodes = db.get_unsent_barcodes_from_qiita_buffer()
if not barcodes:
return

db.set_send_qiita_buffer_status("Pushing...")

try:
yield self._push_to_qiita(self.study_id, barcodes)
except: # noqa
db.set_send_qiita_buffer_status("Failed!")
else:
db.mark_barcodes_sent_to_qiita(barcodes)
db.set_send_qiita_buffer_status("Idle")


@set_access(['Scan Barcodes'])
class BarcodeUtilHandler(BaseHandler, BarcodeUtilHelper):

@authenticated
def get(self):
barcode = self.get_argument('barcode', None)
Expand Down Expand Up @@ -293,9 +376,12 @@ def post(self):

new_proj, parent_project = db.getBarcodeProjType(barcode)
if parent_project == 'American Gut':
db.push_barcode_to_qiita_buffer(barcode)

email_msg, ag_update_msg = self.update_ag_barcode(
barcode, login_user, login_email, email_type, sent_date,
send_mail, sample_date, sample_time, other_text)

self.render("barcode_util.html", div_and_msg=None,
barcode_projects=[],
parent_project=None,
Expand Down
9 changes: 9 additions & 0 deletions knimin/lib/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ def __init__(self, config_fp=None):
self._get_tornado(config)
self._get_email(config)
self._get_vioscreen(config)
self._get_qiita(config)

def _get_main(self, config):
"""Get the configuration of the main section"""
Expand Down Expand Up @@ -100,5 +101,13 @@ def _get_vioscreen(self, config):
config.get('vioscreen',
'registration'))

def _get_qiita(self, config):
self.qiita_host = config.get('qiita', 'QIITA_HOST')
self.qiita_port = config.get('qiita', 'QIITA_PORT')
self.qiita_client_id = config.get('qiita', 'QIITA_CLIENT_ID')
self.qiita_client_secret = config.get('qiita', 'QIITA_CLIENT_SECRET')
self.qiita_certificate = config.get('qiita', 'QIITA_CERT')
self.qiita_study_id = config.get('qiita', 'QIITA_STUDY_ID')


config = KniminConfig()
54 changes: 54 additions & 0 deletions knimin/lib/data_access.py
Original file line number Diff line number Diff line change
Expand Up @@ -1402,6 +1402,60 @@ def getAGKitDetails(self, supplied_kit_id):
else:
return {}

def push_barcode_to_qiita_buffer(self, barcode):
"""Adds barcode to the qiita buffer
Parameters
----------
barcode : str
The identifier to stage
"""
sql = """SELECT barcode
FROM project_qiita_buffer"""
present = {i[0] for i in self._con.execute_fetchall(sql)}

if barcode in present:
return "Barcode in queue or already sent to Qiita"

else:
sql = """INSERT INTO project_qiita_buffer (barcode)
VALUES (%s)"""
self._con.execute(sql, [barcode])
return "Barcode inserted"

def get_send_qiita_buffer_status(self):
"""Obtain the present status of the Qiita submission buffer"""
sql = """SELECT state FROM project_qiita_buffer_status"""
return self._con.execute_fetchone(sql)[0]

def set_send_qiita_buffer_status(self, state):
"""Obtain the present status of the Qiita submission buffer"""
sql = """UPDATE project_qiita_buffer_status
SET state = %s
WHERE id = 0"""
self._con.execute(sql, [state])

def get_unsent_barcodes_from_qiita_buffer(self):
"""Extract the barcodes that have not been sent to Qiita"""
sql = """SELECT barcode
FROM project_qiita_buffer
WHERE pushed_to_qiita='N'"""
return [i[0] for i in self._con.execute_fetchall(sql)]

def mark_barcodes_sent_to_qiita(self, barcodes):
"""Mark the provided barcodes as sent
Parameters
----------
barcodes : list of str
The identifiers to mark a successfully sent to qiita
"""
if barcodes:
sql = """UPDATE project_qiita_buffer
SET pushed_to_qiita = 'Y'
WHERE barcode IN %s"""
self._con.execute(sql, [tuple(barcodes)])

def add_barcodes_to_kit(self, ag_kit_id, num_barcodes=1):
"""Attaches barcodes to an existing american gut kit
Expand Down
9 changes: 9 additions & 0 deletions knimin/lib/tests/test_configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,15 @@ def test_get_tornado(self):
USER = test
PASSWORD = test
REGISTRATION = test
[qiita]
QIITA_HOST = test
QIITA_PORT = 21174
QIITA_CLIENT_ID = test
QIITA_CLIENT_SECRET = test
QIITA_CERT = test
QIITA_STUDY_ID = 1
"""


Expand Down
45 changes: 45 additions & 0 deletions knimin/lib/tests/test_data_access.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,51 @@ def tearDown(self):
db._clear_table('external_survey_answers', 'ag')
db._revert_ready(['000023299'])

def test_push_barcode_to_qiita_buffer(self):
db._con.execute('DELETE from barcodes.project_qiita_buffer')
db.set_send_qiita_buffer_status('Idle')
db.push_barcode_to_qiita_buffer('000004216')
db.push_barcode_to_qiita_buffer('000004215')
exp = ['000004216', '000004215']
obs = db.get_unsent_barcodes_from_qiita_buffer()
self.assertEqual(obs, exp)

def test_get_send_qiita_buffer_status(self):
db._con.execute('DELETE from barcodes.project_qiita_buffer')
db.set_send_qiita_buffer_status('Idle')
exp = 'Idle'
obs = db.get_send_qiita_buffer_status()
self.assertEqual(obs, exp)
db.set_send_qiita_buffer_status('foo')
exp = 'foo'
obs = db.get_send_qiita_buffer_status()
self.assertEqual(obs, exp)

def test_get_unsent_barcodes_from_qiita_buffer(self):
db._con.execute('DELETE from barcodes.project_qiita_buffer')
db.set_send_qiita_buffer_status('Idle')
db.push_barcode_to_qiita_buffer('000004216')
db.push_barcode_to_qiita_buffer('000004215')
db._con.execute("""UPDATE barcodes.project_qiita_buffer
SET pushed_to_qiita = 'Y'
WHERE barcode = '000004215'""")
obs = db.get_unsent_barcodes_from_qiita_buffer()
exp = ['000004216']
self.assertEqual(obs, exp)

def test_set_send_qiita_buffer_status(self):
pass # exercised in test_get_send_qiita_buffer_status

def test_mark_barcodes_sent_to_qiita(self):
db._con.execute('DELETE from barcodes.project_qiita_buffer')
db.set_send_qiita_buffer_status('Idle')
db.push_barcode_to_qiita_buffer('000004216')
db.push_barcode_to_qiita_buffer('000004215')
db.mark_barcodes_sent_to_qiita(['000004216'])
obs = db.get_unsent_barcodes_from_qiita_buffer()
exp = ['000004215']
self.assertEqual(obs, exp)

def test_pulldown_third_party(self):
# Add survey answers
with open(self.ext_survey_fp, 'rU') as f:
Expand Down
20 changes: 20 additions & 0 deletions knimin/static/css/qiime.css
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,21 @@ html, body {
width: 200px;
}

#qiita_buffer_window {
position: fixed;
top: 8px;
right: 8px;
margin: 8px;
background: #fff;
opacity: 0.8;
padding: 8px;
border: 2px black solid;
border-radius: 5px;
font: 15px normal Arial, Helvetica, sans-serif;
word-wrap: break-word;
width: 300px;
}

.login {
float:left;
margin: 8px;
Expand Down Expand Up @@ -294,6 +309,11 @@ h2.verification_text{
width: 100%;
}

h3.qiita_buffer_warning_text{
font-style: italic;
width: 100%;
}

#invalid_barcode {
background-color: #f00;
}
Expand Down
56 changes: 55 additions & 1 deletion knimin/templates/barcode_util.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,51 @@
}
});
});

function update_qiita_buffer(data, status) {
// update the buffer sending status and the buffer level
document.getElementById("qiita_buffer_status").innerHTML = "Send status: " + data['status'];
document.getElementById("qiita_buffer_level").innerHTML = "Samples queued: " + data['barcodes'].length;
console.log(status);
}

function immediate_update_qiita_buffer() {
// immediate update of buffer and status
$.get("/notify-qiita/", function(data, status) {
data = JSON.parse(data);
update_qiita_buffer(data, status);
} );
}

function submit_qiita_buffer() {
// issue a request to the knimin server to push data to qiita
$.post("/notify-qiita/", function(data, status) {
console.log("POST /notify-qiita/");
console.log(data);
console.log(status);
} );
immediate_update_qiita_buffer();
}

(function poll() {
// poll for buffer and submission status on a 5 second interval
setTimeout(function() {
$.ajax({
url: "/notify-qiita/",
type: "GET",
success: function(data, status) {
console.log("polling");
update_qiita_buffer(data, status);
},
dataType: "json",
complete: poll,
timeout: 5000
})
}, 5000);
})();

immediate_update_qiita_buffer();

</script>
{% end %}

Expand Down Expand Up @@ -42,7 +87,16 @@ <h3>Barcode Scanner </h3>
document.check_barcode.barcode.focus()
</script>
</form>
<div>
</div>

<div id="qiita_buffer_window">
<h3 id="qiita_buffer_level">Samples queued: refreshing...</h3>
<h3 id="qiita_buffer_status">Send status: refreshing...</h3>
<h3 class="qiita_buffer_warning_text">
Note: queued samples will be inaccessible to LabControl <br>
</h3>
<button onClick="submit_qiita_buffer()">Send to Qiita</button>
</div>

{% if barcode is not None%}
<div id="{{div_and_msg[0]}}" class="verification_color">
Expand Down

0 comments on commit 1b87de7

Please sign in to comment.