Exemple #1
0
        public async Task <Resource> Get <T>(FhirRequest request) where T : Resource
        {
            ValidateResource(request.StrResourceType);

            request.ProfileUri = _resourceProfile;

            return(await _fhirSearch.Get <T>(request));
        }
        public async Task <Resource> Get(FhirRequest request)
        {
            ValidateResource(request.StrResourceType);

            request.ProfileUri = _resourceProfile;

            return(await _fhirSearch.Get <Organization>(request));
        }
        /// <summary>
        /// Get a DocumentReference by id
        /// </summary>
        /// <remarks>
        /// Get a single DocumentReference using the DocRef logical id
        /// </remarks>
        public async Task <Resource> Get(FhirRequest request)
        {
            ValidateResource(request.StrResourceType);

            request.ProfileUri = _resourceProfile;

            var result = await _fhirSearch.Get <DocumentReference>(request);

            return(result);
        }
        public async SystemTasks.Task <Resource> ValidateConditionalUpdate(FhirRequest request)
        {
            if (!request.Resource.ResourceType.Equals(ResourceType.DocumentReference))
            {
                return(OperationOutcomeFactory.CreateInvalidResource("relatesTo"));
            }

            var document = request.Resource as DocumentReference;

            var relatesTo = _fhirValidation.GetValidRelatesTo(document.RelatesTo);

            if (document.RelatesTo.Count == 0)
            {
                //skip checks, request is just a standard create
                return(null);
            }
            else if (relatesTo.element == null)
            {
                return(OperationOutcomeFactory.CreateInvalidResource(relatesTo.issue));
            }

            //Subject already validated during ValidateCreate
            //relatesTo Reference/Identifier already validated during ValidateCreate => validPointer

            var isRelatesToReference = !string.IsNullOrWhiteSpace(relatesTo.element.Target.Reference);

            FhirRequest       pointerRequest = null;
            DocumentReference oldDocument    = null;

            if (isRelatesToReference)
            {
                var pointerId = _fhirValidation.GetReferenceId(relatesTo.element.Target);
                pointerRequest = NrlsPointerHelper.CreateReferenceSearch(request, pointerId);
                oldDocument    = await _fhirSearch.Get <DocumentReference>(pointerRequest);
            }
            else
            {
                var subjectNhsNumber = _fhirValidation.GetSubjectReferenceId(document.Subject);
                pointerRequest = NrlsPointerHelper.CreateMasterIdentifierSearch(request, relatesTo.element.Target.Identifier, subjectNhsNumber);
                var pointers = await _fhirSearch.Find <DocumentReference>(pointerRequest);

                //There should only ever be zero or one
                oldDocument = pointers.Entry.FirstOrDefault()?.Resource as DocumentReference;
            }

            if (oldDocument == null)
            {
                //Cant find related document
                return(OperationOutcomeFactory.CreateInvalidResource("relatesTo.target", "Referenced DocumentReference does not exist."));
            }

            //related document does not have same patient
            if (string.IsNullOrEmpty(oldDocument.Subject.Reference) || oldDocument.Subject.Reference != document.Subject.Reference)
            {
                return(OperationOutcomeFactory.CreateInvalidResource("relatesTo.target", "Resolved DocumentReference is not associated with the same patient."));
            }

            //Reference type checks
            if (isRelatesToReference)
            {
                //related document does not have masterIdentifier or masterIdentifier does not match new
                var docRelatesToIdentifier = document.RelatesTo.First().Target.Identifier;
                if (docRelatesToIdentifier != null)
                {
                    var oldDocRelatesToIdentifier = oldDocument.MasterIdentifier;

                    if (oldDocRelatesToIdentifier == null)
                    {
                        return(OperationOutcomeFactory.CreateInvalidResource("relatesTo.target", "Resolved DocumentReference does not have an MasterIdentifier."));
                    }

                    if (string.IsNullOrWhiteSpace(docRelatesToIdentifier.System) || string.IsNullOrWhiteSpace(docRelatesToIdentifier.Value) ||
                        docRelatesToIdentifier.Value != oldDocRelatesToIdentifier.Value || docRelatesToIdentifier.System != oldDocRelatesToIdentifier.System)
                    {
                        return(OperationOutcomeFactory.CreateInvalidResource("relatesTo.target", "Resolved DocumentReference does not have a matching MasterIdentifier."));
                    }
                }
            }

            //Custodian already validated against incoming ASID during ValidateCreate
            var custodianOdsCode = _fhirValidation.GetOrganizationReferenceId(document.Custodian);

            if (oldDocument.Custodian == null || string.IsNullOrEmpty(oldDocument.Custodian.Reference) || oldDocument.Custodian.Reference != $"{FhirConstants.SystemODS}{custodianOdsCode}")
            {
                //related document does not have same custodian
                return(OperationOutcomeFactory.CreateInvalidResource("relatesTo.target", $"Resolved DocumentReference is not associated with custodian {custodianOdsCode}"));
            }

            if (oldDocument.Status != DocumentReferenceStatus.Current)
            {
                //Only allowed to transition to superseded from current
                return(OperationOutcomeFactory.CreateInactiveDocumentReference());
            }

            return(oldDocument);
        }
