Skip to content

Commit

Permalink
first
Browse files Browse the repository at this point in the history
  • Loading branch information
rocksnow1942 committed Jan 13, 2022
0 parents commit 1984e58
Show file tree
Hide file tree
Showing 48 changed files with 4,768 additions and 0 deletions.
1 change: 1 addition & 0 deletions ScannerApp/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .scanApp import ScannerApp
280 changes: 280 additions & 0 deletions ScannerApp/pages/AccessionPage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,280 @@
import tkinter as tk
from threading import Thread
import requests
from ..utils import parseISOTime,convertTubeID
import time
from datetime import datetime,timezone
from . import BaseViewPage


class AccessionPage(BaseViewPage):
resultType = dict
# result key consist of:
# name: patient name,
# extId: for booking, is /booking/asdfasdg
# sampleId: sample Id linked to the patient.
def __init__(self, parent, master):
super().__init__(parent, master)
self.create_widgets()
self.fb = self.master.firebase
self.initKeyboard(type='lag',lag=1)
self.bind("<Button-1>", lambda x:self.focus_set())
self.lastInputTime = time.time()
self.patientPageIndex = 0 # the index of currently showing patient search result
self.patientPage = [] # patient results to show
self._forget_to_save = False # a tag to indicate user forget to save, then prevent scan any new tube ID.


def create_widgets(self):
self._msgVar = tk.StringVar()
self.nameVar = tk.StringVar()
self.timeVar = tk.StringVar()
self.dobVar = tk.StringVar() # store DOB of user
self.checkVar = tk.StringVar() # store whether user is checked in
self.codeVar = tk.StringVar() #store tube barcode
self.variables = [self.nameVar,self.timeVar,self.dobVar,self.checkVar,self.codeVar]

font = ('Arial',30)
self._msg = tk.Label(self, textvariable=self._msgVar, font=('Arial',20))
self.name = tk.Entry(self, textvariable=self.nameVar, font=font)
self.time = tk.Label(self, textvariable=self.timeVar, font=font)
self.dob = tk.Label(self, textvariable=self.dobVar, font=font)
self.check = tk.Label(self, textvariable=self.checkVar, font=font)
self.code = tk.Label(self, textvariable=self.codeVar, font=('Arial',30))
self.home = tk.Button(self,text='Home',font=('Arial',32),command=self.prevPageCb)
self.save = tk.Button(self,text='Save',font=('Arial',32),command=self.saveCb)
self.search = tk.Button(self,text='Search',font=('Arial',32),command=self.searchCb)
self.prev = tk.Button(self,text='<',font=('Arial',32),command=self.searchPagerCb(-1))
self.next = tk.Button(self,text='>',font=('Arial',32),command=self.searchPagerCb(1))

# plate widgets
Y_DIS = 63
Y_START = 20
X = 20
tk.Label(self,text='Name:',font=('Arial',30)).place(x=X,y=Y_START)
tk.Label(self,text='DoB:',font=('Arial',30)).place(x=X,y=Y_START+Y_DIS*1)
tk.Label(self,text='Time:',font=('Arial',30)).place(x=X,y=Y_START+Y_DIS*2)
tk.Label(self,text='Check In:',font=('Arial',30)).place(x=X,y=Y_START+Y_DIS*3)
tk.Label(self,text='Sample ID:',font=('Arial',30)).place(x=X,y=Y_START+Y_DIS*4)
X+=230
self.name.place(x=X,y=Y_START,width=500)
self.dob.place(x=X,y=Y_START+Y_DIS*1)
self.time.place(x=X,y=Y_START+Y_DIS*2)
self.check.place(x=X,y=Y_START+Y_DIS*3)
self.code.place(x=X,y=Y_START+Y_DIS*4)

self._msg.place(x=20, y=420, width=760,)
BY=350
self.home.place(x=40 , y=BY, height=60 ,width=130,)
self.save.place(x=630 , y=BY, height=60, width=130)
self.search.place(x=330,y=BY, height=60,width=140)
self.prev.place(x=240,y=BY,height=60,width=60)
self.next.place(x=500,y=BY,height=60,width=60)

def searchPagerCb(self,step):
'generate change result page call back.'
def cb():
N = len(self.patientPage)
nextPage = self.patientPageIndex + step
if nextPage<0 or nextPage>=N:
return
self.patientPageIndex +=step
self.showPatient(self.patientPage[self.patientPageIndex])
self.displaymsg(f"Result {self.patientPageIndex+1} / {N}")
return cb

