コード例 #1
0
        /// <summary>
        /// Runs the analysis with the given ID.
        /// </summary>
        /// <param name="viewModel">The view model of the analysis to run.</param>
        /// <returns></returns>
        public async Task Run(AnalysisRunnerViewModel viewModel)
        {
            // Get the analysis with the given ID.
            var analysis = _context.Analyses
                           .Include(item => item.AnalysisNodes)
                           .ThenInclude(item => item.Node)
                           .Include(item => item.AnalysisEdges)
                           .ThenInclude(item => item.Edge)
                           .ThenInclude(item => item.EdgeNodes)
                           .ThenInclude(item => item.Node)
                           .Include(item => item.AnalysisUsers)
                           .ThenInclude(item => item.User)
                           .FirstOrDefault(item => item.Id == viewModel.Id);

            // Check if the analysis hasn't been found.
            if (analysis == null)
            {
                // End the function.
                return;
            }
            // Run the analysis.
            await analysis.Run(_context);

            // Reload the analysis.
            await _context.Entry(analysis).ReloadAsync();

            // Define the HTTP context host.
            var host = new HostString(viewModel.HostValue);

            // Go over each registered user in the analysis.
            foreach (var user in analysis.AnalysisUsers.Where(item => item.User != null).Select(item => item.User))
            {
                // Send an analysis ending e-mail.
                await _emailSender.SendAnalysisEndedEmailAsync(new EmailAnalysisEndedViewModel
                {
                    Email          = user.Email,
                    Id             = analysis.Id,
                    Name           = analysis.Name,
                    Status         = analysis.Status.GetDisplayName(),
                    Url            = _linkGenerator.GetUriByPage("/Content/Created/Analyses/Details/Index", handler: null, values: new { id = analysis.Id }, scheme: viewModel.Scheme, host: host),
                    ApplicationUrl = _linkGenerator.GetUriByPage("/Index", handler: null, values: null, scheme: viewModel.Scheme, host: host)
                });
            }
        }
