Ejemplo n.º 1
0
        public InteractController()
        {
            string fhirserver       = CloudConfigurationManager.GetSetting("FHIRServerAddress");
            string fhirtenant       = CloudConfigurationManager.GetSetting("FHIRAADTenant");
            string fhirclientid     = CloudConfigurationManager.GetSetting("FHIRClientId");
            string fhirclientsecret = CloudConfigurationManager.GetSetting("FHIRClientSecret");

            _client = new FHIRClient(fhirserver, fhirtenant, fhirclientid, fhirclientsecret);
        }
Ejemplo n.º 2
0
        public async Task <ProxyProcessResult> Process(FHIRResponse response, HttpRequest req, ILogger log, ClaimsPrincipal principal, string res, string id, string hist, string vid)
        {
            if (!req.Method.Equals("GET") || response.StatusCode != HttpStatusCode.OK || response.Content == null)
            {
                return(new ProxyProcessResult(true, "", "", response));
            }
            List <JToken> ss = null;

            if (DATE_SORT_RESOURCES_SUPPORTED.Contains(res) && req.Query.ContainsKey("_sort") && req.Query["_sort"].First().Contains("date"))
            {
                var fhirresp = JObject.Parse(response.Content.ToString());
                if (fhirresp.IsNullOrEmpty() || !((string)fhirresp["resourceType"]).Equals("Bundle") || !((string)fhirresp["type"]).Equals("searchset"))
                {
                    return(new ProxyProcessResult(true, "", "", response));
                }
                ss = new List <JToken>();
                addEntries((JArray)fhirresp["entry"], ss, log);
                //Process Next Pages until out or max array
                bool nextlink = !fhirresp["link"].IsNullOrEmpty() && ((string)fhirresp["link"].getFirstField()["relation"]).Equals("next");
                while (nextlink && ss.Count < MAX_ARRAY_SIZE)
                {
                    string     nextpage   = (string)fhirresp["link"].getFirstField()["url"];
                    FHIRClient fhirClient = FHIRClientFactory.getClient(log);
                    var        nextresult = await fhirClient.LoadResource(nextpage);

                    fhirresp = JObject.Parse(nextresult.Content.ToString());
                    if (fhirresp.IsNullOrEmpty() || !fhirresp.FHIRResourceType().Equals("Bundle") || !((string)fhirresp["type"]).Equals("searchset"))
                    {
                        return(new ProxyProcessResult(false, "Next Page not Returned or server error", "", nextresult));
                    }
                    addEntries((JArray)fhirresp["entry"], ss, log);
                    nextlink = !fhirresp["link"].IsNullOrEmpty() && ((string)fhirresp["link"].getFirstField()["relation"]).Equals("next");
                }
                ss.Sort(new DateSortedIndexComparar(req.Query["_sort"].First().Contains("-date")));
                fhirresp["entry"] = new JArray(ss.ToArray());
                fhirresp["link"]  = new JArray();

                response.Content = fhirresp.ToString();
            }
            var retVal = new ProxyProcessResult();

            if (ss != null && ss.Count >= MAX_ARRAY_SIZE)
            {
                retVal.ErrorMsg = "Warning: _Sort exceeed or met MAX_ARRAY_SIZE results may not be accurate!";
                log.LogWarning("_Sort exceeed or met MAX_ARRAY_SIZE results may not be accurate!");
            }
            retVal.Response = response;
            return(retVal);
        }
        public async Task <ProxyProcessResult> Process(string requestBody, HttpRequest req, ILogger log, ClaimsPrincipal principal, string res, string id, string hist, string vid)
        {
            if (req.Method.Equals("GET") && res.SafeEquals("Patient") && !string.IsNullOrEmpty(id) && hist.SafeEquals("$everything"))
            {
                ConcurrentBag <JToken> ss         = new ConcurrentBag <JToken>();
                FHIRClient             fhirClient = FHIRClientFactory.getClient(log);
                var nextresult = await fhirClient.LoadResource("Patient", "_id=" + id);

                var fhirresp = JObject.Parse(nextresult.Content.ToString());
                if (fhirresp.IsNullOrEmpty() || !fhirresp.FHIRResourceType().Equals("Bundle") || !((string)fhirresp["type"]).Equals("searchset"))
                {
                    return(new ProxyProcessResult(false, "Patient not found", "", nextresult));
                }
                addEntries((JArray)fhirresp["entry"], ss, log, "Patient");
                CountdownEvent countdown = new CountdownEvent(everyresource.Length);
                foreach (string rt in everyresource)
                {
                    ThreadPool.QueueUserWorkItem(async delegate
                    {
                        try
                        {
                            FHIRClient fhirClient1 = FHIRClientFactory.getClient(log);
                            string[] s             = rt.Split(":");
                            log.LogInformation($"Loading {s[0]} resources for patient {id}");
                            var rslt = await fhirClient1.LoadResource(s[0], s[1].Replace("{id}", id) + "&_count=100");
                            var resp = JObject.Parse(rslt.Content.ToString());
                            if (!resp.IsNullOrEmpty() && resp.FHIRResourceType().Equals("Bundle") && ((string)resp["type"]).Equals("searchset"))
                            {
                                addEntries((JArray)resp["entry"], ss, log, s[0]);
                            }
                            countdown.Signal();
                        }
                        catch (Exception e)
                        {
                            log.LogError($"Error fetching {rt} resources for patient {id}:{e.Message}");
                            countdown.Signal();
                        }
                    });
                }
                countdown.Wait();
                fhirresp["entry"]  = new JArray(ss.ToArray());
                fhirresp["link"]   = new JArray();
                nextresult.Content = fhirresp;
                return(new ProxyProcessResult(false, "", requestBody, nextresult));
            }
            return(new ProxyProcessResult(true, "", requestBody, null));
        }
