OrganizationDatabase IOrganizationApiController <TDbContext> .GetOrganizationDatabase(string dbIdentifier) =>
 OrganizationContextActionFilterAttribute.GetOrganisationDatabase(HttpContext, string.IsNullOrWhiteSpace(dbIdentifier) ? DbIdentifier : dbIdentifier);
 /// <summary>
 /// Resets organization context forcing the api to refresh it for the subsequent calls
 /// </summary>
 /// <param name="orgId"></param>
 protected void ResetOrganizationContext(Guid orgId) =>
 OrganizationContextActionFilterAttribute.ResetOrganizationContext(orgId);
 /// <summary>
 /// Organization database object from GetOrganizationDatabasesbActionFilterAttribute action filter
 /// </summary>
 protected OrganizationDatabase GetOrganizationDatabase(string dbIdentifier = null) =>
 OrganizationContextActionFilterAttribute.GetOrganisationDatabase(HttpContext, string.IsNullOrWhiteSpace(dbIdentifier) ? DbIdentifier : dbIdentifier);
        /// <summary>
        /// Whether or now the action is allowed via user config
        /// </summary>
        /// <param name="actionContext"></param>
        /// <param name="failureReason"></param>
        /// <returns></returns>
        protected static bool AllowViaUserConfig(ActionExecutingContext actionContext, out string failureReason)
        {
            failureReason = null;

            var userCfg = GetUserConfiguration(actionContext);

            if (userCfg == null)
            {
                return(false);
            }

            //Note:
            //possible improvement - work out a way of caching output of this method.
            //the problem though is the very same userCfg may be valid for some requests but invalid for some others
            //all depends on context
            //maybe a combination of url, referrer & authorization header attribute???
            //though with not full url, but rather a path with no attributes, so can efficiently use cache with
            //apis such as search api - tons of requests in order to get the suggestions

            //if access is via token make sure to check referrers
            if (userCfg.IsToken && !userCfg.Token.CanIgnoreReferrer)
            {
                var referrer = actionContext.HttpContext.ExtractReferrerHeader();
                if (referrer == null)
                {
                    //cannot ignore referrer, need to fail!
                    failureReason = $"Token '{userCfg.Token.Uuid}' requires a referrer but it has not been provided";
                    return(false);
                }


                if (userCfg.Token.Referrers == null || !userCfg.Token.Referrers.Contains(referrer.Host))
                {
                    failureReason = $"Token '{userCfg.Token.Uuid}' requires a referrer but the actual one {referrer.Host} is not allowed. ";
#if DEBUG
                    failureReason +=
                        $"Allowed referers for this token are: {string.Join(", ", userCfg?.Token?.Referrers?.ToArray() ?? new[] { "referrers not defined" })}";
#endif
                    return(false);
                }
            }


            //org uuid if any - in such case access is via org api: organizations/orgUuid/controller
            Organization org = null;
            if (CheckAttributePresence <OrganizationContextActionFilterAttribute>(actionContext))
            {
                //this throws when org uuid is not known, but since the controller is tagged with the org ctx attribute
                //this should not be the case because a non-guid route would not let the request through
                var orgId = OrganizationContextActionFilterAttribute.GetOrganizationId(actionContext.HttpContext);

                //check the org to work out the context for
                org = userCfg.Orgs.FirstOrDefault(o => o.Uuid == orgId);

                //if org does not exist in the collection then neither user nor token grants the access to it
                if (org == null)
                {
                    failureReason = $"Token / User does not have access to organization '{orgId}'.";
                    return(false);
                }
            }


            //if org is not null, then this is an 'organization' controller - the access should be checked for this very org
            //otherwise the api does not know about the organization context and therefore needs to check if any of the orgs
            //have access to the apps served by this controller.

            var appNames = GetAppNames();

            var orgs = org != null ? new[] { org } : (userCfg.Orgs?.ToArray() ?? new Organization[0]);

            //if any app withn an org(s) is the app representing this api, then can use it
            var ok = orgs.Any(o => o?.Applications?.Any(a => appNames.Contains(a.ShortName)) ?? false);
            if (!ok)
            {
                failureReason = $"Org(s): '{string.Join(",", orgs.AsEnumerable().Select(o=>o.Slug))}' have no access to the '{string.Join(", ", appNames)}' app(s) granted.";
            }
            return(ok);
        }