< Summary

Information
Class: LGDXRobotCloud.API.Services.Administration.ApiKeyService
Assembly: LGDXRobotCloud.API
File(s): /builds/yukaitung/lgdxrobot2-cloud/LGDXRobotCloud.API/Services/Administration/ApiKeyService.cs
Line coverage
19%
Covered lines: 20
Uncovered lines: 81
Coverable lines: 101
Total lines: 149
Line coverage: 19.8%
Branch coverage
11%
Covered branches: 2
Total branches: 18
Branch coverage: 11.1%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)50%22100%
GetApiKeysAsync()50%2281.81%
GetApiKeyAsync()0%620%
GetApiKeySecretAsync()0%620%
GenerateApiKeys()100%210%
AddApiKeyAsync()0%620%
UpdateApiKeyAsync()100%210%
UpdateApiKeySecretAsync()0%4260%
DeleteApiKeyAsync()100%210%
SearchApiKeysAsync()0%620%

File(s)

/builds/yukaitung/lgdxrobot2-cloud/LGDXRobotCloud.API/Services/Administration/ApiKeyService.cs

#LineLine coverage
 1using System.Security.Cryptography;
 2using LGDXRobotCloud.API.Exceptions;
 3using LGDXRobotCloud.Data.DbContexts;
 4using LGDXRobotCloud.Data.Entities;
 5using LGDXRobotCloud.Data.Models.Business.Administration;
 6using LGDXRobotCloud.Utilities.Helpers;
 7using Microsoft.EntityFrameworkCore;
 8
 9namespace LGDXRobotCloud.API.Services.Administration;
 10
 11public interface IApiKeyService
 12{
 13  Task<(IEnumerable<ApiKeyBusinessModel>, PaginationHelper)> GetApiKeysAsync(string? name, bool isThirdParty, int pageNu
 14  Task<ApiKeyBusinessModel> GetApiKeyAsync(int apiKeyId);
 15  Task<ApiKeySecretBusinessModel> GetApiKeySecretAsync(int apiKeyId);
 16  Task<ApiKeyBusinessModel> AddApiKeyAsync(ApiKeyCreateBusinessModel apiKeyCreateBusinessModel);
 17  Task<bool> UpdateApiKeyAsync(int apiKeyId, ApiKeyUpdateBusinessModel apiKeyUpdateBusinessModel);
 18  Task<bool> UpdateApiKeySecretAsync(int apiKeyId, ApiKeySecretUpdateBusinessModel apiKeySecretUpdateBusinessModel);
 19  Task<bool> DeleteApiKeyAsync(int apiKeyId);
 20
 21  Task<IEnumerable<ApiKeySearchBusinessModel>> SearchApiKeysAsync(string? name);
 22}
 23
 124public class ApiKeyService(LgdxContext context) : IApiKeyService
 25{
 126  private readonly LgdxContext _context = context ?? throw new ArgumentNullException(nameof(context));
 27
 28  public async Task<(IEnumerable<ApiKeyBusinessModel>, PaginationHelper)>GetApiKeysAsync(string? name, bool isThirdParty
 129  {
 130    var query = _context.ApiKeys as IQueryable<ApiKey>;
 131    query = query.Where(a => a.IsThirdParty == isThirdParty);
 132    if(!string.IsNullOrWhiteSpace(name))
 033    {
 034      name = name.Trim();
 035      query = query.Where(a => a.Name.Contains(name));
 036    }
 137    var itemCount = await query.CountAsync();
 138    var PaginationHelper = new PaginationHelper(itemCount, pageNumber, pageSize);
 139    var apiKeys = await query.AsNoTracking()
 140      .OrderBy(a => a.Id)
 141      .Skip(pageSize * (pageNumber - 1))
 142      .Take(pageSize)
 143      .Select(a => new ApiKeyBusinessModel {
 144        Id = a.Id,
 145        Name = a.Name,
 146        IsThirdParty = a.IsThirdParty,
 147      })
 148      .ToListAsync();
 149    return (apiKeys, PaginationHelper);
 150  }
 51
 52  public async Task<ApiKeyBusinessModel> GetApiKeyAsync(int apiKeyId)
 053  {
 054    return await _context.ApiKeys.AsNoTracking()
 055      .Where(a => a.Id == apiKeyId)
 056      .Select(a => new ApiKeyBusinessModel {
 057        Id = a.Id,
 058        Name = a.Name,
 059        IsThirdParty = a.IsThirdParty,
 060      })
 061      .FirstOrDefaultAsync()
 062        ?? throw new LgdxNotFound404Exception();
 063  }
 64
 65  public async Task<ApiKeySecretBusinessModel> GetApiKeySecretAsync(int apiKeyId)
 066  {
 067    return await _context.ApiKeys.AsNoTracking()
 068      .Where(a => a.Id == apiKeyId)
 069      .Select(a => new ApiKeySecretBusinessModel {
 070        Secret = a.Secret,
 071      })
 072      .FirstOrDefaultAsync()
 073        ?? throw new LgdxNotFound404Exception();
 074  }
 75
 76  private static string GenerateApiKeys()
 077  {
 078    var bytes = RandomNumberGenerator.GetBytes(32);
 079    string base64String = Convert.ToBase64String(bytes)
 080      .Replace("+", "-")
 081      .Replace("/", "_");
 082    return "LGDX" + base64String;
 083  }
 84
 85  public async Task<ApiKeyBusinessModel> AddApiKeyAsync(ApiKeyCreateBusinessModel apiKeyCreateBusinessModel)
 086  {
 087    apiKeyCreateBusinessModel.Secret ??= GenerateApiKeys();
 088    var apikey = apiKeyCreateBusinessModel.ToEntity();
 089    await _context.ApiKeys.AddAsync(apikey);
 090    await _context.SaveChangesAsync();
 091    return new ApiKeyBusinessModel{
 092      Id = apikey.Id,
 093      Name = apikey.Name,
 094      IsThirdParty = apikey.IsThirdParty
 095    };
 096  }
 97
 98  public async Task<bool> UpdateApiKeyAsync(int apiKeyId, ApiKeyUpdateBusinessModel apiKeyUpdateBusinessModel)
 099  {
 0100    return await _context.ApiKeys
 0101      .Where(a => a.Id == apiKeyId)
 0102      .ExecuteUpdateAsync(setters => setters
 0103        .SetProperty(a => a.Name, apiKeyUpdateBusinessModel.Name)) == 1;
 0104  }
 105
 106  public async Task<bool> UpdateApiKeySecretAsync(int apiKeyId, ApiKeySecretUpdateBusinessModel apiKeySecretUpdateBusine
 0107  {
 0108    var apiKey = await _context.ApiKeys.Where(a => a.Id == apiKeyId).FirstOrDefaultAsync()
 0109      ?? throw new LgdxNotFound404Exception();
 0110    if (!apiKey.IsThirdParty && !string.IsNullOrEmpty(apiKeySecretUpdateBusinessModel.Secret))
 0111    {
 0112      throw new LgdxValidation400Expection(nameof(apiKeySecretUpdateBusinessModel.Secret), "The LGDXRobot Cloud API Key 
 113    }
 114
 0115    apiKey.Secret = apiKeySecretUpdateBusinessModel.Secret;
 0116    return await _context.SaveChangesAsync() == 1;
 0117  }
 118
 119    public async Task<bool> DeleteApiKeyAsync(int apiKeyId)
 0120  {
 0121    return await _context.ApiKeys.Where(a => a.Id == apiKeyId)
 0122      .ExecuteDeleteAsync() == 1;
 0123  }
 124
 125  public async Task<IEnumerable<ApiKeySearchBusinessModel>> SearchApiKeysAsync(string? name)
 0126  {
 0127    if (string.IsNullOrWhiteSpace(name))
 0128    {
 0129      return await _context.ApiKeys.AsNoTracking()
 0130        .Take(10)
 0131        .Select(a => new ApiKeySearchBusinessModel{
 0132          Id = a.Id,
 0133          Name = a.Name
 0134        })
 0135        .ToListAsync();
 136    }
 137    else
 0138    {
 0139      return await _context.ApiKeys.AsNoTracking()
 0140        .Where(w => w.Name.Contains(name))
 0141        .Take(10)
 0142        .Select(a => new ApiKeySearchBusinessModel{
 0143          Id = a.Id,
 0144          Name = a.Name
 0145        })
 0146        .ToListAsync();
 147    }
 0148  }
 149}