diff --git a/cgi-bin/upload.py b/cgi-bin/upload.py index 1167e0f..8489e9c 100755 --- a/cgi-bin/upload.py +++ b/cgi-bin/upload.py @@ -1,48 +1,61 @@ #!/usr/bin/env python3 """ Created on Sat Mar 28 19:29:28 2020 This module implements a CGI service for uploading voice records in the coughvid web application. @author: T. Teijeiro """ import cgi import datetime +import json #TODO disable cgitb in production import cgitb cgitb.enable() #Point this variable to the folder where the data will be stored DB_PATH = '/tmp' form = cgi.FieldStorage() -# Get filename here. -fileitem = form['audio_data'] -latitude = form.getvalue('lat') -longitude = form.getvalue('lon') +#First we check if we are receiving a recording or metadata mimeType = form.getvalue('mimeType') -ext = 'wav' -if 'ogg' in mimeType: - ext = 'ogg' -elif 'webm' in mimeType: - ext = 'webm' -label = 1 -data = fileitem.file.read() -#We limit the file size to 1MB, to prevent possible flooding attacks. -if len(data) < 1000000: - # Test if the file was uploaded - filename = f'{datetime.datetime.now().isoformat()}_{latitude}_{longitude}_{label}.{ext}' - with open(f'{DB_PATH}/{filename}', 'wb') as fout: - fout.write(data) - message = 'The recording was uploaded successfully' -else: - message = 'Record too long.' +if mimeType == "json": + uid = form.getvalue('uuid') + if uid is not None and uid != 'null': + with open(f'{DB_PATH}/{uid}.json', 'w') as fout: + dct = {k:form.getvalue(k) for k in form.keys()} + json.dump(dct, fout) + message = 'The metadata was properly stored' + else: + message = 'Not valid UUID' +else: + # Get filename here. + fileitem = form['audio_data'] + latitude = form.getvalue('lat') + longitude = form.getvalue('lon') + mimeType = form.getvalue('mimeType') + uid = form.getvalue('uuid') + ext = 'wav' + if 'ogg' in mimeType: + ext = 'ogg' + elif 'webm' in mimeType: + ext = 'webm' + data = fileitem.file.read() + #We limit the file size to 1MB, to prevent possible flooding attacks. + if len(data) < 1000000: + # Test if the file was uploaded + filename = f'{uid}_{datetime.datetime.now().isoformat()}_{latitude}_{longitude}.{ext}' + with open(f'{DB_PATH}/{filename}', 'wb') as fout: + fout.write(data) + message = 'The recording was uploaded successfully' + else: + message = 'Record too long.' print(f"""\ Content-Type: text/html\n

{message}

""") diff --git a/index.html b/index.html index fd0d19b..08e1f4c 100644 --- a/index.html +++ b/index.html @@ -1,530 +1,580 @@ Coughvid
Back to top
-
+
Coughvid

Please send us a recording of a cough sound from a patient with COVID-19

Safe coughing instructions
◉ Record
Thank you!
+ + +
+
+
+ + +
+
+ +
    +
  • +
    + + +
    +
  • +
  • +
    + + +
    +
  • +
+
+ +
+
+ + + + +
+
+
+
Submit
+
+
+
+ +
+ diff --git a/js/app.js b/js/app.js index ba5bca5..5eb78dd 100644 --- a/js/app.js +++ b/js/app.js @@ -1,60 +1,77 @@ var recorder, gumStream; var lat=null; var lon=null; +var uuid=null; var recordButton = document.getElementById("recordButton"); var recordText = document.getElementById("recordText"); +var submitButton = document.getElementById("submitButton"); + recordButton.addEventListener("click", toggleRecording); +submitButton.addEventListener("click", submitMetadata); + //ProgressBar API: https://progressbarjs.readthedocs.io/en/latest/ var bar = new ProgressBar.Line(progressBar, { strokeWidth: 1, easing: 'easeInOut', duration: 10000, color: '#DC1200', trailColor: '#eee', trailWidth: 1, svgStyle: {width: '100%', height: '100%'} }); function toggleRecording() { if (recorder && recorder.state == "recording") { bar.stop() recorder.stop(); gumStream.getAudioTracks()[0].stop(); recordText.innerHTML = "◉ Record"; recordButton.classList.remove('btn-danger'); recordButton.classList.add('btn-dark'); } else { navigator.mediaDevices.getUserMedia({ audio: true }).then(function(stream) { gumStream = stream; recorder = new MediaRecorder(stream); recorder.ondataavailable = function(e) { var xhr=new XMLHttpRequest(); var fd=new FormData(); + //Create a unique identifier for the last record + uuid = uuidv4(); fd.append("audio_data", e.data, new Date().toISOString()); fd.append("lat", lat); fd.append("lon", lon); fd.append("mimeType", e.data.type); + fd.append("uuid", uuid); xhr.open("POST","/cgi-bin/upload.py",true); xhr.send(fd); bar.set(0); $("#thanks").animate({opacity: 1}, 1000, function() { setTimeout(function(){ $("#thanks").animate({opacity:0}, 500) }, 2000); }); }; recorder.start(); bar.animate(1.0, {}, toggleRecording); recordText.innerHTML = "◻ Stop"; recordButton.classList.remove('btn-dark'); recordButton.classList.add('btn-danger'); navigator.geolocation.getCurrentPosition(function(position) { lat = position.coords.latitude; lon = position.coords.longitude; }); }); } } + +function submitMetadata() { + var xhr2=new XMLHttpRequest(); + var fd2=new FormData(document.querySelector("form")); + fd2.append("mimeType", "json"); + fd2.append("uuid", uuid); + xhr2.open("POST","/cgi-bin/upload.py",true); + xhr2.send(fd2); +} diff --git a/js/uuidv4.min.js b/js/uuidv4.min.js new file mode 100644 index 0000000..ac3ae0e --- /dev/null +++ b/js/uuidv4.min.js @@ -0,0 +1 @@ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t=t||self).uuidv4=e()}(this,(function(){"use strict";var t="undefined"!=typeof crypto&&crypto.getRandomValues&&crypto.getRandomValues.bind(crypto)||"undefined"!=typeof msCrypto&&"function"==typeof msCrypto.getRandomValues&&msCrypto.getRandomValues.bind(msCrypto),e=new Uint8Array(16);function n(){if(!t)throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");return t(e)}for(var o=[],r=0;r<256;++r)o[r]=(r+256).toString(16).substr(1);return function(t,e,r){var u=e&&r||0;"string"==typeof t&&(e="binary"===t?new Array(16):null,t=null);var i=(t=t||{}).random||(t.rng||n)();if(i[6]=15&i[6]|64,i[8]=63&i[8]|128,e)for(var d=0;d<16;++d)e[u+d]=i[d];return e||function(t,e){var n=e||0,r=o;return[r[t[n++]],r[t[n++]],r[t[n++]],r[t[n++]],"-",r[t[n++]],r[t[n++]],"-",r[t[n++]],r[t[n++]],"-",r[t[n++]],r[t[n++]],"-",r[t[n++]],r[t[n++]],r[t[n++]],r[t[n++]],r[t[n++]],r[t[n++]]].join("")}(i)}})); \ No newline at end of file