add validations to command
This commit is contained in:
parent
8eefa30d52
commit
1451314d56
@ -13,6 +13,7 @@ namespace CH.CQRS.Command.CryptoStats;
|
||||
public class GetCryptoStatsCommand
|
||||
{
|
||||
}
|
||||
|
||||
public class GetCryptoStatsCommandHandler(CryptoService cryptoService) : ICommandHandler<GetCryptoStatsCommand>
|
||||
{
|
||||
public Task HandleAsync(GetCryptoStatsCommand command, CancellationToken cancellationToken = default)
|
||||
@ -20,6 +21,7 @@ public class GetCryptoStatsCommandHandler(CryptoService cryptoService) : IComman
|
||||
return cryptoService.GetCryptoStatsAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
public class GetCryptoStatsCommandValidator : AbstractValidator<GetCryptoStatsCommand>
|
||||
{
|
||||
public GetCryptoStatsCommandValidator()
|
||||
|
@ -1,6 +1,10 @@
|
||||
using CH.CQRS.Service.Energy;
|
||||
using CH.CQRS.Service.Energy.Options;
|
||||
using CH.Dal;
|
||||
using CH.Dal.DbEntity;
|
||||
using CH.Dal.Validators;
|
||||
using FluentValidation;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using OpenHarbor.CQRS.Abstractions;
|
||||
|
||||
namespace CH.CQRS.Command.Energy;
|
||||
@ -24,8 +28,16 @@ public class CreateEnergyProviderCommandHandler(EnergyService energyService) : I
|
||||
|
||||
public class CreateEnergyProviderCommandValidator : AbstractValidator<CreateEnergyProviderCommand>
|
||||
{
|
||||
public CreateEnergyProviderCommandValidator()
|
||||
public CreateEnergyProviderCommandValidator(CHDbContext dbContext)
|
||||
{
|
||||
|
||||
RuleFor(command => command.Name)
|
||||
.NotEmpty()
|
||||
.MinimumLength(3)
|
||||
.MustAsync(async (name, cancellationToken) =>
|
||||
{
|
||||
var nameInUse = await dbContext.EnergyProviders.AnyAsync(energyProvider => energyProvider.Name == name, cancellationToken);
|
||||
return false == nameInUse;
|
||||
})
|
||||
.WithMessage("This Name is already in use by another energy provider.");
|
||||
}
|
||||
}
|
@ -1,6 +1,11 @@
|
||||
using CH.CQRS.Service.Energy;
|
||||
using CH.CQRS.Service.Energy.Options;
|
||||
using CH.Dal;
|
||||
using CH.Dal.DbEntity;
|
||||
using CH.Dal.Validators;
|
||||
using CH.Enum;
|
||||
using FluentValidation;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using OpenHarbor.CQRS.Abstractions;
|
||||
|
||||
namespace CH.CQRS.Command.Energy;
|
||||
@ -10,7 +15,7 @@ public class CreateEnergyRateCommand
|
||||
public long ProviderId { get; set; }
|
||||
public required string Name { get; set; }
|
||||
public decimal Price { get; set; }
|
||||
public required string? Currency { get; set; }
|
||||
public Currency Currency { get; set; }
|
||||
public bool Active { get; set; }
|
||||
}
|
||||
public class CreateEnergyRateCommandHandler(EnergyService energyService) : ICommandHandler<CreateEnergyRateCommand>
|
||||
@ -30,10 +35,21 @@ public class CreateEnergyRateCommandHandler(EnergyService energyService) : IComm
|
||||
|
||||
public class CreateEnergyRateCommandValidator : AbstractValidator<CreateEnergyRateCommand>
|
||||
{
|
||||
public CreateEnergyRateCommandValidator()
|
||||
public CreateEnergyRateCommandValidator(CHDbContext dbContext)
|
||||
{
|
||||
RuleFor(command => command.Name)
|
||||
.NotEmpty()
|
||||
.MinimumLength(3)
|
||||
.MustAsync(async (name, cancellationToken) =>
|
||||
{
|
||||
var nameInUse = await dbContext.EnergyRates.AnyAsync(energyRate => energyRate.Name == name, cancellationToken);
|
||||
return false == nameInUse;
|
||||
})
|
||||
.WithMessage("This Name is already in use by another energy rate.");
|
||||
RuleFor(command => command.Price).GreaterThanOrEqualTo(0);
|
||||
RuleFor(command => command.ProviderId)
|
||||
.NotEmpty();
|
||||
.NotEmpty()
|
||||
.SetValidator(new DbEntityExistValidator<EnergyProvider,long>(dbContext))
|
||||
.WithMessage("The provided provider Id is invalid.");
|
||||
}
|
||||
}
|
@ -1,6 +1,11 @@
|
||||
using CH.CQRS.Service.Energy;
|
||||
using CH.CQRS.Service.Energy.Options;
|
||||
using CH.Dal;
|
||||
using CH.Dal.DbEntity;
|
||||
using CH.Dal.Validators;
|
||||
using CH.Enum;
|
||||
using FluentValidation;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using OpenHarbor.CQRS.Abstractions;
|
||||
|
||||
namespace CH.CQRS.Command.Energy;
|
||||
@ -10,7 +15,7 @@ public class CreateEnergyRateExceptionCommand
|
||||
public long RateId { get; set; }
|
||||
public required string Name { get; set; }
|
||||
public decimal EnergyThreshold { get; set; }
|
||||
public string? ResetType { get; set; }
|
||||
public EnergyRateExceptionThresholdResetType ResetType { get; set; }
|
||||
public DateTime? StartedAt { get; set; }
|
||||
public DateTime? EndedAt { get; set; }
|
||||
}
|
||||
@ -33,11 +38,24 @@ public class CreateEnergyRateExceptionCommandHandler(EnergyService energyService
|
||||
}
|
||||
public class CreateEnergyRateExceptionCommandValidator : AbstractValidator<CreateEnergyRateExceptionCommand>
|
||||
{
|
||||
public CreateEnergyRateExceptionCommandValidator()
|
||||
public CreateEnergyRateExceptionCommandValidator(CHDbContext dbContext)
|
||||
{
|
||||
RuleFor(command => command.Name)
|
||||
.NotEmpty()
|
||||
.MinimumLength(3)
|
||||
.MustAsync(async (name, cancellationToken) =>
|
||||
{
|
||||
var nameInUse = await dbContext.EnergyRateExceptions.AnyAsync(energyRateException => energyRateException.Name == name, cancellationToken);
|
||||
return false == nameInUse;
|
||||
})
|
||||
.WithMessage("This Name is already in use by another energy rate exception.");
|
||||
|
||||
RuleFor(command => command.EnergyThreshold)
|
||||
.GreaterThan(0);
|
||||
|
||||
RuleFor(command => command.RateId)
|
||||
.NotEmpty();
|
||||
.NotEmpty()
|
||||
.SetValidator(new DbEntityExistValidator<EnergyRate,long>(dbContext))
|
||||
.WithMessage("The provided Rate Id is invalid.");
|
||||
}
|
||||
}
|
@ -1,5 +1,8 @@
|
||||
using CH.CQRS.Service.Energy;
|
||||
using CH.CQRS.Service.Energy.Options;
|
||||
using CH.Dal;
|
||||
using CH.Dal.DbEntity;
|
||||
using CH.Dal.Validators;
|
||||
using FluentValidation;
|
||||
using OpenHarbor.CQRS.Abstractions;
|
||||
|
||||
@ -24,9 +27,12 @@ public class DisableEnergyProviderCommandHandler(EnergyService energyService) :
|
||||
|
||||
public class DisableEnergyProviderCommandValidator : AbstractValidator<DisableEnergyProviderCommand>
|
||||
{
|
||||
public DisableEnergyProviderCommandValidator()
|
||||
public DisableEnergyProviderCommandValidator(CHDbContext dbContext)
|
||||
{
|
||||
RuleFor(command => command.ProviderId)
|
||||
.NotEmpty();
|
||||
.NotEmpty()
|
||||
.SetValidator(new DbEntityExistValidator<EnergyProvider,long>(dbContext))
|
||||
.WithMessage("The provided provider Id is invalid.");
|
||||
|
||||
}
|
||||
}
|
@ -1,5 +1,8 @@
|
||||
using CH.CQRS.Service.Energy;
|
||||
using CH.CQRS.Service.Energy.Options;
|
||||
using CH.Dal;
|
||||
using CH.Dal.DbEntity;
|
||||
using CH.Dal.Validators;
|
||||
using FluentValidation;
|
||||
using OpenHarbor.CQRS.Abstractions;
|
||||
|
||||
@ -24,9 +27,11 @@ public class DisableEnergyRateCommandHandler(EnergyService energyService) : ICom
|
||||
|
||||
public class DisableEnergyRateCommandValidator : AbstractValidator<DisableEnergyRateCommand>
|
||||
{
|
||||
public DisableEnergyRateCommandValidator()
|
||||
public DisableEnergyRateCommandValidator(CHDbContext dbContext)
|
||||
{
|
||||
RuleFor(command => command.RateId)
|
||||
.NotEmpty();
|
||||
.NotEmpty()
|
||||
.SetValidator(new DbEntityExistValidator<EnergyRate,long>(dbContext))
|
||||
.WithMessage("The provided Rate Id is invalid.");
|
||||
}
|
||||
}
|
@ -1,5 +1,8 @@
|
||||
using CH.CQRS.Service.Energy;
|
||||
using CH.CQRS.Service.Energy.Options;
|
||||
using CH.Dal;
|
||||
using CH.Dal.DbEntity;
|
||||
using CH.Dal.Validators;
|
||||
using FluentValidation;
|
||||
using OpenHarbor.CQRS.Abstractions;
|
||||
|
||||
@ -22,8 +25,12 @@ public class EnableEnergyProviderCommandHandler(EnergyService energyService) : I
|
||||
|
||||
public class EnableEnergyProviderCommandValidator : AbstractValidator<EnableEnergyProviderCommand>
|
||||
{
|
||||
public EnableEnergyProviderCommandValidator()
|
||||
public EnableEnergyProviderCommandValidator(CHDbContext dbContext)
|
||||
{
|
||||
RuleFor(command => command.ProviderId)
|
||||
.NotEmpty()
|
||||
.SetValidator(new DbEntityExistValidator<EnergyProvider,long>(dbContext))
|
||||
.WithMessage("The provided provider Id is invalid.");
|
||||
|
||||
}
|
||||
}
|
@ -1,4 +1,8 @@
|
||||
using CH.CQRS.Service.Energy;
|
||||
using CH.Dal;
|
||||
using CH.Dal.DbEntity;
|
||||
using CH.Dal.Validators;
|
||||
using FluentValidation;
|
||||
using OpenHarbor.CQRS.Abstractions;
|
||||
|
||||
namespace CH.CQRS.Command.Energy;
|
||||
@ -17,3 +21,14 @@ public class EnableEnergyRateCommandHandler(EnergyService energyService) : IComm
|
||||
}, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
public class EnableEnergyRateCommandValidator : AbstractValidator<EnableEnergyRateCommand>
|
||||
{
|
||||
public EnableEnergyRateCommandValidator(CHDbContext dbContext)
|
||||
{
|
||||
RuleFor(command => command.RateId)
|
||||
.NotEmpty()
|
||||
.SetValidator(new DbEntityExistValidator<EnergyRate,long>(dbContext))
|
||||
.WithMessage("The provided Rate Id is invalid.");
|
||||
}
|
||||
}
|
@ -10,18 +10,24 @@ public static class ServiceCollectionExtension
|
||||
services
|
||||
.AddCommand<CreateEnergyProviderCommand, CreateEnergyProviderCommandHandler,
|
||||
CreateEnergyProviderCommandValidator>();
|
||||
services
|
||||
.AddCommand<CreateEnergyRateExceptionCommand, CreateEnergyRateExceptionCommandHandler,
|
||||
CreateEnergyRateExceptionCommandValidator>();
|
||||
services
|
||||
.AddCommand<CreateEnergyRateCommand, CreateEnergyRateCommandHandler,
|
||||
CreateEnergyRateCommandValidator>();
|
||||
services
|
||||
.AddCommand<CreateEnergyRateExceptionCommand, CreateEnergyRateExceptionCommandHandler,
|
||||
CreateEnergyRateExceptionCommandValidator>();
|
||||
services
|
||||
.AddCommand<DisableEnergyProviderCommand, DisableEnergyProviderCommandHandler,
|
||||
DisableEnergyProviderCommandValidator>();
|
||||
services
|
||||
.AddCommand<DisableEnergyRateCommand, DisableEnergyRateCommandHandler,
|
||||
DisableEnergyRateCommandValidator>();
|
||||
services
|
||||
.AddCommand<EnableEnergyProviderCommand, EnableEnergyProviderCommandHandler,
|
||||
EnableEnergyProviderCommandValidator>();
|
||||
services
|
||||
.AddCommand<EnableEnergyRateCommand, EnableEnergyRateCommandHandler,
|
||||
EnableEnergyRateCommandValidator>();
|
||||
services
|
||||
.AddCommand<UpdateEnergyProviderCommand, UpdateEnergyProviderCommandHandler,
|
||||
UpdateEnergyProviderCommandValidator>();
|
||||
|
@ -1,6 +1,10 @@
|
||||
using CH.CQRS.Service.Energy;
|
||||
using CH.CQRS.Service.Energy.Options;
|
||||
using CH.Dal;
|
||||
using CH.Dal.DbEntity;
|
||||
using CH.Dal.Validators;
|
||||
using FluentValidation;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using OpenHarbor.CQRS.Abstractions;
|
||||
|
||||
namespace CH.CQRS.Command.Energy;
|
||||
@ -24,9 +28,20 @@ public class UpdateEnergyProviderCommandHandler(EnergyService energyService) : I
|
||||
}
|
||||
public class UpdateEnergyProviderCommandValidator : AbstractValidator<UpdateEnergyProviderCommand>
|
||||
{
|
||||
public UpdateEnergyProviderCommandValidator()
|
||||
public UpdateEnergyProviderCommandValidator(CHDbContext dbContext)
|
||||
{
|
||||
RuleFor(command => command.Name)
|
||||
.NotEmpty()
|
||||
.MinimumLength(3)
|
||||
.MustAsync(async (name, cancellationToken) =>
|
||||
{
|
||||
var nameInUse = await dbContext.EnergyProviders.AnyAsync(energyProvider => energyProvider.Name == name, cancellationToken);
|
||||
return false == nameInUse;
|
||||
})
|
||||
.WithMessage("This Name is already in use by another energy provider.");
|
||||
|
||||
RuleFor(command => command.ProviderId)
|
||||
.NotEmpty();
|
||||
.NotEmpty()
|
||||
.SetValidator(new DbEntityExistValidator<EnergyProvider,long>(dbContext));
|
||||
}
|
||||
}
|
@ -1,6 +1,11 @@
|
||||
using System.Data;
|
||||
using CH.CQRS.Service.Energy;
|
||||
using CH.CQRS.Service.Energy.Options;
|
||||
using CH.Dal;
|
||||
using CH.Dal.DbEntity;
|
||||
using CH.Dal.Validators;
|
||||
using FluentValidation;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using OpenHarbor.CQRS.Abstractions;
|
||||
|
||||
namespace CH.CQRS.Command.Energy;
|
||||
@ -8,11 +13,9 @@ namespace CH.CQRS.Command.Energy;
|
||||
public class UpdateEnergyRateCommand
|
||||
{
|
||||
public long RateId { get; set; }
|
||||
public bool SendAlert { get; set; }
|
||||
public required DateTime StartedAt { get; set; }
|
||||
public DateTime? AppliedAt { get; set; }
|
||||
public string? Name { get; set; }
|
||||
public DateTime? StartedAt { get; set; }
|
||||
public decimal? Rate { get; set; }
|
||||
public DateTime? UpdatedAt { get; set; }
|
||||
}
|
||||
public class UpdateEnergyRateCommandHandler(EnergyService energyService) : ICommandHandler<UpdateEnergyRateCommand>
|
||||
{
|
||||
@ -21,19 +24,34 @@ public class UpdateEnergyRateCommandHandler(EnergyService energyService) : IComm
|
||||
return energyService.UpdateEnergyRateAsync(new UpdateEnergyRateCommandOptions
|
||||
{
|
||||
RateId = command.RateId,
|
||||
Name = command.Name,
|
||||
StartedAt = command.StartedAt,
|
||||
AppliedAt = command.AppliedAt,
|
||||
Rate = command.Rate,
|
||||
SendAlert = command.SendAlert,
|
||||
UpdatedAt = command.UpdatedAt
|
||||
Rate = command.Rate
|
||||
}, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
public class UpdateEnergyRateCommandValidator : AbstractValidator<UpdateEnergyRateCommand>
|
||||
{
|
||||
public UpdateEnergyRateCommandValidator()
|
||||
public UpdateEnergyRateCommandValidator(CHDbContext dbContext)
|
||||
{
|
||||
RuleFor(command => command.Name)
|
||||
.NotEmpty()
|
||||
.MinimumLength(3)
|
||||
.When(command => false == String.IsNullOrWhiteSpace(command.Name))
|
||||
.MustAsync(async (name, cancellationToken) =>
|
||||
{
|
||||
var nameInUse = await dbContext.EnergyRates.AnyAsync(energyRate => energyRate.Name == name, cancellationToken);
|
||||
return false == nameInUse;
|
||||
})
|
||||
.WithMessage("This Name is already in use by another energy rate.");
|
||||
|
||||
RuleFor(command => command.RateId)
|
||||
.NotEmpty()
|
||||
.SetValidator(new DbEntityExistValidator<EnergyRate,long>(dbContext))
|
||||
.WithMessage("The provided Rate Id is invalid.");
|
||||
|
||||
RuleFor(command => command.Rate)
|
||||
.GreaterThanOrEqualTo(0);
|
||||
}
|
||||
}
|
@ -1,6 +1,11 @@
|
||||
using CH.CQRS.Service.Energy;
|
||||
using CH.CQRS.Service.Energy.Options;
|
||||
using CH.Dal;
|
||||
using CH.Dal.DbEntity;
|
||||
using CH.Dal.Validators;
|
||||
using CH.Enum;
|
||||
using FluentValidation;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using OpenHarbor.CQRS.Abstractions;
|
||||
|
||||
namespace CH.CQRS.Command.Energy;
|
||||
@ -8,8 +13,8 @@ namespace CH.CQRS.Command.Energy;
|
||||
public class UpdateEnergyRateExceptionCommand
|
||||
{
|
||||
public long EnergyRateExceptionId { get; set; }
|
||||
public decimal EnergyThreshold { get; set; }
|
||||
public string? ResetType { get; set; }
|
||||
public decimal? EnergyThreshold { get; set; }
|
||||
public EnergyRateExceptionThresholdResetType ResetType { get; set; }
|
||||
public DateTime? StartedAt { get; set; }
|
||||
public DateTime? EndedAt { get; set; }
|
||||
}
|
||||
@ -31,11 +36,14 @@ public class UpdateEnergyRateExceptionCommandHandler(EnergyService energyService
|
||||
|
||||
public class UpdateEnergyRateExceptionCommandValidator : AbstractValidator<UpdateEnergyRateExceptionCommand>
|
||||
{
|
||||
public UpdateEnergyRateExceptionCommandValidator()
|
||||
public UpdateEnergyRateExceptionCommandValidator(CHDbContext dbContext)
|
||||
{
|
||||
RuleFor(command => command.EnergyRateExceptionId)
|
||||
.NotEmpty();
|
||||
.NotEmpty()
|
||||
.SetValidator(new DbEntityExistValidator<EnergyRateException,long>(dbContext));
|
||||
|
||||
RuleFor(command => command.EnergyThreshold)
|
||||
.GreaterThan(0);
|
||||
.GreaterThan(0)
|
||||
.When(command => command.EnergyThreshold.HasValue);
|
||||
}
|
||||
}
|
@ -28,7 +28,7 @@ public class EnergyService(CHDbContext dbContext)
|
||||
var energyRate = new EnergyRate
|
||||
{
|
||||
Name = options.Name,
|
||||
Currency = (Currency)System.Enum.Parse(typeof(Currency), options.Currency?.ToUpper()),
|
||||
Currency = options.Currency,
|
||||
Price = options.Price,
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
Provider = provider,
|
||||
@ -51,8 +51,7 @@ public class EnergyService(CHDbContext dbContext)
|
||||
StartedAt = options.StartedAt,
|
||||
EndedAt = options.EndedAt,
|
||||
EnergyThreshold = options.EnergyThreshold,
|
||||
ResetType = (EnergyRateExceptionThresholdResetType)System.Enum
|
||||
.Parse(typeof(EnergyRateExceptionThresholdResetType), options.ResetType.ToLower() ?? ""),
|
||||
ResetType = options.ResetType,
|
||||
};
|
||||
await dbContext.AddAsync(energyRateException, cancellationToken);
|
||||
await dbContext.SaveChangesAsync(cancellationToken);
|
||||
@ -61,29 +60,54 @@ public class EnergyService(CHDbContext dbContext)
|
||||
public async Task UpdateEnergyProviderAsync(UpdateEnergyProviderCommandOptions options,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var provider = await dbContext.EnergyProviders.FirstOrDefaultAsync(provider => provider.Id == options.ProviderId, cancellationToken);
|
||||
if (null != provider)
|
||||
{
|
||||
provider.Name = options.Name;
|
||||
provider.UpdatedAt = DateTime.UtcNow;
|
||||
await dbContext.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
var provider = await dbContext.EnergyProviders
|
||||
.AsTracking()
|
||||
.FirstOrDefaultAsync(provider => provider.Id == options.ProviderId, cancellationToken);
|
||||
|
||||
if (provider is null)
|
||||
return;
|
||||
|
||||
provider.Name = options.Name;
|
||||
provider.UpdatedAt = DateTime.UtcNow;
|
||||
await dbContext.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
|
||||
public async Task UpdateEnergyRateValueAsync(UpdateEnergyRateCommandOptions options, CancellationToken cancellationToken)
|
||||
{
|
||||
var energyRate = await dbContext.EnergyRates
|
||||
.AsTracking()
|
||||
.FirstOrDefaultAsync(energyRate => energyRate.Id == options.RateId, cancellationToken);
|
||||
|
||||
if (energyRate is null)
|
||||
return;
|
||||
|
||||
if (options.Rate.HasValue)
|
||||
energyRate.Price = options.Rate.Value;
|
||||
|
||||
if (false == string.IsNullOrWhiteSpace(options.Name))
|
||||
energyRate.Name = options.Name;
|
||||
|
||||
energyRate.UpdatedAt = DateTime.UtcNow;
|
||||
}
|
||||
public async Task UpdateEnergyRateAsync(UpdateEnergyRateCommandOptions options, CancellationToken cancellationToken)
|
||||
{
|
||||
var energyRateUpdate = new EnergyRateUpdate
|
||||
if (options.StartedAt.HasValue)
|
||||
{
|
||||
RateId = options.RateId,
|
||||
Rate = options.Rate,
|
||||
StartedAt = options.StartedAt,
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
UpdatedAt = options.UpdatedAt,
|
||||
AppliedAt = options.AppliedAt,
|
||||
SendAlert = options.SendAlert,
|
||||
};
|
||||
await dbContext.AddAsync(energyRateUpdate, cancellationToken);
|
||||
var energyRateUpdate = new EnergyRateUpdate
|
||||
{
|
||||
RateId = options.RateId,
|
||||
Rate = options.Rate,
|
||||
Name = options.Name ?? "",
|
||||
StartedAt = options.StartedAt.Value,
|
||||
};
|
||||
|
||||
await dbContext.AddAsync(energyRateUpdate, cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
await UpdateEnergyRateValueAsync(options, cancellationToken);
|
||||
}
|
||||
|
||||
await dbContext.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
|
||||
@ -91,19 +115,29 @@ public class EnergyService(CHDbContext dbContext)
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var energyRateException = await dbContext.EnergyRateExceptions
|
||||
.AsTracking()
|
||||
.FirstOrDefaultAsync(rateException => rateException.Id == options.EnergyRateExceptionId, cancellationToken);
|
||||
if (null != energyRateException)
|
||||
{
|
||||
|
||||
if (energyRateException is null)
|
||||
return;
|
||||
|
||||
if (options.EnergyThreshold.HasValue)
|
||||
energyRateException.EnergyThreshold = options.EnergyThreshold;
|
||||
|
||||
if (options.StartedAt.HasValue)
|
||||
energyRateException.StartedAt = options.StartedAt;
|
||||
|
||||
if (options.EndedAt.HasValue)
|
||||
energyRateException.EndedAt = options.EndedAt;
|
||||
energyRateException.UpdatedAt = DateTime.UtcNow;
|
||||
if (String.IsNullOrWhiteSpace(options.ResetType))
|
||||
{
|
||||
energyRateException.ResetType = (EnergyRateExceptionThresholdResetType)System.Enum.Parse(typeof(EnergyRateExceptionThresholdResetType),options.ResetType) ;
|
||||
}
|
||||
await dbContext.SaveChangesAsync(cancellationToken);
|
||||
|
||||
energyRateException.UpdatedAt = DateTime.UtcNow;
|
||||
|
||||
if (energyRateException.ResetType != options.ResetType)
|
||||
{
|
||||
energyRateException.ResetType = options.ResetType;
|
||||
}
|
||||
|
||||
await dbContext.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
|
||||
public async Task DisableEnergyProviderAsync(DisableEnergyProviderCommandOptions options,
|
||||
@ -113,7 +147,7 @@ public class EnergyService(CHDbContext dbContext)
|
||||
if (null != energyProvider)
|
||||
{
|
||||
energyProvider.Active = false;
|
||||
energyProvider.DisabledAt = options.DisabledAt;
|
||||
energyProvider.DisabledAt = options.DisabledAt ?? DateTime.UtcNow;
|
||||
await dbContext.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
@ -124,7 +158,7 @@ public class EnergyService(CHDbContext dbContext)
|
||||
if (null != energyRate)
|
||||
{
|
||||
energyRate.Active = false;
|
||||
energyRate.DisabledAt = options.DisabledAt;
|
||||
energyRate.DisabledAt = options.DisabledAt ?? DateTime.UtcNow;
|
||||
await dbContext.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Amazon.Runtime.Internal.Transform;
|
||||
using CH.Enum;
|
||||
|
||||
namespace CH.CQRS.Service.Energy.Options;
|
||||
|
||||
@ -7,6 +8,6 @@ public class CreateEnergyRateCommandOptions
|
||||
public long ProviderId { get; set; }
|
||||
public required string Name { get; set; }
|
||||
public decimal? Price { get; set; }
|
||||
public required string? Currency { get; set; }
|
||||
public Currency Currency { get; set; }
|
||||
public bool Active { get; set; }
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
using CH.Enum;
|
||||
|
||||
namespace CH.CQRS.Service.Energy.Options;
|
||||
|
||||
public class CreateEnergyRateExceptionCommandOptions
|
||||
@ -5,7 +7,7 @@ public class CreateEnergyRateExceptionCommandOptions
|
||||
public long RateId { get; set; }
|
||||
public required string Name { get; set; }
|
||||
public decimal EnergyThreshold { get; set; }
|
||||
public string? ResetType { get; set; }
|
||||
public EnergyRateExceptionThresholdResetType ResetType { get; set; }
|
||||
public DateTime? StartedAt { get; set; }
|
||||
public DateTime? EndedAt { get; set; }
|
||||
}
|
@ -3,9 +3,7 @@ namespace CH.CQRS.Service.Energy.Options;
|
||||
public class UpdateEnergyRateCommandOptions
|
||||
{
|
||||
public long RateId { get; set; }
|
||||
public bool SendAlert { get; set; }
|
||||
public required DateTime StartedAt { get; set; }
|
||||
public DateTime? AppliedAt { get; set; }
|
||||
public DateTime? StartedAt { get; set; }
|
||||
public decimal? Rate { get; set; }
|
||||
public DateTime? UpdatedAt { get; set; }
|
||||
public string? Name { get; set; }
|
||||
}
|
@ -1,10 +1,12 @@
|
||||
using CH.Enum;
|
||||
|
||||
namespace CH.CQRS.Service.Energy.Options;
|
||||
|
||||
public class UpdateEnergyRateExceptionCommandOptions
|
||||
{
|
||||
public long EnergyRateExceptionId { get; set; }
|
||||
public decimal EnergyThreshold { get; set; }
|
||||
public string? ResetType { get; set; }
|
||||
public decimal? EnergyThreshold { get; set; }
|
||||
public EnergyRateExceptionThresholdResetType ResetType { get; set; }
|
||||
public DateTime? StartedAt { get; set; }
|
||||
public DateTime? EndedAt { get; set; }
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
namespace CH.Dal.Abstractions
|
||||
{
|
||||
public class Class1
|
||||
{
|
||||
|
||||
}
|
||||
}
|
6
CH.Dal.Abstractions/IHasId.cs
Normal file
6
CH.Dal.Abstractions/IHasId.cs
Normal file
@ -0,0 +1,6 @@
|
||||
namespace CH.Dal.Abstractions;
|
||||
|
||||
public interface IHasId<T>
|
||||
{
|
||||
public T Id { get; set; }
|
||||
}
|
@ -18,6 +18,7 @@
|
||||
<PackageReference Include="PoweredSoft.Module.Abstractions" Version="2.0.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\CH.Dal.Abstractions\CH.Dal.Abstractions.csproj" />
|
||||
<ProjectReference Include="..\CH.Enum\CH.Enum.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
@ -112,15 +112,14 @@ public partial class CHDbScaffoldedContext : DbContext
|
||||
entity.ToTable("energy_rate_update");
|
||||
|
||||
entity.Property(e => e.Id).HasColumnName("id");
|
||||
entity.Property(e => e.AppliedAt).HasColumnName("applied_at");
|
||||
entity.Property(e => e.CreatedAt)
|
||||
.HasDefaultValueSql("(CURRENT_TIMESTAMP AT TIME ZONE 'UTC'::text)")
|
||||
.HasColumnName("created_at");
|
||||
entity.Property(e => e.Name)
|
||||
.HasMaxLength(255)
|
||||
.HasColumnName("name");
|
||||
entity.Property(e => e.Rate).HasColumnName("rate");
|
||||
entity.Property(e => e.RateId).HasColumnName("rate_id");
|
||||
entity.Property(e => e.SendAlert)
|
||||
.HasDefaultValue(false)
|
||||
.HasColumnName("send_alert");
|
||||
entity.Property(e => e.StartedAt).HasColumnName("started_at");
|
||||
entity.Property(e => e.UpdatedAt).HasColumnName("updated_at");
|
||||
|
||||
|
8
CH.Dal/DbEntity/EnergyProvider.Extensions.cs
Normal file
8
CH.Dal/DbEntity/EnergyProvider.Extensions.cs
Normal file
@ -0,0 +1,8 @@
|
||||
using CH.Dal.Abstractions;
|
||||
|
||||
namespace CH.Dal.DbEntity;
|
||||
|
||||
public partial class EnergyProvider : IHasId<long>
|
||||
{
|
||||
|
||||
}
|
@ -1,9 +1,10 @@
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using CH.Dal.Abstractions;
|
||||
using CH.Enum;
|
||||
|
||||
namespace CH.Dal.DbEntity;
|
||||
|
||||
public partial class EnergyRate
|
||||
public partial class EnergyRate : IHasId<long>
|
||||
{
|
||||
[Column(TypeName = "currency")]
|
||||
public Currency Currency { get; set; }
|
||||
|
@ -1,9 +1,10 @@
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using CH.Dal.Abstractions;
|
||||
using CH.Enum;
|
||||
namespace CH.Dal.DbEntity;
|
||||
|
||||
public partial class EnergyRateException
|
||||
public partial class EnergyRateException : IHasId<long>
|
||||
{
|
||||
[Column(TypeName = "energy_rate_exception_treshold_reset_type")]
|
||||
[Column(TypeName = "energy_rate_exception_threshold_reset_type")]
|
||||
public EnergyRateExceptionThresholdResetType ResetType { get; set; }
|
||||
}
|
@ -9,14 +9,12 @@ public partial class EnergyRateUpdate
|
||||
|
||||
public long? RateId { get; set; }
|
||||
|
||||
public bool SendAlert { get; set; }
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
public DateTime StartedAt { get; set; }
|
||||
|
||||
public decimal? Rate { get; set; }
|
||||
|
||||
public DateTime? AppliedAt { get; set; }
|
||||
|
||||
public DateTime CreatedAt { get; set; }
|
||||
|
||||
public DateTime? UpdatedAt { get; set; }
|
||||
|
25
CH.Dal/Validators/DbEntityExistValidator.cs
Normal file
25
CH.Dal/Validators/DbEntityExistValidator.cs
Normal file
@ -0,0 +1,25 @@
|
||||
using CH.Dal.Abstractions;
|
||||
using FluentValidation;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace CH.Dal.Validators;
|
||||
|
||||
public class DbEntityExistValidator<TEntity, TValue> : AbstractValidator<TValue>
|
||||
where TEntity : class, IHasId<TValue>
|
||||
{
|
||||
private readonly CHDbContext _dbContext;
|
||||
|
||||
public DbEntityExistValidator(CHDbContext dbContext)
|
||||
{
|
||||
_dbContext = dbContext;
|
||||
|
||||
RuleFor(value => value)
|
||||
.NotNull()
|
||||
.MustAsync(IsEntityExist)
|
||||
.WithMessage("Invalid Entity");
|
||||
}
|
||||
|
||||
private Task<bool> IsEntityExist(TValue id,
|
||||
CancellationToken cancellationToken)
|
||||
=> _dbContext.Set<TEntity>().AnyAsync(entity => entity.Id!.Equals(id), cancellationToken);
|
||||
}
|
@ -1,12 +1,12 @@
|
||||
using System.Text;
|
||||
using IdentityModel.Client;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text;
|
||||
using IdentityModel.Client;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace CH.KeycloakApi;
|
||||
namespace CH.KeycloakApi;
|
||||
|
||||
public class KeycloakService
|
||||
{
|
||||
public class KeycloakService
|
||||
{
|
||||
private readonly KeycloakSettings settings;
|
||||
|
||||
public KeycloakService(IConfiguration configuration)
|
||||
@ -17,9 +17,10 @@
|
||||
|
||||
public KeycloakSettings Settings => settings;
|
||||
|
||||
public async Task<string> GetTokenAsync()
|
||||
// use token manager instead
|
||||
public async Task<string> GetTokenAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
var tokenEndpoint = $"{this.settings.Endpoint}/realms/master/protocol/openid-connect/token";
|
||||
var tokenEndpoint = $"{this.settings.Endpoint}/realms/${settings.ApiRealm}/protocol/openid-connect/token";
|
||||
var client = new HttpClient();
|
||||
var response = await client.RequestTokenAsync(new TokenRequest
|
||||
{
|
||||
@ -27,12 +28,12 @@
|
||||
GrantType = "client_credentials",
|
||||
ClientId = this.settings.ClientId,
|
||||
ClientSecret = this.settings.ClientSecret,
|
||||
});
|
||||
}, cancellationToken);
|
||||
|
||||
return response.AccessToken;
|
||||
}
|
||||
|
||||
public async Task<KeycloakUser> GetUserByEmailAsync(string realm, string email)
|
||||
public async Task<KeycloakUser?> GetUserByEmailAsync(string realm, string email)
|
||||
{
|
||||
var httpClient = new HttpClient();
|
||||
var url = $"{this.settings.Endpoint}/admin/realms/{realm}/users?email={email}";
|
||||
@ -40,11 +41,11 @@
|
||||
var response = await httpClient.GetAsync(url);
|
||||
response.EnsureSuccessStatusCode();
|
||||
var json = await response.Content.ReadAsStringAsync();
|
||||
var ret = JsonConvert.DeserializeObject<List<KeycloakUser>>(json);
|
||||
return ret.FirstOrDefault();
|
||||
var keycloakUsers = JsonConvert.DeserializeObject<List<KeycloakUser>>(json);
|
||||
return keycloakUsers?.FirstOrDefault();
|
||||
}
|
||||
|
||||
public async Task<KeycloakUser> GetUserByIdAsync(string realm, string id)
|
||||
public async Task<KeycloakUser?> GetUserByIdAsync(string realm, string id)
|
||||
{
|
||||
var httpClient = new HttpClient();
|
||||
httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("bearer", await GetTokenAsync());
|
||||
@ -52,8 +53,8 @@
|
||||
var response = await httpClient.GetAsync(url);
|
||||
response.EnsureSuccessStatusCode();
|
||||
var json = await response.Content.ReadAsStringAsync();
|
||||
var ret = JsonConvert.DeserializeObject<KeycloakUser>(json);
|
||||
return ret;
|
||||
var keycloakUser = JsonConvert.DeserializeObject<KeycloakUser>(json);
|
||||
return keycloakUser;
|
||||
}
|
||||
|
||||
public async Task SendChangePasswordEmailAsync(string realm, string id)
|
||||
@ -69,7 +70,7 @@
|
||||
response.EnsureSuccessStatusCode();
|
||||
}
|
||||
|
||||
public async Task<List<KeycloakUser>> GetUsersAsync(string realm, string search = null, int max = 100)
|
||||
public async Task<List<KeycloakUser>?> GetUsersAsync(string realm, string? search = null, int max = 100)
|
||||
{
|
||||
var httpClient = new HttpClient();
|
||||
httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("bearer", await GetTokenAsync());
|
||||
@ -79,14 +80,15 @@
|
||||
|
||||
var response = await httpClient.GetAsync(url);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var json = await response.Content.ReadAsStringAsync();
|
||||
var ret = JsonConvert.DeserializeObject<List<KeycloakUser>>(json);
|
||||
return ret;
|
||||
var keycloakUsers = JsonConvert.DeserializeObject<List<KeycloakUser>>(json);
|
||||
return keycloakUsers;
|
||||
}
|
||||
|
||||
public async Task ChangePasswordAsync(string realm, string id, string newPassword, bool temporary)
|
||||
{
|
||||
///auth/admin/realms/{realm}/users/{id}/reset-password
|
||||
// auth/admin/realms/{realm}/users/{id}/reset-password
|
||||
/////{ "type": "password", "temporary": false, "value": "my-new-password" }
|
||||
var url = $"{this.settings.Endpoint}/admin/realms/{realm}/users/{id}/reset-password";
|
||||
var httpClient = new HttpClient();
|
||||
@ -128,7 +130,7 @@
|
||||
return await this.GetUserByEmailAsync(realm, email) != null;
|
||||
}
|
||||
|
||||
public async Task<KeycloakUser> CreateOrUpdateAsync(string realm, string email, string firstName, string lastName, bool enabled)
|
||||
public async Task<KeycloakUser?> CreateOrUpdateAsync(string realm, string email, string firstName, string lastName, bool enabled)
|
||||
{
|
||||
var existingUser = await GetUserByEmailAsync(realm, email);
|
||||
if (existingUser != null)
|
||||
@ -140,7 +142,7 @@
|
||||
return await CreateUserAsync(realm, email, firstName, lastName, enabled);
|
||||
}
|
||||
|
||||
public async Task<KeycloakUser> CreateUserAsync(string realm, string email, string firstName, string lastName, bool enabled)
|
||||
public async Task<KeycloakUser?> CreateUserAsync(string realm, string email, string firstName, string lastName, bool enabled)
|
||||
{
|
||||
long epochTicks = new DateTime(1970, 1, 1).Ticks;
|
||||
long unixTime = ((DateTime.UtcNow.Ticks - epochTicks) / TimeSpan.TicksPerSecond);
|
||||
@ -174,7 +176,7 @@
|
||||
var postJson = JsonConvert.SerializeObject(user);
|
||||
var response = await httpClient.PostAsync(url, new StringContent(postJson, Encoding.UTF8, "application/json"));
|
||||
response.EnsureSuccessStatusCode();
|
||||
var ret = await GetUserByEmailAsync(realm, email);
|
||||
return ret;
|
||||
}
|
||||
var keycloakUser = await GetUserByEmailAsync(realm, email);
|
||||
return keycloakUser;
|
||||
}
|
||||
}
|
@ -5,6 +5,6 @@ public class KeycloakSettings
|
||||
public string Endpoint { get; set; }
|
||||
public string ClientId { get; set; }
|
||||
public string ClientSecret { get; set; }
|
||||
public string EmployeeRealm { get; set; }
|
||||
public string UserRealm { get; set; }
|
||||
public string ApiRealm { get; set; }
|
||||
public string Realm { get; set; }
|
||||
}
|
@ -7,28 +7,40 @@ public class KeycloakUser
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public string Id { get; set; }
|
||||
|
||||
[JsonProperty("createdTimestamp")]
|
||||
public long CreatedTimestamp { get; set; }
|
||||
|
||||
[JsonProperty("username")]
|
||||
public string Username { get; set; }
|
||||
|
||||
[JsonProperty("enabled")]
|
||||
public bool Enabled { get; set; }
|
||||
|
||||
[JsonProperty("totp")]
|
||||
public bool Totp { get; set; }
|
||||
|
||||
[JsonProperty("emailVerified")]
|
||||
public bool EmailVerified { get; set; }
|
||||
|
||||
[JsonProperty("firstName")]
|
||||
public string FirstName { get; set; }
|
||||
|
||||
[JsonProperty("lastName")]
|
||||
public string LastName { get; set; }
|
||||
|
||||
[JsonProperty("email")]
|
||||
public string Email { get; set; }
|
||||
|
||||
[JsonProperty("notBefore")]
|
||||
public int NotBefore { get; set; }
|
||||
|
||||
[JsonProperty("requiredActions")]
|
||||
public List<string> RequiredActions { get; set; }
|
||||
|
||||
[JsonProperty("attributes")]
|
||||
public JObject Attributes { get; set; }
|
||||
public JObject? Attributes { get; set; }
|
||||
|
||||
[JsonProperty("access")]
|
||||
public Dictionary<string, object> Access { get; set; }
|
||||
}
|
@ -25,6 +25,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CH.Enum", "CH.Enum\CH.Enum.
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CH.KeycloakApi", "CH.KeycloakApi\CH.KeycloakApi.csproj", "{28648B65-7D84-460A-993E-0F98D94CECFB}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CH.Dal.Abstractions", "CH.Dal.Abstractions\CH.Dal.Abstractions.csproj", "{C1584D53-DEC2-42B4-BEC9-3CCEECA88CB6}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -75,6 +77,10 @@ Global
|
||||
{28648B65-7D84-460A-993E-0F98D94CECFB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{28648B65-7D84-460A-993E-0F98D94CECFB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{28648B65-7D84-460A-993E-0F98D94CECFB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C1584D53-DEC2-42B4-BEC9-3CCEECA88CB6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C1584D53-DEC2-42B4-BEC9-3CCEECA88CB6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C1584D53-DEC2-42B4-BEC9-3CCEECA88CB6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C1584D53-DEC2-42B4-BEC9-3CCEECA88CB6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
Loading…
Reference in New Issue
Block a user