< Summary

Information
Class: LGDXRobotCloud.API.Services.Automation.FlowService
Assembly: LGDXRobotCloud.API
File(s): /builds/yukaitung/lgdxrobot2-cloud/LGDXRobotCloud.API/Services/Automation/FlowService.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 150
Coverable lines: 150
Total lines: 199
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 26
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)0%620%
GetFlowsAsync()0%620%
GetFlowAsync()0%620%
ValidateFlow()0%110100%
CreateFlowAsync()100%210%
UpdateFlowAsync()0%4260%
TestDeleteFlowAsync()0%620%
DeleteFlowAsync()100%210%
SearchFlowsAsync()0%620%

File(s)

/builds/yukaitung/lgdxrobot2-cloud/LGDXRobotCloud.API/Services/Automation/FlowService.cs

#LineLine coverage
 1using LGDXRobotCloud.API.Exceptions;
 2using LGDXRobotCloud.Data.DbContexts;
 3using LGDXRobotCloud.Data.Entities;
 4using LGDXRobotCloud.Data.Models.Business.Automation;
 5using LGDXRobotCloud.Utilities.Enums;
 6using LGDXRobotCloud.Utilities.Helpers;
 7using Microsoft.EntityFrameworkCore;
 8
 9namespace LGDXRobotCloud.API.Services.Automation;
 10
 11public interface IFlowService
 12{
 13  Task<(IEnumerable<FlowListBusinessModel>, PaginationHelper)> GetFlowsAsync(string? name, int pageNumber, int pageSize)
 14  Task<FlowBusinessModel> GetFlowAsync(int flowId);
 15  Task<FlowBusinessModel> CreateFlowAsync(FlowCreateBusinessModel flowCreateBusinessModel);
 16  Task<bool> UpdateFlowAsync(int flowId, FlowUpdateBusinessModel flowUpdateBusinessModel);
 17  Task<bool> TestDeleteFlowAsync(int flowId);
 18  Task<bool> DeleteFlowAsync(int flowId);
 19
 20  Task<IEnumerable<FlowSearchBusinessModel>> SearchFlowsAsync(string? name);
 21}
 22
 023public class FlowService(LgdxContext context) : IFlowService
 24{
 025  private readonly LgdxContext _context = context ?? throw new ArgumentNullException(nameof(context));
 26
 27  public async Task<(IEnumerable<FlowListBusinessModel>, PaginationHelper)> GetFlowsAsync(string? name, int pageNumber, 
 028  {
 029    var query = _context.Flows as IQueryable<Flow>;
 030      if(!string.IsNullOrWhiteSpace(name))
 031      {
 032        name = name.Trim();
 033        query = query.Where(f => f.Name.Contains(name));
 034      }
 035      var itemCount = await query.CountAsync();
 036      var PaginationHelper = new PaginationHelper(itemCount, pageNumber, pageSize);
 037      var flows = await query.AsNoTracking()
 038        .OrderBy(t => t.Id)
 039        .Skip(pageSize * (pageNumber - 1))
 040        .Take(pageSize)
 041        .Select(t => new FlowListBusinessModel {
 042          Id = t.Id,
 043          Name = t.Name,
 044        })
 045        .ToListAsync();
 046      return (flows, PaginationHelper);
 047  }
 48
 49  public async Task<FlowBusinessModel> GetFlowAsync(int flowId)
 050  {
 051    return await _context.Flows.Where(f => f.Id == flowId)
 052      .Include(f => f.FlowDetails
 053        .OrderBy(fd => fd.Order))
 054        .ThenInclude(fd => fd.Progress)
 055      .Include(f => f.FlowDetails)
 056        .ThenInclude(fd => fd.Trigger)
 057      .Select(f => new FlowBusinessModel {
 058        Id = f.Id,
 059        Name = f.Name,
 060        FlowDetails = f.FlowDetails.Select(fd => new FlowDetailBusinessModel {
 061          Id = fd.Id,
 062          Order = fd.Order,
 063          ProgressId = fd.Progress.Id,
 064          ProgressName = fd.Progress.Name,
 065          AutoTaskNextControllerId = fd.AutoTaskNextControllerId,
 066          TriggerId = fd.Trigger!.Id,
 067          TriggerName = fd.Trigger!.Name,
 068        }).OrderBy(fd => fd.Order).ToList(),
 069      })
 070      .FirstOrDefaultAsync()
 071        ?? throw new LgdxNotFound404Exception();
 072  }
 73
 74  private async Task ValidateFlow(HashSet<int> progressIds, HashSet<int> triggerIds)
 075  {
 076    var progresses = await _context.Progresses.Where(p => progressIds.Contains(p.Id)).ToDictionaryAsync(p => p.Id);
 077    foreach (var progressId in progressIds)
 078    {
 079      if (progresses.TryGetValue(progressId, out var progress))
 080      {
 081        if (progress.Reserved)
 082        {
 083          throw new LgdxValidation400Expection("Progress", $"The Progress ID: {progressId} is reserved.");
 84        }
 085      }
 86      else
 087      {
 088        throw new LgdxValidation400Expection("Progress", $"The Progress Id: {progressId} is invalid.");
 89      }
 090    }
 091    var triggers = await _context.Triggers.Where(t => triggerIds.Contains(t.Id)).ToDictionaryAsync(t => t.Id);
 092    foreach (var triggerId in triggerIds)
 093    {
 094      if (!triggers.TryGetValue(triggerId, out var trigger))
 095      {
 096        throw new LgdxValidation400Expection("Trigger", $"The Trigger ID: {triggerId} is invalid.");
 97      }
 098    }
 099  }
 100
 101  public async Task<FlowBusinessModel> CreateFlowAsync(FlowCreateBusinessModel flowCreateBusinessModel)
 0102  {
 0103    HashSet<int> progressIds = flowCreateBusinessModel.FlowDetails.Select(d => d.ProgressId).ToHashSet();
 0104    HashSet<int> triggerIds = flowCreateBusinessModel.FlowDetails.Where(d => d.TriggerId != null).Select(d => d.TriggerI
 0105    await ValidateFlow(progressIds, triggerIds);
 0106    var flow = new Flow {
 0107      Name = flowCreateBusinessModel.Name,
 0108      FlowDetails = flowCreateBusinessModel.FlowDetails.Select(fd => new FlowDetail {
 0109        Order = fd.Order,
 0110        ProgressId = fd.ProgressId,
 0111        AutoTaskNextControllerId = fd.AutoTaskNextControllerId,
 0112        TriggerId = fd.TriggerId,
 0113      }).ToList(),
 0114    };
 0115    await _context.Flows.AddAsync(flow);
 0116    await _context.SaveChangesAsync();
 117
 0118    return new FlowBusinessModel {
 0119      Id = flow.Id,
 0120      Name = flow.Name,
 0121      FlowDetails = flow.FlowDetails.Select(fd => new FlowDetailBusinessModel {
 0122        Id = fd.Id,
 0123        Order = fd.Order,
 0124        ProgressId = fd.ProgressId,
 0125        ProgressName = fd.Progress.Name,
 0126        AutoTaskNextControllerId = fd.AutoTaskNextControllerId,
 0127        TriggerId = fd.TriggerId,
 0128        TriggerName = fd.Trigger?.Name,
 0129      }).ToList(),
 0130    };
 0131  }
 132
 133  public async Task<bool> UpdateFlowAsync(int flowId, FlowUpdateBusinessModel flowUpdateBusinessModel)
 0134  {
 0135    var flow = await _context.Flows.Where(f => f.Id == flowId)
 0136      .Include(f => f.FlowDetails
 0137        .OrderBy(fd => fd.Order))
 0138        .ThenInclude(fd => fd.Progress)
 0139      .Include(f => f.FlowDetails)
 0140        .ThenInclude(fd => fd.Trigger)
 0141      .FirstOrDefaultAsync()
 0142        ?? throw new LgdxNotFound404Exception();
 143
 0144    HashSet<int?> dbDetailIds = flowUpdateBusinessModel.FlowDetails.Where(d => d.Id != null).Select(d => d.Id).ToHashSet
 0145    foreach(var dtoDetailId in flowUpdateBusinessModel.FlowDetails.Where(d => d.Id != null).Select(d => d.Id))
 0146    {
 0147      if(!dbDetailIds.Contains((int)dtoDetailId!))
 0148      {
 0149        throw new LgdxValidation400Expection("FlowDetails", $"The Flow Detail ID {(int)dtoDetailId} is belongs to other 
 150      }
 0151    }
 0152    HashSet<int> progressIds = flowUpdateBusinessModel.FlowDetails.Select(d => d.ProgressId).ToHashSet();
 0153    HashSet<int> triggerIds = flowUpdateBusinessModel.FlowDetails.Where(d => d.TriggerId != null).Select(d => d.TriggerI
 0154    await ValidateFlow(progressIds, triggerIds);
 155
 0156    flow.Name = flowUpdateBusinessModel.Name;
 0157    flow.FlowDetails = flowUpdateBusinessModel.FlowDetails.Select(fd => new FlowDetail {
 0158        Id = (int)fd.Id!,
 0159        Order = fd.Order,
 0160        ProgressId = fd.ProgressId,
 0161        AutoTaskNextControllerId = fd.AutoTaskNextControllerId,
 0162        TriggerId = fd.TriggerId,
 0163      }).ToList();
 0164    await _context.SaveChangesAsync();
 0165    return true;
 0166  }
 167
 168  public async Task<bool> TestDeleteFlowAsync(int flowId)
 0169  {
 0170    var depeendencies = await _context.AutoTasks
 0171      .Where(a => a.FlowId == flowId)
 0172      .Where(a => a.CurrentProgressId != (int)ProgressState.Completed && a.CurrentProgressId != (int)ProgressState.Abort
 0173      .CountAsync();
 0174    if (depeendencies > 0)
 0175    {
 0176      throw new LgdxValidation400Expection(nameof(flowId), $"This flow has been used by {depeendencies} running/waiting/
 177    }
 0178    return true;
 0179  }
 180
 181  public async Task<bool> DeleteFlowAsync(int flowId)
 0182  {
 0183    return await _context.Flows.Where(f => f.Id == flowId)
 0184      .ExecuteDeleteAsync() >= 1;
 0185  }
 186
 187  public async Task<IEnumerable<FlowSearchBusinessModel>> SearchFlowsAsync(string? name)
 0188  {
 0189    var n = name ?? string.Empty;
 0190    return await _context.Flows.AsNoTracking()
 0191      .Where(w => w.Name.ToLower().Contains(n.ToLower()))
 0192      .Take(10)
 0193      .Select(t => new FlowSearchBusinessModel {
 0194        Id = t.Id,
 0195        Name = t.Name,
 0196      })
 0197      .ToListAsync();
 0198  }
 199}