Exemple #1
0
        /// <summary>
        /// Determines if the advert has been changed and defers to ChangeState
        /// </summary>
        /// <param name="scope"></param>
        /// <param name="state"></param>
        /// <param name="subState"></param>
        /// <param name="package"></param>
        /// <param name="adType"></param>
        /// <param name="affiliateLink"></param>
        /// <param name="accountSubState"></param>
        /// <param name="source"></param>
        /// <param name="existing"></param>
        /// <param name="changed"></param>
        /// <param name="firstTimeAdvertiser"></param>
        /// <returns></returns>
        public ChangeStateResult ChangeStateAdvert <T>(
            ApiScopeResult scope,
            string state,
            string subState,
            string package,
            string adType,
            string affiliateLink,
            string accountSubState,
            string source,
            T existing,
            T changed,
            bool firstTimeAdvertiser) where T : BaseAdvert
        {
            bool isEdit = CheckChange(existing, changed);

            return(ChangeState(
                       scope,
                       state,
                       subState,
                       changed.State,
                       package,
                       adType,
                       affiliateLink,
                       accountSubState,
                       isEdit,
                       firstTimeAdvertiser,
                       changed.Category,
                       changed.SubCategory,
                       changed.SubSubCategory,
                       changed.Intention,
                       source,
                       changed.AdPromotions));
        }
        public async Task <IActionResult> Create([FromBody] object @object, string serviceName)
        {
            if (!ModelState.IsValid)
            {
                return(BadRequest(ModelState));
            }

            var apiInfo = new ApiInfo(serviceName.ToLowerInvariant(), method: "command");

            ApiScopeResult scope = _authProvider.IsApiInScope(apiInfo);

            if (!scope.IsInScope)
            {
                return(NotFound());
            }

            if (scope.ScopeToUser)
            {
                PropertyInfo propertyInfo = @object.GetType().GetProperty("UserId");

                if (propertyInfo == null)
                {
                    return(BadRequest("The requested type requires a UserId"));
                }

                propertyInfo.SetValue(@object, _authProvider.GetUserId());
            }

            var pathWithQuery = Request.QueryString.HasValue ? Request.Path.Value + Request.QueryString : Request.Path.Value;

            var response = await _apiClient.CreateAsync <object, object>(apiInfo, @object, pathWithQuery);

            if (response.IsError)
            {
                if (response.ResponseError == ResponseError.Http)
                {
                    if (response.HttpStatusCode == HttpStatusCode.BadRequest)
                    {
                        ModelState.AddModelError(string.Empty, response.Raw);
                        return(BadRequest(ModelState));
                    }

                    return(StatusCode((int)response.HttpStatusCode, response.Error));
                }

                if (response.ResponseError == ResponseError.Exception)
                {
                    return(StatusCode(500, response.Error));
                }
                return(StatusCode(500));
            }

            return(Ok(response.Content));
        }
        public async Task <IActionResult> Delete(string serviceName)
        {
            var apiInfo = new ApiInfo(serviceName.ToLowerInvariant(), method: "command");

            var pathWithQuery = Request.QueryString.HasValue ? Request.Path.Value + Request.QueryString : Request.Path.Value;

            ApiScopeResult scope = _authProvider.IsApiInScope(apiInfo);

            if (!scope.IsInScope)
            {
                return(NotFound());
            }

            if (scope.ScopeToUser)
            {
                string id = Request.Path.Value.Split('/').Last();

                var checkResponse = await _apiClient.GetAsync <UserIdResponse>(
                    new ApiInfo(name : apiInfo.Name, method : "query"),
                    pathWithQuery : $"/service/{apiInfo.Name}?id={id}"
                    );

                if (checkResponse?.Content?.UserId != _authProvider.GetUserId())
                {
                    return(BadRequest($"No {apiInfo.Name} found to delete"));
                }
            }

            var response = await _apiClient.DeleteAsync <object>(apiInfo, pathWithQuery);

            if (response.IsError)
            {
                if (response.ResponseError == ResponseError.Http)
                {
                    if (response.HttpStatusCode == HttpStatusCode.NotFound)
                    {
                        return(NotFound());
                    }

                    return(StatusCode((int)response.HttpStatusCode));
                }

                if (response.ResponseError == ResponseError.Exception)
                {
                    return(StatusCode(500, response.Error));
                }

                return(StatusCode(500));
            }

            return(Ok(response.Content));
        }
