/// <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) }); } }
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")); }