Ejemplo n.º 4
0
        public async Task <ProxyProcessResult> Process(string requestBody, HttpRequest req, ILogger log, ClaimsPrincipal principal, string res, string id, string hist, string vid)
        {
            if (req.Method.Equals("GET") && res.SafeEquals("Patient") && !string.IsNullOrEmpty(id) && hist.SafeEquals("$everything"))
            {
                ConcurrentBag <JToken> ss         = new ConcurrentBag <JToken>();
                FHIRClient             fhirClient = FHIRClientFactory.getClient(log);
                var nextresult = await fhirClient.LoadResource("Patient", "_id=" + id);

                var fhirresp = JObject.Parse(nextresult.Content.ToString());
                if (fhirresp.IsNullOrEmpty() || fhirresp["entry"].IsNullOrEmpty())
                {
                    return(new ProxyProcessResult(false, "Patient not found or server error", "", null));
                }
                addEntries((JArray)fhirresp["entry"], ss, log);
                nextresult = await fhirClient.LoadResource($"Patient/{id}/*", "_count=100");

                fhirresp = JObject.Parse(nextresult.Content.ToString());

                if (!fhirresp.IsNullOrEmpty() && !fhirresp["entry"].IsNullOrEmpty())
                {
                    addEntries((JArray)fhirresp["entry"], ss, log);
                    bool nextlink = !fhirresp["link"].IsNullOrEmpty() && ((string)fhirresp["link"].getFirstField()["relation"]).Equals("next");
                    while (nextlink && ss.Count < MAX_ARRAY_SIZE)
                    {
                        string     nextpage    = (string)fhirresp["link"].getFirstField()["url"];
                        FHIRClient fhirClient1 = FHIRClientFactory.getClient(log);
                        nextresult = await fhirClient1.LoadResource(nextpage);

                        fhirresp = JObject.Parse(nextresult.Content.ToString());
                        if (fhirresp.IsNullOrEmpty() || !fhirresp.FHIRResourceType().Equals("Bundle") || !((string)fhirresp["type"]).Equals("searchset"))
                        {
                            return(new ProxyProcessResult(false, "Next Page not Returned or server error", "", null));
                        }
                        addEntries((JArray)fhirresp["entry"], ss, log);
                        nextlink = !fhirresp["link"].IsNullOrEmpty() && ((string)fhirresp["link"].getFirstField()["relation"]).Equals("next");
                    }
                }
                fhirresp["entry"]  = new JArray(ss.ToArray());
                fhirresp["link"]   = new JArray();
                nextresult.Content = fhirresp;
                return(new ProxyProcessResult(false, "", requestBody, nextresult));
            }
            return(new ProxyProcessResult(true, "", requestBody, null));
        }