Exemple #4
0
        /// <summary>
        /// Determine API scope
        /// </summary>
        /// <param name="info"></param>
        /// <param name="path"></param>
        /// <returns></returns>
        public ApiScopeResult IsApiInScope(ApiInfo info, string path = null)
        {
            List <string> roles = new List <string>()
            {
                "any"
            };

            foreach (var claim in _contextAccessor.HttpContext.User.Claims)
            {
                if (claim.Type == ClaimTypes.Role)
                {
                    roles.Add(claim.Value);
                }
            }

            var source = GetSource();

            var isFeed = !(string.IsNullOrWhiteSpace(source) || _knownApps.Contains(source));

            //root may perform any action
            if (roles.Contains("root"))
            {
                return(new ApiScopeResult()
                {
                    AllowCreateAccount = true,
                    ScopeToUser = false,
                    IsInScope = true,
                    IsModerator = true,
                    AllowRepeat = isFeed
                });
            }

            //Find all scopes related to the api info
            List <ApiScope> apiScopes = _scopes.Where(tbl =>
                                                      (tbl.Type == info.Name ||
                                                       (tbl.Type.StartsWith("*") && info.Name.EndsWith(tbl.Type.Replace("*", ""))) ||
                                                       (tbl.Type.EndsWith("*") && info.Name.StartsWith(tbl.Type.Replace("*", "")))) &&
                                                      tbl.Tags.Contains(info.Method)).ToList();

            //Find all scopes with matching sub claims
            apiScopes = apiScopes.Where(tbl => tbl.SubClaims.Any(a => roles.Contains(a))).ToList();

            //Filter/Limit scopes to the specified path
            if (string.IsNullOrEmpty(path))
            {
                apiScopes = apiScopes.Where(tbl => tbl.Paths == null).ToList();
            }
            else
            {
                var pathScopes = apiScopes.Where(tbl => tbl.Paths != null && tbl.Paths.Any(p => path.ToLower().StartsWith(p.ToLower()))).ToList();

                //Specific permissions specified for this path and should replace broarder permissions
                if (pathScopes.Count > 0)
                {
                    apiScopes = pathScopes;
                }
                else
                {
                    //Path specific scopes should not apply to other paths
                    apiScopes = apiScopes.Where(tbl => tbl.Paths == null).ToList();
                }
            }

            //if no scope is defined for the service, root access is required and request is not in scope
            if (apiScopes.Count == 0)
            {
                return(new ApiScopeResult()
                {
                    AllowCreateAccount = false,
                    ScopeToUser = false,
                    IsInScope = false,
                    IsModerator = false
                });
            }

            ApiScopeResult result = new ApiScopeResult();

            result.IsInScope = true;
            //If any scope allows the create priveledge
            result.AllowCreateAccount = apiScopes.Any(tbl => tbl.Scope.Contains("create"));

            //Only scope to the account if the 'any' scope is present
            if (apiScopes.Any(tbl => tbl.Scope.Contains("any")))
            {
                result.ScopeToUser = false;
            }
            else
            {
                result.ScopeToUser = true;
            }

            result.IsModerator = roles.Contains("moderator");

            result.AllowRepeat = isFeed && (_contextAccessor?
                                            .HttpContext?
                                            .User?
                                            .Identity?
                                            .IsAuthenticated ?? false);

            return(result);
        }
        public async Task <IActionResult> Get(string serviceName, string page)
        {
            var apiInfo = new ApiInfo(serviceName.ToLowerInvariant(), method: "query");

            ApiScopeResult scope = _authProvider.IsApiInScope(apiInfo, page);

            if (!scope.IsInScope)
            {
                //Return not found to avoid unwanted consumers discovering services
                return(NotFound());
            }

            string pathWithQuery;

            if (scope.ScopeToUser)
            {
                if (Request.QueryString.HasValue)
                {
                    //Requests that should be in scope may not add the userid parameter
                    if (Request.QueryString.ToString().ToLower().Contains("userid"))
                    {
                        return(NotFound());
                    }
                }

                string userId = _authProvider.GetUserId();

                if (string.IsNullOrEmpty(userId))
                {
                    return(NotFound());
                }

                pathWithQuery = Request.QueryString.HasValue ?
                                Request.Path.Value + Request.QueryString + $"&userId={userId}"
                    : Request.Path.Value + $"?userId={userId}";
            }
            else
            {
                pathWithQuery = Request.QueryString.HasValue ? Request.Path.Value + Request.QueryString : Request.Path.Value;
            }

            var response = await _apiClient.GetAsync <object>(apiInfo, pathWithQuery);

            if (response.IsError)
            {
                if (response.ResponseError == ResponseError.Http)
                {
                    if (string.IsNullOrWhiteSpace(response.Raw))
                    {
                        return(StatusCode((int)response.HttpStatusCode));
                    }
                    else
                    {
                        return(StatusCode((int)response.HttpStatusCode, response.Raw));
                    }
                }

                if (!string.IsNullOrWhiteSpace(response.Error))
                {
                    return(StatusCode(500, response.Error));
                }

                return(StatusCode(500, "unexpected response received while executing the request"));
            }

            return(Ok(response.Content));
        }
        public async Task <IActionResult> Edit([FromBody] object @object, string serviceName)
        {
            if (!ModelState.IsValid)
            {
                return(BadRequest(ModelState));
            }

            var apiInfo = new ApiInfo(serviceName.ToLowerInvariant(), method: "command");

            ApiScopeResult scope = _authProvider.IsApiInScope(apiInfo);

            if (!scope.IsInScope)
            {
                return(NotFound());
            }

            if (scope.ScopeToUser)
            {
                string id = Request.Path.Value.Split('/').Last();

                var checkResponse = await _apiClient.GetAsync <UserIdResponse>(
                    new ApiInfo(name : apiInfo.Name, method : "query"),
                    pathWithQuery : $"/service/{apiInfo.Name}?id={id}"
                    );

                if (checkResponse?.Content?.UserId != _authProvider.GetUserId())
                {
                    return(BadRequest($"No {apiInfo.Name} found to edit"));
                }

                PropertyInfo propertyInfo = @object.GetType().GetProperty("UserId");

                if (propertyInfo == null)
                {
                    return(BadRequest("The requested type requires a UserId"));
                }

                propertyInfo.SetValue(@object, _authProvider.GetUserId());
            }

            var pathWithQuery = Request.QueryString.HasValue ? Request.Path.Value + Request.QueryString : Request.Path.Value;

            @object = await _nameResolver.ResolveNamesAsync(@object);

            var response = await _apiClient.EditAsync <object, object>(apiInfo, @object, pathWithQuery);

            if (response.IsError)
            {
                if (response.ResponseError == ResponseError.Http)
                {
                    if (response.HttpStatusCode == HttpStatusCode.NotFound)
                    {
                        return(NotFound());
                    }

                    if (response.HttpStatusCode == HttpStatusCode.BadRequest)
                    {
                        ModelState.AddModelError(string.Empty, response.Raw);
                        return(BadRequest(ModelState));
                    }

                    return(StatusCode((int)response.HttpStatusCode, response.Error));
                }

                return(StatusCode(500, response.Error));
            }

            return(Ok(response.Content));
        }
