Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions API/API.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

<ItemGroup>
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="12.0.1" />
<PackageReference Include="CsvHelper" Version="33.1.0" />
<PackageReference Include="Flurl" Version="4.0.0" />
<PackageReference Include="Flurl.Http" Version="4.0.2" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.7" />
Expand Down
43 changes: 43 additions & 0 deletions API/Controllers/ExportController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using API.Constants;
using API.Data;
using API.Data.Repositories;
using API.DTOs;
using API.Extensions;
using API.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace API.Controllers;

public class ExportController(ILogger<ExportController> logger, IExportService exportService, IUnitOfWork unitOfWork): BaseApiController
{

[HttpPost]
[Authorize(PolicyConstants.HandleDeliveries)]
public async Task<ActionResult<string>> Export(ExportRequestDto dto)
{
logger.LogInformation("Creating export on behalf of {UserId}", User.GetUserId());

var deliveries =
await unitOfWork.DeliveryRepository.GetDeliveryByIds(dto.DeliveryIds, DeliveryIncludes.Complete);
if (deliveries.Count == 0)
{
return BadRequest();
}


var uuid = await exportService.Export(deliveries, dto);
return Ok(uuid);
}

[HttpGet("{uuid}")]
[Authorize(PolicyConstants.HandleDeliveries)]
public async Task<ActionResult> GetExport(string uuid)
{
var export = await exportService.GetExport(uuid);
if (export == null) return NotFound();

return export;
}

}
27 changes: 27 additions & 0 deletions API/Controllers/SettingsController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using API.Constants;
using API.DTOs;
using API.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace API.Controllers;

[Authorize(PolicyConstants.ManageApplication)]
public class SettingsController(ILogger<SettingsController> logger, ISettingsService settingsService): BaseApiController
{

[HttpGet]
public async Task<ActionResult<ServerSettingsDto>> GetSettings()
{
var settings = await settingsService.GetSettingsAsync();
return Ok(settings);
}

[HttpPost]
public async Task<AcceptedResult> SaveSettings(ServerSettingsDto settings)
{
await settingsService.SaveSettingsAsync(settings);
return Accepted();
}

}
56 changes: 56 additions & 0 deletions API/DTOs/Enum/DeliveryExportField.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using API.Entities;

namespace API.DTOs.Enum;

public enum DeliveryExportField
{
/// <summary>
/// <see cref="Delivery.Id"/>
/// </summary>
Id = 0,
/// <summary>
/// <see cref="Delivery.State"/>
/// </summary>
State = 1,
/// <summary>
/// <see cref="User.Id"/>
/// </summary>
FromId = 2,
/// <summary>
/// <see cref="User.Name"/>
/// </summary>
From = 3,
/// <summary>
/// <see cref="Client.Id"/>
/// </summary>
RecipientId = 4,
/// <summary>
/// <see cref="Client.Name"/>
/// </summary>
RecipientName = 5,
/// <summary>
/// <see cref="Client.InvoiceEmail"/>
/// </summary>
RecipientEmail = 6,
/// <summary>
/// <see cref="Client.CompanyNumber"/>
/// </summary>
CompanyNumber = 7,
/// <summary>
/// <see cref="Delivery.Message"/>
/// </summary>
Message = 8,
/// <summary>
/// <see cref="Delivery.Lines"/>
/// All products accross exported deliveries will be added as headers. Each row will have 0 or n as value
/// </summary>
Products = 9,
/// <summary>
/// <see cref="Delivery.CreatedUtc"/>
/// </summary>
CreatedUtc = 10,
/// <summary>
/// <see cref="Delivery.LastModifiedUtc"/>
/// </summary>
LastModifiedUtc = 11,
}
9 changes: 9 additions & 0 deletions API/DTOs/Enum/ExportKind.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System.ComponentModel;

namespace API.DTOs.Enum;

public enum ExportKind
{
[Description("csv")]
Csv = 0,
}
13 changes: 13 additions & 0 deletions API/DTOs/Export/CsvExportConfigurationDto.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using API.DTOs.Enum;

namespace API.DTOs;

public class CsvExportConfigurationDto
{
/// <summary>
/// The order in which to export fields, if empty or unset exports in the natural enum order
/// </summary>
public IList<DeliveryExportField> HeaderOrder { get; set; } = [];

public IList<string> HeaderNames { get; set; } = [];
}
12 changes: 12 additions & 0 deletions API/DTOs/Export/ExportRequestDto.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using API.DTOs.Enum;

namespace API.DTOs;

public class ExportRequestDto
{

public ExportKind Kind { get; set; }

public IList<int> DeliveryIds { get; set; }

}
6 changes: 0 additions & 6 deletions API/DTOs/ServerSettingDto.cs

This file was deleted.

10 changes: 10 additions & 0 deletions API/DTOs/ServerSettingsDto.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using Serilog.Events;

namespace API.DTOs;