Ejemplo n.º 5
0
        private async Task MessageReceivedAsync(IDialogContext context, IAwaitable <object> result)
        {
            var    activity = await result as Activity;
            string msg      = activity.Text.ToLower().Trim();

            if (msg == "start over" || msg == "exit" || msg == "quit" || msg == "done" || msg == "start again" || msg == "restart" || msg == "leave" || msg == "reset" || msg == "bye" || msg == "goodbye")
            {
                context.Done("end");
            }
            else
            {
                if (isSessionTimedOut(context))
                {
                    context.Fail(new SessionTimedOutException("Your session has timedout or is invalid."));
                }
                else
                {
                    string fhirserver = null;
                    context.PrivateConversationData.TryGetValue <string>("fhirserver", out fhirserver);
                    string token = null;
                    context.PrivateConversationData.TryGetValue <string>("bearertoken", out token);
                    string patid = null;
                    context.PrivateConversationData.TryGetValue <string>("id", out patid);
                    //Initialize FHIR Client
                    FHIRClient client = new FHIRClient(fhirserver, token);
                    //Determine Intent/Entities from LUIS
                    var luisresp = await LUISClient.RequestAsync <LUISResponse>(activity.Text);

                    var intent = luisresp.topScoringIntent;

                    //Nothing over 50% confidence bail
                    if (intent == null)
                    {
                        await context.PostAsync($"Sorry, I didn't understand {activity.Text}...");
                    }

                    if (intent.intent == "FindPractitioner")
                    {
                        if (luisresp.entities == null || luisresp.entities.Count() == 0)
                        {
                            await context.PostAsync($"Sorry, I think you want to find a practioner but I can't determine the location you want");
                        }
                        //Handle Geography
                        var geo = luisresp.entities.FirstOrDefault();
                        //Call FHIR Server
                        string parm   = geo.entity.ToLower().StartsWith("anywhere") ? "" : $"city={geo.entity}";
                        var    bundle = (Hl7.Fhir.Model.Bundle)client.LoadResource("Practitioner", parm);
                        if (bundle.Entry.Count == 0)
                        {
                            await context.PostAsync($"Sorry, I couldn't find providers in {geo.entity}...");
                        }
                        else
                        {
                            StringBuilder sb = new StringBuilder();
                            sb.Append($"Got {bundle.Entry.Count()} practioners in {geo.entity}\n\n");
                            foreach (var entry in bundle.Entry)
                            {
                                Hl7.Fhir.Model.Practitioner p = (Hl7.Fhir.Model.Practitioner)entry.Resource;
                                var address = (p.Address.Count > 0 ? p.Address[0] : null);
                                var tel     = (p.Telecom.Count > 0 ? p.Telecom[0] : null);
                                sb.Append($"{p.Name[0].Text} is accepting new patients.");
                                if (address != null)
                                {
                                    sb.Append($"Located at " + address.LineElement[0] + " " + address.City);
                                }
                                if (tel != null)
                                {
                                    sb.Append($" Phone:" + tel.Value);
                                }
                                sb.Append("\n\n");
                            }
                            await context.PostAsync(sb.ToString());
                        }
                    }
                    else if (intent.intent == "ChartHeartRate")
                    {
                        var entity = luisresp.FindEntityByType("builtin.number");
                        if (entity != null)
                        {
                            var hr = Convert.ToDecimal(new String(entity.entity.Where(Char.IsDigit).ToArray()));
                            Hl7.Fhir.Model.Observation rv = new Hl7.Fhir.Model.Observation();
                            rv.Status   = Hl7.Fhir.Model.ObservationStatus.Final;
                            rv.Category = new List <Hl7.Fhir.Model.CodeableConcept>();
                            Hl7.Fhir.Model.CodeableConcept cc = new Hl7.Fhir.Model.CodeableConcept("http://hl7.org/fhir/observation-category", "vital-signs", "Vital Signs");
                            rv.Category.Add(cc);
                            rv.Code      = new Hl7.Fhir.Model.CodeableConcept("http://loinc.org", "8867-4", "Heart rate");
                            rv.Subject   = new Hl7.Fhir.Model.ResourceReference("patient/" + patid);
                            rv.Effective = Hl7.Fhir.Model.FhirDateTime.Now();
                            rv.Value     = new Hl7.Fhir.Model.Quantity(hr, "beats/minute");
                            var rslt = client.SaveResource(rv);
                            if (rslt)
                            {
                                await context.PostAsync($"Thanks, I recorded your heart rate of {entity.entity} in your medical record");
                            }
                            else
                            {
                                await context.PostAsync($"Sorry I had a problem posting your heartrate...try again later.");
                            }
                        }
                        else
                        {
                            await context.PostAsync($"Sorry, I think you want to record your heartrate vital but I can't understand the value you provided.");
                        }
                    }
                    else if (intent.intent == "ChartWeight")
                    {
                        string entity_weight = null;
                        var    entity        = luisresp.FindEntityByType("weight");
                        if (entity == null)
                        {
                            entity = luisresp.FindEntityByType("builtin.number");
                            if (entity != null)
                            {
                                entity_weight = entity.entity;
                                var wt = luisresp.FindEntityByType("builtin.dimension");
                                if (wt != null)
                                {
                                    if (wt.entity.ToLower().EndsWith("kilograms") || wt.entity.ToLower().EndsWith("kg"))
                                    {
                                        entity_weight = entity_weight + "kg";
                                    }
                                    else
                                    {
                                        entity_weight = entity_weight + "lbs";
                                    }
                                }
                            }
                        }
                        else
                        {
                            entity_weight = entity.entity;
                        }
                        if (entity_weight != null)
                        {
                            var weight = Convert.ToDecimal(new String(entity_weight.Where(Char.IsDigit).ToArray()));
                            //Determine pounds or kg
                            if (entity_weight.ToLower().EndsWith("kg"))
                            {
                                weight = weight * (decimal)2.20462;
                            }
                            Hl7.Fhir.Model.Observation rv = new Hl7.Fhir.Model.Observation();
                            rv.Status   = Hl7.Fhir.Model.ObservationStatus.Final;
                            rv.Category = new List <Hl7.Fhir.Model.CodeableConcept>();
                            Hl7.Fhir.Model.CodeableConcept cc = new Hl7.Fhir.Model.CodeableConcept("http://hl7.org/fhir/observation-category", "vital-signs", "Vital Signs");
                            rv.Category.Add(cc);
                            rv.Code = new Hl7.Fhir.Model.CodeableConcept("http://loinc.org", "29463-7", "Body Weight");
                            rv.Code.Coding.Add(new Hl7.Fhir.Model.Coding("http://snomed.info/sct", "27113001", "Body Weight"));
                            rv.Subject   = new Hl7.Fhir.Model.ResourceReference("patient/" + patid);
                            rv.Effective = Hl7.Fhir.Model.FhirDateTime.Now();
                            rv.Value     = new Hl7.Fhir.Model.Quantity(weight, "lbs");
                            ((Hl7.Fhir.Model.Quantity)rv.Value).Code = "[lb_av]";
                            var rslt = client.SaveResource(rv);
                            if (rslt)
                            {
                                string weightmsg = "";
                                string parm      = $"patient={patid}";
                                var    bundle    = (Hl7.Fhir.Model.Bundle)client.LoadResource("Observation", parm);
                                List <Hl7.Fhir.Model.Observation> weights = new List <Hl7.Fhir.Model.Observation>();
                                foreach (Hl7.Fhir.Model.Bundle.EntryComponent entry in bundle.Entry)
                                {
                                    Hl7.Fhir.Model.Observation o = (Hl7.Fhir.Model.Observation)entry.Resource;
                                    if (FHIRUtils.isCodeMatch(o.Code.Coding, "http://loinc.org", "29463-7"))
                                    {
                                        weights.Add(o);
                                    }
                                }
                                if (weights.Count > 1)
                                {
                                    Hl7.Fhir.Model.Observation[] sorted = weights.OrderBy(o => Convert.ToDateTime(o.Effective.ToString())).ToArray();
                                    decimal prevw = ((Hl7.Fhir.Model.SimpleQuantity)sorted[sorted.Length - 2].Value).Value.Value;
                                    decimal curw  = ((Hl7.Fhir.Model.SimpleQuantity)sorted[sorted.Length - 1].Value).Value.Value;
                                    decimal dif   = prevw - curw;
                                    if (dif < 0)
                                    {
                                        weightmsg = "Looks like you gained around " + Math.Round(Math.Abs(dif), 1) + " lbs.";
                                    }
                                    else if (dif > 0)
                                    {
                                        weightmsg = "Looks like you loss around " + Math.Round(Math.Abs(dif), 1) + " lbs. Keep it up!!";
                                    }
                                    else
                                    {
                                        weightmsg = "Your weight is holding steady";
                                    }
                                }
                                await context.PostAsync($"Thanks, I recorded your weight of {weight} lbs in your medical record\n\n{weightmsg}");
                            }
                            else
                            {
                                await context.PostAsync($"Sorry I had a problem posting your weight...try again later.");
                            }
                        }
                    }
                    else if (intent.intent == "ChartGlucose")
                    {
                        var entity = luisresp.FindEntityByType("builtin.number");
                        if (entity != null)
                        {
                            var glucose = Convert.ToDecimal(new String(entity.entity.Where(Char.IsDigit).ToArray()));
                            var unit    = "mg/dL";
                            Hl7.Fhir.Model.CodeableConcept loinc = new Hl7.Fhir.Model.CodeableConcept("http://loinc.org", "2345-7", "Glucose [Mass/​volume] in Serum or Plasma");
                            //convert mg/DL if mmol/l
                            if (glucose < 20)
                            {
                                glucose = glucose * 18;
                            }
                            Hl7.Fhir.Model.Observation rv = new Hl7.Fhir.Model.Observation();
                            rv.Status   = Hl7.Fhir.Model.ObservationStatus.Final;
                            rv.Category = new List <Hl7.Fhir.Model.CodeableConcept>();
                            Hl7.Fhir.Model.CodeableConcept cc = new Hl7.Fhir.Model.CodeableConcept("http://hl7.org/fhir/observation-category", "laboratory", "Laboratory");
                            rv.Category.Add(cc);
                            rv.Code           = loinc;
                            rv.Subject        = new Hl7.Fhir.Model.ResourceReference("patient/" + patid);
                            rv.Effective      = Hl7.Fhir.Model.FhirDateTime.Now();
                            rv.Issued         = DateTimeOffset.UtcNow;
                            rv.ReferenceRange = new List <Hl7.Fhir.Model.Observation.ReferenceRangeComponent>();
                            Hl7.Fhir.Model.Observation.ReferenceRangeComponent rrc = new Hl7.Fhir.Model.Observation.ReferenceRangeComponent();
                            rrc.High        = new Hl7.Fhir.Model.SimpleQuantity();
                            rrc.High.Unit   = "mg/dL";
                            rrc.High.Code   = rrc.High.Unit;
                            rrc.High.System = "http://unitsofmeasure.org";
                            rrc.High.Value  = 140;
                            rrc.Low         = new Hl7.Fhir.Model.SimpleQuantity();
                            rrc.Low.Unit    = "mg/dL";
                            rrc.Low.Code    = rrc.Low.Unit;
                            rrc.Low.System  = "http://unitsofmeasure.org";
                            rrc.Low.Value   = 70;
                            rv.ReferenceRange.Add(rrc);
                            rv.Value = new Hl7.Fhir.Model.Quantity(glucose, unit);
                            ((Hl7.Fhir.Model.Quantity)rv.Value).Code = unit;
                            var rslt = client.SaveResource(rv);
                            if (rslt)
                            {
                                int     numglucose = 0;
                                string  parm       = $"patient={patid}";
                                var     bundle     = (Hl7.Fhir.Model.Bundle)client.LoadResource("Observation", parm);
                                decimal bga        = 0;
                                foreach (Hl7.Fhir.Model.Bundle.EntryComponent entry in bundle.Entry)
                                {
                                    Hl7.Fhir.Model.Observation o = (Hl7.Fhir.Model.Observation)entry.Resource;
                                    if (FHIRUtils.isCodeMatch(o.Code.Coding, "http://loinc.org", "2345-7"))
                                    {
                                        bga = bga + ((Hl7.Fhir.Model.SimpleQuantity)o.Value).Value.Value;
                                        numglucose++;
                                    }
                                }
                                bga = Math.Round(bga / numglucose, 1);
                                decimal a1c   = ((Convert.ToDecimal(46.7) + bga) / Convert.ToDecimal(28.7));
                                string  bgmsg = $"Your blood glucose is averaging {bga}  mg/dL " + (bga > 140 ? "looks like it's running high" : (bga < 70 ? "looks like it's running low" : ""));
                                bgmsg = bgmsg + "\n\nYour estimated A1C is " + Convert.ToString(Math.Round(a1c, 1));

                                await context.PostAsync($"Thanks, I recorded your blood glucose of {glucose} mg/dL in your medical record\n\n{bgmsg}");
                            }
                            else
                            {
                                await context.PostAsync($"Sorry I had a problem posting your blood glucose...you can try again later.");
                            }
                        }
                        else
                        {
                            await context.PostAsync($"Sorry, I couldnt determine your blood glucose value...try again");
                        }
                    }
                    else if (intent.intent == "DisplayGlucose")
                    {
                        int      numglucose = 0;
                        string   parm       = $"patient={patid}";
                        var      bundle     = (Hl7.Fhir.Model.Bundle)client.LoadResource("Observation", parm);
                        decimal  bga        = 0;
                        decimal  la1c       = 0;
                        decimal  ea1c       = 0;
                        DateTime?dta1c      = null;
                        foreach (Hl7.Fhir.Model.Bundle.EntryComponent entry in bundle.Entry)
                        {
                            Hl7.Fhir.Model.Observation o = (Hl7.Fhir.Model.Observation)entry.Resource;
                            if (FHIRUtils.isCodeMatch(o.Code.Coding, "http://loinc.org", "2345-7"))
                            {
                                bga = bga + ((Hl7.Fhir.Model.SimpleQuantity)o.Value).Value.Value;
                                numglucose++;
                            }
                            else if (FHIRUtils.isCodeMatch(o.Code.Coding, "http://loinc.org", "4548-4"))
                            {
                                la1c  = ((Hl7.Fhir.Model.SimpleQuantity)o.Value).Value.Value;
                                dta1c = Convert.ToDateTime(o.Effective.ToString());
                            }
                        }
                        if (numglucose > 0)
                        {
                            bga  = Math.Round(bga / numglucose, 1);
                            ea1c = ((Convert.ToDecimal(46.7) + bga) / Convert.ToDecimal(28.7));
                        }
                        string a1cmsg = "I don't see any A1C tests on file for you.";
                        string bgmsg  = "I don't see any blood glucose tests on file for you.";
                        if (la1c > 0)
                        {
                            a1cmsg = $"Your last A1C test was on " + String.Format("{0:MM/dd/yyyy}", dta1c.Value) + " the result was " + Convert.ToString(la1c) + "% " + (la1c > 6 ? "thats high" : "");
                        }
                        if (bga > 0)
                        {
                            bgmsg = $"Your blood glucose is averaging {bga}  mg/dL " + (bga > 140 ? "looks like it's running high" : (bga < 70 ? "looks like it's running low" : ""));
                            bgmsg = bgmsg + "\n\nYour current estimated A1C is " + Convert.ToString(Math.Round(ea1c, 1)) + (ea1c < 6 ? " great control!" : (ea1c <= 7 ? " doing good for a diabetic!" : " need to work at lowering!"));
                        }
                        await context.PostAsync($"{a1cmsg}\n\n{bgmsg}");
                    }
                    else if (intent.intent == "DisplayCareplan")
                    {
                        //Call FHIR Server
                        string parm   = $"patient={patid}";
                        var    bundle = (Hl7.Fhir.Model.Bundle)client.LoadResource("CarePlan", parm);
                        if (bundle.Entry.Count == 0)
                        {
                            await context.PostAsync($"Sorry, I couldn't find a plan of care for you in the database...");
                        }
                        else
                        {
                            StringBuilder sb = new StringBuilder();
                            sb.Append("Your current plan of care addresses the following conditions:\n\n");
                            Hl7.Fhir.Model.CarePlan cp = (Hl7.Fhir.Model.CarePlan)bundle.Entry[0].Resource;
                            int x = 1;
                            foreach (var cond in cp.Addresses)
                            {
                                sb.Append(x++ + ". " + cond.Display + "\n\n");
                            }
                            sb.Append("\n\nYou have the following goals:\n\n");
                            x = 1;
                            foreach (var goal in cp.Goal)
                            {
                                sb.Append(x++ + ". " + goal.Display + "\n\n");
                            }
                            sb.Append("\n\nYou should:\n\n");
                            x = 1;
                            foreach (var act in cp.Activity)
                            {
                                if (act.Detail != null)
                                {
                                    sb.Append(x++ + ". " + act.Detail.Description + "\n\n");
                                }
                                else
                                {
                                    if (act.Reference != null && act.Reference.Reference.StartsWith("MedicationRequest"))
                                    {
                                        sb.Append(x++ + ". Take " + act.Reference.Display + " as directed.\n\n");
                                    }
                                }
                            }
                            await context.PostAsync(sb.ToString());
                        }
                    }
                    else
                    {
                        await context.PostAsync($"Sorry, I didn't understand {activity.Text}...");
                    }
                }
                context.Wait(MessageReceivedAsync);
            }
        }
