def servicelist(): conn = get_db() cur = conn.cursor() cur.execute(""" (SELECT id, name, type, active, (SELECT type AS othertype FROM service WHERE type != 'NF9132' LIMIT 1) AS othertype FROM service WHERE type = 'NF9132' UNION SELECT id, name, type, active, (SELECT type AS othertype FROM service WHERE type != 'NF9133' LIMIT 1) AS othertype FROM service WHERE type = 'NF9133') ORDER BY id ASC;""") results = cur.fetchall() slist = [{ "id": x[0], "name": x[1], "type": x[2], "active": x[3], "othertype": x[4] } for x in results] return render_template("servicelist.html", servicelist=slist)
def service(): if request.args.get("id") is None or request.args.get("action") is None: # dbg("MISSING ARGS") return redirect(url_for("servicelist")) else: service_id = int(request.args.get("id")) action = request.args.get("action") conn = get_db() cur = conn.cursor() cur.execute("SELECT id, name FROM service WHERE id=%s ORDER BY id ASC", (service_id, )) slist = [{"id": x[0], "name": x[1]} for x in cur.fetchall()] service = slist[0] # dbg(slist) msg = f"Setting '{service['name']}' (id #{service['id']}) to" if action == "activate": cur.execute("UPDATE service set active = true where id = %s", (str(service_id), )) conn.commit() msg += " ACTIVE" elif action == "deactivate": cur.execute("UPDATE service set active = false where id = %s", (str(service_id), )) conn.commit() msg += " INACTIVE" elif action == "set_type": newtype = request.args.get("newtype") cur.execute("UPDATE service set type = %s where id = %s", (newtype, str(service_id))) conn.commit() msg += f" Night float list '{newtype}'" # dbg({"msg": msg, "service": service, "slist": slist}) cur.close() conn.close() return render_template("service.html", msg=msg, service=service)
def get_callback_number(nflist): """Get the phone number to text if there are missing signouts for a given list. :param str nflist: the night float list to get the callback number for (ex: "NF9132") :returns: The twilio_formatted callback to text (ex: '+13128675309') :rtype: str """ conn = get_db() cur = conn.cursor() dayofyear = datetime.datetime.today().timetuple().tm_yday cur.execute( """ SELECT callback FROM assignments INNER JOIN nightfloat ON assignments.nightfloat = nightfloat.id WHERE dayofyear = %s AND type = %s""", (dayofyear, nflist), ) callback = cur.fetchall() if len(callback) > 0: callback = callback[0][0] else: callback = "+17732403395" cur.close() conn.close() if app.config["DEBUG_CALLBACKS"]: print( "DEBUG_CALLBACKS set -- would have returned '%s' but returning '%s' instead" % (callback, app.config["DEBUG_TARGET_NUMBER"])) callback = app.config["DEBUG_TARGET_NUMBER"] return callback
def notify_late_signup(signout_id, notify=True): """TODO: Send a text message to night float indicating that a 'late' addition to the signout list has occured :param int signout_id: DB id of the late signup :returns: none """ conn = get_db() cur = conn.cursor() cur.execute( """ SELECT intern_name, service.name, intern_callback, TYPE FROM signout INNER JOIN service ON signout.service = service.id WHERE signout.id = %s """, (signout_id, ), ) results = cur.fetchall()[0] cur.close() conn.close() if (app.config["twilio_sid"] == "" or app.config["twilio_auth_token"] == "" or app.config["twilio_number"] == "+"): print( "Skipping notifications as twilio configuration not set in dbsettings.json" ) return callback_number = get_callback_number(results[3]) client = Client(app.config["twilio_sid"], app.config["twilio_auth_token"]) body = ( f"Notifying that the list {results[1]} was added when all other " + f"callbacks were complete. Please call back {results[0]} at {results[2]}" ) if app.config["DEBUG_PRINT_NOT_MESSAGE"] == 0 and notify: client.messages.create(to=callback_number, from_=app.config["twilio_number"], body=body) elif not notify: print( f"DEBUG_PRINT: Since notify=True, printing message rather than sending: {body}" ) else: print( f"DEBUG_PRINT: Since DEBUG_PRINT_NOT_MESSAGE > 0, printing message rather than sending: {body}" )
def addservice(): if request.method == "GET": return render_template("addservice.html") conn = get_db() cur = conn.cursor() cur.execute( "INSERT INTO SERVICE (name, type) VALUES (%s, %s) RETURNING id", (request.form["name"], request.form["nflist"]), ) cur.fetchone()[0] conn.commit() conn.close() return redirect(url_for("servicelist"))
def start_signout(): signout_id = 0 if request.args.get("id") is None: return "ERROR: Tried to start signout without an id query parameter for which signout db entry" try: signout_id = request.args.get("id") conn = get_db() cur = conn.cursor() cur.execute( "UPDATE signout set starttime=current_timestamp where id=%s" % str(signout_id)) conn.commit() cur.close() conn.close() return json.dumps({"id": signout_id, "status": "OK"}) except Exception: return json.dumps({"id": signout_id, "status": "ERROR"})
def get_missing_signouts(nflist): """Get the active signouts that have not yet happened for the current day. :param str nflist: the night float list to get the missing signouts for (ex: "NF9132") :returns: a list of strings representing the names of the lists that haven't been signed out yet (ex: ["Breast, APP", "STR, Intern #1"]) or None if all lists are signed out :rtype: [str] """ conn = get_db() cur = conn.cursor() cur.execute( """ SELECT id, name FROM service WHERE active IS true AND type = %s AND id NOT IN ( SELECT service FROM signout INNER JOIN service ON signout.service = service.id WHERE date_part('day', addtime) = date_part('day', current_timestamp) AND date_part('month', addtime) = date_part('month', current_timestamp) AND date_part('year', addtime) = date_part('year', current_timestamp) AND type = %s );""", (nflist, nflist), ) results = cur.fetchall() cur.close() conn.close() if len(results) == 0: return None return [x[1] for x in results]
def submission_weekday(): conn = get_db() if request.method == "GET": cur = conn.cursor() cur.execute(""" SELECT id, name FROM service WHERE TYPE='NF9132' AND active='t' ORDER BY name ASC """) solid_services = [{"id": x[0], "name": x[1]} for x in cur.fetchall()] cur.execute(""" SELECT id, name FROM service WHERE TYPE='NF9133' AND active='t' ORDER BY name ASC""") liquid_services = [{"id": x[0], "name": x[1]} for x in cur.fetchall()] cur.execute(""" SELECT intern_name, name, addtime::TIMESTAMP::TIME, signout.active, completetime - starttime AS elapsedtime FROM signout LEFT JOIN service ON signout.service = service.id WHERE date_part('day', addtime) = date_part('day', CURRENT_TIMESTAMP) AND date_part('month', addtime) = date_part('month', CURRENT_TIMESTAMP) AND date_part('year', addtime) = date_part('year', CURRENT_TIMESTAMP) AND oncall IS FALSE AND TYPE = 'NF9132' ORDER BY addtime ASC""") noncall_solid_interns = [{ "intern_name": x[0], "name": x[1], "addtime": fix_earlytimes(CLEANUP_TIMESTAMP.sub(".\\1", str(x[2]))), "active": x[3], "fgcolor": get_foreground_color(x[3]), "elapsedtime": format_timestamp(str(x[4])), } for x in cur.fetchall()] cur.execute(""" SELECT intern_name, name, addtime::TIMESTAMP::TIME, signout.active, completetime - starttime AS elapsedtime FROM signout LEFT JOIN service ON signout.service = service.id WHERE date_part('day', addtime) = date_part('day', CURRENT_TIMESTAMP) AND date_part('month', addtime) = date_part('month', CURRENT_TIMESTAMP) AND date_part('year', addtime) = date_part('year', CURRENT_TIMESTAMP) AND oncall IS TRUE AND TYPE = 'NF9132' ORDER BY addtime ASC""") call_solid_interns = [{ "intern_name": x[0], "name": x[1], "addtime": fix_earlytimes(CLEANUP_TIMESTAMP.sub(".\\1", str(x[2]))), "active": x[3], "fgcolor": get_foreground_color(x[3]), "elapsedtime": format_timestamp(str(x[4])), } for x in cur.fetchall()] cur.execute(""" SELECT intern_name, name, addtime::TIMESTAMP::TIME, signout.active, completetime - starttime AS elapsedtime FROM signout LEFT JOIN service ON signout.service = service.id WHERE date_part('day', addtime) = date_part('day', CURRENT_TIMESTAMP) AND date_part('month', addtime) = date_part('month', CURRENT_TIMESTAMP) AND date_part('year', addtime) = date_part('year', CURRENT_TIMESTAMP) AND oncall IS FALSE AND TYPE = 'NF9133' ORDER BY addtime ASC""") noncall_liquid_interns = gen_med_sorter([{ "intern_name": x[0], "name": x[1], "addtime": fix_earlytimes(CLEANUP_TIMESTAMP.sub(".\\1", str(x[2]))), "active": x[3], "fgcolor": get_foreground_color(x[3]), "elapsedtime": format_timestamp(str(x[4])), } for x in cur.fetchall()]) cur.execute(""" SELECT intern_name, name, addtime::TIMESTAMP::TIME, signout.active, completetime - starttime AS elapsedtime FROM signout LEFT JOIN service ON signout.service = service.id WHERE date_part('day', addtime) = date_part('day', CURRENT_TIMESTAMP) AND date_part('month', addtime) = date_part('month', CURRENT_TIMESTAMP) AND date_part('year', addtime) = date_part('year', CURRENT_TIMESTAMP) AND oncall IS TRUE AND TYPE = 'NF9133' ORDER BY addtime ASC""") call_liquid_interns = [{ "intern_name": x[0], "name": x[1], "addtime": fix_earlytimes(CLEANUP_TIMESTAMP.sub(".\\1", str(x[2]))), "active": x[3], "fgcolor": get_foreground_color(x[3]), "elapsedtime": format_timestamp(str(x[4])), } for x in cur.fetchall()] cur.close() conn.close() return render_template( "submission.html", solid_services=solid_services, liquid_services=liquid_services, noncall_solid_interns=noncall_solid_interns, call_solid_interns=call_solid_interns, noncall_liquid_interns=noncall_liquid_interns, call_liquid_interns=call_liquid_interns, ) else: cur = conn.cursor() if request.form.getlist("service") is None: # This should never happen return render_template("received.html") # dbg(request.form) # dbg(request.form.getlist("service")) for serviceid in request.form.getlist("service"): cur.execute( """ INSERT INTO signout (intern_name, intern_callback, service, oncall, ipaddress, hosttimestamp) VALUES (%s, %s, %s, %s, %s, %s) RETURNING id;""", ( request.form["intern_name"], request.form["intern_callback"], serviceid, request.form["oncall"], request.remote_addr, request.form["hosttimestamp"], ), ) callback_id = cur.fetchone()[0] conn.commit() cur.execute("SELECT type FROM service WHERE id = %s", (serviceid, )) nflist = cur.fetchall()[0][0] cur.execute( """ SELECT count(distinct(hosttimestamp, intern_name)) FROM signout INNER JOIN service ON signout.service = service.id WHERE date_part('day', addtime) = date_part('day', CURRENT_TIMESTAMP) AND date_part('month', addtime) = date_part('month', CURRENT_TIMESTAMP) AND date_part('year', addtime) = date_part('year', CURRENT_TIMESTAMP) AND signout.active = 't' AND service.type = %s;""", (nflist, ), ) count = cur.fetchall()[0][0] cur.close() conn.close() timenow = datetime.datetime.now() if count < 2: if ((timenow.hour == 19 and timenow.minute > 30) or (timenow.hour > 19) or (timenow.hour < 12)): notify_late_signup(callback_id) return render_template("received.html")
def query(): conn = get_db() if request.method == "GET": cur = conn.cursor() rangestring = "Showing signouts for %s" % ( datetime.date.today() - datetime.timedelta(days=1)).strftime("%m-%d-%Y") cur.execute(""" SELECT intern_name, name, TYPE, addtime::TIMESTAMP::TIME, starttime::TIMESTAMP, completetime::TIMESTAMP, addtime::TIMESTAMP::DATE AS adddate FROM signout LEFT JOIN service ON signout.service = service.id WHERE date_part('day', addtime) = date_part('day', CURRENT_TIMESTAMP - interval '1 day') AND date_part('month', addtime) = date_part('month', CURRENT_TIMESTAMP) AND date_part('year', addtime) = date_part('year', CURRENT_TIMESTAMP) ORDER BY completetime ASC""") signoutlog = [{ "intern_name": x[0], "name": x[1], "type": x[2], "addtime": fix_earlytimes(CLEANUP_TIMESTAMP.sub(".\\1", str(x[3]))), "starttime": x[4], "completetime": x[5], "adddate": x[6].strftime("%m-%d-%Y"), "elapsedtime": "", } for x in cur.fetchall()] for idx in range(len(signoutlog)): sout = signoutlog[idx] try: timediff = sout["completetime"] - sout["starttime"] elapsed_minutes = int(timediff.seconds / 60) elapsed_seconds = timediff.seconds % 60 sout["elapsedtime"] = "%i:%02d" % (elapsed_minutes, elapsed_seconds) except Exception: sout["elapsedtime"] = "Unable to be computed" if sout["starttime"] != None: sout["starttime"] = CLEANUP_TIMESTAMP.sub( "", str(sout["starttime"].time())) else: sout["starttime"] = "" if sout["completetime"] != None: sout["completetime"] = CLEANUP_TIMESTAMP.sub( "", str(sout["completetime"].time())) else: sout["completetime"] = "" cur.close() conn.close() return render_template("query.html", signoutlog=signoutlog, rangestring=rangestring) else: cur = conn.cursor() if "NF9133" in request.form.keys(): if "NF9132" in request.form.keys(): typestring = "" else: typestring = " AND type = 'NF9133' " else: if "NF9132" in request.form.keys(): typestring = " AND type = 'NF9132' " else: typestring = " AND type = 'notarealtype' " if request.form["addtime_date2"] == "": rangestring = "Showing signouts for %s" % request.form[ "addtime_date"] splitdate = cleanup_date_input( request.form["addtime_date"]).split("-") cur.execute(""" SELECT intern_name, name, TYPE, addtime::TIMESTAMP::TIME, starttime::TIMESTAMP, completetime::TIMESTAMP, addtime::TIMESTAMP::DATE AS adddate FROM signout LEFT JOIN service ON signout.service = service.id WHERE date_part('day', addtime) = %s AND date_part('month', addtime) = %s AND date_part('year', addtime) = %s %s ORDER BY completetime ASC """ % (splitdate[2], splitdate[1], splitdate[0], typestring)) # dbg(cur.query) else: rangestring = "Showing signouts from %s to %s inclusive" % ( request.form["addtime_date"], request.form["addtime_date2"], ) splitdate = cleanup_date_input( request.form["addtime_date"]).split("-") splitenddate = cleanup_date_input( request.form["addtime_date2"]).split("-") cur.execute(""" SELECT intern_name, name, TYPE, addtime::TIMESTAMP::TIME, starttime::TIMESTAMP, completetime::TIMESTAMP, addtime::TIMESTAMP::DATE AS adddate FROM signout LEFT JOIN service ON signout.service = service.id WHERE addtime BETWEEN '""" + "-".join(splitdate) + """' and '""" + "-".join(splitenddate) + """' ORDER BY completetime ASC""") # dbg(cur.query) signoutlog = [{ "intern_name": x[0], "name": x[1], "type": x[2], "addtime": fix_earlytimes(CLEANUP_TIMESTAMP.sub("", str(x[3]))), "starttime": x[4], "completetime": x[5], "adddate": x[6].strftime("%m-%d-%Y"), "elapsedtime": "", } for x in cur.fetchall()] for idx in range(len(signoutlog)): sout = signoutlog[idx] try: timediff = sout["completetime"] - sout["starttime"] elapsed_minutes = int(timediff.seconds / 60) elapsed_seconds = timediff.seconds % 60 sout["elapsedtime"] = "%i:%02d" % (elapsed_minutes, elapsed_seconds) except Exception: sout["elapsedtime"] = "Unable to be computed" if sout["starttime"] != None: sout["starttime"] = CLEANUP_TIMESTAMP.sub( "", str(sout["starttime"].time())) else: sout["starttime"] = "" if sout["completetime"] != None: sout["completetime"] = CLEANUP_TIMESTAMP.sub( "", str(sout["completetime"].time())) else: sout["completetime"] = "" signoutlog[idx] = sout cur.close() conn.close() return render_template("query.html", signoutlog=signoutlog, rangestring=rangestring)
def nightfloat(): if request.args.get("list") is None: listtype = "NF9132" else: listtype = request.args.get("list") # TODO: This is sort of dangerous. Should do differently conn = get_db() if request.method == "GET": cur = conn.cursor() cur.execute(""" SELECT signout.id, intern_name, name, intern_callback FROM signout LEFT JOIN service ON signout.service = service.id WHERE signout.active IS TRUE AND TYPE = '%s' AND date_part('day', addtime) = date_part('day', CURRENT_TIMESTAMP) AND date_part('month', addtime) = date_part('month', CURRENT_TIMESTAMP) AND date_part('year', addtime) = date_part('year', CURRENT_TIMESTAMP) ORDER BY addtime ASC""" % listtype.upper()) waiting_interns = gen_med_sorter([{ "id": x[0], "intern_name": x[1], "name": x[2], "intern_callback": x[3] } for x in cur.fetchall()]) cur.execute(""" SELECT intern_name, name, intern_callback FROM signout LEFT JOIN service ON signout.service = service.id WHERE signout.active IS FALSE AND TYPE = '%s' AND date_part('day', addtime) = date_part('day', CURRENT_TIMESTAMP) AND date_part('month', addtime) = date_part('month', CURRENT_TIMESTAMP) AND date_part('year', addtime) = date_part('year', CURRENT_TIMESTAMP) ORDER BY completetime ASC """ % listtype.upper()) completed_interns = [{ "intern_name": x[0], "name": x[1], "intern_callback": x[2] } for x in cur.fetchall()] cur.close() conn.close() return render_template( "nightfloat.html", waiting_interns=waiting_interns, completed_interns=completed_interns, type=listtype, querystring="?list=" + listtype, ) cur = conn.cursor() cur.execute(""" UPDATE signout SET active = FALSE, completetime = CURRENT_TIMESTAMP WHERE id = %s""" % request.form["signout.id"]) conn.commit() cur.close() conn.close() return render_template("removed.html", type=listtype)