# def scanlistener(self,e):
# "need to handle the special case in QR code."
# char = e.char
# if time.time() - self.lastInputTime >1:
# # if the last input is more than 1 seconds ago, reset keySequence.
# self.keySequence=[]
# if char=='\r':
# if self.keySequence:
# self.keyboardCb(''.join(self.keySequence))
# self.keySequence=[]
# else:
# self.keySequence.append(char)
# self.lastInputTime = time.time()
# #return 'break' to stop keyboard event propagation.
# return 'break'

def showPatient(self,data):
"""
show the patient information from data dictionary to display.
also update self.result
self.result format :{
name: patient Name,
extId: /booking/docID
sampleIds:[ list of sample ID ]
}
"""
name = data.get('name','No Name!!!')
dob = data.get('dob','No DoB')
self.nameVar.set(name)
self.dobVar.set(dob)
if data.get('date',None) and data.get('time',None):
self.timeVar.set( f"{parseISOTime(data['date']).strftime('%Y-%m-%d')} , {data['time']}" )
else:
self.timeVar.set('No appointment time found.')
if data['checkin']:
self.checkVar.set('Already Check In.')
else:
self.checkVar.set("Not Yet.")
self.result.update(name=name,extId=data.get('docID'))

def keyboardCb(self,code):
"call back when a QR code is scanned."
def getInfo():
# first check if a tube is already scanned.
# if the code is a booking reservation:
if self._forget_to_save:
return

if code.startswith('/booking'):
if self.result.get('sampleIds',None):
self.displaymsg('Did you forget to save?','red')
self.debug(f'Forget to save triggered. Current result: {self.result}')
self._forget_to_save = True
return
# first reset state.
self.resetState()
try:
self.displaymsg('Validating with server...','green')
res = self.fb.get(f'/booking/info{code}')
if res.status_code == 200:
data = res.json()
self.showPatient(data)
self.debug(f'Validate Patient with firebase: {code}')
self.displaymsg('Please confirm patient info.','green')
else:
self.error(f"keyboardCb: server response [{res.status_code}], {res.json()}")
self.nameVar.set("")
self.dobVar.set('')
self.timeVar.set('')
self.checkVar.set('')
self.displaymsg(f'Error: [{res.status_code}] {res.json().get("error","No response was returned.[102]")}')
except requests.ReadTimeout:
self.error('keyboarCb: ReadTimeout.')
self.displaymsg('Server timeout. Slow internet?','red')
except requests.ConnectionError as e:
self.error(f'keyboarCb: connection error: {e}')
self.displaymsg('Connection error. Check Wifi or wait and retry.','red')
except Exception as e:
self.error(f'keyboarCb: Other exception {e}')
self.displaymsg('Read QR code error.[200]','red')
else:
# otherwise the code should be tube barcode.
# and we FORCE_UPPER_CASE for tube IDs
converted = convertTubeID(code)
self.codeVar.set(converted)
valid,msg = self.master.currentRoutine.validateResult(converted)
if valid:
self.save['state'] ='normal'
self.displaymsg('Sample Id read. Verify before save.','green')
self.result['sampleIds'] = [converted]
self.result['company'] = 'online-booking'
self.debug(f'Scanned valid tube barcode: {converted}')
else:
self.save['state'] ='disabled'
self.displaymsg(msg,'red')

Thread(target=getInfo).start()

def showPage(self,*_,**__ ):
self.keySequence = []
self.tkraise()
self.focus_set()
self.displaymsg('Scan QR code to start.')
self.save['state'] ='disabled'

def closePage(self):
self.home['state']='normal'
self.search['state']='normal'
self.save['state'] ='normal'


def resetState(self):
for v in self.variables:
v.set('')
self.result = self.resultType()
self.patientPage = []
self.patientPageIndex = 0
self._forget_to_save = False



def searchCb(self):
self.focus_set()
name = self.nameVar.get()

if not name.strip():
self.displaymsg('Enter name to search.' , 'red')
return

def search():
self.resetState()
self.displaymsg('Searching name...','green')
self.disableBtn()
res = self.fb.post('/booking/query',json={"firstName":name,'lastName':""})
if res.status_code == 200:
self.patientPage = res.json()
self.showPatient(self.patientPage[0])
N = len(self.patientPage)
self.displaymsg(f'Found {N} matching results. 1/{N}')
else:
self.displaymsg(res.json()['error'],'red')
self.enableBtn()

Thread(target=search).start()