Exemple #7
0
        /// <summary>
        ///  Rule 1: There are 5 main states that determine when and where content is shown: Active, Pending, Inactive, Archived, Rejected<para/>
        ///  Rule 2: The list of substates is ongoing and determines the next state<para/>
        ///  Rule 3: Affiliate content from Auto Mart, Truck &amp; Trailer, Agrimag and Job Mail use the AffiliateMap<para/>
        ///  Rule 3.b: CCAP content use the AffiliateMap<para/>
        ///  Rule 4: Auto ban if account is banned<para/>
        ///  Rule 6: Request is made by a moderator<para/>
        ///  Rule 6.a: If the account is Unpaid and the requested state is active or inactive, move to ActiveUnpaid or InactiveUnpaid<para/>
        ///  Rule 6.b: The state is change according to the ModerationMap<para/>
        ///  Rule 7: Promoted Content. The state is set to Active PostModeration
        ///  Rule 10: If the account is unpaid<para/>
        ///  Rule 10.a: If the content is edited, the state is set to Pending PreModeration<para/>
        ///  Rule 10.b: Archived ads are archived<para/>
        ///  Rule 10.c: The ads go to Active Unpaid or Inactive Unpaid states<para/>
        ///  Rule 11: If the ad is not edited, the state is changed according to UserNoEditMap<para/>
        ///  Rule 12: If the ad is edited<para/>
        ///  Rule 12.a: If the user is a first time advertiser, the state is set to Pending PreModeration<para/>
        ///  Rule 12.b: If the user is premium, set the state to Active PostModeration and skip PreModeration keyword check<para/>
        ///  Rule 12.c: If the category is premod, the state is set to Pending PreModeration<para/>
        ///  Rule 12.c.ii: If package is owner and category is cars, the state is set to Pending Premoderation
        ///  Rule 12.d: If the intention is give away, the state is set to Pending PreModerationg<para/>
        ///  Rule 12.e: The state is changed according to UserEditMap<para/>
        ///  Rule 13: If the ad matches rule 12, the content is checked for spam<para/>
        ///  Rule 13.a: Found more than 9 high level unicode in text<para/>
        ///  Rule 13.b: Found Reject keyword in text<para/>
        ///  Rule 13.c: Found Premod keyword in text<para/>
        ///  Rule 13.d: Found Url in text<para/>
        /// </summary>
        /// <param name="scope"></param>
        /// <param name="currentState"></param>
        /// <param name="currentSubState"></param>
        /// <param name="requestedState"></param>
        /// <param name="package"></param>
        /// <param name="adType"></param>
        /// <param name="affiliateLink"></param>
        /// <param name="accountSubState"></param>
        /// <param name="isEdit"></param>
        /// <param name="firstTimeAdvertiser"></param>
        /// <param name="category"></param>
        /// <param name="subCategory"></param>
        /// <param name="subSubCategory"></param>
        /// <param name="intention"></param>
        /// <param name="source"></param>
        /// <param name="promotions"></param>
        /// <returns></returns>
        public ChangeStateResult ChangeState(
            ApiScopeResult scope,
            string currentState,
            string currentSubState,
            string requestedState,
            string package,
            string adType,
            string affiliateLink,
            string accountSubState,
            bool isEdit,
            bool firstTimeAdvertiser,
            string category,
            string subCategory,
            string subSubCategory,
            string intention,
            string source,
            IEnumerable <AdPromotion> promotions)
        {
            // modified
            UnknownState.Modified        = isEdit;
            UnknownStatePremium.Modified = isEdit;
            AccountBanState.Modified     = isEdit;

            if (string.IsNullOrEmpty(currentState))
            {
                currentState = "";
            }

            //we assume if no state has been specified, the poster intends for the ad to go active
            if (string.IsNullOrEmpty(requestedState))
            {
                requestedState = "Active";
            }

            //Rule 3
            affiliateLink = (affiliateLink ?? "").ToLower();

            if (affiliateLink.Contains("auto") || affiliateLink.Contains("truck") || affiliateLink.Contains("agri") || affiliateLink.Contains("job") || affiliateLink.Contains("gotproperty"))
            {
                if (!AffiliateMap.TryGetValue(requestedState, out var affiliateState))
                {
                    //All these state should be mapped
                    return(UnknownState);
                }
                else
                {
                    return(new ChangeStateResult(
                               affiliateState.Item1,
                               affiliateState.Item2,
                               isEdit,
                               "Rule 3: Affiliate content from Auto Mart, Truck &amp; Trailer, Agrimag and Job Mail use the AffiliateMap"));
                }
            }

            //Rule 3.b
            if (string.Compare(source, "ccap", StringComparison.OrdinalIgnoreCase) == 0)
            {
                if (!AffiliateMap.TryGetValue(requestedState, out var affiliateState))
                {
                    //All these state should be mapped
                    return(UnknownState);
                }
                else
                {
                    return(new ChangeStateResult(
                               affiliateState.Item1,
                               affiliateState.Item2,
                               isEdit,
                               "Rule 3b: CCAP content use the AffiliateMap"));
                }
            }

            //Rule 4
            if (accountSubState == "AccountBan")
            {
                return(AccountBanState);
            }

            var stateKey = new Tuple <string, string>(currentSubState, requestedState);

            //Rule 5 (deprecated since it does not take into account subState)
            //if (!isEdit && requestedState == currentState)
            //{
            //    return new ChangeStateResult(currentState, currentSubState, "Rule 5: If the ad is not edited and no new state is requested, the current state is kept");
            //}

            //Rule 6
            if (scope.IsModerator)
            {
                if (accountSubState == "ActiveUnpaid" || accountSubState == "InactiveUnpaid")
                {
                    if (requestedState == "Active")
                    {
                        return(new ChangeStateResult(
                                   "Active",
                                   "ActiveUnpaid",
                                   isEdit,
                                   "Rule 6.a: If the account is Unpaid and the requested active, move to ActiveUnpaid"));
                    }
                    else if (requestedState == "Inactive")
                    {
                        return(new ChangeStateResult(
                                   "Inactive",
                                   "InactiveUnpaid",
                                   isEdit,
                                   "Rule 6.a: If the account is Unpaid and the requested state is inactive, move to InactiveUnpaid"));
                    }
                }

                if (ModerationMap.TryGetValue(requestedState, out var moderatorState))
                {
                    return(new ChangeStateResult(
                               moderatorState.Item1,
                               moderatorState.Item2,
                               isEdit,
                               "Rule 6.b: The state is change according to the ModerationMap"));
                }
                //Unmapped moderator state, could indicate new font end functionality
                else
                {
                    return(UnknownState);
                }
            }
            else
            {
                //Rule 7
                if (promotions != null && promotions.Any(tbl => tbl.EndDate > DateTime.Now && (tbl.AdPromotionType?.ToLower() == "top" || tbl.AdPromotionType?.ToLower() == "homepage")))
                {
                    var recommendedStateChange = new ChangeStateResult(
                        "Active",
                        "PostModeration",
                        isEdit,
                        "Rule 7: Promoted Content",
                        false,
                        true);

                    if (requestedState == "Active")
                    {
                        return(recommendedStateChange);
                    }
                    // use no edit for other actions?
                    else if (UserNoEditMap.TryGetValue(stateKey, out var noEditState))
                    {
                        return(new ChangeStateResult(
                                   noEditState.Item1,
                                   noEditState.Item2,
                                   isEdit,
                                   "Rule 7: Promoted Content",
                                   false,
                                   true));
                    }

                    return(recommendedStateChange);
                }

                //Rule 10
                if (accountSubState == "ActiveUnpaid" || accountSubState == "InactiveUnpaid")
                {
                    //Rule 10.a
                    if (isEdit)
                    {
                        return(new ChangeStateResult(
                                   "Pending",
                                   "PreModeration",
                                   isEdit,
                                   "Rule 10.a: If the content is edited, the state is set to Pending PreModeration"));
                    }

                    //Rule 10.c
                    if (requestedState == "Active")
                    {
                        return(new ChangeStateResult(
                                   "Active",
                                   "ActiveUnpaid",
                                   isEdit,
                                   "Rule 10.c: The ads go to Active Unpaid"));
                    }
                    else if (requestedState == "Inactive")
                    {
                        return(new ChangeStateResult(
                                   "Inactive",
                                   "InactiveUnpaid",
                                   isEdit,
                                   "Rule 10.c: The ads go to Inactive Unpaid"));
                    }
                    else
                    {
                        //Rule 10.b
                        //This rule falls to the edit rule with archived state
                    }
                }

                //Rule 11
                if (!isEdit && currentSubState != "InactiveEdited")
                {
                    if (UserNoEditMap.TryGetValue(stateKey, out var noEditState))
                    {
                        return(new ChangeStateResult(
                                   noEditState.Item1,
                                   noEditState.Item2,
                                   isEdit,
                                   "Rule 11: If the ad is not edited, the state is changed according to UserNoEditMap",
                                   false,
                                   true));
                    }
                    //These state should all be mapped. Could indicate an invalid request
                    else
                    {
                        //Defer to edit check when no state is specified
                        //if (package?.ToLower().Contains("premium") == true)
                        //{
                        //    return UnknownStatePremium;
                        //}
                        //else
                        //{
                        //    return UnknownState;
                        //}
                    }
                }

                //Rule 12
                //Rule 12.a
                if (firstTimeAdvertiser)
                {
                    return(new ChangeStateResult(
                               "Pending",
                               "PreModeration",
                               isEdit,
                               "Rule 12.a: First time advertiser",
                               true,
                               true));
                }

                //Rule 12.b
                if (package?.ToLower().Contains("premium") == true)
                {
                    return(new ChangeStateResult(
                               "Active",
                               "PostModeration",
                               isEdit,
                               "Rule 12.b: Premium User",
                               false,
                               true));
                }

                //Rule 12.c
                if (PremodCategories.Contains(category, StringComparer.OrdinalIgnoreCase) ||
                    PremodCategories.Contains(subCategory, StringComparer.OrdinalIgnoreCase) ||
                    PremodCategories.Contains(subSubCategory, StringComparer.OrdinalIgnoreCase))
                {
                    return(new ChangeStateResult(
                               "Pending",
                               "PreModeration",
                               isEdit,
                               "Rule 12.c: Premod Category",
                               true,
                               true));
                }

                //Rule 12.c.ii Owner Motoring
                if (category?.ToLower() == "cars" && package?.ToLower() == "owner")
                {
                    return(new ChangeStateResult(
                               "Pending",
                               "PreModeration",
                               isEdit,
                               "Rule 12.c.ii: Owner Cars",
                               true,
                               true));
                }

                //Rule 12.d
                if (intention == "Give Away")
                {
                    return(new ChangeStateResult(
                               "Pending",
                               "PreModeration",
                               isEdit,
                               "Rule 12.d: Give Away",
                               true,
                               true));
                }

                if (UserEditMap.TryGetValue(stateKey, out var editState))
                {
                    //Rule 12.e
                    return(new ChangeStateResult(
                               editState.Item1,
                               editState.Item2,
                               isEdit,
                               "Rule 12.e: If the ad is edited, the state is changed according to the UserEditMap",
                               true,
                               true));
                }
                //These state should all be mapped. Could indicate an invalid request
                else
                {
                    //This code is unreachable, see 12.b
                    if (package?.ToLower().Contains("premium") == true)
                    {
                        return(UnknownStatePremium);
                    }
                    else
                    {
                        return(UnknownState);
                    }
                }
            }
        }