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