예제 #1
0
        public async Task <IActionResult> GetRecs([FromBody] AnimeRecsInputJson input,
                                                  [FromServices] IOptionsSnapshot <Config.RecommendationsConfig> recConfig,
                                                  [FromServices] IMyAnimeListApiFactory malApiFactory, [FromServices] IAnimeRecsClientFactory recClientFactory,
                                                  [FromServices] IAnimeRecsDbConnectionFactory dbConnFactory, [FromServices] IRazorViewEngine viewEngine,
                                                  [FromServices] ITempDataProvider tempProvider)
        {
            if (!ModelState.IsValid)
            {
                AjaxError error = new AjaxError(ModelState);
                _logger.LogDebug("Invalid input received for GetRecs: {0}", error.Message);
                return(BadRequest(error));
            }

            if (input.RecSourceName == null)
            {
                input.RecSourceName = recConfig.Value.DefaultRecSource;
            }

            try
            {
                MalUserLookupResults userLookup = await GetUserLookupAsync(input, malApiFactory).ConfigureAwait(false);

                Dictionary <int, MalListEntry> animeList = new Dictionary <int, MalListEntry>();
                foreach (MyAnimeListEntry listEntry in userLookup.AnimeList)
                {
                    animeList[listEntry.AnimeInfo.AnimeId] = new AnimeRecs.RecEngine.MAL.MalListEntry((byte?)listEntry.Score, listEntry.Status, (short)listEntry.NumEpisodesWatched);
                }

                Dictionary <int, MalListEntry> animeWithheld = WithholdAnime(input, animeList);

                MalRecResults <IEnumerable <IRecommendation> > recResults = await GetRecommendationsAsync(input, recConfig.Value, animeList, animeWithheld, recClientFactory).ConfigureAwait(false);

                GetRecsViewModel viewModel = new GetRecsViewModel(
                    results: recResults,
                    userId: userLookup.UserId,
                    userName: userLookup.CanonicalUserName,
                    userLookup: userLookup,
                    userAnimeList: animeList,
                    maximumRecommendationsToReturn: recConfig.Value.MaximumRecommendationsToReturn,
                    maximumRecommendersToReturn: recConfig.Value.MaximumRecommendersToReturn,
                    animeWithheld: animeWithheld,
                    dbConnectionFactory: dbConnFactory
                    );

                RecResultsAsHtmlJson resultsJson = await GetResultHtmlAsync(viewModel, input, viewEngine, tempProvider).ConfigureAwait(false);

                return(Ok(resultsJson));
            }
            catch (ShortCircuitException ex)
            {
                return(ex.Result);
            }
        }
        private static UpdatePropertyResultViewModel createResultForConversionFailure(
            UpdatePropertyModel <TEntity> updatePropertyModel, Exception ex)
        {
            var message      = ex.Message;
            var accessor     = PropertyUtility.FindPropertyByName <TEntity>(updatePropertyModel.PropertyName);
            var propertyName = LocalizationManager.GetHeader(accessor.InnerProperty);

            var error = new AjaxError {
                field = propertyName, message = message
            };
            var updatePropertyResultViewModel = new UpdatePropertyResultViewModel
            {
                Success = false,
            };

            updatePropertyResultViewModel.Errors.Add(error);
            return(updatePropertyResultViewModel);
        }
예제 #3
0
        protected async Task <JsonResult> IfModelStateValidAjaxAsync(Func <Task <object> > func)
        {
            object data;

            if (ModelState.IsValid)
            {
                try
                {
                    data = await func();
                }
                catch (Exception ex)
                {
                    data = ex;
                }
            }
            else
            {
                data = new AjaxError(ViewData);
            }

            return(Json(data));
        }
예제 #4
0
        private async Task <MalUserLookupResults> GetUserLookupAsync(AnimeRecsInputJson input, IMyAnimeListApiFactory malApiFactory)
        {
            using (IMyAnimeListApi malApi = malApiFactory.GetMalApi())
            {
                _logger.LogInformation("Getting MAL list for user {0}.", input.MalName);
                MalUserLookupResults userLookup;
                try
                {
                    userLookup = await malApi.GetAnimeListForUserAsync(input.MalName).ConfigureAwait(false);

                    _logger.LogInformation("Got MAL list for user {0}.", input.MalName);
                    return(userLookup);
                }
                catch (MalUserNotFoundException)
                {
                    _logger.LogInformation("User {0} not found.", input.MalName);
                    AjaxError  error  = new AjaxError(AjaxError.NoSuchMALUser, "No such MAL user.");
                    JsonResult result = Json(error);
                    result.StatusCode = 404;
                    throw new ShortCircuitException(result);
                }
            }
        }