def enableBtn(self,):
self.home['state']='normal'
self.search['state']='normal'

def disableBtn(self):
self.home['state'] = 'disabled'
self.save['state'] ='disabled'
self.search['state'] ='disabled'

def saveCb(self):
self.focus_set()
def save():
# save self.result
if self.result.get('extId',None) == None:
self.displaymsg('Nothing to save. Scan QR code to start.','red')
elif self.result.get('sampleIds',None) == None:
self.displaymsg('Scan sample tube ID before save.','red')
elif self.checkVar.get() == 'Already Check In.':
self.displaymsg('This patient already submitted sample.','red')
else:
try:
# save result to firebase
for msg in self.master.currentRoutine.saveResult():
self.displaymsg(msg)
# check this patient in on firestore so that we know he already submitted sample.
self.displaymsg('Writing back to cloud...')
sampleId = self.result['sampleIds'][0]
res = self.fb.post('/booking/checkin',
json={'docID':self.result['extId'],
# use server time to update.
"collectedAt":datetime.now(timezone.utc).isoformat(),
'accession_id':sampleId})
if res.status_code==200:
self.displaymsg('Saved successfully.','green')
self.info(f'Saved {sampleId} to firebase successfully.')
self.resetState()
else:
self.error(f'Save {sampleId} to firebase error {res.status_code}.')
self.displaymsg('Save result to cloud error.','red')
except Exception as e:
self.error(f"AccessionPage.saveCb error: {e}")
self.displaymsg(f'Error in saving: {str(e)[0:40]}','red')
self.enableBtn()
Thread(target=save).start()
self.displaymsg('Saving results...','green')

self.disableBtn()


100 changes: 100 additions & 0 deletions ScannerApp/pages/AuthorizationPage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import tkinter as tk
from . import BaseViewPage
import time
from ..utils import decode
import sys


class AuthorizationPage(BaseViewPage):
def __init__(self, parent, master):
super().__init__(parent,master)
self.createDefaultWidgets()
self.placeDefaultWidgets()
self.create_widgets()
self.initKeyboard(type='lag',lag=1)
self.state = ['validationStatus', ]
self.lastInputTime = 0
if not self.master.devMode:
self.disableNextBtn()

def placeDefaultWidgets(self):
self._msg.place(x=20, y=430, width=740)
self._prevBtn.place(x=340 , y=300, height=90 ,width=130,)

self._title.place(x=0,y=20,width=800,height=30)

def create_widgets(self):
self.scanVar = tk.StringVar()
# self.scanVar1.set('1234567890')
self.scan = tk.Label(
self, textvariable=self.scanVar, font=('Arial', 65), )
l1 = tk.Label(self, text='User Name', font=('Arial', 35)
)
self.scan.place(x=100, y=160,width=600) # grid(column=1,row=0,)
l1.place(x=200, y=110,width=400)

def showPage(self,):
self.setTitle('Please Scan Your Badge','black')
self.keySequence = []
self.tkraise()
self.focus_set()
self.displaymsg('Scan Your Badge Before Proceed')


def closePage(self):
self.resetState()


def resetState(self):
self.result = self.resultType()
self.scanVar.set("")
self.keySequence = []

def prevPageCb(self):
"return to previous page in the current routine"
self.resetState()
self.master.currentRoutine.prevPage()

def keyboardCb(self,code):
self.result = code
if sys.argv[-1] == '--dev':
self.master.db.setUser({'username':'Hui Dev'})
self.displaymsg(f'User is in dev mode.','green')
self.after(500,self.startRoutine)
return
try:
res = self.master.db.get(f'/user/{code}')
if res.status_code == 200:
requirement = self.master.currentRoutine.requireAuthorization
user = res.json()
self.scanVar.set(user.get('username','Unknown User'))
if self.authorize(res.json(), requirement):
self.master.db.setUser(res.json())
self.after(500,self.startRoutine)
self.displaymsg(f'User is authorized.','green')
else:
self.displaymsg(f'You are not authorized for this task.','red')
else:
self.scanVar.set('Invalid User')
self.displaymsg('Invalid user ID.')
except Exception as e:
self.error(f'Authorization error: {e}')
self.displaymsg(f'Auth error:{e}','red')

def authorize(self,userObj,requirement):
role = userObj.get('role',[])
return requirement in role

def startRoutine(self):
self.resetState()
self.master.currentRoutine.startRoutine()










Loading

0 comments on commit 1984e58

Please sign in to comment.