Ejemplo n.º 6
0
        /* Opt-out: Default is for health information of patients to be included automatically, but the patient can opt out completely.
         * Note: This is an access only policy, it does not prevent updates to the medical record as these could be valid */
        public async Task <ProxyProcessResult> Process(FHIRResponse response, HttpRequest req, ILogger log, ClaimsPrincipal principal, string res, string id, string hist, string vid)
        {
            FHIRResponse fr = response;

            if (!req.Method.Equals("GET"))
            {
                return(new ProxyProcessResult(true, "", "", fr));
            }
            //Load the consent category code from settings
            string consent_category = System.Environment.GetEnvironmentVariable("FP-MOD-CONSENT-OPTOUT-CATEGORY");

            if (string.IsNullOrEmpty(consent_category))
            {
                log.LogWarning("ConsentOptOutFilter: No value for FP-MOD-CONSENT-OPTOUT-CATEGORY in settings...Filter will not execute");
                return(new ProxyProcessResult(true, "", "", fr));
            }
            if (fr == null || fr.Content == null || string.IsNullOrEmpty(fr.Content.ToString()))
            {
                log.LogInformation("ConsentOptOutFilter: No FHIR Response found in context...Nothing to filter");
                return(new ProxyProcessResult(true, "", "", fr));
            }
            JObject result = JObject.Parse(fr.ToString());

            //Administrator is allowed access
            if (Utils.inServerAccessRole(req, "A"))
            {
                return(new ProxyProcessResult(true, "", "", fr));
            }
            ClaimsIdentity ci     = (ClaimsIdentity)principal.Identity;
            string         aadten = ci.Tenant();
            string         name   = principal.Identity.Name;
            //We'll need FHIRClient to check server
            FHIRClient    fhirClient   = FHIRClientFactory.getClient(log);
            var           cache        = Utils.RedisConnection.GetDatabase();
            List <string> associations = ((string)cache.StringGet($"{ASSOCIATION_CACHE_PREFIX}{aadten}-{name}")).DeSerializeList <string>();

            if (associations == null)
            {
                //Load Associations if not in cache
                associations = new List <string>();
                var table = Utils.getTable();
                //Practioner
                var practitioner = Utils.getLinkEntity(table, "Practitioner", aadten + "-" + name);
                if (practitioner != null)
                {
                    associations.Add(practitioner.PartitionKey + "/" + practitioner.LinkedResourceId);
                    //Load organization from PractionerRoles
                    var prs = await fhirClient.LoadResource("PractitionerRole", "practitioner=" + practitioner.LinkedResourceId, true, req.Headers);

                    var ro = (JObject)prs.Content;
                    if (ro.FHIRResourceType().Equals("Bundle"))
                    {
                        JArray entries = (JArray)ro["entry"];
                        if (!entries.IsNullOrEmpty())
                        {
                            foreach (JToken tok in entries)
                            {
                                associations.Add(tok["resource"].FHIRReferenceId());
                                if (!tok["resource"]["organization"].IsNullOrEmpty() && !tok["resource"]["organization"]["reference"].IsNullOrEmpty())
                                {
                                    associations.Add((string)tok["resource"]["organization"]["reference"]);
                                }
                            }
                        }
                    }
                }
                //RealtedPerson
                var related = Utils.getLinkEntity(table, "RelatedPerson", aadten + "-" + name);
                if (related != null)
                {
                    associations.Add(related.PartitionKey + "/" + related.LinkedResourceId);
                }

                cache.StringSet($"{ASSOCIATION_CACHE_PREFIX}{aadten}-{name}", associations.Distinct().ToList().SerializeList(), TimeSpan.FromMinutes(Utils.GetIntEnvironmentVariable("CONSENT_CACHE_TTL_MINUTES", "60")));
            }

            //Loop through results load any consent records and validate no opt-out default is to allow
            if (result.FHIRResourceType().Equals("Bundle"))
            {
                JArray entries = (JArray)result["entry"];
                if (!entries.IsNullOrEmpty())
                {
                    foreach (JToken tok in entries)
                    {
                        if (await denyAccess(tok["resource"], fhirClient, cache, associations, consent_category, req.Headers))
                        {
                            JObject denyObj = new JObject();
                            denyObj["resourceType"]   = tok["resource"].FHIRResourceType();
                            denyObj["id"]             = tok["resource"].FHIRResourceId();
                            denyObj["text"]           = new JObject();
                            denyObj["text"]["status"] = "generated";
                            denyObj["text"]["div"]    = "<div xmlns =\"http://www.w3.org/1999/xhtml\"><p>Patient has withheld access to this resource</p></div>";
                            tok["resource"]           = denyObj;
                        }
                    }
                }
            }
            else if (!result.FHIRResourceType().Equals("OperationalOutcome"))
            {
                if (await denyAccess(result, fhirClient, cache, associations, consent_category, req.Headers))
                {
                    fr.Content    = Utils.genOOErrResponse("access-denied", $"The patient has withheld access to this resource: {res + (id == null ? "" : "/" + id)}");
                    fr.StatusCode = System.Net.HttpStatusCode.Unauthorized;
                    return(new ProxyProcessResult(false, "access-denied", "", fr));
                }
            }
            fr.Content = result.ToString();
            return(new ProxyProcessResult(true, "", "", fr));
        }