Exemple #5
0
        /// <summary>
        /// Delete a DocumentReference using the id value found in the request _id query parameter
        /// </summary>
        /// <remarks>
        /// First we do a search to get the document, then we check the incoming ASID associated OrgCode against the custodian on the document.
        /// If valid we can delete.
        /// We use the FhirMaintain service and FhirSearch service to facilitate this
        /// </remarks>
        public async SystemTasks.Task <OperationOutcome> Delete <T>(FhirRequest request) where T : Resource
        {
            ValidateResource(request.StrResourceType);

            request.ProfileUri = _resourceProfile;

            // NRLS Layers of validation before Fhir Delete Call
            var id         = request.IdParameter;
            var identifier = request.IdentifierParameter;
            var subject    = request.SubjectParameter;

            if (string.IsNullOrEmpty(id) && _fhirValidation.ValidateIdentifierParameter("identifier", identifier) != null && _fhirValidation.ValidatePatientParameter(subject) != null)
            {
                throw new HttpFhirException("Missing or Invalid _id parameter", OperationOutcomeFactory.CreateInvalidParameter("Invalid parameter: _id"), HttpStatusCode.BadRequest);
            }

            if (string.IsNullOrEmpty(id) && _fhirValidation.ValidateIdentifierParameter("identifier", identifier) == null && _fhirValidation.ValidatePatientParameter(subject) != null)
            {
                throw new HttpFhirException("Missing or Invalid subject parameter", OperationOutcomeFactory.CreateInvalidParameter("Invalid parameter: subject"), HttpStatusCode.BadRequest);
            }

            if (string.IsNullOrEmpty(id) && _fhirValidation.ValidateIdentifierParameter("identifier", identifier) != null && _fhirValidation.ValidatePatientParameter(subject) == null)
            {
                throw new HttpFhirException("Missing or Invalid identifier parameter", OperationOutcomeFactory.CreateInvalidParameter("Invalid parameter: identifier"), HttpStatusCode.BadRequest);
            }


            request.Id = id;

            Resource document;

            if (!string.IsNullOrEmpty(id))
            {
                ObjectId mongoId;

                if (!ObjectId.TryParse(id, out mongoId))
                {
                    throw new HttpFhirException("Invalid _id parameter", OperationOutcomeFactory.CreateInvalidParameter("Invalid parameter", $"The Logical ID format does not apply to the given Logical ID - {id}"), HttpStatusCode.BadRequest);
                }

                document = await _fhirSearch.Get <T>(request);
            }
            else
            {
                document = await _fhirSearch.GetByMasterId <T>(request);
            }

            var documentResponse = ParseRead(document, id);

            if (documentResponse.ResourceType == ResourceType.Bundle)
            {
                var result = documentResponse as Bundle;

                if (!result.Total.HasValue || result.Total.Value < 1 || result.Entry.FirstOrDefault() == null)
                {
                    return(OperationOutcomeFactory.CreateNotFound(id));
                }

                var orgDocument = result.Entry.FirstOrDefault().Resource as DocumentReference;

                var orgCode = _fhirValidation.GetOrganizationReferenceId(orgDocument.Custodian);

                var invalidAsid = InvalidAsid(orgCode, request.RequestingAsid, false);

                if (invalidAsid != null)
                {
                    return(invalidAsid);
                }
            }
            else
            {
                return(documentResponse as OperationOutcome);
            }

            bool deleted;

            if (!string.IsNullOrEmpty(id))
            {
                deleted = await _fhirMaintain.Delete <T>(request);
            }
            else
            {
                //Add identifier on the fly as it is not a standard search parameter
                request.AllowedParameters = request.AllowedParameters.Concat(new[] { "identifier" }).ToArray();

                deleted = await _fhirMaintain.DeleteConditional <T>(request);
            }

            if (!deleted)
            {
                return(OperationOutcomeFactory.CreateNotFound(request.Id));
            }

            return(OperationOutcomeFactory.CreateDelete(request.RequestUrl?.AbsoluteUri, request.AuditId));
        }
        /// <summary>
        /// Search for Documents or Get one by _id
        /// </summary>
        /// <remarks>
        /// As the NRLS is implemented with just a search and not read, to read a document the _id parameter is supplied
        /// </remarks>
        public async Task<Resource> Find<T>(FhirRequest request) where T : Resource
        {
            ValidateResource(request.StrResourceType);

            request.ProfileUri = _resourceProfile;

            var id = request.IdParameter;

            //We are going to be strict hear for search and only proceed if we have valid parameters
            if(request.InvalidParameters.Count() > 0)
            {
                throw new HttpFhirException("Invalid parameters", OperationOutcomeFactory.CreateInvalidParameter($"Invalid parameter: {string.Join(", ", request.InvalidParameters)}"), HttpStatusCode.BadRequest);
            }

            //If we have an _id param it should be the only param so check for that here.
            if (request.HasIdParameter)
            {
                ObjectId mongoId;
                if (!ObjectId.TryParse(id, out mongoId))
                {
                    return OperationOutcomeFactory.CreateNotFound("");
                }

                if (request.QueryParameters.Count() > 1)
                {
                    throw new HttpFhirException("Invalid _id parameter", OperationOutcomeFactory.CreateInvalidParameter("Invalid parameter: _id"), HttpStatusCode.BadRequest);
                }

                request.Id = id;

                var results = await _fhirSearch.Get<T>(request);

                var response = ParseRead(results, id);

                return response;
            }

            //If we are here then it is a standard search query
            var patient = request.QueryParameters.FirstOrDefault(x => x.Item1 == "subject");

            if (patient != null)
            {
                var invalidPatient = _fhirValidation.ValidatePatientParameter(patient.Item2);

                if (invalidPatient != null)
                {
                    throw new HttpFhirException("Missing or Invalid patient parameter", invalidPatient, HttpStatusCode.BadRequest);
                }
            }
            else
            {
                throw new HttpFhirException("Missing or Invalid patient parameter", OperationOutcomeFactory.CreateInvalidParameter("Missing parameter: subject"), HttpStatusCode.BadRequest);
            }

            var custodian = request.QueryParameters.FirstOrDefault(x => x.Item1 == "custodian");
            var useCustodianIdentifierValidation = false;

            if (custodian == null)
            {
                //temporarily also support the incorrectly spec'd custodian.identifier parameter
                //custodian is a reference type and should not be used in this way
                custodian = request.QueryParameters.FirstOrDefault(x => x.Item1 == "custodian.identifier");

                useCustodianIdentifierValidation = custodian != null;
            }

            if (custodian != null)
            {
                //temporarily also support the incorrectly spec'd custodian.identifier parameter
                var invalidCustodian = useCustodianIdentifierValidation ? _fhirValidation.ValidateCustodianIdentifierParameter(custodian.Item2) :
                                                                          _fhirValidation.ValidateCustodianParameter(custodian.Item2);

                if (invalidCustodian != null)
                {
                    throw new HttpFhirException("Missing or Invalid custodian parameter", invalidCustodian, HttpStatusCode.BadRequest);
                }

                var custodianOrgCode = useCustodianIdentifierValidation? _fhirValidation.GetOrganizationParameterIdentifierId(custodian.Item2) : 
                                                                         _fhirValidation.GetOrganizationParameterId(custodian.Item2);

                var custodianRequest = NrlsPointerHelper.CreateOrgSearch(request, custodianOrgCode);
                var custodians = await _fhirSearch.Find<Organization>(custodianRequest) as Bundle;

                if (custodians.Entry.Count == 0)
                {
                    var invalidOrg = OperationOutcomeFactory.CreateOrganizationNotFound(custodianOrgCode);

                    throw new HttpFhirException("Missing or Invalid custodian parameter", invalidOrg, HttpStatusCode.NotFound);
                }

                var invalidOrgInteraction = ValidateOrganisationInteraction(request.RequestingAsid, custodianOrgCode, true);

                if (invalidOrgInteraction != null)
                {
                    throw new HttpFhirException("Invalid Provider Request Exception", invalidOrgInteraction, HttpStatusCode.Unauthorized);
                }
            }

            var type = request.QueryParameters.FirstOrDefault(x => x.Item1 == "type.coding");

            if (type != null)
            {
                var invalidType = _fhirValidation.ValidTypeParameter(type.Item2);

                if (invalidType != null)
                {
                    throw new HttpFhirException("Missing or Invalid type parameter", invalidType, HttpStatusCode.BadRequest);
                }
            }

            var summary = request.QueryParameters.FirstOrDefault(x => x.Item1 == "_summary");

            if (summary != null)
            {
                var validSummaryParams = new string[] { "subject", "_format", "_summary" };
                var invalidSummaryParams = request.QueryParameters.Where(x => !validSummaryParams.Contains(x.Item1));
                OperationOutcome invalidSummary = null;

                if (invalidSummaryParams.Any())
                {
                    var invalidSummaryParamsList = string.Join(", ", invalidSummaryParams.Select(x => $"{x.Item1}={x.Item2}"));

                    invalidSummary = OperationOutcomeFactory.CreateInvalidParameter("Invalid parameter", $"Unsupported search parameter - {invalidSummaryParamsList}");

                    throw new HttpFhirException("Missing or Invalid type parameter", invalidSummary, HttpStatusCode.BadRequest);
                }

                invalidSummary = _fhirValidation.ValidSummaryParameter(summary.Item2);

                if (invalidSummary != null)
                {
                    throw new HttpFhirException("Missing or Invalid type parameter", invalidSummary, HttpStatusCode.BadRequest);
                }            

                request.IsSummary = true;
            }

            return await _fhirSearch.Find<T>(request);

         }