< Summary

Information
Class: LGDXRobotCloud.API.Services.Automation.TriggerService
Assembly: LGDXRobotCloud.API
File(s): /builds/yukaitung/lgdxrobot2-cloud/LGDXRobotCloud.API/Services/Automation/TriggerService.cs
Line coverage
81%
Covered lines: 189
Uncovered lines: 42
Coverable lines: 231
Total lines: 306
Line coverage: 81.8%
Branch coverage
66%
Covered branches: 50
Total branches: 75
Branch coverage: 66.6%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)50%88100%
GetTriggersAsync()100%22100%
GetTriggerAsync()100%22100%
ValidateApiKey()100%44100%
CreateTriggerAsync()75%44100%
UpdateTriggerAsync()0%2040%
TestDeleteTriggerAsync()100%22100%
DeleteTriggerAsync()0%620%
SearchTriggersAsync()50%22100%
GetRobotName(...)50%44100%
GetRealmName(...)50%44100%
GeneratePresetValue(...)70.58%171792.85%
InitialiseTriggerAsync()87.5%1616100%
RetryTriggerAsync()50%4494.11%

File(s)

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

#LineLine coverage
 1using System.Text.Json;
 2using LGDXRobotCloud.API.Exceptions;
 3using LGDXRobotCloud.API.Services.Administration;
 4using LGDXRobotCloud.Data.Contracts;
 5using LGDXRobotCloud.Data.DbContexts;
 6using LGDXRobotCloud.Data.Entities;
 7using LGDXRobotCloud.Data.Models.Business.Administration;
 8using LGDXRobotCloud.Data.Models.Business.Automation;
 9using LGDXRobotCloud.Utilities.Enums;
 10using LGDXRobotCloud.Utilities.Helpers;
 11using MassTransit;
 12using Microsoft.EntityFrameworkCore;
 13
 14namespace LGDXRobotCloud.API.Services.Automation;
 15
 16public interface ITriggerService
 17{
 18  Task<(IEnumerable<TriggerListBusinessModel>, PaginationHelper)> GetTriggersAsync(string? name, int pageNumber, int pag
 19  Task<TriggerBusinessModel> GetTriggerAsync(int triggerId);
 20  Task<TriggerBusinessModel> CreateTriggerAsync(TriggerCreateBusinessModel triggerCreateBusinessModel);
 21  Task<bool> UpdateTriggerAsync(int triggerId, TriggerUpdateBusinessModel triggerUpdateBusinessModel);
 22  Task<bool> TestDeleteTriggerAsync(int triggerId);
 23  Task<bool> DeleteTriggerAsync(int triggerId);
 24
 25  Task<IEnumerable<TriggerSearchBusinessModel>> SearchTriggersAsync(string? name);
 26
 27  Task InitialiseTriggerAsync(AutoTask autoTask, FlowDetail flowDetail);
 28  Task<bool> RetryTriggerAsync(AutoTask autoTask, Trigger trigger, string body);
 29}
 30
 1831public sealed class TriggerService (
 1832  IActivityLogService activityService,
 1833  IApiKeyService apiKeyService,
 1834  IBus bus,
 1835  LgdxContext context
 1836) : ITriggerService
 37{
 1838  private readonly IActivityLogService _activityService = activityService ?? throw new ArgumentNullException(nameof(acti
 1839  private readonly IApiKeyService _apiKeyService = apiKeyService ?? throw new ArgumentNullException(nameof(apiKeyService
 1840  private readonly IBus _bus = bus ?? throw new ArgumentNullException(nameof(bus));
 1841  private readonly LgdxContext _context = context ?? throw new ArgumentNullException(nameof(context));
 42
 43  public async Task<(IEnumerable<TriggerListBusinessModel>, PaginationHelper)> GetTriggersAsync(string? name, int pageNu
 444  {
 445    var query = _context.Triggers as IQueryable<Trigger>;
 446    if(!string.IsNullOrWhiteSpace(name))
 347    {
 348      name = name.Trim();
 349      query = query.Where(t => t.Name.ToLower().Contains(name.ToLower()));
 350    }
 451    var itemCount = await query.CountAsync();
 452    var PaginationHelper = new PaginationHelper(itemCount, pageNumber, pageSize);
 453    var triggers = await query.AsNoTracking()
 454      .OrderBy(t => t.Id)
 455      .Skip(pageSize * (pageNumber - 1))
 456      .Take(pageSize)
 457      .Select(t => new TriggerListBusinessModel {
 458        Id = t.Id,
 459        Name = t.Name,
 460        Url = t.Url,
 461        HttpMethodId = t.HttpMethodId,
 462      })
 463      .ToListAsync();
 464    return (triggers, PaginationHelper);
 465  }
 66
 67  public async Task<TriggerBusinessModel> GetTriggerAsync(int triggerId)
 268  {
 269    return await _context.Triggers.Where(t => t.Id == triggerId)
 270      .Include(t => t.ApiKey)
 271      .Select(t => new TriggerBusinessModel {
 272        Id = t.Id,
 273        Name = t.Name,
 274        Url = t.Url,
 275        HttpMethodId = t.HttpMethodId,
 276        Body = t.Body,
 277        ApiKeyInsertLocationId = t.ApiKeyInsertLocationId,
 278        ApiKeyFieldName = t.ApiKeyFieldName,
 279        ApiKeyId = t.ApiKey!.Id,
 280        ApiKeyName = t.ApiKey!.Name,
 281      })
 282      .FirstOrDefaultAsync()
 283        ?? throw new LgdxNotFound404Exception();
 184  }
 85
 86  private async Task ValidateApiKey(int apiKeyId)
 387  {
 388    var apiKey = await _apiKeyService.GetApiKeyAsync(apiKeyId);
 389    if (apiKey == null)
 190    {
 191      throw new LgdxValidation400Expection(nameof(TriggerBusinessModel.Id), $"The API Key Id {apiKeyId} is invalid.");
 92    }
 293    else if (!apiKey.IsThirdParty)
 194    {
 195      throw new LgdxValidation400Expection(nameof(TriggerBusinessModel.Id), "Only third party API key is allowed.");
 96    }
 197  }
 98
 99  public async Task<TriggerBusinessModel> CreateTriggerAsync(TriggerCreateBusinessModel triggerCreateBusinessModel)
 3100  {
 3101    if (triggerCreateBusinessModel.ApiKeyId != null)
 3102    {
 3103      await ValidateApiKey((int)triggerCreateBusinessModel.ApiKeyId);
 1104    }
 105
 1106    var trigger = new Trigger {
 1107      Name = triggerCreateBusinessModel.Name,
 1108      Url = triggerCreateBusinessModel.Url,
 1109      HttpMethodId = triggerCreateBusinessModel.HttpMethodId,
 1110      Body = triggerCreateBusinessModel.Body,
 1111      ApiKeyInsertLocationId = triggerCreateBusinessModel.ApiKeyInsertLocationId,
 1112      ApiKeyFieldName = triggerCreateBusinessModel.ApiKeyFieldName,
 1113      ApiKeyId = triggerCreateBusinessModel.ApiKeyId,
 1114    };
 1115    await _context.Triggers.AddAsync(trigger);
 1116    await _context.SaveChangesAsync();
 117
 1118    await _activityService.CreateActivityLogAsync(new ActivityLogCreateBusinessModel
 1119    {
 1120      EntityName = nameof(Trigger),
 1121      EntityId = trigger.Id.ToString(),
 1122      Action = ActivityAction.Create,
 1123    });
 124
 1125    return new TriggerBusinessModel
 1126    {
 1127      Id = trigger.Id,
 1128      Name = trigger.Name,
 1129      Url = trigger.Url,
 1130      HttpMethodId = trigger.HttpMethodId,
 1131      Body = trigger.Body,
 1132      ApiKeyInsertLocationId = trigger.ApiKeyInsertLocationId,
 1133      ApiKeyFieldName = trigger.ApiKeyFieldName,
 1134      ApiKeyId = trigger.ApiKeyId,
 1135      ApiKeyName = trigger.ApiKey?.Name,
 1136    };
 1137  }
 138
 139  public async Task<bool> UpdateTriggerAsync(int triggerId, TriggerUpdateBusinessModel triggerUpdateBusinessModel)
 0140  {
 0141    if (triggerUpdateBusinessModel.ApiKeyId != null)
 0142    {
 0143      await ValidateApiKey((int)triggerUpdateBusinessModel.ApiKeyId);
 0144    }
 145
 0146    bool result = await _context.Triggers
 0147      .Where(t => t.Id == triggerId)
 0148      .ExecuteUpdateAsync(setters => setters
 0149        .SetProperty(t => t.Name, triggerUpdateBusinessModel.Name)
 0150        .SetProperty(t => t.Url, triggerUpdateBusinessModel.Url)
 0151        .SetProperty(t => t.HttpMethodId, triggerUpdateBusinessModel.HttpMethodId)
 0152        .SetProperty(t => t.Body, triggerUpdateBusinessModel.Body)
 0153        .SetProperty(t => t.ApiKeyInsertLocationId, triggerUpdateBusinessModel.ApiKeyInsertLocationId)
 0154        .SetProperty(t => t.ApiKeyFieldName, triggerUpdateBusinessModel.ApiKeyFieldName)
 0155        .SetProperty(t => t.ApiKeyId, triggerUpdateBusinessModel.ApiKeyId)) == 1;
 156
 0157    if (result)
 0158    {
 0159      await _activityService.CreateActivityLogAsync(new ActivityLogCreateBusinessModel
 0160      {
 0161        EntityName = nameof(Trigger),
 0162        EntityId = triggerId.ToString(),
 0163        Action = ActivityAction.Update,
 0164      });
 0165    }
 0166    return result;
 0167  }
 168
 169  public async Task<bool> TestDeleteTriggerAsync(int triggerId)
 2170  {
 2171    var depeendencies = await _context.FlowDetails.Where(t => t.TriggerId == triggerId).CountAsync();
 2172    if (depeendencies > 0)
 1173    {
 1174      throw new LgdxValidation400Expection(nameof(triggerId), $"This trigger has been used by {depeendencies} details in
 175    }
 1176    return true;
 1177  }
 178
 179  public async Task<bool> DeleteTriggerAsync(int triggerId)
 0180  {
 0181    bool result = await _context.Triggers.Where(t => t.Id == triggerId)
 0182      .ExecuteDeleteAsync() == 1;
 183
 0184    if (result)
 0185    {
 0186      await _activityService.CreateActivityLogAsync(new ActivityLogCreateBusinessModel
 0187      {
 0188        EntityName = nameof(Trigger),
 0189        EntityId = triggerId.ToString(),
 0190        Action = ActivityAction.Delete,
 0191      });
 0192    }
 0193    return result;
 0194  }
 195
 196  public async Task<IEnumerable<TriggerSearchBusinessModel>> SearchTriggersAsync(string? name)
 4197  {
 4198    var n = name ?? string.Empty;
 4199    return await _context.Triggers.AsNoTracking()
 4200      .Where(w => w.Name.ToLower().Contains(n.ToLower()))
 4201      .Take(10)
 4202      .Select(t => new TriggerSearchBusinessModel {
 4203        Id = t.Id,
 4204        Name = t.Name,
 4205      })
 4206      .ToListAsync();
 4207  }
 208
 209  private string GetRobotName(Guid robotId)
 3210  {
 3211    return _context.Robots.AsNoTracking().Where(r => r.Id == robotId).FirstOrDefault()?.Name ?? string.Empty;
 3212  }
 213
 214  private string GetRealmName(int realmId)
 3215  {
 3216    return _context.Realms.AsNoTracking().Where(r => r.Id == realmId).FirstOrDefault()?.Name ?? string.Empty;
 3217  }
 218
 219  private string GeneratePresetValue(int i, AutoTask autoTask)
 8220  {
 8221    return i switch
 8222    {
 1223      (int)TriggerPresetValue.AutoTaskId => $"{autoTask.Id}",
 1224      (int)TriggerPresetValue.AutoTaskName => $"{autoTask.Name}",
 1225      (int)TriggerPresetValue.AutoTaskCurrentProgressId => $"{autoTask.CurrentProgressId}",
 1226      (int)TriggerPresetValue.AutoTaskCurrentProgressName => $"{autoTask.CurrentProgress.Name!}",
 1227      (int)TriggerPresetValue.RobotId => $"{autoTask.AssignedRobotId}",
 1228      (int)TriggerPresetValue.RobotName => $"{GetRobotName((Guid)autoTask.AssignedRobotId!)}",
 1229      (int)TriggerPresetValue.RealmId => $"{autoTask.RealmId}",
 1230      (int)TriggerPresetValue.RealmName => $"{GetRealmName(autoTask.RealmId)}",
 0231      _ => string.Empty,
 8232    };
 8233  }
 234
 235  public async Task InitialiseTriggerAsync(AutoTask autoTask, FlowDetail flowDetail)
 2236  {
 2237    var trigger = await _context.Triggers.AsNoTracking()
 2238      .Where(t => t.Id == flowDetail.TriggerId)
 2239      .FirstOrDefaultAsync();
 2240    if (trigger == null)
 1241    {
 1242      return;
 243    }
 244
 1245    var bodyDictionary = JsonSerializer.Deserialize<Dictionary<string, string>>(trigger.Body ?? "{}");
 1246    if (bodyDictionary != null)
 1247    {
 248      // Replace Preset Value
 19249      foreach (var pair in bodyDictionary)
 8250      {
 8251        if (pair.Value.Length >= 5) // ((1)) has 5 characters
 8252        {
 8253          if (int.TryParse(pair.Value[2..^2], out int p))
 8254          {
 8255            bodyDictionary[pair.Key] = GeneratePresetValue(p, autoTask);
 8256          }
 8257        }
 8258      }
 259      // Add Next Token
 1260      if (flowDetail.AutoTaskNextControllerId != (int)AutoTaskNextController.Robot && autoTask.NextToken != null)
 1261      {
 1262        bodyDictionary.Add("NextToken", autoTask.NextToken);
 1263      }
 264
 1265      await _bus.Publish(new AutoTaskTriggerContract
 1266      {
 1267        Trigger = trigger,
 1268        Body = bodyDictionary,
 1269        AutoTaskId = autoTask.Id,
 1270        AutoTaskName = autoTask.Name!,
 1271        RobotId = (Guid)autoTask.AssignedRobotId!,
 1272        RobotName = GetRobotName((Guid)autoTask.AssignedRobotId!),
 1273        RealmId = autoTask.RealmId,
 1274        RealmName = GetRealmName(autoTask.RealmId),
 1275      });
 276
 1277      await _activityService.CreateActivityLogAsync(new ActivityLogCreateBusinessModel
 1278      {
 1279        EntityName = nameof(Trigger),
 1280        EntityId = trigger.Id.ToString(),
 1281        Action = ActivityAction.TriggerExecute,
 1282      });
 1283    }
 2284  }
 285
 286  public async Task<bool> RetryTriggerAsync(AutoTask autoTask, Trigger trigger, string body)
 1287  {
 1288    var bodyDictionary = JsonSerializer.Deserialize<Dictionary<string, string>>(body ?? "{}");
 1289    if (bodyDictionary != null)
 1290    {
 1291      await _bus.Publish(new AutoTaskTriggerContract {
 1292        Trigger = trigger,
 1293        Body = bodyDictionary,
 1294        AutoTaskId = autoTask.Id,
 1295        AutoTaskName = autoTask.Name!,
 1296        RobotId = (Guid)autoTask.AssignedRobotId!,
 1297        RobotName = GetRobotName((Guid)autoTask.AssignedRobotId!),
 1298        RealmId = autoTask.RealmId,
 1299        RealmName = GetRealmName(autoTask.RealmId),
 1300      });
 301      // Don't add activity log
 1302      return true;
 303    }
 0304    return false;
 1305  }
 306}