Ejemplo n.º 7
0
        private async Task <bool> denyAccess(JToken resource, FHIRClient fhirclient, IDatabase cache, List <string> associations, string consentcat, IHeaderDictionary headers)
        {
            string patientId = null;
            string rt        = resource.FHIRResourceType();

            //Check for Patient resource or load patient resource id from subject/patient member
            if (rt.Equals("Patient"))
            {
                patientId = rt + "/" + (string)resource["id"];
            }
            if (patientId == null)
            {
                patientId = (string)resource?["subject"]?["reference"];
                if (string.IsNullOrEmpty(patientId) || !patientId.StartsWith("Patient"))
                {
                    patientId = (string)resource?["patient"]?["reference"];
                }
            }
            //If no patient id present assume not tied to patient do not filter;
            if (string.IsNullOrEmpty(patientId))
            {
                return(false);
            }
            //Load Cache if needed
            List <string> denyactors = ((string)cache.StringGet($"{PATIENT_DENY_ACTORS_PREFIX}{patientId}")).DeSerializeList <string>();

            if (denyactors == null)
            {
                //Fetch and Cache Deny access Consent Information
                var pid         = patientId.Split("/")[1];
                var consentrecs = await fhirclient.LoadResource("Consent", "patient=" + pid + "&category=" + consentcat, true, headers);

                var result = (JObject)consentrecs.Content;
                if (result.FHIRResourceType().Equals("Bundle"))
                {
                    JArray entries = (JArray)result["entry"];
                    if (!entries.IsNullOrEmpty())
                    {
                        denyactors = new List <string>();
                        foreach (JToken tok in entries)
                        {
                            var r = tok["resource"];
                            if (!r["provision"].IsNullOrEmpty())
                            {
                                //Check enforceemnt period
                                if (isEnforced(r["provision"]["period"]))
                                {
                                    string type = (string)r["provision"]["type"];
                                    //Load deny provisions only

                                    if (type != null && type.Equals("deny"))
                                    {
                                        //Load actor references to deny
                                        JArray actors = (JArray)r["provision"]["actors"];
                                        if (!actors.IsNullOrEmpty())
                                        {
                                            foreach (JToken actor in actors)
                                            {
                                                denyactors.Add((string)actor["reference"]);
                                            }
                                        }
                                        else
                                        {
                                            //Nobody specified so everybody is denied access this trumps all opt out advise
                                            denyactors.Clear();
                                            denyactors.Add("*");
                                            break;
                                        }
                                    }
                                }
                            }
                        }
                    }
                    else
                    {
                        denyactors = new List <string>();
                    }
                    cache.StringSet($"{PATIENT_DENY_ACTORS_PREFIX}{patientId}", denyactors.Distinct().ToList().SerializeList(), TimeSpan.FromHours(Utils.GetIntEnvironmentVariable("CONSENT_CACHE_TTL_MINUTES", "60")));
                }
            }
            //If there is an empty actor array that means there is no deny provision specified so return false to allow access
            if (denyactors.Count == 0)
            {
                return(false);
            }
            //It there is a wildcard in first entry then everyone is denied return true
            if (denyactors.First().Equals("*"))
            {
                return(true);
            }
            //Check for intersection of denied actors and associations of current user if found access will be denied
            return(associations.Select(x => x)
                   .Intersect(denyactors)
                   .Any());
        }
        public async Task <ProxyProcessResult> Process(FHIRResponse response, HttpRequest req, ILogger log, ClaimsPrincipal principal, string res, string id, string hist, string vid)
        {
            FHIRResponse fr = response;

            if (!req.Method.Equals("GET"))
            {
                return(new ProxyProcessResult(true, "", "", fr));
            }
            JObject result = (fr == null ? null : JObject.Parse(fr.ToString()));

            if (fr == null)
            {
                log.LogInformation("ParticipantFilter: No FHIR Response found in context");
                return(new ProxyProcessResult());
            }

            //Needed Variables
            ClaimsIdentity ci     = (ClaimsIdentity)principal.Identity;
            string         aadten = ci.Tenant();
            string         name   = principal.Identity.Name;

            bool          admin = Utils.inServerAccessRole(req, "A");
            List <string> resourceidentities = new List <string>();
            List <string> inroles            = ci.Roles();
            List <string> fhirresourceroles  = new List <string>();

            fhirresourceroles.AddRange(Environment.GetEnvironmentVariable("FP-PARTICIPANT-ACCESS-ROLES").Split(","));
            fhirresourceroles.AddRange(Environment.GetEnvironmentVariable("FP-PATIENT-ACCESS-ROLES").Split(","));
            Dictionary <string, bool> porcache = new Dictionary <string, bool>();
            FHIRClient fhirClient = FHIRClientFactory.getClient(log);
            var        table      = Utils.getTable();

            //Load linked Resource Identifiers from linkentities table for each known role the user is in
            foreach (string r in inroles)
            {
                if (fhirresourceroles.Any(r.Equals))
                {
                    var entity = Utils.getLinkEntity(table, r, aadten + "-" + name);
                    if (entity != null)
                    {
                        resourceidentities.Add(r + "/" + entity.LinkedResourceId);
                    }
                }
            }
            if (!admin && !ci.IsInFHIRRole(Environment.GetEnvironmentVariable("FP-GLOBAL-ACCESS-ROLES")))
            {
                if (((string)result["resourceType"]).Equals("Bundle"))
                {
                    JArray entries = (JArray)result["entry"];
                    if (!entries.IsNullOrEmpty())
                    {
                        foreach (JToken entry in entries)
                        {
                            if (!await IsAParticipantOrPatient(entry["resource"], fhirClient, resourceidentities, porcache, req.Headers))
                            {
                                JObject denyObj = new JObject();
                                denyObj["resourceType"]   = entry["resource"].FHIRResourceType();
                                denyObj["id"]             = entry["resource"].FHIRResourceId();
                                denyObj["text"]           = new JObject();
                                denyObj["text"]["status"] = "generated";
                                denyObj["text"]["div"]    = "<div xmlns =\"http://www.w3.org/1999/xhtml\"><p>You do not have access to data contained in this resource</p></div>";
                                entry["resource"]         = denyObj;
                            }
                        }
                    }
                }
                else if (!((string)result["resourceType"]).Equals("OperationalOutcome"))
                {
                    if (!await IsAParticipantOrPatient(result, fhirClient, resourceidentities, porcache, req.Headers))
                    {
                        fr.Content    = Utils.genOOErrResponse("access-denied", $"You are not an authorized Paticipant in care and cannot access this resource: {res + (id == null ? "" : "/" + id)}");
                        fr.StatusCode = System.Net.HttpStatusCode.Unauthorized;
                        return(new ProxyProcessResult(false, "access-denied", "", fr));
                    }
                }
            }
            fr.Content = result.ToString();
            return(new ProxyProcessResult(true, "", "", fr));
        }
        private static async Task <bool> IsAParticipantOrPatient(JToken resource, FHIRClient fhirClient, IEnumerable <string> knownresourceIdentities, Dictionary <string, bool> porcache, IHeaderDictionary auditheaders)
        {
            string patientId   = null;
            string encounterId = null;
            JToken patient     = null;
            JToken encounter   = null;

            string rt = (string)resource["resourceType"];

            //Check for Patient resource or load patient resource from subject member
            if (rt.Equals("Patient"))
            {
                patient   = resource;
                patientId = rt + "/" + (string)resource["id"];
            }
            if (patient == null)
            {
                patientId = (string)resource?["subject"]?["reference"];
                if (string.IsNullOrEmpty(patientId))
                {
                    patientId = (string)resource?["patient"]?["reference"];
                }
            }
            if (rt.Equals("Encounter"))
            {
                encounter   = resource;
                encounterId = rt + "/" + (string)resource["id"];
                patientId   = (string)resource?["subject"]?["reference"];
            }
            if (encounter == null)
            {
                encounterId = (string)resource?["encounter"]?["reference"];
            }
            //If no patient or encounter records present assume not tied to patient do not filter;
            if (patientId == null && encounterId == null)
            {
                return(true);
            }
            //See if patientId is in POR Cache
            if (!string.IsNullOrEmpty(patientId) && porcache.ContainsKey(patientId))
            {
                return(porcache[patientId]);
            }
            if (!string.IsNullOrEmpty(encounterId) && porcache.ContainsKey(encounterId))
            {
                return(porcache[encounterId]);
            }
            //Load the patient if needed
            if (patient == null)
            {
                if (!string.IsNullOrEmpty(patientId))
                {
                    var pat = await fhirClient.LoadResource(patientId, null, false, auditheaders);

                    JObject temp = JObject.Parse((string)pat.Content);
                    if (temp != null && ((string)temp["resourceType"]).Equals("Patient"))
                    {
                        patient = temp;
                    }
                    else
                    {
                        porcache[patientId] = false;
                        return(false);
                    }
                }
                else if (!string.IsNullOrEmpty(encounterId) && patient == null)
                {
                    var enc = await fhirClient.LoadResource(encounterId, null, false, auditheaders);

                    if (enc != null)
                    {
                        JObject temp = JObject.Parse((string)enc.Content);
                        if (temp != null && ((string)temp["resourceType"]).Equals("Encounter") && (string)temp["subject"]?["reference"] != null)
                        {
                            patientId = (string)temp["subject"]?["reference"];
                            var pat = await fhirClient.LoadResource(patientId, null, false, auditheaders);

                            JObject temp1 = JObject.Parse((string)pat.Content);
                            if (temp1 != null && ((string)temp1["resourceType"]).Equals("Patient"))
                            {
                                patient = temp1;
                            }
                            else
                            {
                                porcache[patientId] = false;
                                return(false);
                            }
                        }
                        else
                        {
                            porcache[encounterId] = false;
                            return(false);
                        }
                    }
                }
                else
                {
                    //Cannot Determine/Find a Patient or Encounter reference assume it's not a patient reference
                    return(true);
                }
            }


            foreach (string rid in knownresourceIdentities)
            {
                if (rid.StartsWith("Patient"))
                {
                    string pid = rid;
                    if (pid.Equals(patientId))
                    {
                        porcache[patientId] = true;
                        if (!string.IsNullOrEmpty(encounterId))
                        {
                            porcache[encounterId] = true;
                        }
                        return(true);
                    }
                }
                else if (rid.StartsWith("Practitioner"))
                {
                    if (patient["generalPractitioner"] != null)
                    {
                        var gp_s = from gp in patient["generalPractitioner"]
                                   where (string)gp["reference"] == rid
                                   select(string) gp["reference"];

                        if (gp_s != null && gp_s.Count() > 0)
                        {
                            porcache[patientId] = true;
                            if (!string.IsNullOrEmpty(encounterId))
                            {
                                porcache[encounterId] = true;
                            }
                            return(true);
                        }
                    }
                    string pid     = rid.Split("/")[1];
                    string patid   = (string)patient["id"];
                    var    porencs = await fhirClient.LoadResource("Encounter", $"patient={patid}&participant={pid}", false, auditheaders);

                    if (porencs != null)
                    {
                        JObject temp2 = JObject.Parse((string)porencs.Content);
                        if (temp2 != null && ((string)temp2["resourceType"]).Equals("Bundle"))
                        {
                            JArray entries = (JArray)temp2["entry"];
                            if (entries != null && entries.Count > 0)
                            {
                                porcache[patientId] = true;
                                if (!string.IsNullOrEmpty(encounterId))
                                {
                                    porcache[encounterId] = true;
                                }
                                return(true);
                            }
                        }
                    }
                }
            }
            porcache[patientId] = false;
            if (!string.IsNullOrEmpty(encounterId))
            {
                porcache[encounterId] = false;
            }
            return(false);
        }
