Esempio n. 1
0
        public Hl7.Fhir.ElementModel.ITypedElement Resolver(string url)
        {
            CustomResolveElementNavigator ResolveElementNavigator = new CustomResolveElementNavigator();

#pragma warning disable IDE0059 // Unnecessary assignment of a value
            if (IFhirUriFactory.TryParse(url, Common.Enums.FhirVersion.R4, out IFhirUri? fhirUri, out string ErrorMessage))
#pragma warning restore IDE0059 // Unnecessary assignment of a value
            {
                if (fhirUri is object && !string.IsNullOrWhiteSpace(fhirUri.ResourseName))
                {
                    ResolveElementNavigator.Name = fhirUri.ResourseName;
                    //This type property is the key property to set for resolve() as it needs to match the comparison
                    //for example 'AuditEvent.agent.who.where(resolve() is Patient)' Patient is Patient
                    //PyroElementNavigator.Type = PyroRequestUri.FhirRequestUri.ResourseName;
                    ResolveElementNavigator.InstanceType = fhirUri.ResourseName;
                    ResolveElementNavigator.Value        = fhirUri.ResourseName;
                    ResolveElementNavigator.Location     = url;
                    return(ResolveElementNavigator);
                }
            }

#pragma warning disable CS8603 // Possible null reference return.
            return(null);

#pragma warning restore CS8603 // Possible null reference return.
        }
