implement cqrs command, add keycloak service
This commit is contained in:
parent
77fdada230
commit
8eefa30d52
@ -17,6 +17,7 @@ using PoweredSoft.Data.EntityFrameworkCore;
|
|||||||
using PoweredSoft.DynamicQuery;
|
using PoweredSoft.DynamicQuery;
|
||||||
using PoweredSoft.Module.Abstractions;
|
using PoweredSoft.Module.Abstractions;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
using CH.Enum;
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
@ -110,7 +111,8 @@ mvcBuilder
|
|||||||
|
|
||||||
var connectionString = builder.Configuration.GetSection("Database").GetValue<string>("ConnectionString");
|
var connectionString = builder.Configuration.GetSection("Database").GetValue<string>("ConnectionString");
|
||||||
var dataSourceBuilder = new NpgsqlDataSourceBuilder(connectionString);
|
var dataSourceBuilder = new NpgsqlDataSourceBuilder(connectionString);
|
||||||
|
dataSourceBuilder.MapEnum<Currency>("currency");
|
||||||
|
dataSourceBuilder.MapEnum<EnergyRateExceptionThresholdResetType>("energy_rate_exception_threshold_reset_type");
|
||||||
var dataSource = dataSourceBuilder.Build();
|
var dataSource = dataSourceBuilder.Build();
|
||||||
|
|
||||||
builder.Services.AddDbContextPool<CHDbContext>(options =>
|
builder.Services.AddDbContextPool<CHDbContext>(options =>
|
||||||
|
@ -1,6 +1,31 @@
|
|||||||
|
using CH.CQRS.Service.Energy;
|
||||||
|
using CH.CQRS.Service.Energy.Options;
|
||||||
|
using FluentValidation;
|
||||||
|
using OpenHarbor.CQRS.Abstractions;
|
||||||
|
|
||||||
namespace CH.CQRS.Command.Energy;
|
namespace CH.CQRS.Command.Energy;
|
||||||
|
|
||||||
public class CreateEnergyProviderCommand
|
public class CreateEnergyProviderCommand
|
||||||
{
|
{
|
||||||
|
public required string Name { get; set; }
|
||||||
|
public bool Active { get; set; }
|
||||||
|
}
|
||||||
|
public class CreateEnergyProviderCommandHandler(EnergyService energyService) : ICommandHandler<CreateEnergyProviderCommand>
|
||||||
|
{
|
||||||
|
public Task HandleAsync(CreateEnergyProviderCommand command, CancellationToken cancellationToken = new CancellationToken())
|
||||||
|
{
|
||||||
|
return energyService.CreateEnergyProviderAsync(new CreateEnergyProviderCommandOptions
|
||||||
|
{
|
||||||
|
Name = command.Name,
|
||||||
|
Active = command.Active
|
||||||
|
},cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CreateEnergyProviderCommandValidator : AbstractValidator<CreateEnergyProviderCommand>
|
||||||
|
{
|
||||||
|
public CreateEnergyProviderCommandValidator()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,6 +1,39 @@
|
|||||||
|
using CH.CQRS.Service.Energy;
|
||||||
|
using CH.CQRS.Service.Energy.Options;
|
||||||
|
using FluentValidation;
|
||||||
|
using OpenHarbor.CQRS.Abstractions;
|
||||||
|
|
||||||
namespace CH.CQRS.Command.Energy;
|
namespace CH.CQRS.Command.Energy;
|
||||||
|
|
||||||
public class CreateEnergyRateCommand
|
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 bool Active { get; set; }
|
||||||
|
}
|
||||||
|
public class CreateEnergyRateCommandHandler(EnergyService energyService) : ICommandHandler<CreateEnergyRateCommand>
|
||||||
|
{
|
||||||
|
public Task HandleAsync(CreateEnergyRateCommand command, CancellationToken cancellationToken = new CancellationToken())
|
||||||
|
{
|
||||||
|
return energyService.CreateEnergyRateAsync(new CreateEnergyRateCommandOptions
|
||||||
|
{
|
||||||
|
ProviderId = command.ProviderId,
|
||||||
|
Name = command.Name,
|
||||||
|
Price = command.Price,
|
||||||
|
Currency = command.Currency,
|
||||||
|
Active = command.Active
|
||||||
|
},cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CreateEnergyRateCommandValidator : AbstractValidator<CreateEnergyRateCommand>
|
||||||
|
{
|
||||||
|
public CreateEnergyRateCommandValidator()
|
||||||
|
{
|
||||||
|
RuleFor(command => command.Price).GreaterThanOrEqualTo(0);
|
||||||
|
RuleFor(command => command.ProviderId)
|
||||||
|
.NotEmpty();
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,6 +1,43 @@
|
|||||||
|
using CH.CQRS.Service.Energy;
|
||||||
|
using CH.CQRS.Service.Energy.Options;
|
||||||
|
using FluentValidation;
|
||||||
|
using OpenHarbor.CQRS.Abstractions;
|
||||||
|
|
||||||
namespace CH.CQRS.Command.Energy;
|
namespace CH.CQRS.Command.Energy;
|
||||||
|
|
||||||
public class CreateEnergyRateExceptionCommand
|
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 DateTime? StartedAt { get; set; }
|
||||||
|
public DateTime? EndedAt { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CreateEnergyRateExceptionCommandHandler(EnergyService energyService) : ICommandHandler<CreateEnergyRateExceptionCommand>
|
||||||
|
{
|
||||||
|
public Task HandleAsync(CreateEnergyRateExceptionCommand command,
|
||||||
|
CancellationToken cancellationToken = new CancellationToken())
|
||||||
|
{
|
||||||
|
return energyService.CreateEnergyRateExceptionAsync(new CreateEnergyRateExceptionCommandOptions
|
||||||
|
{
|
||||||
|
RateId = command.RateId,
|
||||||
|
Name = command.Name,
|
||||||
|
EnergyThreshold = command.EnergyThreshold,
|
||||||
|
ResetType = command.ResetType,
|
||||||
|
StartedAt = command.StartedAt,
|
||||||
|
EndedAt = command.EndedAt
|
||||||
|
}, cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public class CreateEnergyRateExceptionCommandValidator : AbstractValidator<CreateEnergyRateExceptionCommand>
|
||||||
|
{
|
||||||
|
public CreateEnergyRateExceptionCommandValidator()
|
||||||
|
{
|
||||||
|
RuleFor(command => command.EnergyThreshold)
|
||||||
|
.GreaterThan(0);
|
||||||
|
RuleFor(command => command.RateId)
|
||||||
|
.NotEmpty();
|
||||||
|
}
|
||||||
}
|
}
|
32
CH.CQRS/Command/Energy/DisableEnergyProviderCommand.cs
Normal file
32
CH.CQRS/Command/Energy/DisableEnergyProviderCommand.cs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
using CH.CQRS.Service.Energy;
|
||||||
|
using CH.CQRS.Service.Energy.Options;
|
||||||
|
using FluentValidation;
|
||||||
|
using OpenHarbor.CQRS.Abstractions;
|
||||||
|
|
||||||
|
namespace CH.CQRS.Command.Energy;
|
||||||
|
|
||||||
|
public class DisableEnergyProviderCommand
|
||||||
|
{
|
||||||
|
public long ProviderId { get; set; }
|
||||||
|
public DateTime? DisabledAt { get; set; }
|
||||||
|
}
|
||||||
|
public class DisableEnergyProviderCommandHandler(EnergyService energyService) : ICommandHandler<DisableEnergyProviderCommand>
|
||||||
|
{
|
||||||
|
public Task HandleAsync(DisableEnergyProviderCommand command, CancellationToken cancellationToken = new CancellationToken())
|
||||||
|
{
|
||||||
|
return energyService.DisableEnergyProviderAsync(new DisableEnergyProviderCommandOptions
|
||||||
|
{
|
||||||
|
ProviderId = command.ProviderId,
|
||||||
|
DisabledAt = command.DisabledAt,
|
||||||
|
}, cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DisableEnergyProviderCommandValidator : AbstractValidator<DisableEnergyProviderCommand>
|
||||||
|
{
|
||||||
|
public DisableEnergyProviderCommandValidator()
|
||||||
|
{
|
||||||
|
RuleFor(command => command.ProviderId)
|
||||||
|
.NotEmpty();
|
||||||
|
}
|
||||||
|
}
|
32
CH.CQRS/Command/Energy/DisableEnergyRateCommand.cs
Normal file
32
CH.CQRS/Command/Energy/DisableEnergyRateCommand.cs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
using CH.CQRS.Service.Energy;
|
||||||
|
using CH.CQRS.Service.Energy.Options;
|
||||||
|
using FluentValidation;
|
||||||
|
using OpenHarbor.CQRS.Abstractions;
|
||||||
|
|
||||||
|
namespace CH.CQRS.Command.Energy;
|
||||||
|
|
||||||
|
public class DisableEnergyRateCommand
|
||||||
|
{
|
||||||
|
public long RateId { get; set; }
|
||||||
|
public DateTime? DisabledAt { get; set; }
|
||||||
|
}
|
||||||
|
public class DisableEnergyRateCommandHandler(EnergyService energyService) : ICommandHandler<DisableEnergyRateCommand>
|
||||||
|
{
|
||||||
|
public Task HandleAsync(DisableEnergyRateCommand command, CancellationToken cancellationToken = new CancellationToken())
|
||||||
|
{
|
||||||
|
return energyService.DisableEnergyRateAsync(new DisableEnergyRateCommandOptions
|
||||||
|
{
|
||||||
|
RateId = command.RateId,
|
||||||
|
DisabledAt = command.DisabledAt
|
||||||
|
}, cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DisableEnergyRateCommandValidator : AbstractValidator<DisableEnergyRateCommand>
|
||||||
|
{
|
||||||
|
public DisableEnergyRateCommandValidator()
|
||||||
|
{
|
||||||
|
RuleFor(command => command.RateId)
|
||||||
|
.NotEmpty();
|
||||||
|
}
|
||||||
|
}
|
29
CH.CQRS/Command/Energy/EnableEnergyProviderCommand.cs
Normal file
29
CH.CQRS/Command/Energy/EnableEnergyProviderCommand.cs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
using CH.CQRS.Service.Energy;
|
||||||
|
using CH.CQRS.Service.Energy.Options;
|
||||||
|
using FluentValidation;
|
||||||
|
using OpenHarbor.CQRS.Abstractions;
|
||||||
|
|
||||||
|
namespace CH.CQRS.Command.Energy;
|
||||||
|
|
||||||
|
public class EnableEnergyProviderCommand
|
||||||
|
{
|
||||||
|
public long ProviderId { get; set; }
|
||||||
|
}
|
||||||
|
public class EnableEnergyProviderCommandHandler(EnergyService energyService) : ICommandHandler<EnableEnergyProviderCommand>
|
||||||
|
{
|
||||||
|
public Task HandleAsync(EnableEnergyProviderCommand command, CancellationToken cancellationToken = new CancellationToken())
|
||||||
|
{
|
||||||
|
return energyService.EnableEnergyProviderAsync(new EnableEnergyProviderCommandOptions()
|
||||||
|
{
|
||||||
|
ProviderId = command.ProviderId
|
||||||
|
}, cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EnableEnergyProviderCommandValidator : AbstractValidator<EnableEnergyProviderCommand>
|
||||||
|
{
|
||||||
|
public EnableEnergyProviderCommandValidator()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
19
CH.CQRS/Command/Energy/EnableEnergyRateCommand.cs
Normal file
19
CH.CQRS/Command/Energy/EnableEnergyRateCommand.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
using CH.CQRS.Service.Energy;
|
||||||
|
using OpenHarbor.CQRS.Abstractions;
|
||||||
|
|
||||||
|
namespace CH.CQRS.Command.Energy;
|
||||||
|
|
||||||
|
public class EnableEnergyRateCommand
|
||||||
|
{
|
||||||
|
public long RateId { get; set; }
|
||||||
|
}
|
||||||
|
public class EnableEnergyRateCommandHandler(EnergyService energyService) : ICommandHandler<EnableEnergyRateCommand>
|
||||||
|
{
|
||||||
|
public Task HandleAsync(EnableEnergyRateCommand command, CancellationToken cancellationToken = new CancellationToken())
|
||||||
|
{
|
||||||
|
return energyService.EnableEnergyRateAsync(new EnableEnergyRateCommandOptions
|
||||||
|
{
|
||||||
|
RateId = command.RateId
|
||||||
|
}, cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,37 @@
|
|||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using OpenHarbor.CQRS.Abstractions;
|
||||||
|
using OpenHarbor.CQRS.FluentValidation;
|
||||||
namespace CH.CQRS.Command.Energy;
|
namespace CH.CQRS.Command.Energy;
|
||||||
|
|
||||||
public class ServiceCollectionExtension
|
public static class ServiceCollectionExtension
|
||||||
{
|
{
|
||||||
|
public static IServiceCollection AddEnergyCommand(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
services
|
||||||
|
.AddCommand<CreateEnergyProviderCommand, CreateEnergyProviderCommandHandler,
|
||||||
|
CreateEnergyProviderCommandValidator>();
|
||||||
|
services
|
||||||
|
.AddCommand<CreateEnergyRateExceptionCommand, CreateEnergyRateExceptionCommandHandler,
|
||||||
|
CreateEnergyRateExceptionCommandValidator>();
|
||||||
|
services
|
||||||
|
.AddCommand<CreateEnergyRateCommand, CreateEnergyRateCommandHandler,
|
||||||
|
CreateEnergyRateCommandValidator>();
|
||||||
|
services
|
||||||
|
.AddCommand<DisableEnergyProviderCommand, DisableEnergyProviderCommandHandler,
|
||||||
|
DisableEnergyProviderCommandValidator>();
|
||||||
|
services
|
||||||
|
.AddCommand<DisableEnergyRateCommand, DisableEnergyRateCommandHandler,
|
||||||
|
DisableEnergyRateCommandValidator>();
|
||||||
|
services
|
||||||
|
.AddCommand<UpdateEnergyProviderCommand, UpdateEnergyProviderCommandHandler,
|
||||||
|
UpdateEnergyProviderCommandValidator>();
|
||||||
|
services
|
||||||
|
.AddCommand<UpdateEnergyRateCommand, UpdateEnergyRateCommandHandler,
|
||||||
|
UpdateEnergyRateCommandValidator>();
|
||||||
|
services
|
||||||
|
.AddCommand<UpdateEnergyRateExceptionCommand, UpdateEnergyRateExceptionCommandHandler,
|
||||||
|
UpdateEnergyRateExceptionCommandValidator>();
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,6 +1,32 @@
|
|||||||
|
using CH.CQRS.Service.Energy;
|
||||||
|
using CH.CQRS.Service.Energy.Options;
|
||||||
|
using FluentValidation;
|
||||||
|
using OpenHarbor.CQRS.Abstractions;
|
||||||
|
|
||||||
namespace CH.CQRS.Command.Energy;
|
namespace CH.CQRS.Command.Energy;
|
||||||
|
|
||||||
public class UpdateEnergyProviderCommand
|
public class UpdateEnergyProviderCommand
|
||||||
{
|
{
|
||||||
|
public long ProviderId { get; set; }
|
||||||
|
public required string Name { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class UpdateEnergyProviderCommandHandler(EnergyService energyService) : ICommandHandler<UpdateEnergyProviderCommand>
|
||||||
|
{
|
||||||
|
public Task HandleAsync(UpdateEnergyProviderCommand command, CancellationToken cancellationToken = new CancellationToken())
|
||||||
|
{
|
||||||
|
return energyService.UpdateEnergyProviderAsync(new UpdateEnergyProviderCommandOptions
|
||||||
|
{
|
||||||
|
ProviderId = command.ProviderId,
|
||||||
|
Name = command.Name
|
||||||
|
},cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public class UpdateEnergyProviderCommandValidator : AbstractValidator<UpdateEnergyProviderCommand>
|
||||||
|
{
|
||||||
|
public UpdateEnergyProviderCommandValidator()
|
||||||
|
{
|
||||||
|
RuleFor(command => command.ProviderId)
|
||||||
|
.NotEmpty();
|
||||||
|
}
|
||||||
}
|
}
|
39
CH.CQRS/Command/Energy/UpdateEnergyRateCommand.cs
Normal file
39
CH.CQRS/Command/Energy/UpdateEnergyRateCommand.cs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
using CH.CQRS.Service.Energy;
|
||||||
|
using CH.CQRS.Service.Energy.Options;
|
||||||
|
using FluentValidation;
|
||||||
|
using OpenHarbor.CQRS.Abstractions;
|
||||||
|
|
||||||
|
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 decimal? Rate { get; set; }
|
||||||
|
public DateTime? UpdatedAt { get; set; }
|
||||||
|
}
|
||||||
|
public class UpdateEnergyRateCommandHandler(EnergyService energyService) : ICommandHandler<UpdateEnergyRateCommand>
|
||||||
|
{
|
||||||
|
public Task HandleAsync(UpdateEnergyRateCommand command, CancellationToken cancellationToken = new CancellationToken())
|
||||||
|
{
|
||||||
|
return energyService.UpdateEnergyRateAsync(new UpdateEnergyRateCommandOptions
|
||||||
|
{
|
||||||
|
RateId = command.RateId,
|
||||||
|
StartedAt = command.StartedAt,
|
||||||
|
AppliedAt = command.AppliedAt,
|
||||||
|
Rate = command.Rate,
|
||||||
|
SendAlert = command.SendAlert,
|
||||||
|
UpdatedAt = command.UpdatedAt
|
||||||
|
}, cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class UpdateEnergyRateCommandValidator : AbstractValidator<UpdateEnergyRateCommand>
|
||||||
|
{
|
||||||
|
public UpdateEnergyRateCommandValidator()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,41 @@
|
|||||||
|
using CH.CQRS.Service.Energy;
|
||||||
|
using CH.CQRS.Service.Energy.Options;
|
||||||
|
using FluentValidation;
|
||||||
|
using OpenHarbor.CQRS.Abstractions;
|
||||||
|
|
||||||
namespace CH.CQRS.Command.Energy;
|
namespace CH.CQRS.Command.Energy;
|
||||||
|
|
||||||
public class UpdateEnergyRateExceptionCommand
|
public class UpdateEnergyRateExceptionCommand
|
||||||
{
|
{
|
||||||
|
public long EnergyRateExceptionId { get; set; }
|
||||||
|
public decimal EnergyThreshold { get; set; }
|
||||||
|
public string? ResetType { get; set; }
|
||||||
|
public DateTime? StartedAt { get; set; }
|
||||||
|
public DateTime? EndedAt { get; set; }
|
||||||
|
}
|
||||||
|
public class UpdateEnergyRateExceptionCommandHandler(EnergyService energyService) : ICommandHandler<UpdateEnergyRateExceptionCommand>
|
||||||
|
{
|
||||||
|
public Task HandleAsync(UpdateEnergyRateExceptionCommand command,
|
||||||
|
CancellationToken cancellationToken = new CancellationToken())
|
||||||
|
{
|
||||||
|
return energyService.UpdateEnergyRateExceptionAsync(new UpdateEnergyRateExceptionCommandOptions
|
||||||
|
{
|
||||||
|
EnergyRateExceptionId = command.EnergyRateExceptionId,
|
||||||
|
EnergyThreshold = command.EnergyThreshold,
|
||||||
|
ResetType = command.ResetType,
|
||||||
|
StartedAt = command.StartedAt,
|
||||||
|
EndedAt = command.EndedAt
|
||||||
|
},cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class UpdateEnergyRateExceptionCommandValidator : AbstractValidator<UpdateEnergyRateExceptionCommand>
|
||||||
|
{
|
||||||
|
public UpdateEnergyRateExceptionCommandValidator()
|
||||||
|
{
|
||||||
|
RuleFor(command => command.EnergyRateExceptionId)
|
||||||
|
.NotEmpty();
|
||||||
|
RuleFor(command => command.EnergyThreshold)
|
||||||
|
.GreaterThan(0);
|
||||||
|
}
|
||||||
}
|
}
|
@ -7,6 +7,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using CH.CQRS.Command.Energy;
|
||||||
|
|
||||||
namespace CH.CQRS;
|
namespace CH.CQRS;
|
||||||
public class CommandModule : IModule
|
public class CommandModule : IModule
|
||||||
@ -15,7 +16,7 @@ public class CommandModule : IModule
|
|||||||
{
|
{
|
||||||
services.AddUserCommand();
|
services.AddUserCommand();
|
||||||
services.AddCryptoCommand();
|
services.AddCryptoCommand();
|
||||||
|
services.AddEnergyCommand();
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
|
using CH.CryptoStats.CoinGecko;
|
||||||
using CH.CryptoStats.CoinGecko;
|
|
||||||
using CH.CryptoStats.CoinMarketCap;
|
using CH.CryptoStats.CoinMarketCap;
|
||||||
|
|
||||||
namespace CH.CQRS.Service.CryptoStats;
|
namespace CH.CQRS.Service.CryptoStats;
|
||||||
|
@ -1,6 +1,153 @@
|
|||||||
|
using CH.CQRS.Command.Energy;
|
||||||
|
using CH.CQRS.Service.Energy.Options;
|
||||||
|
using CH.Dal;
|
||||||
|
using CH.Dal.DbEntity;
|
||||||
|
using CH.Enum;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace CH.CQRS.Service.Energy;
|
namespace CH.CQRS.Service.Energy;
|
||||||
|
|
||||||
public class EnergyService
|
public class EnergyService(CHDbContext dbContext)
|
||||||
{
|
{
|
||||||
|
public async Task CreateEnergyProviderAsync(CreateEnergyProviderCommandOptions options, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var energyProvider = new EnergyProvider
|
||||||
|
{
|
||||||
|
Name = options.Name,
|
||||||
|
CreatedAt = DateTime.UtcNow,
|
||||||
|
Active = options.Active
|
||||||
|
};
|
||||||
|
await dbContext.AddAsync(energyProvider, cancellationToken);
|
||||||
|
await dbContext.SaveChangesAsync(cancellationToken);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task CreateEnergyRateAsync(CreateEnergyRateCommandOptions options, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var provider = await dbContext.EnergyProviders.FirstOrDefaultAsync(provider => provider.Id == options.ProviderId, cancellationToken);
|
||||||
|
var energyRate = new EnergyRate
|
||||||
|
{
|
||||||
|
Name = options.Name,
|
||||||
|
Currency = (Currency)System.Enum.Parse(typeof(Currency), options.Currency?.ToUpper()),
|
||||||
|
Price = options.Price,
|
||||||
|
CreatedAt = DateTime.UtcNow,
|
||||||
|
Provider = provider,
|
||||||
|
Active = options.Active
|
||||||
|
};
|
||||||
|
await dbContext.AddAsync(energyRate, cancellationToken);
|
||||||
|
await dbContext.SaveChangesAsync(cancellationToken);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task CreateEnergyRateExceptionAsync(CreateEnergyRateExceptionCommandOptions options,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var energyRate = await dbContext.EnergyRates.FirstOrDefaultAsync(energyRate => energyRate.Id == options.RateId,cancellationToken);
|
||||||
|
var energyRateException = new EnergyRateException
|
||||||
|
{
|
||||||
|
Name = options.Name,
|
||||||
|
CreatedAt = DateTime.UtcNow,
|
||||||
|
Rate = energyRate,
|
||||||
|
StartedAt = options.StartedAt,
|
||||||
|
EndedAt = options.EndedAt,
|
||||||
|
EnergyThreshold = options.EnergyThreshold,
|
||||||
|
ResetType = (EnergyRateExceptionThresholdResetType)System.Enum
|
||||||
|
.Parse(typeof(EnergyRateExceptionThresholdResetType), options.ResetType.ToLower() ?? ""),
|
||||||
|
};
|
||||||
|
await dbContext.AddAsync(energyRateException, cancellationToken);
|
||||||
|
await dbContext.SaveChangesAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UpdateEnergyRateAsync(UpdateEnergyRateCommandOptions options, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var energyRateUpdate = new EnergyRateUpdate
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
await dbContext.SaveChangesAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UpdateEnergyRateExceptionAsync(UpdateEnergyRateExceptionCommandOptions options,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var energyRateException = await dbContext.EnergyRateExceptions
|
||||||
|
.FirstOrDefaultAsync(rateException => rateException.Id == options.EnergyRateExceptionId, cancellationToken);
|
||||||
|
if (null != energyRateException)
|
||||||
|
{
|
||||||
|
energyRateException.EnergyThreshold = options.EnergyThreshold;
|
||||||
|
energyRateException.StartedAt = options.StartedAt;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task DisableEnergyProviderAsync(DisableEnergyProviderCommandOptions options,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var energyProvider = await dbContext.EnergyProviders.FirstOrDefaultAsync(provider => provider.Id == options.ProviderId, cancellationToken);
|
||||||
|
if (null != energyProvider)
|
||||||
|
{
|
||||||
|
energyProvider.Active = false;
|
||||||
|
energyProvider.DisabledAt = options.DisabledAt;
|
||||||
|
await dbContext.SaveChangesAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task DisableEnergyRateAsync(DisableEnergyRateCommandOptions options, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var energyRate = await dbContext.EnergyRates.FirstOrDefaultAsync(rate => rate.Id == options.RateId, cancellationToken);
|
||||||
|
if (null != energyRate)
|
||||||
|
{
|
||||||
|
energyRate.Active = false;
|
||||||
|
energyRate.DisabledAt = options.DisabledAt;
|
||||||
|
await dbContext.SaveChangesAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public async Task EnableEnergyProviderAsync(EnableEnergyProviderCommandOptions options,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var energyProvider = await dbContext.EnergyProviders.FirstOrDefaultAsync(provider => provider.Id == options.ProviderId, cancellationToken);
|
||||||
|
if (null != energyProvider)
|
||||||
|
{
|
||||||
|
energyProvider.Active = true;
|
||||||
|
energyProvider.DisabledAt = null;
|
||||||
|
await dbContext.SaveChangesAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task EnableEnergyRateAsync(EnableEnergyRateCommandOptions options, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var energyRate = await dbContext.EnergyRates.FirstOrDefaultAsync(rate => rate.Id == options.RateId, cancellationToken);
|
||||||
|
if (null != energyRate)
|
||||||
|
{
|
||||||
|
energyRate.Active = true;
|
||||||
|
energyRate.DisabledAt = null;
|
||||||
|
await dbContext.SaveChangesAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -2,5 +2,6 @@ namespace CH.CQRS.Service.Energy.Options;
|
|||||||
|
|
||||||
public class CreateEnergyProviderCommandOptions
|
public class CreateEnergyProviderCommandOptions
|
||||||
{
|
{
|
||||||
|
public required string Name { get; set; }
|
||||||
|
public bool Active { get; set; }
|
||||||
}
|
}
|
@ -1,6 +1,12 @@
|
|||||||
|
using Amazon.Runtime.Internal.Transform;
|
||||||
|
|
||||||
namespace CH.CQRS.Service.Energy.Options;
|
namespace CH.CQRS.Service.Energy.Options;
|
||||||
|
|
||||||
public class CreateEnergyRateCommandOptions
|
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 bool Active { get; set; }
|
||||||
}
|
}
|
@ -2,5 +2,10 @@ namespace CH.CQRS.Service.Energy.Options;
|
|||||||
|
|
||||||
public class CreateEnergyRateExceptionCommandOptions
|
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 DateTime? StartedAt { get; set; }
|
||||||
|
public DateTime? EndedAt { get; set; }
|
||||||
}
|
}
|
@ -2,5 +2,6 @@ namespace CH.CQRS.Service.Energy.Options;
|
|||||||
|
|
||||||
public class DisableEnergyProviderCommandOptions
|
public class DisableEnergyProviderCommandOptions
|
||||||
{
|
{
|
||||||
|
public long ProviderId { get; set; }
|
||||||
|
public DateTime? DisabledAt { get; set; }
|
||||||
}
|
}
|
@ -2,5 +2,6 @@ namespace CH.CQRS.Service.Energy.Options;
|
|||||||
|
|
||||||
public class DisableEnergyRateCommandOptions
|
public class DisableEnergyRateCommandOptions
|
||||||
{
|
{
|
||||||
|
public long RateId { get; set; }
|
||||||
|
public DateTime? DisabledAt { get; set; }
|
||||||
}
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
namespace CH.CQRS.Service.Energy.Options;
|
||||||
|
|
||||||
|
public class EnableEnergyProviderCommandOptions
|
||||||
|
{
|
||||||
|
public long ProviderId { get; set; }
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
namespace CH.CQRS.Command.Energy;
|
||||||
|
|
||||||
|
public class EnableEnergyRateCommandOptions
|
||||||
|
{
|
||||||
|
public long RateId { get; set; }
|
||||||
|
}
|
@ -2,5 +2,6 @@ namespace CH.CQRS.Service.Energy.Options;
|
|||||||
|
|
||||||
public class UpdateEnergyProviderCommandOptions
|
public class UpdateEnergyProviderCommandOptions
|
||||||
{
|
{
|
||||||
|
public long ProviderId { get; set; }
|
||||||
|
public required string Name { get; set; }
|
||||||
}
|
}
|
@ -2,5 +2,10 @@ namespace CH.CQRS.Service.Energy.Options;
|
|||||||
|
|
||||||
public class UpdateEnergyRateCommandOptions
|
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 decimal? Rate { get; set; }
|
||||||
|
public DateTime? UpdatedAt { get; set; }
|
||||||
}
|
}
|
@ -2,5 +2,9 @@ namespace CH.CQRS.Service.Energy.Options;
|
|||||||
|
|
||||||
public class UpdateEnergyRateExceptionCommandOptions
|
public class UpdateEnergyRateExceptionCommandOptions
|
||||||
{
|
{
|
||||||
|
public long EnergyRateExceptionId { get; set; }
|
||||||
|
public decimal EnergyThreshold { get; set; }
|
||||||
|
public string? ResetType { get; set; }
|
||||||
|
public DateTime? StartedAt { get; set; }
|
||||||
|
public DateTime? EndedAt { get; set; }
|
||||||
}
|
}
|
@ -1,4 +1,5 @@
|
|||||||
using CH.CQRS.Service.CryptoStats;
|
using CH.CQRS.Service.CryptoStats;
|
||||||
|
using CH.CQRS.Service.Energy;
|
||||||
using CH.CQRS.Service.User;
|
using CH.CQRS.Service.User;
|
||||||
using CH.CryptoStats.Abstractions;
|
using CH.CryptoStats.Abstractions;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
@ -11,6 +12,7 @@ public class SharedModule : IModule
|
|||||||
{
|
{
|
||||||
services.AddScoped<UserService>();
|
services.AddScoped<UserService>();
|
||||||
services.AddScoped<CryptoService>();
|
services.AddScoped<CryptoService>();
|
||||||
|
services.AddScoped<EnergyService>();
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,12 +9,12 @@ public class CHDbContext(DbContextOptions options) : CHDbScaffoldedContext(optio
|
|||||||
{
|
{
|
||||||
static CHDbContext() => NpgsqlConnection.GlobalTypeMapper
|
static CHDbContext() => NpgsqlConnection.GlobalTypeMapper
|
||||||
.MapEnum<Currency>("currency")
|
.MapEnum<Currency>("currency")
|
||||||
.MapEnum<EnergyRateExceptionTresholdResetType>("energy_rate_exception_treshold_reset_type");
|
.MapEnum<EnergyRateExceptionThresholdResetType>("energy_rate_exception_threshold_reset_type");
|
||||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
{
|
{
|
||||||
base.OnModelCreating(modelBuilder);
|
base.OnModelCreating(modelBuilder);
|
||||||
modelBuilder.HasPostgresEnum<Currency>("currency");
|
modelBuilder.HasPostgresEnum<Currency>("currency");
|
||||||
modelBuilder.HasPostgresEnum<EnergyRateExceptionTresholdResetType>("energy_rate_exception_treshold_reset_type");
|
modelBuilder.HasPostgresEnum<EnergyRateExceptionThresholdResetType>("energy_rate_exception_threshold_reset_type");
|
||||||
|
|
||||||
modelBuilder.Entity<EnergyRate>(entity =>
|
modelBuilder.Entity<EnergyRate>(entity =>
|
||||||
{
|
{
|
||||||
@ -26,7 +26,7 @@ public class CHDbContext(DbContextOptions options) : CHDbScaffoldedContext(optio
|
|||||||
{
|
{
|
||||||
entity.Property(e => e.ResetType)
|
entity.Property(e => e.ResetType)
|
||||||
.HasColumnName("reset_type")
|
.HasColumnName("reset_type")
|
||||||
.HasColumnType("energy_rate_exception_treshold_reset_type");
|
.HasColumnType("energy_rate_exception_threshold_reset_type");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +22,8 @@ public partial class CHDbScaffoldedContext : DbContext
|
|||||||
|
|
||||||
public virtual DbSet<EnergyRateException> EnergyRateExceptions { get; set; }
|
public virtual DbSet<EnergyRateException> EnergyRateExceptions { get; set; }
|
||||||
|
|
||||||
|
public virtual DbSet<EnergyRateUpdate> EnergyRateUpdates { get; set; }
|
||||||
|
|
||||||
public virtual DbSet<Location> Locations { get; set; }
|
public virtual DbSet<Location> Locations { get; set; }
|
||||||
|
|
||||||
public virtual DbSet<Machine> Machines { get; set; }
|
public virtual DbSet<Machine> Machines { get; set; }
|
||||||
@ -35,7 +37,7 @@ public partial class CHDbScaffoldedContext : DbContext
|
|||||||
{
|
{
|
||||||
modelBuilder
|
modelBuilder
|
||||||
.HasPostgresEnum("currency", new[] { "USD", "CAD" })
|
.HasPostgresEnum("currency", new[] { "USD", "CAD" })
|
||||||
.HasPostgresEnum("energy_rate_exception_treshold_reset_type", new[] { "daily" });
|
.HasPostgresEnum("energy_rate_exception_threshold_reset_type", new[] { "daily" });
|
||||||
|
|
||||||
modelBuilder.Entity<EnergyProvider>(entity =>
|
modelBuilder.Entity<EnergyProvider>(entity =>
|
||||||
{
|
{
|
||||||
@ -44,9 +46,11 @@ public partial class CHDbScaffoldedContext : DbContext
|
|||||||
entity.ToTable("energy_provider");
|
entity.ToTable("energy_provider");
|
||||||
|
|
||||||
entity.Property(e => e.Id).HasColumnName("id");
|
entity.Property(e => e.Id).HasColumnName("id");
|
||||||
|
entity.Property(e => e.Active).HasColumnName("active");
|
||||||
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.DisabledAt).HasColumnName("disabled_at");
|
||||||
entity.Property(e => e.Name)
|
entity.Property(e => e.Name)
|
||||||
.HasMaxLength(255)
|
.HasMaxLength(255)
|
||||||
.HasColumnName("name");
|
.HasColumnName("name");
|
||||||
@ -60,9 +64,11 @@ public partial class CHDbScaffoldedContext : DbContext
|
|||||||
entity.ToTable("energy_rate");
|
entity.ToTable("energy_rate");
|
||||||
|
|
||||||
entity.Property(e => e.Id).HasColumnName("id");
|
entity.Property(e => e.Id).HasColumnName("id");
|
||||||
|
entity.Property(e => e.Active).HasColumnName("active");
|
||||||
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.DisabledAt).HasColumnName("disabled_at");
|
||||||
entity.Property(e => e.Name)
|
entity.Property(e => e.Name)
|
||||||
.HasMaxLength(255)
|
.HasMaxLength(255)
|
||||||
.HasColumnName("name");
|
.HasColumnName("name");
|
||||||
@ -86,7 +92,7 @@ public partial class CHDbScaffoldedContext : DbContext
|
|||||||
.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.EndedAt).HasColumnName("ended_at");
|
entity.Property(e => e.EndedAt).HasColumnName("ended_at");
|
||||||
entity.Property(e => e.EnergyTreshold).HasColumnName("energy_treshold");
|
entity.Property(e => e.EnergyThreshold).HasColumnName("energy_threshold");
|
||||||
entity.Property(e => e.Name)
|
entity.Property(e => e.Name)
|
||||||
.HasMaxLength(255)
|
.HasMaxLength(255)
|
||||||
.HasColumnName("name");
|
.HasColumnName("name");
|
||||||
@ -99,6 +105,30 @@ public partial class CHDbScaffoldedContext : DbContext
|
|||||||
.HasConstraintName("energy_rate_exception_rate_id_fkey");
|
.HasConstraintName("energy_rate_exception_rate_id_fkey");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity<EnergyRateUpdate>(entity =>
|
||||||
|
{
|
||||||
|
entity.HasKey(e => e.Id).HasName("energy_rate_update_pkey");
|
||||||
|
|
||||||
|
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.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");
|
||||||
|
|
||||||
|
entity.HasOne(d => d.RateNavigation).WithMany(p => p.EnergyRateUpdates)
|
||||||
|
.HasForeignKey(d => d.RateId)
|
||||||
|
.HasConstraintName("energy_rate_update_rate_id_fkey");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity<Location>(entity =>
|
modelBuilder.Entity<Location>(entity =>
|
||||||
{
|
{
|
||||||
entity.HasKey(e => e.Id).HasName("location_pkey");
|
entity.HasKey(e => e.Id).HasName("location_pkey");
|
||||||
|
@ -9,6 +9,10 @@ public partial class EnergyProvider
|
|||||||
|
|
||||||
public string Name { get; set; } = null!;
|
public string Name { get; set; } = null!;
|
||||||
|
|
||||||
|
public bool Active { get; set; }
|
||||||
|
|
||||||
|
public DateTime? DisabledAt { get; set; }
|
||||||
|
|
||||||
public DateTime CreatedAt { get; set; }
|
public DateTime CreatedAt { get; set; }
|
||||||
|
|
||||||
public DateTime? UpdatedAt { get; set; }
|
public DateTime? UpdatedAt { get; set; }
|
||||||
|
@ -13,11 +13,17 @@ public partial class EnergyRate
|
|||||||
|
|
||||||
public decimal? Price { get; set; }
|
public decimal? Price { get; set; }
|
||||||
|
|
||||||
|
public bool Active { get; set; }
|
||||||
|
|
||||||
|
public DateTime? DisabledAt { get; set; }
|
||||||
|
|
||||||
public DateTime CreatedAt { get; set; }
|
public DateTime CreatedAt { get; set; }
|
||||||
|
|
||||||
public DateTime? UpdatedAt { get; set; }
|
public DateTime? UpdatedAt { get; set; }
|
||||||
|
|
||||||
public virtual ICollection<EnergyRateException> EnergyRateExceptions { get; set; } = new List<EnergyRateException>();
|
public virtual ICollection<EnergyRateException> EnergyRateExceptions { get; set; } = new List<EnergyRateException>();
|
||||||
|
|
||||||
|
public virtual ICollection<EnergyRateUpdate> EnergyRateUpdates { get; set; } = new List<EnergyRateUpdate>();
|
||||||
|
|
||||||
public virtual EnergyProvider? Provider { get; set; }
|
public virtual EnergyProvider? Provider { get; set; }
|
||||||
}
|
}
|
||||||
|
@ -5,5 +5,5 @@ namespace CH.Dal.DbEntity;
|
|||||||
public partial class EnergyRateException
|
public partial class EnergyRateException
|
||||||
{
|
{
|
||||||
[Column(TypeName = "energy_rate_exception_treshold_reset_type")]
|
[Column(TypeName = "energy_rate_exception_treshold_reset_type")]
|
||||||
public EnergyRateExceptionTresholdResetType ResetType { get; set; }
|
public EnergyRateExceptionThresholdResetType ResetType { get; set; }
|
||||||
}
|
}
|
@ -11,7 +11,7 @@ public partial class EnergyRateException
|
|||||||
|
|
||||||
public string? Name { get; set; }
|
public string? Name { get; set; }
|
||||||
|
|
||||||
public decimal? EnergyTreshold { get; set; }
|
public decimal? EnergyThreshold { get; set; }
|
||||||
|
|
||||||
public DateTime? StartedAt { get; set; }
|
public DateTime? StartedAt { get; set; }
|
||||||
|
|
||||||
|
25
CH.Dal/DbEntity/EnergyRateUpdate.cs
Normal file
25
CH.Dal/DbEntity/EnergyRateUpdate.cs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace CH.Dal.DbEntity;
|
||||||
|
|
||||||
|
public partial class EnergyRateUpdate
|
||||||
|
{
|
||||||
|
public long Id { get; set; }
|
||||||
|
|
||||||
|
public long? RateId { get; set; }
|
||||||
|
|
||||||
|
public bool SendAlert { get; set; }
|
||||||
|
|
||||||
|
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; }
|
||||||
|
|
||||||
|
public virtual EnergyRate? RateNavigation { get; set; }
|
||||||
|
}
|
@ -2,8 +2,8 @@ using NpgsqlTypes;
|
|||||||
|
|
||||||
namespace CH.Enum;
|
namespace CH.Enum;
|
||||||
|
|
||||||
public enum EnergyRateExceptionTresholdResetType
|
public enum EnergyRateExceptionThresholdResetType
|
||||||
{
|
{
|
||||||
[PgName("daily")]
|
[PgName("daily")]
|
||||||
Daily,
|
daily,
|
||||||
}
|
}
|
13
CH.KeycloakApi/CH.KeycloakApi.csproj
Normal file
13
CH.KeycloakApi/CH.KeycloakApi.csproj
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="IdentityModel" Version="7.0.0" />
|
||||||
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="8.0.2" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
180
CH.KeycloakApi/KeycloakService.cs
Normal file
180
CH.KeycloakApi/KeycloakService.cs
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
using System.Text;
|
||||||
|
using IdentityModel.Client;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace CH.KeycloakApi;
|
||||||
|
|
||||||
|
public class KeycloakService
|
||||||
|
{
|
||||||
|
private readonly KeycloakSettings settings;
|
||||||
|
|
||||||
|
public KeycloakService(IConfiguration configuration)
|
||||||
|
{
|
||||||
|
this.settings = new KeycloakSettings();
|
||||||
|
configuration.Bind("Keycloak", settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public KeycloakSettings Settings => settings;
|
||||||
|
|
||||||
|
public async Task<string> GetTokenAsync()
|
||||||
|
{
|
||||||
|
var tokenEndpoint = $"{this.settings.Endpoint}/realms/master/protocol/openid-connect/token";
|
||||||
|
var client = new HttpClient();
|
||||||
|
var response = await client.RequestTokenAsync(new TokenRequest
|
||||||
|
{
|
||||||
|
Address = tokenEndpoint,
|
||||||
|
GrantType = "client_credentials",
|
||||||
|
ClientId = this.settings.ClientId,
|
||||||
|
ClientSecret = this.settings.ClientSecret,
|
||||||
|
});
|
||||||
|
|
||||||
|
return response.AccessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<KeycloakUser> GetUserByEmailAsync(string realm, string email)
|
||||||
|
{
|
||||||
|
var httpClient = new HttpClient();
|
||||||
|
var url = $"{this.settings.Endpoint}/admin/realms/{realm}/users?email={email}";
|
||||||
|
httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("bearer", await GetTokenAsync());
|
||||||
|
var response = await httpClient.GetAsync(url);
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
var json = await response.Content.ReadAsStringAsync();
|
||||||
|
var ret = JsonConvert.DeserializeObject<List<KeycloakUser>>(json);
|
||||||
|
return ret.FirstOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
var url = $"{this.settings.Endpoint}/admin/realms/{realm}/users/{id}";
|
||||||
|
var response = await httpClient.GetAsync(url);
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
var json = await response.Content.ReadAsStringAsync();
|
||||||
|
var ret = JsonConvert.DeserializeObject<KeycloakUser>(json);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SendChangePasswordEmailAsync(string realm, string id)
|
||||||
|
{
|
||||||
|
//PUT /{realm}/users/{id}/execute-actions-email
|
||||||
|
var url = $"{this.settings.Endpoint}/admin/realms/{realm}/users/{id}/execute-actions-email";
|
||||||
|
var httpClient = new HttpClient();
|
||||||
|
httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("bearer", await GetTokenAsync());
|
||||||
|
var putJson = JsonConvert.SerializeObject(new string[] {
|
||||||
|
"UPDATE_PASSWORD"
|
||||||
|
});
|
||||||
|
var response = await httpClient.PutAsync(url, new StringContent(putJson, Encoding.UTF8, "application/json"));
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
var url = $"{this.settings.Endpoint}/admin/realms/{realm}/users?max={max}";
|
||||||
|
if (!string.IsNullOrWhiteSpace(search))
|
||||||
|
url += $"&search={search}";
|
||||||
|
|
||||||
|
var response = await httpClient.GetAsync(url);
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
var json = await response.Content.ReadAsStringAsync();
|
||||||
|
var ret = JsonConvert.DeserializeObject<List<KeycloakUser>>(json);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task ChangePasswordAsync(string realm, string id, string newPassword, bool temporary)
|
||||||
|
{
|
||||||
|
///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();
|
||||||
|
httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("bearer", await GetTokenAsync());
|
||||||
|
var putJson = JsonConvert.SerializeObject(new {
|
||||||
|
type = "password",
|
||||||
|
temporary,
|
||||||
|
value = newPassword
|
||||||
|
});
|
||||||
|
var response = await httpClient.PutAsync(url, new StringContent(putJson, Encoding.UTF8, "application/json"));
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public async Task UpdateUserByIdAsync(string realm, string id, string email, string firstName, string lastName, bool enabled)
|
||||||
|
{
|
||||||
|
var user = await GetUserByIdAsync(realm, id);
|
||||||
|
if (user == null)
|
||||||
|
throw new Exception($"no user {email} from on realm {realm}");
|
||||||
|
|
||||||
|
user.Email = email;
|
||||||
|
user.FirstName = firstName;
|
||||||
|
user.LastName = lastName;
|
||||||
|
user.Username = email;
|
||||||
|
user.Enabled = enabled;
|
||||||
|
|
||||||
|
var url = $"{this.settings.Endpoint}/admin/realms/{realm}/users/{id}";
|
||||||
|
|
||||||
|
var httpClient = new HttpClient();
|
||||||
|
httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("bearer", await GetTokenAsync());
|
||||||
|
var putJson = JsonConvert.SerializeObject(user);
|
||||||
|
var response = await httpClient.PutAsync(url, new StringContent(putJson, Encoding.UTF8, "application/json"));
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> EmailExistsAsync(string realm, string email)
|
||||||
|
{
|
||||||
|
return await this.GetUserByEmailAsync(realm, email) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<KeycloakUser> CreateOrUpdateAsync(string realm, string email, string firstName, string lastName, bool enabled)
|
||||||
|
{
|
||||||
|
var existingUser = await GetUserByEmailAsync(realm, email);
|
||||||
|
if (existingUser != null)
|
||||||
|
{
|
||||||
|
await UpdateUserByIdAsync(realm, existingUser.Id, email, firstName, lastName, enabled);
|
||||||
|
return await GetUserByEmailAsync(realm, email);
|
||||||
|
}
|
||||||
|
|
||||||
|
return await CreateUserAsync(realm, email, firstName, lastName, 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);
|
||||||
|
|
||||||
|
var user = new KeycloakUser()
|
||||||
|
{
|
||||||
|
CreatedTimestamp = unixTime,
|
||||||
|
Username = email,
|
||||||
|
FirstName = firstName,
|
||||||
|
LastName = lastName,
|
||||||
|
Enabled = enabled,
|
||||||
|
Totp = false,
|
||||||
|
EmailVerified = false,
|
||||||
|
RequiredActions = new List<String>(),
|
||||||
|
Attributes = null,
|
||||||
|
Email = email,
|
||||||
|
NotBefore = 0,
|
||||||
|
Access = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "manageGroupMembership", true },
|
||||||
|
{ "view", true },
|
||||||
|
{ "mapRoles", true },
|
||||||
|
{ "impersonate", true },
|
||||||
|
{ "manage", true }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var httpClient = new HttpClient();
|
||||||
|
httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("bearer", await GetTokenAsync());
|
||||||
|
var url = $"{this.settings.Endpoint}/admin/realms/{realm}/users";
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
10
CH.KeycloakApi/KeycloakSettings.cs
Normal file
10
CH.KeycloakApi/KeycloakSettings.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
namespace CH.KeycloakApi;
|
||||||
|
|
||||||
|
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; }
|
||||||
|
}
|
34
CH.KeycloakApi/KeycloakUser.cs
Normal file
34
CH.KeycloakApi/KeycloakUser.cs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
|
namespace CH.KeycloakApi;
|
||||||
|
|
||||||
|
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; }
|
||||||
|
[JsonProperty("access")]
|
||||||
|
public Dictionary<string, object> Access { get; set; }
|
||||||
|
}
|
@ -23,6 +23,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CH.Energy.HydroQuebec", "CH
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CH.Enum", "CH.Enum\CH.Enum.csproj", "{45E17ADC-A1C9-4EE0-BA6E-A4B52F0621BD}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CH.Enum", "CH.Enum\CH.Enum.csproj", "{45E17ADC-A1C9-4EE0-BA6E-A4B52F0621BD}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CH.KeycloakApi", "CH.KeycloakApi\CH.KeycloakApi.csproj", "{28648B65-7D84-460A-993E-0F98D94CECFB}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@ -69,6 +71,10 @@ Global
|
|||||||
{45E17ADC-A1C9-4EE0-BA6E-A4B52F0621BD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{45E17ADC-A1C9-4EE0-BA6E-A4B52F0621BD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{45E17ADC-A1C9-4EE0-BA6E-A4B52F0621BD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{45E17ADC-A1C9-4EE0-BA6E-A4B52F0621BD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{45E17ADC-A1C9-4EE0-BA6E-A4B52F0621BD}.Release|Any CPU.Build.0 = Release|Any CPU
|
{45E17ADC-A1C9-4EE0-BA6E-A4B52F0621BD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{28648B65-7D84-460A-993E-0F98D94CECFB}.Debug|Any CPU.ActiveCfg = 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.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