Skip to content

Commit

Permalink
Merge branch 'main' into support-http-etags-and-if-none-match-header
Browse files Browse the repository at this point in the history
  • Loading branch information
MH321Productions authored Feb 27, 2025
2 parents 436b57e + f8dd7e9 commit 7046d5b
Show file tree
Hide file tree
Showing 34 changed files with 460 additions and 206 deletions.
2 changes: 2 additions & 0 deletions .ci/compose.test.postgres.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ services:
command: psql -h postgres -U postgres -d enmeshed -f /app/sql-scripts/setup.sql

admin-cli:
volumes:
- ./appsettings.override.postgres.docker.json:/app/appsettings.override.json
environment:
Database__Provider: Postgres
Database__ConnectionString: "Server=postgres;Database=enmeshed;User Id=devices;Password=Passw0rd;Port=5432"
Expand Down
2 changes: 2 additions & 0 deletions .ci/compose.test.sqlserver.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ services:
command: bash -c " sleep 20 && /opt/mssql-tools/bin/sqlcmd -S sqlserver -U SA -P Passw0rd -i /app/sql-scripts/setup.sql"

admin-cli:
volumes:
- ./appsettings.override.sqlserver.docker.json:/app/appsettings.override.json
environment:
Database__Provider: SqlServer
Database__ConnectionString: "Server=sqlserver;Database=enmeshed;User Id=devices;Password=Passw0rd;TrustServerCertificate=True"
Expand Down
4 changes: 2 additions & 2 deletions .run/Admin API.run.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Admin API" type="LaunchSettings" factoryName=".NET Launch Settings Profile">
<option name="LAUNCH_PROFILE_PROJECT_FILE_PATH" value="$PROJECT_DIR$/Applications/AdminApi/src/AdminApi/AdminApi.csproj"/>
<option name="LAUNCH_PROFILE_TFM" value="net8.0" />
<option name="LAUNCH_PROFILE_PROJECT_FILE_PATH" value="$PROJECT_DIR$/Applications/AdminApi/src/AdminApi/AdminApi.csproj" />
<option name="LAUNCH_PROFILE_TFM" value="net9.0" />
<option name="LAUNCH_PROFILE_NAME" value="Default" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="USE_MONO" value="0" />
Expand Down
4 changes: 2 additions & 2 deletions .run/Consumer API.run.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Consumer API" type="LaunchSettings" factoryName=".NET Launch Settings Profile">
<option name="LAUNCH_PROFILE_PROJECT_FILE_PATH" value="$PROJECT_DIR$/Applications/ConsumerApi/src/ConsumerApi.csproj"/>
<option name="LAUNCH_PROFILE_TFM" value="net8.0" />
<option name="LAUNCH_PROFILE_PROJECT_FILE_PATH" value="$PROJECT_DIR$/Applications/ConsumerApi/src/ConsumerApi.csproj" />
<option name="LAUNCH_PROFILE_TFM" value="net9.0" />
<option name="LAUNCH_PROFILE_NAME" value="Default" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="USE_MONO" value="0" />
Expand Down
2 changes: 1 addition & 1 deletion Applications/AdminApi/src/AdminApi/AdminApi.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OData" Version="9.2.0" />
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="10.0.0" />
<PackageReference Include="OpenIddict.EntityFrameworkCore" Version="6.1.0" />
<PackageReference Include="OpenIddict.EntityFrameworkCore" Version="6.1.1" />
<PackageReference Include="FluentValidation.AspNetCore" Version="11.3.0" />
<PackageReference Include="NetEscapades.AspNetCore.SecurityHeaders" Version="0.24.0" />
<PackageReference Include="ReHackt.Extensions.Options.Validation" Version="9.0.2" />
Expand Down
19 changes: 19 additions & 0 deletions Applications/AdminCli/src/AdminCli/AdminCli.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,30 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="10.0.0" />
<PackageReference Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\..\Infrastructure\Infrastructure.csproj" />
<ProjectReference Include="..\..\..\..\Modules\Announcements\src\Announcements.Application\Announcements.Application.csproj" />
<ProjectReference Include="..\..\..\..\Modules\Announcements\src\Announcements.Infrastructure\Announcements.Infrastructure.csproj" />
<ProjectReference Include="..\..\..\..\Modules\Devices\src\Devices.Infrastructure\Devices.Infrastructure.csproj" />
</ItemGroup>