Esempio n. 2
0
        public override void ParseValue(string Values)
        {
            this.IsValid   = true;
            this.ValueList = new List <SearchQueryReferenceValue>();
            foreach (string Value in Values.Split(OrDelimiter))
            {
                if (this.Modifier.HasValue && this.Modifier == SearchModifierCode.Missing)
                {
                    bool?IsMissing = SearchQueryReferenceValue.ParseModifierEqualToMissing(Value);
                    if (IsMissing.HasValue)
                    {
                        this.ValueList.Add(new SearchQueryReferenceValue(IsMissing.Value, null));
                    }
                    else
                    {
                        this.InvalidMessage = $"Found the {SearchModifierCode.Missing.GetCode()} Modifier yet is value was expected to be true or false yet found '{Value}'. ";
                        this.IsValid        = false;
                        break;
                    }
                }
                else if (!this.IsChained) // If IsChained then there is no value to check
                {
                    SearchQueryReferenceValue?SearchQueryReferenceValue = null;
                    if (!Value.Contains('/') && !string.IsNullOrWhiteSpace(Value.Trim()) && this.TargetResourceTypeList.Count() == 1)
                    {
                        //If only one allowed Resource type then use this so the reference is just a resource Id '10' and we add on the appropriate ResourceName i.e 'Patient/10'
                        string ParseValue = $"{this.TargetResourceTypeList.ToArray()[0].ResourceTypeId.GetCode()}/{Value.Trim()}";
                        if (IFhirUriFactory.TryParse(ParseValue, this.FhirVersionId, out IFhirUri? FhirUri, out string ErrorMessage))
                        {
                            SearchQueryReferenceValue = new SearchQueryReferenceValue(false, FhirUri);
                        }
                        else
                        {
                            this.InvalidMessage = $"The resource reference was {Value} and the only allowed resource type was appended to give {ParseValue} however parsing of this as a FHIR reference failed with the error: {ErrorMessage}";
                            this.IsValid        = false;
                            break;
                        }
                    }
                    else if (IFhirUriFactory.TryParse(Value.Trim(), this.FhirVersionId, out IFhirUri? FhirUri, out string ErrorMessage))
                    {
                        if (string.IsNullOrWhiteSpace(FhirUri !.ResourseName))
                        {
                            //After parsing the search parameter of type reference if there is no Resource Type for the reference
                            //e.g no Patient is the example 'Patient/123456'
                            string RefResources = string.Empty;
                            this.TargetResourceTypeList.ToList().ForEach(v => RefResources += ", " + v.ResourceTypeId.GetCode());
                            string ResourceName = this.ResourceContext.GetCode();
                            string Message      = string.Empty;
                            Message      = $"The search parameter: {this.Name} is ambiguous. ";
                            Message     += $"Additional information: ";
                            Message     += $"The search parameter: {this.Name} can reference the following resource types ({RefResources.TrimStart(',').Trim()}). ";
                            Message     += $"To correct this you must prefix the search parameter with a Type modifier, for example: {this.Name}={this.TargetResourceTypeList.ToArray()[0].ResourceTypeId.GetCode()}/{FhirUri.ResourceId}";
                            Message     += $"or: {this.Name}:{this.TargetResourceTypeList.ToArray()[0].ResourceTypeId.GetCode()}={FhirUri.ResourceId} ";
                            Message     += $"If the: {this.TargetResourceTypeList.ToArray()[0].ResourceTypeId.GetCode()} resource was the intended reference for the search parameter: {this.Name}.";
                            this.IsValid = false;
                            break;
                        }

                        //Most likely an absolute or relative so just parse it
                        SearchQueryReferenceValue = new SearchQueryReferenceValue(false, FhirUri);
                    }
                    else
                    {
                        this.InvalidMessage = $"Unable to parse the reference search parameter of: '{Value}'. {ErrorMessage}";
                        this.IsValid        = false;
                        break;
                    }

                    if (SearchQueryReferenceValue is object && SearchQueryReferenceValue.FhirUri is object)
                    {
                        //Check the Resource type we resolved to is allowed for the search parameter
                        if (!string.IsNullOrWhiteSpace(SearchQueryReferenceValue.FhirUri.ResourseName) && !this.TargetResourceTypeList.Any(x => x.ResourceTypeId.GetCode() == SearchQueryReferenceValue.FhirUri.ResourseName))
                        {
                            this.InvalidMessage = $"The resource name used in the reference search parameter is not allowed for this search parameter type against this resource type.";
                            this.IsValid        = false;
                            break;
                        }
                        else
                        {
                            this.ValueList.Add(SearchQueryReferenceValue);
                        }
                    }
                    else
                    {
                        throw new ArgumentNullException($"Internal Server Error: Either {nameof(SearchQueryReferenceValue)} or {nameof(SearchQueryReferenceValue.FhirUri)} was found to be null");
                    }
                }
            }

            if (ValueList.Count > 1)
            {
                this.HasLogicalOrProperties = true;
            }

            if (this.ValueList.Count == 0)
            {
                if (!this.IsChained)
                {
                    this.InvalidMessage = $"Unable to parse any values into a {this.GetType().Name} from the string: {Values}.";
                    this.IsValid        = false;
                }
            }
        }
        public bool IsValid(FhirBaseApiQuery fhirApiQuery, out Common.FhirTools.FhirResource?OperationOutCome)
        {
            OperationOutCome = null;

            if (!IFhirUriFactory.TryParse(fhirApiQuery.RequestUri.OriginalString, fhirApiQuery.FhirVersion, out IFhirUri? FhirUri, out string ErrorMessage))
            {
                OperationOutCome = IOperationOutcomeSupport.GetError(fhirApiQuery.FhirVersion, new string[] { ErrorMessage });
                return(false);
            }

            if (FhirUri is null)
            {
                throw new ArgumentNullException(nameof(FhirUri));
            }


            if (fhirApiQuery is FhirApiResourceQuery fhirApiResourceQuery)
            {
                if (string.IsNullOrWhiteSpace(fhirApiResourceQuery.ResourceName))
                {
                    string message = $"An empty resource name found in the request URL for a {nameof(fhirApiResourceQuery)} request. " +
                                     $"All {nameof(fhirApiResourceQuery)} requests must have a resource name. The full URL was: {FhirUri.OriginalString}";
                    throw new Bug.Common.Exceptions.FhirFatalException(System.Net.HttpStatusCode.InternalServerError, message);
                }
            }

            if (fhirApiQuery is FhirApiResourceInstanceQuery fhirApiResourceInstanceQuery)
            {
                if (string.IsNullOrWhiteSpace(fhirApiResourceInstanceQuery.ResourceId))
                {
                    string message = $"An empty {nameof(fhirApiResourceInstanceQuery.ResourceId)} found in the {nameof(fhirApiResourceInstanceQuery)} object instance for the request. " +
                                     $"All {nameof(fhirApiResourceInstanceQuery)} requests must have a populated {nameof(fhirApiResourceInstanceQuery.ResourceId)}.";
                    throw new Bug.Common.Exceptions.FhirFatalException(System.Net.HttpStatusCode.InternalServerError, message);
                }

                if (string.IsNullOrWhiteSpace(FhirUri.ResourceId))
                {
                    string message = $"An empty resource id found in the request URL for a {nameof(fhirApiResourceInstanceQuery)} request. " +
                                     $"All {nameof(fhirApiResourceInstanceQuery)} requests must have a resource id. The full URL was: {FhirUri.OriginalString}";
                    throw new Bug.Common.Exceptions.FhirFatalException(System.Net.HttpStatusCode.InternalServerError, message);
                }
            }

            if (fhirApiQuery is FhirApiResourceInstanceHistoryInstanceQuery fhirApiResourceInstanceHistoryInstanceQuery)
            {
                if (fhirApiResourceInstanceHistoryInstanceQuery.VersionId == 0)
                {
                    string message = $"A {nameof(fhirApiResourceInstanceHistoryInstanceQuery.VersionId)} must begin at one for this server. The request had a {nameof(fhirApiResourceInstanceHistoryInstanceQuery.VersionId)} equal to {fhirApiResourceInstanceHistoryInstanceQuery.VersionId.ToString()}. " +
                                     $"All {nameof(fhirApiResourceInstanceHistoryInstanceQuery.VersionId)} requests must be numeric and begin from one within this server.";
                    OperationOutCome = IOperationOutcomeSupport.GetError(fhirApiResourceInstanceHistoryInstanceQuery.FhirVersion, new string[] { message });
                    return(false);
                }

                if (string.IsNullOrWhiteSpace(FhirUri.VersionId))
                {
                    string message = $"An empty {nameof(FhirUri.VersionId)} found in the request URL for a {nameof(fhirApiResourceInstanceHistoryInstanceQuery)} request. " +
                                     $"All {nameof(fhirApiResourceInstanceHistoryInstanceQuery)} requests must have a {nameof(FhirUri.VersionId)}. The full URL was: {FhirUri.OriginalString}";
                    throw new Bug.Common.Exceptions.FhirFatalException(System.Net.HttpStatusCode.InternalServerError, message);
                }
            }

            if (fhirApiQuery is CreateQuery createQuery)
            {
                //Check the Method is set correctly
                if (createQuery.Method != HttpVerb.POST)
                {
                    string message = $"The {nameof(createQuery)} did not have a Method of: {HttpVerb.POST.GetCode()}. The Method found was: {createQuery.Method.GetCode()}. All CreateQueries must be of Method: {HttpVerb.POST.GetCode()}";
                    throw new Bug.Common.Exceptions.FhirFatalException(System.Net.HttpStatusCode.InternalServerError, message);
                }

                //Check we have a FHIR Resource
                if (createQuery.FhirResource is null)
                {
                    string message = $"A {HttpVerb.POST.GetCode()} request must have a FHIR resource provided in the body of the request.";
                    OperationOutCome = IOperationOutcomeSupport.GetError(fhirApiQuery.FhirVersion, new string[] { message });
                    return(false);
                }

                //Check the FHIR Resource's name equals the FHIR URL endpoint
                string ResourceName = IFhirResourceNameSupport.GetName(createQuery.FhirResource);
                if (!ResourceName.Equals(FhirUri.ResourseName, StringComparison.CurrentCulture))
                {
                    string message = $"The resource provided in the body of the request does not match the resource type stated in the URL. The resource in the body was of type '{ResourceName}' and the URL stated the type '{FhirUri.ResourseName}'. The full URL was: {FhirUri.OriginalString}";
                    OperationOutCome = IOperationOutcomeSupport.GetError(createQuery.FhirResource.FhirVersion, new string[] { message });
                    return(false);
                }

                //Check the FHIR Resource's name equals the query property ResourceName (should never fail but worth checking)
                if (!ResourceName.Equals(createQuery.ResourceName, StringComparison.CurrentCulture))
                {
                    string message = $"The resource provided in the body of the request does not match the resource type found on the {nameof(createQuery)}. The resource in the body was of type: {ResourceName} and the {nameof(createQuery)} stated the type: {createQuery.ResourceName}. The full URL was: {FhirUri.OriginalString}";
                    throw new Bug.Common.Exceptions.FhirFatalException(System.Net.HttpStatusCode.InternalServerError, message);
                }

                //Check that the Create resource has no resourceId
                string?ResourceResourceId = IFhirResourceIdSupport.GetResourceId(createQuery.FhirResource);
                if (!string.IsNullOrWhiteSpace(ResourceResourceId))
                {
                    string message = $"The Create ({createQuery.Method.GetCode()}) interaction creates a new resource in a server-assigned location with a server assigned resource id. If the client wishes to have control over the id of a newly submitted resource, it should use the update ({HttpVerb.PUT.GetCode()}) interaction instead. The resource provide was found to contain the id: {ResourceResourceId}";
                    OperationOutCome = IOperationOutcomeSupport.GetError(createQuery.FhirResource.FhirVersion, new string[] { message });
                    return(false);
                }
            }

            if (fhirApiQuery is UpdateQuery updateQuery)
            {
                //Check the Method is set correctly
                if (updateQuery.Method != HttpVerb.PUT)
                {
                    string message = $"The {nameof(updateQuery)} did not have a Method of: {HttpVerb.PUT.GetCode()}. The Method found was: {updateQuery.Method.GetCode()}. All CreateQueries must be of Method: {HttpVerb.PUT.GetCode()}";
                    throw new Bug.Common.Exceptions.FhirFatalException(System.Net.HttpStatusCode.InternalServerError, message);
                }

                //Check we have a FHIR Resource
                if (updateQuery.FhirResource is null)
                {
                    string message = $"A {HttpVerb.PUT.GetCode()} request must have a FHIR resource provided in the body of the request.";
                    OperationOutCome = IOperationOutcomeSupport.GetError(fhirApiQuery.FhirVersion, new string[] { message });
                    return(false);
                }

                //Check the FHIR Resource's name equals the FHIR URL endpoint
                string ResourceName = IFhirResourceNameSupport.GetName(updateQuery.FhirResource);
                if (!ResourceName.Equals(FhirUri.ResourseName, StringComparison.CurrentCulture))
                {
                    string message = $"The resource provided in the body of the request does not match the resource type stated in the URL. The resource in the body was of type '{ResourceName}' and the URL stated the type '{FhirUri.ResourseName}'. The full URL was: {FhirUri.OriginalString}";
                    OperationOutCome = IOperationOutcomeSupport.GetError(updateQuery.FhirResource.FhirVersion, new string[] { message });
                    return(false);
                }

                //Check the FHIR Resource's name equals the query property ResourceName (should never fail but worth checking)
                if (!ResourceName.Equals(updateQuery.ResourceName, StringComparison.CurrentCulture))
                {
                    string message = $"The resource provided in the body of the request does not match the resource type found on the {nameof(updateQuery)}. The resource in the body was of type: {ResourceName} and the {nameof(updateQuery)} stated the type: {updateQuery.ResourceName}. The full URL was: {FhirUri.OriginalString}";
                    throw new Bug.Common.Exceptions.FhirFatalException(System.Net.HttpStatusCode.InternalServerError, message);
                }

                string?ResourceResourceId = IFhirResourceIdSupport.GetResourceId(updateQuery.FhirResource);

                //Check resource has a resource id
                if (string.IsNullOrWhiteSpace(ResourceResourceId))
                {
                    string message = $"There was no resource id found in the resource of the request. " +
                                     $"An update ({updateQuery.Method.GetCode()}) request must contain a resource with a resource id in the body of the request.";
                    OperationOutCome = IOperationOutcomeSupport.GetError(updateQuery.FhirResource.FhirVersion, new string[] { message });
                    return(false);
                }

                //Check the URL has a resource id equals the resource's id
                if (!ResourceResourceId.Equals(FhirUri.ResourceId, StringComparison.CurrentCulture))
                {
                    string message = $"The resource id found in the resource of the request does not match the resource id stated in the request URL. " +
                                     $"The resource id in the body was: '{ResourceResourceId}' and in the URL it was: '{FhirUri.ResourceId}'. The full URL was: {FhirUri.OriginalString}";
                    OperationOutCome = IOperationOutcomeSupport.GetError(updateQuery.FhirResource.FhirVersion, new string[] { message });
                    return(false);
                }

                //Check the UpdateQuery ResourceId property matches the URL and Resource (this should never fail)
                if (!updateQuery.ResourceId.Equals(FhirUri.ResourceId, StringComparison.CurrentCulture) &&
                    !updateQuery.ResourceId.Equals(ResourceResourceId, StringComparison.CurrentCulture))
                {
                    string message = $"The resource id found in the body of the request does not match the resource id stated in the request URL. " +
                                     $"The resource id in the body was: '{ResourceResourceId}' and in the URL it was: '{FhirUri.ResourceId}'. The full URL was: {FhirUri.OriginalString}";
                    OperationOutCome = IOperationOutcomeSupport.GetError(updateQuery.FhirResource.FhirVersion, new string[] { message });
                    return(false);
                }
            }

            //if (fhirApiQuery is ReadQuery readQuery)
            //{

            //}

            //if (fhirApiQuery is VReadQuery vReadQuery)
            //{

            //}

            //if (fhirApiQuery is DeleteQuery DeleteQuery)
            //{

            //}

            return(true);
        }