public async Task <Organization> GetByQuery(FhirRequest request) { ValidateResource(request.StrResourceType); request.ProfileUri = _resourceProfile; var bundle = await _fhirSearch.GetAsBundle <Organization>(request); if (bundle == null || (bundle.Total != 1)) { return(null); } return(bundle.Entry.FirstOrDefault()?.Resource as Organization); }
/// <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 <Bundle> Find(FhirRequest request) { 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)) { throw new HttpFhirException("Invalid _id parameter", OperationOutcomeFactory.CreateNotFound(id), HttpStatusCode.NotFound); } if (request.QueryParameters.Count() > 1) { throw new HttpFhirException("Invalid _id parameter combination", OperationOutcomeFactory.CreateInvalidParameter("Invalid parameter: _id"), HttpStatusCode.BadRequest); } request.Id = id; request.IsIdQuery = true; var results = await _fhirSearch.GetAsBundle <DocumentReference>(request); var response = ParseRead(results, id) as Bundle; 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); } var nhsNumber = _fhirValidation.GetSubjectReferenceParameterId(patient.Item2); var patientRequest = NrlsPointerHelper.CreatePatientSearch(request, nhsNumber); var patients = await _fhirSearch.Find <Patient>(patientRequest); if (patients.Entry.Count == 0) { throw new HttpFhirException("Unknown patient", OperationOutcomeFactory.CreatePatientNotFound(nhsNumber), HttpStatusCode.NotFound); } } 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); if (custodians.Entry.Count == 0) { var invalidOrg = OperationOutcomeFactory.CreateOrganizationNotFound(custodianOrgCode); throw new HttpFhirException("Missing or Invalid custodian parameter", invalidOrg, HttpStatusCode.NotFound); } //This is now out of scope //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; } //Only allow current pointers var queryParameters = request.QueryParameters.ToList(); queryParameters.Add(new Tuple <string, string>("status", "current")); request.QueryParameters = queryParameters; request.AllowedParameters = request.AllowedParameters.Concat(new string[] { "status" }).ToArray(); return(await _fhirSearch.Find <DocumentReference>(request)); }
/// <summary> /// Update a DocumentReference using the id in the path or by Master Identifier /// </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 patch. /// We use the FhirMaintain service and FhirSearch service to facilitate this /// </remarks> public async SystemTasks.Task <OperationOutcome> Patch(FhirRequest request) { ValidateResource(request.StrResourceType); request.ProfileUri = _resourceProfile; // NRLS Layers of validation before Fhir Delete Call //If we have id path segment we should have nothing else if (!string.IsNullOrEmpty(request.Id) && (!string.IsNullOrEmpty(request.IdentifierParameter) || !string.IsNullOrEmpty(request.SubjectParameter))) { throw new HttpFhirException("Invalid query parameters for Update by Logical Id", OperationOutcomeFactory.CreateInvalidParameter("Invalid query parameters for Update by Logical Id"), HttpStatusCode.BadRequest); } var identifier = request.IdentifierParameter; var identifierValidationResult = _fhirValidation.ValidateIdentifierParameter("identifier", identifier); var subject = request.SubjectParameter; var subjectValidationResult = _fhirValidation.ValidatePatientParameter(subject); if (string.IsNullOrEmpty(request.Id) && identifierValidationResult != null && subjectValidationResult != null) { throw new HttpFhirException("Missing or Invalid id", OperationOutcomeFactory.CreateInvalidParameter("Invalid parameter: id"), HttpStatusCode.BadRequest); } if (string.IsNullOrEmpty(request.Id) && identifierValidationResult == null && subjectValidationResult != null) { throw new HttpFhirException("Missing or Invalid subject parameter", OperationOutcomeFactory.CreateInvalidParameter("Invalid parameter: subject"), HttpStatusCode.BadRequest); } if (string.IsNullOrEmpty(request.Id) && identifierValidationResult != null && subjectValidationResult == null) { throw new HttpFhirException("Missing or Invalid identifier parameter", OperationOutcomeFactory.CreateInvalidParameter("Invalid parameter: identifier"), HttpStatusCode.BadRequest); } var parameters = request.Resource as Parameters; var validParameters = _fhirValidation.ValidateParameters(parameters); if (!validParameters.Success) { throw new HttpFhirException("Missing or Invalid parameter", validParameters, HttpStatusCode.BadRequest); } Resource documentBundle; if (!string.IsNullOrEmpty(request.Id)) { ObjectId mongoId; if (!ObjectId.TryParse(request.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 - {request.Id}"), HttpStatusCode.BadRequest); } request.IsIdQuery = true; documentBundle = await _fhirSearch.GetAsBundle <DocumentReference>(request); } else { documentBundle = await _fhirSearch.GetByMasterId <DocumentReference>(request); } var documentResponse = ParseRead(documentBundle, request.Id); string oldVersionId; 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(request.Id)); } var orgDocument = result.Entry.FirstOrDefault().Resource as DocumentReference; oldVersionId = orgDocument.Meta?.VersionId; var orgCode = _fhirValidation.GetOrganizationReferenceId(orgDocument.Custodian); var invalidAsid = InvalidAsid(orgCode, request.RequestingAsid); if (invalidAsid != null) { return(invalidAsid); } if (orgDocument.Status != DocumentReferenceStatus.Current) { //Only allowed to transition to entered-in-error from current return(OperationOutcomeFactory.CreateInactiveDocumentReference()); } if (string.IsNullOrEmpty(request.Id)) { request.Id = orgDocument.Id; } } else { return(documentResponse as OperationOutcome); } UpdateDefinition <BsonDocument> updates = null; BuildEnteredInError(oldVersionId, out updates); var patched = await _fhirMaintain.Update <DocumentReference>(request, updates); if (!patched) { return(OperationOutcomeFactory.CreateNotFound(request.Id)); } return(OperationOutcomeFactory.CreateUpdated(request.RequestUrl?.AbsoluteUri, request.AuditId)); }