<Target Name="PreBuild" BeforeTargets="BeforeBuild" Condition="$(Configuration) == Debug">
<Delete Files="$(ProjectDir)appsettings.override.json" />
<Copy SourceFiles="..\..\..\..\appsettings.override.json" DestinationFolder="$(ProjectDir)" UseHardlinksIfPossible="true" />
</Target>

<ItemGroup>
<Content Include="appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>

<Content Include="appsettings.override.json" Condition="$(Configuration) == Debug">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System.CommandLine;

namespace Backbone.AdminCli.Commands.Announcements;

public class AnnouncementCommand : Command
{
public AnnouncementCommand(SendAnnouncementCommand sendAnnouncementCommand) : base("announcement")
{
AddCommand(sendAnnouncementCommand);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
using System.CommandLine;
using System.Text.Json;
using Backbone.AdminCli.Commands.BaseClasses;
using Backbone.Modules.Announcements.Application.Announcements.Commands.CreateAnnouncement;
using Backbone.Modules.Announcements.Domain.Entities;
using MediatR;

namespace Backbone.AdminCli.Commands.Announcements;

public class SendAnnouncementCommand : AdminCliCommand
{
public SendAnnouncementCommand(IMediator mediator) : base(mediator, "send")
{
var expiresAt = new Option<string?>("--expiration")
{
IsRequired = false,
Description = "The expiration date of the announcement."
};

var severity = new Option<string?>("--severity")
{
IsRequired = true,
Description = "The severity of the announcement. Possible values: Low, Medium, High"
};

AddOption(expiresAt);
AddOption(severity);

this.SetHandler(SendAnnouncement, severity, expiresAt);
}

private async Task SendAnnouncement(string? severityInput, string? expiresAtInput)
{
try
{
var severity = severityInput switch
{
_ when Enum.TryParse<AnnouncementSeverity>(severityInput, ignoreCase: true, out var parsedSeverity) => parsedSeverity,
_ => throw new ArgumentException($@"Specified severity '{severityInput}' is not a valid severity.")
};

DateTime? expiresAt = expiresAtInput switch
{
_ when string.IsNullOrWhiteSpace(expiresAtInput) => null,
_ when DateTime.TryParse(expiresAtInput, out var parsedDateTime) => parsedDateTime,
_ => throw new ArgumentException($@"Specified expiration datetime '{expiresAtInput}' is not a valid DateTime.")
};

var texts = ReadTextsFromCommandLineInput();

if (texts.Count == 0)
{
Console.WriteLine(@"No texts provided. Exiting...");
return;
}

Console.WriteLine(@"You entered the following texts:");
Console.WriteLine(JsonSerializer.Serialize(texts, JSON_SERIALIZER_OPTIONS));
if (!PromptForConfirmation(@"Do you want to proceed?")) return;

Console.WriteLine(@"Sending announcement...");

try
{
var response = await _mediator.Send(new CreateAnnouncementCommand
{
Texts = texts,
Severity = severity,
ExpiresAt = expiresAt
}, CancellationToken.None);

Console.WriteLine(@"Announcement sent successfully");
Console.WriteLine(JsonSerializer.Serialize(response, JSON_SERIALIZER_OPTIONS));
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
catch (Exception e)
{
Console.WriteLine($@"An error occurred: {e.Message}");
}
}

private static List<CreateAnnouncementCommandText> ReadTextsFromCommandLineInput()
{
var texts = new List<CreateAnnouncementCommandText>();

var englishTitle = PromptForInput(@"Enter english title: ");
var englishBody = PromptForInput(@"Enter english body: ");

if (englishTitle == null || englishBody == null) return texts;

texts.Add(new CreateAnnouncementCommandText
{
Language = "en",
Title = englishTitle,
Body = englishBody
});

while (PromptForConfirmation(@"Do you want to add another language?"))
{
var language = PromptForInput(@"Enter a two-letter language code (e.g. de, it, nl): ");
var title = PromptForInput(@"Enter title: ");
var body = PromptForInput(@"Enter body: ");

if (language == null || title == null || body == null)
{
break;
}

texts.Add(new CreateAnnouncementCommandText
{
Language = language,
Title = title,
Body = body
});
}

return texts;
}

private static string? PromptForInput(string prompt, bool allowEmpty = false)
{
Console.Write(prompt);
var input = Console.ReadLine();

while (!allowEmpty && string.IsNullOrWhiteSpace(input))
{
Console.WriteLine(@"Input cannot be empty. Press x to exit.");
Console.Write(prompt);
input = Console.ReadLine();

if (string.IsNullOrWhiteSpace(input))
continue;
if (input.Trim().Equals("x", StringComparison.CurrentCultureIgnoreCase))
return null;

break;
}

return input;
}

private static bool PromptForConfirmation(string prompt)
{
var input = PromptForInput($"{prompt} ([y]es/[N]o): ", true);
return input?.Trim().ToLower() is "yes" or "y";
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
using System.CommandLine;
using System.Text.Json;
using MediatR;

namespace Backbone.AdminCli.Commands.BaseClasses;

public abstract class AdminCliCommand : Command
{
protected readonly IMediator _mediator;

protected static readonly JsonSerializerOptions JSON_SERIALIZER_OPTIONS =
new() { WriteIndented = true, PropertyNamingPolicy = JsonNamingPolicy.CamelCase };

protected readonly ServiceLocator _serviceLocator;

protected AdminCliCommand(string name, ServiceLocator serviceLocator, string? description = null) : base(name, description)
protected AdminCliCommand(IMediator mediator, string name, string? description = null) : base(name, description)
{
_serviceLocator = serviceLocator;
_mediator = mediator;
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
using Backbone.AdminCli.Commands.BaseClasses;
using System.CommandLine;

namespace Backbone.AdminCli.Commands.Clients;

public class ClientCommand : AdminCliCommand
public class ClientCommand : Command
{
public ClientCommand(ServiceLocator serviceLocator) : base("client", serviceLocator)
public ClientCommand(CreateClientCommand createClientCommand, ListClientsCommand listClientsCommand, DeleteClientsCommand deleteClientsCommand) : base("client")
{
AddCommand(new CreateClientCommand(serviceLocator));
AddCommand(new ListClientsCommand(serviceLocator));
AddCommand(new DeleteClientsCommand(serviceLocator));
AddCommand(createClientCommand);
AddCommand(listClientsCommand);
AddCommand(deleteClientsCommand);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@

namespace Backbone.AdminCli.Commands.Clients;

public class CreateClientCommand : AdminCliDbCommand
public class CreateClientCommand : AdminCliCommand
{
public CreateClientCommand(ServiceLocator serviceLocator) : base("create", serviceLocator, "Create an OAuth client")
public CreateClientCommand(IMediator mediator) : base(mediator, "create", "Create an OAuth client")
{
var clientId = new Option<string>("--clientId")
{
Expand Down Expand Up @@ -44,16 +44,13 @@ public CreateClientCommand(ServiceLocator serviceLocator) : base("create", servi
AddOption(defaultTierId);
AddOption(maxIdentities);

this.SetHandler(CreateClient, DB_PROVIDER_OPTION, DB_CONNECTION_STRING_OPTION, clientId, displayName, clientSecret,
defaultTierId, maxIdentities);
this.SetHandler(CreateClient, clientId, displayName, clientSecret, defaultTierId, maxIdentities);
}

private async Task CreateClient(string dbProvider, string dbConnectionString, string? clientId,
private async Task CreateClient(string? clientId,
string? displayName, string? clientSecret, string defaultTier, int? maxIdentities)
{
var mediator = _serviceLocator.GetService<IMediator>(dbProvider, dbConnectionString);

var response = await mediator.Send(new Modules.Devices.Application.Clients.Commands.CreateClient.CreateClientCommand(clientId, displayName, clientSecret, defaultTier, maxIdentities),
var response = await _mediator.Send(new Modules.Devices.Application.Clients.Commands.CreateClient.CreateClientCommand(clientId, displayName, clientSecret, defaultTier, maxIdentities),
CancellationToken.None);

Console.WriteLine(JsonSerializer.Serialize(response, JSON_SERIALIZER_OPTIONS));
Expand Down
Loading

0 comments on commit 7046d5b

Please sign in to comment.