예제 #5
0
        private async Task <MalRecResults <IEnumerable <IRecommendation> > > GetRecommendationsAsync(AnimeRecsInputJson input,
                                                                                                     Config.RecommendationsConfig recConfig, Dictionary <int, MalListEntry> animeList,
                                                                                                     Dictionary <int, MalListEntry> animeWithheld, IAnimeRecsClientFactory recClientFactory)
        {
            int numRecsToTryToGet = recConfig.MaximumRecommendationsToReturn;

            if (animeWithheld.Count > 0)
            {
                // Get rating prediction information about all anime if in debug mode and withholding anime.
                // For all currently implemented algorithms, this does not cause a performance problem.
                numRecsToTryToGet = 100000;
            }

            using (AnimeRecsClient recClient = recClientFactory.GetClient(input.RecSourceName))
            {
                MalRecResults <IEnumerable <IRecommendation> > recResults;
                try
                {
                    if (input.GoodPercentile != null)
                    {
                        decimal targetFraction = input.GoodPercentile.Value / 100;
                        _logger.LogInformation("Querying rec source {0} for {1} recommendations for {2} using target of top {3}%.",
                                               input.RecSourceName, numRecsToTryToGet, input.MalName, targetFraction);
                        recResults = await recClient.GetMalRecommendationsWithFractionTargetAsync(animeList,
                                                                                                  input.RecSourceName, numRecsToTryToGet, targetFraction,
                                                                                                  TimeSpan.FromMilliseconds(recConfig.TimeoutMilliseconds), CancellationToken.None).ConfigureAwait(false);
                    }
                    else if (input.GoodCutoff != null)
                    {
                        _logger.LogInformation("Querying rec source {0} for {1} recommendations for {2} using target of {3}.",
                                               input.RecSourceName, numRecsToTryToGet, input.MalName, input.GoodCutoff.Value);
                        recResults = await recClient.GetMalRecommendationsAsync(animeList, input.RecSourceName,
                                                                                numRecsToTryToGet, input.GoodCutoff.Value, TimeSpan.FromMilliseconds(recConfig.TimeoutMilliseconds),
                                                                                CancellationToken.None).ConfigureAwait(false);
                    }
                    else
                    {
                        decimal targetFraction = recConfig.DefaultTargetPercentile / 100;
                        _logger.LogInformation("Querying rec source {0} for {1} recommendations for {2} using default target of top {3}%.",
                                               input.RecSourceName, numRecsToTryToGet, input.MalName, targetFraction);
                        recResults = await recClient.GetMalRecommendationsWithFractionTargetAsync(animeList,
                                                                                                  input.RecSourceName, numRecsToTryToGet, targetFraction,
                                                                                                  TimeSpan.FromMilliseconds(recConfig.TimeoutMilliseconds), CancellationToken.None)
                                     .ConfigureAwait(false);
                    }
                }
                catch (AnimeRecs.RecService.DTO.RecServiceErrorException ex)
                {
                    if (ex.Error.ErrorCode == AnimeRecs.RecService.DTO.ErrorCodes.Maintenance)
                    {
                        _logger.LogInformation("Could not service recommendation request for {0}. The rec service is currently undergoing maintenance.",
                                               input.MalName);
                        AjaxError  error  = new AjaxError(AjaxError.InternalError, "The site is currently undergoing scheduled maintenance. Check back in a few minutes.");
                        JsonResult result = Json(error);
                        result.StatusCode = 500;
                        throw new ShortCircuitException(result);
                    }
                    else
                    {
                        throw;
                    }
                }
                _logger.LogInformation("Got results from rec service for {0}.", input.MalName);

                return(recResults);
            }
        }
예제 #6
0
        private IActionResult ApiError(int statusCode, Exception ex)
        {
            AjaxError error = new AjaxError(AjaxError.InternalError, "Sorry, something went wrong when processing your request.");

            return(StatusCode(statusCode, error));
        }
 public static AjaxContinuation AddError(this AjaxContinuation ajaxContinuation, AjaxError ajaxError)
 {
     if (ajaxError == null)
     {
         return(ajaxContinuation);
     }
     ajaxContinuation.Errors.Add(ajaxError);
     return(ajaxContinuation);
 }