public sealed record ServerSettingsDto
{
public CsvExportConfigurationDto CsvExportConfiguration { get; set; }

public LogEventLevel LogLevel { get; set; }
}
9 changes: 9 additions & 0 deletions API/Data/Repositories/DeliveryRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public interface IDeliveryRepository
{
public Task<IList<DeliveryDto>> GetDeliveries(FilterDto filter, PaginationParams pagination, DeliveryIncludes includes = DeliveryIncludes.None);
public Task<Delivery?> GetDeliveryById(int deliveryId, DeliveryIncludes includes = DeliveryIncludes.None);
public Task<IList<Delivery>> GetDeliveryByIds(IEnumerable<int> deliveryIds, DeliveryIncludes includes = DeliveryIncludes.None);
public Task<DeliveryDto?> GetDelivery(int deliveryId, DeliveryIncludes includes = DeliveryIncludes.From);
public Task<IList<Delivery>> GetDeliveriesForClient(int clientId, IList<DeliveryState> states, DeliveryIncludes includes = DeliveryIncludes.None);

Expand Down Expand Up @@ -65,6 +66,14 @@ public async Task<IList<DeliveryDto>> GetDeliveries(FilterDto filter, Pagination
.FirstOrDefaultAsync();
}

public async Task<IList<Delivery>> GetDeliveryByIds(IEnumerable<int> deliveryIds, DeliveryIncludes includes = DeliveryIncludes.None)
{
return await ctx.Deliveries
.Where(d => deliveryIds.Contains(d.Id))
.Includes(includes)
.ToListAsync();
}

public async Task<DeliveryDto?> GetDelivery(int deliveryId, DeliveryIncludes includes = DeliveryIncludes.From)
{
return mapper.Map<DeliveryDto>(await ctx.Deliveries
Expand Down
10 changes: 10 additions & 0 deletions API/Data/Repositories/SettingsRepository.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using API.DTOs;
using API.Entities;
using API.Entities.Enums;
using AutoMapper;
using Microsoft.EntityFrameworkCore;

Expand All @@ -9,6 +11,7 @@ public interface ISettingsRepository
void Update(ServerSetting settings);
void Remove(ServerSetting setting);

Task<ServerSetting> GetSettingsAsync(ServerSettingKey key);
Task<IList<ServerSetting>> GetSettingsAsync();
}

Expand All @@ -25,6 +28,13 @@ public void Remove(ServerSetting setting)
ctx.Remove(setting);
}

public async Task<ServerSetting> GetSettingsAsync(ServerSettingKey key)
{
return await ctx.ServerSettings
.Where(x => x.Key == key)
.FirstAsync();
}

public async Task<IList<ServerSetting>> GetSettingsAsync()
{
return await ctx.ServerSettings.ToListAsync();
Expand Down
32 changes: 32 additions & 0 deletions API/Data/Seed.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System.Text.Json;
using API.DTOs;
using API.Entities;
using API.Entities.Enums;
using Serilog.Events;

namespace API.Data;

public static class Seed
{

private static readonly IList<ServerSetting> DefaultServerSettings = [
new() { Key = ServerSettingKey.CsvExportConfiguration, Value = JsonSerializer.Serialize(new CsvExportConfigurationDto()) },
new () { Key = ServerSettingKey.LogLevel, Value = nameof(LogEventLevel.Information) }
];

public static async Task Run(DataContext ctx)
{
foreach (var defaultServerSetting in DefaultServerSettings)
{
var existing = ctx.ServerSettings.FirstOrDefault(s => s.Key == defaultServerSetting.Key);
if (existing == null)
{
ctx.ServerSettings.Add(defaultServerSetting);
}
}


await ctx.SaveChangesAsync();
}

}
10 changes: 9 additions & 1 deletion API/Entities/Enums/ServerSettingKey.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
using System.ComponentModel;

namespace API.Entities.Enums;

public enum ServerSettingKey
{

/**
* Json object of type <see cref="DTOs.CsvExportConfigurationDto"/>
*/
[Description("Csv Export Configuration")]
CsvExportConfiguration = 0,
[Description("Log Level")]
LogLevel = 1,
}
2 changes: 1 addition & 1 deletion API/Entities/SystemMessage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ namespace API.Entities;

public class SystemMessage
{
public string Message;
public string Message { get; set; }
public DateTime CreatedUtc { get; set; }
}
7 changes: 7 additions & 0 deletions API/Extensions/ApplicationServiceExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
using System.Reflection;
using API.Data;
using API.Data.Repositories;
using API.DTOs.Enum;
using API.Helpers;
using API.Services;
using API.Services.Exporters;
using API.Services.Store;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.EntityFrameworkCore;
Expand Down Expand Up @@ -31,6 +33,11 @@ public static void AddApplicationServices(this IServiceCollection services, ICon
services.AddScoped<IUserService, UserService>();
services.AddScoped<IStockService, StockService>();
services.AddScoped<IOidcService, OidcService>();
services.AddScoped<ISettingsService, SettingsService>();

// Exporters
services.AddScoped<IExportService, ExportService>();
services.AddKeyedScoped<IExporter, CsvExporter>(nameof(ExportKind.Csv));

services.AddSignalR(opt => opt.EnableDetailedErrors = true);

Expand Down
32 changes: 32 additions & 0 deletions API/Extensions/DistributedCacheExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System.Text.Json;
using Microsoft.Extensions.Caching.Distributed;

namespace API.Extensions;

public static class DistributedCacheExtensions
{

public static Task SetAsJsonAsync<T>(
this IDistributedCache cache,
string key,
T value,
DistributedCacheEntryOptions options,
CancellationToken token = default (CancellationToken)
)
{
var bytes = JsonSerializer.SerializeToUtf8Bytes(value);
return cache.SetAsync(key, bytes, options, token);
}

public static async Task<T?> GetAsJsonAsync<T>(
this IDistributedCache cache,
string key,
CancellationToken token = default(CancellationToken))
{
var bytes = await cache.GetAsync(key, token);
if (bytes == null) return default;

return JsonSerializer.Deserialize<T>(bytes);
}

}
2 changes: 1 addition & 1 deletion API/Helpers/Telemetry/TelemetryHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ static TelemetryHelper()
Meter = new Meter(serviceName);

MethodTiming = Meter.CreateHistogram<double>(
"method_timing_duration_ms",
"method_timing_duration",
"ms",
"Duration of specific method, see method tag"
);
Expand Down
Loading