コード例 #2
0
        public async Task <IActionResult> OnPostAsync()
        {
            // Get the current user.
            var user = await _userManager.GetUserAsync(User);

            // Check if the user does not exist.
            if (user == null)
            {
                // Display a message.
                TempData["StatusMessage"] = "Error: An error occured while trying to load the user data. If you are already logged in, please log out and try again.";
                // Redirect to the home page.
                return(RedirectToPage("/Index"));
            }
            // Check if there isn't any database type ID provided.
            if (string.IsNullOrEmpty(Input.DatabaseTypeId))
            {
                // Display a message.
                TempData["StatusMessage"] = "Error: A type is required for creating an analysis.";
                // Redirect to the index page.
                return(RedirectToPage("/Content/Created/Analyses/Index"));
            }
            // Try to get the database type with the provided ID.
            var databaseType = _context.DatabaseTypes.FirstOrDefault(item => item.Id == Input.DatabaseTypeId);

            // Check if there wasn't any database type found.
            if (databaseType == null)
            {
                // Display a message.
                TempData["StatusMessage"] = "Error: No type could be found with the provided ID.";
                // Redirect to the index page.
                return(RedirectToPage("/Content/Created/Analyses/Index"));
            }
            // Check if there isn't any algorithm provided.
            if (Input.Algorithm == null)
            {
                // Display a message.
                TempData["StatusMessage"] = "Error: An algorithm is required for creating an analysis.";
                // Redirect to the index page.
                return(RedirectToPage("/Content/Created/Analyses/Index"));
            }
            // Define the view.
            View = new ViewModel
            {
                Algorithm = Input.Algorithm.Value,
                Networks  = _context.Networks
                            .Where(item => item.NetworkDatabases.Any(item1 => item1.Database.DatabaseType == databaseType))
                            .Where(item => item.NetworkDatabases.Any(item1 => item1.Database.IsPublic || item1.Database.DatabaseUsers.Any(item2 => item2.User == user))),
                SourceNodeCollections = _context.NodeCollections
                                        .Where(item => item.NodeCollectionDatabases.Any(item1 => item1.Database.DatabaseType == databaseType))
                                        .Where(item => item.NodeCollectionDatabases.Any(item1 => item1.Database.IsPublic || item1.Database.DatabaseUsers.Any(item2 => item2.User == user))),
                TargetNodeCollections = _context.NodeCollections
                                        .Where(item => item.NodeCollectionDatabases.Any(item1 => item1.Database.DatabaseType == databaseType))
                                        .Where(item => item.NodeCollectionDatabases.Any(item1 => item1.Database.IsPublic || item1.Database.DatabaseUsers.Any(item2 => item2.User == user)))
            };
            // Check if there weren't any networks available.
            if (!View.Networks.Any())
            {
                // Display a message.
                TempData["StatusMessage"] = "Error: A new analysis can't be created, as there are no networks available.";
                // Redirect to the index page.
                return(RedirectToPage("/Content/Created/Analyses/Index"));
            }
            // Check if the provided model isn't valid.
            if (!ModelState.IsValid)
            {
                // Add an error to the model.
                ModelState.AddModelError(string.Empty, "An error has been encountered. Please check again the input fields.");
                // Redisplay the page.
                return(Page());
            }
            // Get the provided network IDs.
            var networkIds = Input.NetworkIds ?? Enumerable.Empty <string>();

            // Check if there weren't any network IDs provided.
            if (!networkIds.Any())
            {
                // Add an error to the model.
                ModelState.AddModelError(string.Empty, "At least one network must be selected.");
                // Redisplay the page.
                return(Page());
            }
            // Try to get the networks with the provided IDs.
            var networks = View.Networks
                           .Where(item => networkIds.Contains(item.Id));

            // Check if there weren't any networks found.
            if (!networks.Any())
            {
                // Add an error to the model.
                ModelState.AddModelError(string.Empty, "No networks could be found with the provided IDs.");
                // Redisplay the page.
                return(Page());
            }
            // Get the databases to which the user has access.
            var databases = _context.Databases
                            .Where(item => item.DatabaseType == databaseType)
                            .Where(item => item.IsPublic || item.DatabaseUsers.Any(item1 => item1.User == user));

            // Try to deserialize the source data.
            if (!Input.SourceData.TryDeserializeJsonObject <IEnumerable <string> >(out var sourceItems))
            {
                // Add an error to the model.
                ModelState.AddModelError(string.Empty, "The provided source data is not a valid JSON object of nodes.");
                // Redisplay the page.
                return(Page());
            }
            // Get the provided source node collection IDs.
            var sourceNodeCollectionIds = Input.SourceNodeCollectionIds ?? Enumerable.Empty <string>();
            // Try to get the source node collections with the provided IDs.
            var sourceNodeCollections = View.SourceNodeCollections
                                        .Where(item => sourceNodeCollectionIds.Contains(item.Id));
            // Get all of the source nodes that match the given data.
            var sourceNodes = networks
                              .Select(item => item.NetworkNodes)
                              .SelectMany(item => item)
                              .Select(item => item.Node)
                              .Where(item => item.DatabaseNodeFieldNodes.Where(item1 => databases.Contains(item1.DatabaseNodeField.Database) && item1.DatabaseNodeField.IsSearchable).Any(item1 => sourceItems.Contains(item1.Node.Id) || sourceItems.Contains(item1.Value)))
                              .Concat(sourceNodeCollections
                                      .Select(item => item.NodeCollectionNodes)
                                      .SelectMany(item => item)
                                      .Select(item => item.Node))
                              .Distinct();

            // Try to deserialize the target data.
            if (!Input.TargetData.TryDeserializeJsonObject <IEnumerable <string> >(out var targetItems))
            {
                // Add an error to the model.
                ModelState.AddModelError(string.Empty, "The provided target data is not a valid JSON object of nodes.");
                // Redisplay the page.
                return(Page());
            }
            // Get the provided source node collection IDs.
            var targetNodeCollectionIds = Input.TargetNodeCollectionIds ?? Enumerable.Empty <string>();
            // Try to get the target node collections with the provided IDs.
            var targetNodeCollections = View.TargetNodeCollections
                                        .Where(item => targetNodeCollectionIds.Contains(item.Id));
            // Get all of the target nodes that match the given data.
            var targetNodes = networks
                              .Select(item => item.NetworkNodes)
                              .SelectMany(item => item)
                              .Select(item => item.Node)
                              .Where(item => item.DatabaseNodeFieldNodes.Where(item1 => databases.Contains(item1.DatabaseNodeField.Database) && item1.DatabaseNodeField.IsSearchable).Any(item1 => targetItems.Contains(item1.Node.Id) || targetItems.Contains(item1.Value)))
                              .Concat(targetNodeCollections
                                      .Select(item => item.NodeCollectionNodes)
                                      .SelectMany(item => item)
                                      .Select(item => item.Node))
                              .Distinct();

            // Check if there haven't been any target nodes found.
            if (targetNodes == null || !targetNodes.Any())
            {
                // Add an error to the model.
                ModelState.AddModelError(string.Empty, "No target nodes could be found with the provided target data.");
                // Redisplay the page.
                return(Page());
            }
            // Define the JSON serializer options.
            var jsonSerializerOptions = new JsonSerializerOptions
            {
                IgnoreReadOnlyProperties = true
            };
            // Define the new analysis.
            var analysis = new Analysis
            {
                Name             = Input.Name,
                Description      = Input.Description,
                DateTimeStarted  = null,
                DateTimeEnded    = null,
                Algorithm        = View.Algorithm,
                CurrentIteration = 0,
                CurrentIterationWithoutImprovement = 0,
                MaximumIterations = Input.MaximumIterations,
                MaximumIterationsWithoutImprovement = Input.MaximumIterationsWithoutImprovement,
                Parameters = View.Algorithm == AnalysisAlgorithm.Algorithm1 ? JsonSerializer.Serialize(Input.Algorithm1Parameters, jsonSerializerOptions) :
                             View.Algorithm == AnalysisAlgorithm.Algorithm2 ? JsonSerializer.Serialize(Input.Algorithm2Parameters, jsonSerializerOptions) : null,
                Status = AnalysisStatus.Scheduled,
                Log    = JsonSerializer.Serialize(new List <string> {
                    $"{DateTime.Now}: Analysis has been created and scheduled."
                }),
                AnalysisUsers = new List <AnalysisUser>
                {
                    new AnalysisUser
                    {
                        User            = user,
                        DateTimeCreated = DateTime.Now
                    }
                },
                AnalysisDatabases = networks
                                    .Select(item => item.NetworkDatabases)
                                    .SelectMany(item => item)
                                    .Select(item => item.Database)
                                    .Distinct()
                                    .Select(item => new AnalysisDatabase
                {
                    Database = item
                })
                                    .ToList(),
                AnalysisNodes = networks
                                .Select(item => item.NetworkNodes)
                                .SelectMany(item => item)
                                .Select(item => item.Node)
                                .Distinct()
                                .Select(item => new AnalysisNode
                {
                    Node = item,
                    Type = AnalysisNodeType.None
                })
                                .Concat(sourceNodes
                                        .Select(item => new AnalysisNode
                {
                    Node = item,
                    Type = AnalysisNodeType.Source
                }))
                                .Concat(targetNodes
                                        .Select(item => new AnalysisNode
                {
                    Node = item,
                    Type = AnalysisNodeType.Target
                }))
                                .ToList(),
                AnalysisEdges = networks
                                .Select(item => item.NetworkEdges)
                                .SelectMany(item => item)
                                .Select(item => item.Edge)
                                .Distinct()
                                .Select(item => new AnalysisEdge
                {
                    Edge = item
                })
                                .ToList(),
                AnalysisNodeCollections = sourceNodeCollections
                                          .Select(item => new AnalysisNodeCollection
                {
                    NodeCollection = item,
                    Type           = AnalysisNodeCollectionType.Source
                })
                                          .Concat(targetNodeCollections
                                                  .Select(item => new AnalysisNodeCollection
                {
                    NodeCollection = item,
                    Type           = AnalysisNodeCollectionType.Target
                }))
                                          .ToList(),
                AnalysisNetworks = networks
                                   .Select(item => new AnalysisNetwork
                {
                    Network = item
                })
                                   .ToList()
            };

            // Mark the data for addition.
            _context.Analyses.Add(analysis);
            // Save the changes to the database.
            await _context.SaveChangesAsync();

            // Define the analysis runner view model.
            var viewModel = new AnalysisRunnerViewModel
            {
                Id        = analysis.Id,
                Scheme    = HttpContext.Request.Scheme,
                HostValue = HttpContext.Request.Host.Value
            };

            // Mark the data for updating.
            _context.Analyses.Update(analysis);
            // Add a new Hangfire background task.
            analysis.JobId = BackgroundJob.Enqueue <IAnalysisRunner>(item => item.Run(viewModel));
            // Save the changes to the database.
            await _context.SaveChangesAsync();

            // Display a message.
            TempData["StatusMessage"] = $"Success: 1 analysis of type \"{databaseType.Name}\" using the algorithm \"{analysis.Algorithm.GetDisplayName()}\" created and scheduled successfully.";
            // Redirect to the index page.
            return(RedirectToPage("/Content/Created/Analyses/Index"));
        }