Ejemplo n.º 10
0
        private async Task MessageReceivedAsync(IDialogContext context, IAwaitable <object> result)
        {
            var    activity = await result as Activity;
            string msg      = activity.Text.Trim().ToLower();

            if (msg == "start over" || msg == "exit" || msg == "quit" || msg == "done" || msg == "start again" || msg == "restart" || msg == "leave" || msg == "reset" || msg == "bye" || msg == "goodbye")
            {
                context.PrivateConversationData.Clear();
                await context.PostAsync($"Ending your session...Dont' forget to delete your conversation for privacy!");

                context.Done("");
            }
            else
            {
                model.Patient pat = null;
                // Within the code body set your variable
                string     fhirserver       = CloudConfigurationManager.GetSetting("FHIRServerAddress");
                string     fhirtenant       = CloudConfigurationManager.GetSetting("FHIRAADTenant");
                string     fhirclientid     = CloudConfigurationManager.GetSetting("FHIRClientId");
                string     fhirclientsecret = CloudConfigurationManager.GetSetting("FHIRClientSecret");
                FHIRClient fhirclient       = new FHIRClient(fhirserver, fhirtenant, fhirclientid, fhirclientsecret);
                var        rslt             = (model.Bundle)fhirclient.LoadResource("Patient", "identifier=http://fhirbot.org|" + activity.Text.Trim());
                if (rslt != null && rslt.Entry != null && rslt.Entry.Count > 0)
                {
                    pat = (model.Patient)rslt.Entry.FirstOrDefault().Resource;
                    if (pat != null)
                    {
                        var fbid = pat.Identifier.Single(ident => ident.System == "http://fhirbot.org");
                        if (fbid != null)
                        {
                            var period = fbid.Period;
                            var now    = model.FhirDateTime.Now();
                            if (period != null && (now > period.EndElement))
                            {
                                //Use Period Expired remove the token from the patient and update db
                                pat.Identifier.Remove(fbid);
                                fhirclient.SaveResource(pat);
                                pat = null;
                                context.PrivateConversationData.Clear();
                            }
                        }
                    }
                }
                if (pat != null)
                {
                    // Set BotUserData
                    context.PrivateConversationData.SetValue <string>(
                        "id", pat.Id);
                    context.PrivateConversationData.SetValue <string>(
                        "name", pat.Name[0].Text);
                    context.PrivateConversationData.SetValue <DateTime?>(
                        "sessionstart", DateTime.Now);
                    context.PrivateConversationData.SetValue <string>("bearertoken", fhirclient.BearerToken);
                    context.PrivateConversationData.SetValue <string>("fhirserver", fhirserver);
                    context.Done(pat.Name[0].Text);
                }
                else
                {
                    context.Fail(new InvalidPINException("Not a valid PIN Code"));
                }
            }
        }