예제 #8
0
 private MalUserLookupResults GetUserLookup(AnimeRecsInputJson input)
 {
     using (IMyAnimeListApi malApi = _malApiFactory.GetMalApi())
     {
         Logging.Log.InfoFormat("Getting MAL list for user {0}.", input.MalName);
         MalUserLookupResults userLookup;
         try
         {
             userLookup = malApi.GetAnimeListForUser(input.MalName);
             Logging.Log.InfoFormat("Got MAL list for user {0}.", input.MalName);
             return userLookup;
         }
         catch (MalUserNotFoundException)
         {
             Logging.Log.InfoFormat("User {0} not found.", input.MalName);
             AjaxError error = new AjaxError(AjaxError.NoSuchMALUser, "No such MAL user.");
             Response response = Response.AsJson(error, HttpStatusCode.BadRequest);
             throw new ShortCircuitException(response);
         }
     }
 }
예제 #9
0
        private object GetRecs(dynamic arg)
        {
            Logging.Log.Info("Started processing GetRecs request.");

            AnimeRecsInputJson input;
            try
            {
                input = this.BindAndValidate<AnimeRecsInputJson>();
            }
            catch (JsonSerializationException ex)
            {
                AjaxError error = new AjaxError(AjaxError.InvalidInput, ex.Message);
                return Response.AsJson(error, HttpStatusCode.BadRequest);
            }
            if (!ModelValidationResult.IsValid)
            {
                string errorString = ModelBindingHelpers.ConstructErrorString(ModelValidationResult.Errors);
                AjaxError error = new AjaxError(AjaxError.InvalidInput, errorString);
                return Response.AsJson(error, HttpStatusCode.BadRequest);
            }

            try
            {
                return DoGetRecs(input);
            }
            catch (ShortCircuitException earlyResponse)
            {
                return earlyResponse.Response;
            }
        }
예제 #10
0
        private MalRecResults<IEnumerable<IRecommendation>> GetRecommendations(AnimeRecsInputJson input, Dictionary<int, MalListEntry> animeList, Dictionary<int, MalListEntry> animeWithheld)
        {
            int numRecsToTryToGet = _config.MaximumRecommendationsToReturn;
            if (animeWithheld.Count > 0)
            {
                // Get rating prediction information about all anime if in debug mode and withholding anime.
                // For all currently implemented algorithms, this does not cause a performance problem.
                numRecsToTryToGet = 100000;
            }

            using (AnimeRecsClient recClient = _recClientFactory.GetClient(input.RecSourceName))
            {
                MalRecResults<IEnumerable<IRecommendation>> recResults;
                try
                {
                    if (input.GoodPercentile != null)
                    {
                        Logging.Log.InfoFormat("Querying rec source {0} for {1} recommendations for {2} using target of top {3}%.",
                            input.RecSourceName, numRecsToTryToGet, input.MalName, input.GoodPercentile.Value);
                        recResults = recClient.GetMalRecommendationsWithPercentileTarget(animeList, input.RecSourceName, numRecsToTryToGet,
                            input.GoodPercentile.Value);
                    }
                    else if (input.GoodCutoff != null)
                    {
                        Logging.Log.InfoFormat("Querying rec source {0} for {1} recommendations for {2} using target of {3}.",
                            input.RecSourceName, numRecsToTryToGet, input.MalName, input.GoodCutoff.Value);
                        recResults = recClient.GetMalRecommendations(animeList, input.RecSourceName, numRecsToTryToGet,
                            input.GoodCutoff.Value);
                    }
                    else
                    {
                        Logging.Log.InfoFormat("Querying rec source {0} for {1} recommendations for {2} using default target of top {3}%.",
                            input.RecSourceName, numRecsToTryToGet, input.MalName, AppGlobals.Config.DefaultTargetPercentile);
                        recResults = recClient.GetMalRecommendationsWithPercentileTarget(animeList, input.RecSourceName, numRecsToTryToGet,
                            AppGlobals.Config.DefaultTargetPercentile);
                    }
                }
                catch (AnimeRecs.RecService.DTO.RecServiceErrorException ex)
                {
                    if (ex.Error.ErrorCode == AnimeRecs.RecService.DTO.ErrorCodes.Maintenance)
                    {
                        Logging.Log.InfoFormat("Could not service recommendation request for {0}. The rec service is currently undergoing maintenance.",
                            input.MalName);
                        AjaxError error = new AjaxError(AjaxError.InternalError, "The site is currently undergoing scheduled maintenance. Check back in a few minutes.");
                        Response response = Response.AsJson(error, HttpStatusCode.InternalServerError);
                        throw new ShortCircuitException(response);
                    }
                    else
                    {
                        throw;
                    }
                }
                Logging.Log.InfoFormat("Got results from rec service for {0}.", input.MalName);

                return recResults;
            }
        }