mirror of
https://github.com/meysamhadeli/booking-microservices.git
synced 2026-04-15 05:25:36 +08:00
add passenger integration tests
This commit is contained in:
parent
0573d68f32
commit
7b1e1f0e43
@ -7,126 +7,126 @@
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Ardalis.GuardClauses" Version="3.3.0"/>
|
||||
<PackageReference Include="AspNetCore.HealthChecks.UI.SQLite.Storage" Version="5.0.1"/>
|
||||
<PackageReference Include="Ben.BlockingDetector" Version="0.0.4"/>
|
||||
<PackageReference Include="EasyCaching.Core" Version="1.4.1"/>
|
||||
<PackageReference Include="EasyCaching.InMemory" Version="1.4.1"/>
|
||||
<PackageReference Include="EFCore.NamingConventions" Version="6.0.0"/>
|
||||
<PackageReference Include="EntityFrameworkCore.Triggered" Version="3.0.0"/>
|
||||
<PackageReference Include="Figgle" Version="0.4.0"/>
|
||||
<PackageReference Include="FluentValidation" Version="10.3.6"/>
|
||||
<PackageReference Include="FluentValidation.AspNetCore" Version="10.3.6"/>
|
||||
<PackageReference Include="Grpc.Net.Client" Version="2.44.0"/>
|
||||
<PackageReference Include="MagicOnion" Version="4.4.0"/>
|
||||
<PackageReference Include="MagicOnion.Abstractions" Version="4.4.0"/>
|
||||
<PackageReference Include="MagicOnion.Client" Version="4.4.0"/>
|
||||
<PackageReference Include="MagicOnion.Server" Version="4.4.0"/>
|
||||
<PackageReference Include="MagicOnion.Server" Version="4.4.0"/>
|
||||
<PackageReference Include="NSubstitute" Version="4.3.0"/>
|
||||
<PackageReference Include="Polly" Version="7.2.3"/>
|
||||
<PackageReference Include="Ardalis.GuardClauses" Version="3.3.0" />
|
||||
<PackageReference Include="AspNetCore.HealthChecks.UI.SQLite.Storage" Version="5.0.1" />
|
||||
<PackageReference Include="Ben.BlockingDetector" Version="0.0.4" />
|
||||
<PackageReference Include="EasyCaching.Core" Version="1.4.1" />
|
||||
<PackageReference Include="EasyCaching.InMemory" Version="1.4.1" />
|
||||
<PackageReference Include="EFCore.NamingConventions" Version="6.0.0" />
|
||||
<PackageReference Include="EntityFrameworkCore.Triggered" Version="3.0.0" />
|
||||
<PackageReference Include="Figgle" Version="0.4.0" />
|
||||
<PackageReference Include="FluentValidation" Version="10.3.6" />
|
||||
<PackageReference Include="FluentValidation.AspNetCore" Version="10.3.6" />
|
||||
<PackageReference Include="Grpc.Net.Client" Version="2.44.0" />
|
||||
<PackageReference Include="MagicOnion" Version="4.4.0" />
|
||||
<PackageReference Include="MagicOnion.Abstractions" Version="4.4.0" />
|
||||
<PackageReference Include="MagicOnion.Client" Version="4.4.0" />
|
||||
<PackageReference Include="MagicOnion.Server" Version="4.4.0" />
|
||||
<PackageReference Include="MagicOnion.Server" Version="4.4.0" />
|
||||
<PackageReference Include="NSubstitute" Version="4.3.0" />
|
||||
<PackageReference Include="Polly" Version="7.2.3" />
|
||||
<PackageReference Include="protobuf-net.BuildTools" Version="3.0.115">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="protobuf-net.Grpc" Version="1.0.152"/>
|
||||
<PackageReference Include="Hellang.Middleware.ProblemDetails" Version="6.3.0"/>
|
||||
<PackageReference Include="Humanizer.Core" Version="2.14.1"/>
|
||||
<PackageReference Include="IdGen" Version="3.0.0"/>
|
||||
<PackageReference Include="Mapster" Version="7.3.0"/>
|
||||
<PackageReference Include="Mapster.DependencyInjection" Version="1.0.0"/>
|
||||
<PackageReference Include="MediatR" Version="9.0.0"/>
|
||||
<PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="9.0.0"/>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.0"/>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.2.2"/>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer" Version="5.0.0"/>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.1"/>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="6.0.1"/>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.1"/>
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0"/>
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="6.0.0"/>
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0"/>
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.0"/>
|
||||
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="6.0.1"/>
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.0"/>
|
||||
<PackageReference Include="Microsoft.Extensions.PlatformAbstractions" Version="1.1.0"/>
|
||||
<PackageReference Include="MongoDB.Driver" Version="2.14.1"/>
|
||||
<PackageReference Include="Moq" Version="4.16.1"/>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1"/>
|
||||
<PackageReference Include="OpenTelemetry.Contrib.Instrumentation.MassTransit" Version="1.0.0-beta2"/>
|
||||
<PackageReference Include="protobuf-net.Grpc.AspNetCore" Version="1.0.152"/>
|
||||
<PackageReference Include="Scrutor" Version="3.3.0"/>
|
||||
<PackageReference Include="Scrutor.AspNetCore" Version="3.3.0"/>
|
||||
<PackageReference Include="Serilog" Version="2.10.0"/>
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="4.1.0"/>
|
||||
<PackageReference Include="Serilog.Enrichers.Span" Version="2.2.0"/>
|
||||
<PackageReference Include="Serilog.Exceptions" Version="8.1.0"/>
|
||||
<PackageReference Include="Serilog.Formatting.Elasticsearch" Version="8.4.1"/>
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1"/>
|
||||
<PackageReference Include="Serilog.Sinks.Elasticsearch" Version="8.4.1"/>
|
||||
<PackageReference Include="Serilog.Sinks.Seq" Version="5.1.0"/>
|
||||
<PackageReference Include="Serilog.Sinks.SpectreConsole" Version="0.1.1"/>
|
||||
<PackageReference Include="Serilog.Sinks.XUnit" Version="3.0.3"/>
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="6.2.3"/>
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.2.3"/>
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="6.2.3"/>
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3"/>
|
||||
<PackageReference Include="AspNetCore.HealthChecks.UI" Version="5.0.1"/>
|
||||
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="5.0.1"/>
|
||||
<PackageReference Include="AspNetCore.HealthChecks.UI.InMemory.Storage" Version="5.0.1"/>
|
||||
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="6.0.1"/>
|
||||
<PackageReference Include="AspNetCore.HealthChecks.MongoDb" Version="6.0.1"/>
|
||||
<PackageReference Include="System.Interactive.Async" Version="5.1.0"/>
|
||||
<PackageReference Include="MassTransit" Version="8.0.0"/>
|
||||
<PackageReference Include="MassTransit.RabbitMQ" Version="8.0.0"/>
|
||||
<PackageReference Include="DotNetCore.CAP" Version="6.0.0"/>
|
||||
<PackageReference Include="DotNetCore.CAP.Dashboard" Version="6.0.0"/>
|
||||
<PackageReference Include="DotNetCore.CAP.MongoDB" Version="6.0.0"/>
|
||||
<PackageReference Include="DotNetCore.CAP.OpenTelemetry" Version="6.0.0"/>
|
||||
<PackageReference Include="DotNetCore.CAP.RabbitMQ" Version="6.0.0"/>
|
||||
<PackageReference Include="DotNetCore.CAP.SqlServer" Version="6.0.0"/>
|
||||
<PackageReference Include="Duende.IdentityServer" Version="6.0.0"/>
|
||||
<PackageReference Include="Duende.IdentityServer.AspNetIdentity" Version="6.0.0"/>
|
||||
<PackageReference Include="Duende.IdentityServer.EntityFramework" Version="6.0.0"/>
|
||||
<PackageReference Include="Duende.IdentityServer.EntityFramework.Storage" Version="6.0.3"/>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.1"/>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="6.0.0"/>
|
||||
<PackageReference Include="Yarp.ReverseProxy" Version="1.0.0"/>
|
||||
<PackageReference Include="Microsoft.Identity.Web" Version="1.22.3"/>
|
||||
<PackageReference Include="protobuf-net.Grpc" Version="1.0.152" />
|
||||
<PackageReference Include="Hellang.Middleware.ProblemDetails" Version="6.3.0" />
|
||||
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
|
||||
<PackageReference Include="IdGen" Version="3.0.0" />
|
||||
<PackageReference Include="Mapster" Version="7.3.0" />
|
||||
<PackageReference Include="Mapster.DependencyInjection" Version="1.0.0" />
|
||||
<PackageReference Include="MediatR" Version="9.0.0" />
|
||||
<PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.2.2" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="6.0.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="6.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.PlatformAbstractions" Version="1.1.0" />
|
||||
<PackageReference Include="MongoDB.Driver" Version="2.14.1" />
|
||||
<PackageReference Include="Moq" Version="4.16.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="OpenTelemetry.Contrib.Instrumentation.MassTransit" Version="1.0.0-beta2" />
|
||||
<PackageReference Include="protobuf-net.Grpc.AspNetCore" Version="1.0.152" />
|
||||
<PackageReference Include="Scrutor" Version="3.3.0" />
|
||||
<PackageReference Include="Scrutor.AspNetCore" Version="3.3.0" />
|
||||
<PackageReference Include="Serilog" Version="2.10.0" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="4.1.0" />
|
||||
<PackageReference Include="Serilog.Enrichers.Span" Version="2.2.0" />
|
||||
<PackageReference Include="Serilog.Exceptions" Version="8.1.0" />
|
||||
<PackageReference Include="Serilog.Formatting.Elasticsearch" Version="8.4.1" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1" />
|
||||
<PackageReference Include="Serilog.Sinks.Elasticsearch" Version="8.4.1" />
|
||||
<PackageReference Include="Serilog.Sinks.Seq" Version="5.1.0" />
|
||||
<PackageReference Include="Serilog.Sinks.SpectreConsole" Version="0.1.1" />
|
||||
<PackageReference Include="Serilog.Sinks.XUnit" Version="3.0.3" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="6.2.3" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.2.3" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="6.2.3" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
|
||||
<PackageReference Include="AspNetCore.HealthChecks.UI" Version="5.0.1" />
|
||||
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="5.0.1" />
|
||||
<PackageReference Include="AspNetCore.HealthChecks.UI.InMemory.Storage" Version="5.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="6.0.1" />
|
||||
<PackageReference Include="AspNetCore.HealthChecks.MongoDb" Version="6.0.1" />
|
||||
<PackageReference Include="System.Interactive.Async" Version="5.1.0" />
|
||||
<PackageReference Include="MassTransit" Version="8.0.0" />
|
||||
<PackageReference Include="MassTransit.RabbitMQ" Version="8.0.0" />
|
||||
<PackageReference Include="DotNetCore.CAP" Version="6.0.0" />
|
||||
<PackageReference Include="DotNetCore.CAP.Dashboard" Version="6.0.0" />
|
||||
<PackageReference Include="DotNetCore.CAP.MongoDB" Version="6.0.0" />
|
||||
<PackageReference Include="DotNetCore.CAP.OpenTelemetry" Version="6.0.0" />
|
||||
<PackageReference Include="DotNetCore.CAP.RabbitMQ" Version="6.0.0" />
|
||||
<PackageReference Include="DotNetCore.CAP.SqlServer" Version="6.0.0" />
|
||||
<PackageReference Include="Duende.IdentityServer" Version="6.0.0" />
|
||||
<PackageReference Include="Duende.IdentityServer.AspNetIdentity" Version="6.0.0" />
|
||||
<PackageReference Include="Duende.IdentityServer.EntityFramework" Version="6.0.0" />
|
||||
<PackageReference Include="Duende.IdentityServer.EntityFramework.Storage" Version="6.0.3" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="6.0.0" />
|
||||
<PackageReference Include="Yarp.ReverseProxy" Version="1.0.0" />
|
||||
<PackageReference Include="Microsoft.Identity.Web" Version="1.22.3" />
|
||||
|
||||
<PackageReference Include="Jaeger" Version="0.3.7"/>
|
||||
<PackageReference Include="OpenTracing" Version="0.12.1"/>
|
||||
<PackageReference Include="prometheus-net" Version="6.0.0"/>
|
||||
<PackageReference Include="prometheus-net.AspNetCore" Version="6.0.0"/>
|
||||
<PackageReference Include="Jaeger" Version="0.3.7" />
|
||||
<PackageReference Include="OpenTracing" Version="0.12.1" />
|
||||
<PackageReference Include="prometheus-net" Version="6.0.0" />
|
||||
<PackageReference Include="prometheus-net.AspNetCore" Version="6.0.0" />
|
||||
|
||||
<PackageReference Include="OpenTelemetry" Version="1.2.0-rc3"/>
|
||||
<PackageReference Include="OpenTelemetry.Exporter.Jaeger" Version="1.2.0-rc3"/>
|
||||
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.0.0-rc9"/>
|
||||
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.0.0-rc9"/>
|
||||
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.0.0-rc9"/>
|
||||
<PackageReference Include="OpenTelemetry" Version="1.2.0-rc3" />
|
||||
<PackageReference Include="OpenTelemetry.Exporter.Jaeger" Version="1.2.0-rc3" />
|
||||
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.0.0-rc9" />
|
||||
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.0.0-rc9" />
|
||||
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.0.0-rc9" />
|
||||
|
||||
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.0.64">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
|
||||
<PackageReference Include="EventStore.Client.Grpc.Streams" Version="22.0.0"/>
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.1"/>
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="6.0.3"/>
|
||||
<PackageReference Include="EventStore.Client.Grpc.Streams" Version="22.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.1" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="6.0.3" />
|
||||
|
||||
<PackageReference Include="Nito.AsyncEx" Version="5.1.2"/>
|
||||
<PackageReference Include="AutoBogus" Version="2.13.1"/>
|
||||
<PackageReference Include="Bogus" Version="34.0.1"/>
|
||||
<PackageReference Include="FluentAssertions" Version="6.2.0"/>
|
||||
<PackageReference Include="MediatR" Version="9.0.0"/>
|
||||
<PackageReference Include="Respawn" Version="4.0.0"/>
|
||||
<PackageReference Include="Nito.AsyncEx" Version="5.1.2" />
|
||||
<PackageReference Include="AutoBogus" Version="2.13.1" />
|
||||
<PackageReference Include="Bogus" Version="34.0.1" />
|
||||
<PackageReference Include="FluentAssertions" Version="6.2.0" />
|
||||
<PackageReference Include="MediatR" Version="9.0.0" />
|
||||
<PackageReference Include="Respawn" Version="4.0.0" />
|
||||
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Contracts"/>
|
||||
<Folder Include="EventStoreDB\BackgroundWorkers"/>
|
||||
<Folder Include="Contracts" />
|
||||
<Folder Include="EventStoreDB\BackgroundWorkers" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@ -2,9 +2,8 @@ namespace BuildingBlocks.Exception;
|
||||
|
||||
public class AggregateNotFoundException : System.Exception
|
||||
{
|
||||
public AggregateNotFoundException(string typeName, long id): base($"{typeName} with id '{id}' was not found")
|
||||
public AggregateNotFoundException(string typeName, long id) : base($"{typeName} with id '{id}' was not found")
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public static AggregateNotFoundException For<T>(long id)
|
||||
|
||||
@ -5,26 +5,19 @@ namespace BuildingBlocks.Exception;
|
||||
|
||||
public class AppException : CustomException
|
||||
{
|
||||
public AppException(string message, string code = default!) : base(message)
|
||||
public AppException(string message, string code = null) : base(message, code: code)
|
||||
{
|
||||
Code = code;
|
||||
}
|
||||
|
||||
public AppException() : base()
|
||||
{
|
||||
}
|
||||
|
||||
public AppException(string message) : base(message)
|
||||
public AppException(string message, HttpStatusCode statusCode, string code = null) : base(message, statusCode, code)
|
||||
{
|
||||
}
|
||||
|
||||
public AppException(string message, HttpStatusCode statusCode) : base(message, statusCode)
|
||||
public AppException(string message, System.Exception innerException, string code = null) : base(message, innerException, code: code)
|
||||
{
|
||||
}
|
||||
|
||||
public AppException(string message, System.Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
|
||||
public string Code { get; }
|
||||
}
|
||||
|
||||
@ -4,9 +4,9 @@ namespace BuildingBlocks.Exception
|
||||
{
|
||||
public class BadRequestException : CustomException
|
||||
{
|
||||
public BadRequestException(string message) : base(message)
|
||||
public BadRequestException(string message, string code = null) : base(message, code: code)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,10 +2,8 @@ namespace BuildingBlocks.Exception
|
||||
{
|
||||
public class ConflictException : CustomException
|
||||
{
|
||||
public virtual string Code { get; }
|
||||
public ConflictException(string message, string code = default!) : base(message)
|
||||
public ConflictException(string message, string code = null) : base(message, code: code)
|
||||
{
|
||||
Code = code;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,28 +2,36 @@ using System.Net;
|
||||
|
||||
namespace BuildingBlocks.Exception;
|
||||
|
||||
public class CustomException: System.Exception
|
||||
public class CustomException : System.Exception
|
||||
{
|
||||
public CustomException(
|
||||
string message,
|
||||
HttpStatusCode statusCode = HttpStatusCode.BadRequest) : base(message)
|
||||
HttpStatusCode statusCode = HttpStatusCode.BadRequest,
|
||||
string code = null) : base(message)
|
||||
{
|
||||
StatusCode = statusCode;
|
||||
Code = code;
|
||||
}
|
||||
|
||||
public CustomException(
|
||||
string message,
|
||||
System.Exception innerException,
|
||||
HttpStatusCode statusCode = HttpStatusCode.BadRequest) : base(message, innerException)
|
||||
HttpStatusCode statusCode = HttpStatusCode.BadRequest,
|
||||
string code = null) : base(message, innerException)
|
||||
{
|
||||
StatusCode = statusCode;
|
||||
Code = code;
|
||||
}
|
||||
|
||||
public CustomException(
|
||||
HttpStatusCode statusCode = HttpStatusCode.BadRequest) : base()
|
||||
HttpStatusCode statusCode = HttpStatusCode.BadRequest,
|
||||
string code = null) : base()
|
||||
{
|
||||
StatusCode = statusCode;
|
||||
Code = code;
|
||||
}
|
||||
|
||||
public HttpStatusCode StatusCode { get; }
|
||||
|
||||
public string Code { get; }
|
||||
}
|
||||
|
||||
@ -6,13 +6,6 @@ namespace BuildingBlocks.Exception;
|
||||
|
||||
public class GrpcExceptionInterceptor : Interceptor
|
||||
{
|
||||
private readonly ILogger<GrpcExceptionInterceptor> _logger;
|
||||
|
||||
public GrpcExceptionInterceptor(ILogger<GrpcExceptionInterceptor> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public override async Task<TResponse> UnaryServerHandler<TRequest, TResponse>(
|
||||
TRequest request,
|
||||
ServerCallContext context,
|
||||
|
||||
@ -2,10 +2,10 @@ using System.Net;
|
||||
|
||||
namespace BuildingBlocks.Exception;
|
||||
|
||||
public class IdentityException: CustomException
|
||||
public class IdentityException : CustomException
|
||||
{
|
||||
public IdentityException(string message = default, HttpStatusCode statusCode = default)
|
||||
: base(message, statusCode)
|
||||
public IdentityException(string message = default, HttpStatusCode statusCode = default, string code = null)
|
||||
: base(message, statusCode, code)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Net;
|
||||
|
||||
namespace BuildingBlocks.Exception
|
||||
{
|
||||
@ -7,11 +8,11 @@ namespace BuildingBlocks.Exception
|
||||
{
|
||||
public InternalServerException() : base() { }
|
||||
|
||||
public InternalServerException(string message) : base(message) { }
|
||||
public InternalServerException(string message, string code) : base(message, HttpStatusCode.InternalServerError, code: code) { }
|
||||
|
||||
public InternalServerException(string message, params object[] args)
|
||||
: base(String.Format(CultureInfo.CurrentCulture, message, args))
|
||||
public InternalServerException(string message, string code = null, params object[] args)
|
||||
: base(message:String.Format(CultureInfo.CurrentCulture, message, args, HttpStatusCode.InternalServerError, code))
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,8 +2,8 @@ namespace BuildingBlocks.Exception
|
||||
{
|
||||
public class NotFoundException : CustomException
|
||||
{
|
||||
public NotFoundException(string message) : base(message)
|
||||
public NotFoundException(string message, string code = null) : base(message, code: code)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
8
src/BuildingBlocks/Exception/ProblemDetailsWithCode.cs
Normal file
8
src/BuildingBlocks/Exception/ProblemDetailsWithCode.cs
Normal file
@ -0,0 +1,8 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace BuildingBlocks.Exception;
|
||||
|
||||
public class ProblemDetailsWithCode : ProblemDetails
|
||||
{
|
||||
public string Code { get; set; }
|
||||
}
|
||||
@ -8,6 +8,7 @@ namespace BuildingBlocks.Exception
|
||||
{
|
||||
ValidationResultModel = validationResultModel;
|
||||
}
|
||||
|
||||
public ValidationResultModel ValidationResultModel { get; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -22,60 +22,66 @@ public static class ProblemDetailsExtensions
|
||||
var env = ctx.RequestServices.GetRequiredService<IHostEnvironment>();
|
||||
return env.IsDevelopment() || env.IsStaging();
|
||||
};
|
||||
x.Map<ConflictException>(ex => new ProblemDetails
|
||||
x.Map<ConflictException>(ex => new ProblemDetailsWithCode
|
||||
{
|
||||
Title = "Application rule broken",
|
||||
Status = StatusCodes.Status409Conflict,
|
||||
Detail = ex.Message,
|
||||
Type = "https://somedomain/application-rule-validation-error"
|
||||
Type = "https://somedomain/application-rule-validation-error",
|
||||
Code = ex.Code
|
||||
});
|
||||
|
||||
// Exception will produce and returns from our FluentValidation RequestValidationBehavior
|
||||
x.Map<ValidationException>(ex => new ProblemDetails
|
||||
x.Map<ValidationException>(ex => new ProblemDetailsWithCode
|
||||
{
|
||||
Title = "input validation rules broken",
|
||||
Status = StatusCodes.Status400BadRequest,
|
||||
Detail = JsonConvert.SerializeObject(ex.ValidationResultModel.Errors),
|
||||
Type = "https://somedomain/input-validation-rules-error"
|
||||
Type = "https://somedomain/input-validation-rules-error",
|
||||
Code = ex.Code
|
||||
});
|
||||
x.Map<BadRequestException>(ex => new ProblemDetails
|
||||
x.Map<BadRequestException>(ex => new ProblemDetailsWithCode
|
||||
{
|
||||
Title = "bad request exception",
|
||||
Status = StatusCodes.Status400BadRequest,
|
||||
Detail = ex.Message,
|
||||
Type = "https://somedomain/bad-request-error"
|
||||
Type = "https://somedomain/bad-request-error",
|
||||
Code = ex.Code
|
||||
});
|
||||
x.Map<NotFoundException>(ex => new ProblemDetails
|
||||
x.Map<NotFoundException>(ex => new ProblemDetailsWithCode
|
||||
{
|
||||
Title = "not found exception",
|
||||
Status = StatusCodes.Status404NotFound,
|
||||
Detail = ex.Message,
|
||||
Type = "https://somedomain/not-found-error"
|
||||
Type = "https://somedomain/not-found-error",
|
||||
Code = ex.Code
|
||||
});
|
||||
x.Map<InternalServerException>(ex => new ProblemDetails
|
||||
x.Map<InternalServerException>(ex => new ProblemDetailsWithCode
|
||||
{
|
||||
Title = "api server exception",
|
||||
Status = StatusCodes.Status500InternalServerError,
|
||||
Detail = ex.Message,
|
||||
Type = "https://somedomain/api-server-error"
|
||||
Type = "https://somedomain/api-server-error",
|
||||
Code = ex.Code
|
||||
});
|
||||
x.Map<AppException>(ex => new ProblemDetails
|
||||
x.Map<AppException>(ex => new ProblemDetailsWithCode
|
||||
{
|
||||
Title = "application exception",
|
||||
Status = StatusCodes.Status500InternalServerError,
|
||||
Detail = ex.Message,
|
||||
Type = "https://somedomain/application-error"
|
||||
Type = "https://somedomain/application-error",
|
||||
Code = ex.Code
|
||||
});
|
||||
x.Map<IdentityException>(ex =>
|
||||
{
|
||||
var pd = new ProblemDetails
|
||||
var pd = new ProblemDetailsWithCode
|
||||
{
|
||||
Status = (int)ex.StatusCode,
|
||||
Title = "identity exception",
|
||||
Detail = ex.Message,
|
||||
Type = "https://somedomain/identity-error"
|
||||
Type = "https://somedomain/identity-error",
|
||||
Code = ex.Code
|
||||
};
|
||||
|
||||
return pd;
|
||||
});
|
||||
x.MapToStatusCode<ArgumentNullException>(StatusCodes.Status400BadRequest);
|
||||
|
||||
@ -0,0 +1,14 @@
|
||||
using Flight.Flights.Features.CreateFlight;
|
||||
|
||||
namespace Integration.Test.Fakes;
|
||||
|
||||
public static class FakeFlightCreated
|
||||
{
|
||||
public static global::Flight.Flights.Models.Flight Generate(CreateFlightCommand command)
|
||||
{
|
||||
return global::Flight.Flights.Models.Flight.Create(command.Id, command.FlightNumber,
|
||||
command.AircraftId, command.DepartureAirportId, command.DepartureDate,
|
||||
command.ArriveDate, command.ArriveAirportId, command.DurationMinutes,
|
||||
command.FlightDate, command.Status, command.Price);
|
||||
}
|
||||
}
|
||||
@ -24,13 +24,8 @@ public class GetAvailableFlightsTests
|
||||
var flightCommand1 = new FakeCreateFlightCommand().Generate();
|
||||
var flightCommand2 = new FakeCreateFlightCommand().Generate();
|
||||
|
||||
var flightEntity1 = global::Flight.Flights.Models.Flight.Create(
|
||||
flightCommand1.Id, flightCommand1.FlightNumber, flightCommand1.AircraftId, flightCommand1.DepartureAirportId, flightCommand1.DepartureDate,
|
||||
flightCommand1.ArriveDate, flightCommand1.ArriveAirportId, flightCommand1.DurationMinutes, flightCommand1.FlightDate, flightCommand1.Status, flightCommand1.Price);
|
||||
|
||||
var flightEntity2 = global::Flight.Flights.Models.Flight.Create(
|
||||
flightCommand2.Id, flightCommand2.FlightNumber, flightCommand2.AircraftId, flightCommand2.DepartureAirportId, flightCommand2.DepartureDate,
|
||||
flightCommand2.ArriveDate, flightCommand2.ArriveAirportId, flightCommand2.DurationMinutes, flightCommand2.FlightDate, flightCommand2.Status, flightCommand2.Price);
|
||||
var flightEntity1 = FakeFlightCreated.Generate(flightCommand1);
|
||||
var flightEntity2 = FakeFlightCreated.Generate(flightCommand2);
|
||||
|
||||
await _fixture.InsertAsync(flightEntity1, flightEntity2);
|
||||
|
||||
|
||||
@ -21,9 +21,7 @@ public class GetFlightByIdTests
|
||||
{
|
||||
// Arrange
|
||||
var command = new FakeCreateFlightCommand().Generate();
|
||||
var flightEntity = global::Flight.Flights.Models.Flight.Create(
|
||||
command.Id, command.FlightNumber, command.AircraftId, command.DepartureAirportId, command.DepartureDate,
|
||||
command.ArriveDate, command.ArriveAirportId, command.DurationMinutes, command.FlightDate, command.Status, command.Price);
|
||||
var flightEntity = FakeFlightCreated.Generate(command);
|
||||
await _fixture.InsertAsync(flightEntity);
|
||||
|
||||
var query = new GetFlightByIdQuery(flightEntity.Id);
|
||||
|
||||
@ -25,10 +25,7 @@ public class UpdateFlightTests
|
||||
{
|
||||
// Arrange
|
||||
var fakeCreateCommandFlight = new FakeCreateFlightCommand().Generate();
|
||||
var flightEntity = global::Flight.Flights.Models.Flight.Create(fakeCreateCommandFlight.Id, fakeCreateCommandFlight.FlightNumber,
|
||||
fakeCreateCommandFlight.AircraftId, fakeCreateCommandFlight.DepartureAirportId, fakeCreateCommandFlight.DepartureDate,
|
||||
fakeCreateCommandFlight.ArriveDate, fakeCreateCommandFlight.ArriveAirportId, fakeCreateCommandFlight.DurationMinutes,
|
||||
fakeCreateCommandFlight.FlightDate, fakeCreateCommandFlight.Status, fakeCreateCommandFlight.Price);
|
||||
var flightEntity = FakeFlightCreated.Generate(fakeCreateCommandFlight);
|
||||
await _fixture.InsertAsync(flightEntity);
|
||||
|
||||
var command = new FakeUpdateFlightCommand(flightEntity.Id).Generate();
|
||||
|
||||
@ -6,10 +6,10 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0"/>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.4"/>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0"/>
|
||||
<PackageReference Include="xunit" Version="2.4.1"/>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.4" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
|
||||
@ -1,98 +0,0 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Passenger.Data;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Passenger.Data.Migrations
|
||||
{
|
||||
[DbContext(typeof(PassengerDbContext))]
|
||||
[Migration("20220309230648_initial")]
|
||||
partial class initial
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "6.0.1")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder, 1L, 1);
|
||||
|
||||
modelBuilder.Entity("BuildingBlocks.Outbox.OutboxMessage", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<Guid?>("CorrelationId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<string>("Data")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("EventType")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.IsUnicode(false)
|
||||
.HasColumnType("varchar(50)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<DateTime>("OccurredOn")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<DateTime?>("ProcessedOn")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Type")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("OutboxMessages", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Passenger.Passenger.Models.Passenger", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<int>("Age")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<DateTime>("LastModified")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int?>("ModifiedBy")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<int>("PassengerType")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("PassportNumber")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Passenger", "dbo");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,85 +0,0 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Passenger.Data.Migrations
|
||||
{
|
||||
public partial class Audit : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.RenameColumn(
|
||||
name: "ModifiedBy",
|
||||
schema: "dbo",
|
||||
table: "Passenger",
|
||||
newName: "LastModifiedBy");
|
||||
|
||||
migrationBuilder.AlterColumn<DateTime>(
|
||||
name: "LastModified",
|
||||
schema: "dbo",
|
||||
table: "Passenger",
|
||||
type: "datetime2",
|
||||
nullable: true,
|
||||
oldClrType: typeof(DateTime),
|
||||
oldType: "datetime2");
|
||||
|
||||
migrationBuilder.AddColumn<DateTime>(
|
||||
name: "CreatedAt",
|
||||
schema: "dbo",
|
||||
table: "Passenger",
|
||||
type: "datetime2",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "CreatedBy",
|
||||
schema: "dbo",
|
||||
table: "Passenger",
|
||||
type: "int",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<long>(
|
||||
name: "Version",
|
||||
schema: "dbo",
|
||||
table: "Passenger",
|
||||
type: "bigint",
|
||||
nullable: false,
|
||||
defaultValue: 0L);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "CreatedAt",
|
||||
schema: "dbo",
|
||||
table: "Passenger");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "CreatedBy",
|
||||
schema: "dbo",
|
||||
table: "Passenger");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Version",
|
||||
schema: "dbo",
|
||||
table: "Passenger");
|
||||
|
||||
migrationBuilder.RenameColumn(
|
||||
name: "LastModifiedBy",
|
||||
schema: "dbo",
|
||||
table: "Passenger",
|
||||
newName: "ModifiedBy");
|
||||
|
||||
migrationBuilder.AlterColumn<DateTime>(
|
||||
name: "LastModified",
|
||||
schema: "dbo",
|
||||
table: "Passenger",
|
||||
type: "datetime2",
|
||||
nullable: false,
|
||||
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
|
||||
oldClrType: typeof(DateTime),
|
||||
oldType: "datetime2",
|
||||
oldNullable: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,139 +0,0 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Passenger.Data;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Passenger.Data.Migrations
|
||||
{
|
||||
[DbContext(typeof(PassengerDbContext))]
|
||||
[Migration("20220422175724_Update-EventId")]
|
||||
partial class UpdateEventId
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "6.0.1")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder, 1L, 1);
|
||||
|
||||
modelBuilder.Entity("BuildingBlocks.InternalProcessor.InternalMessage", b =>
|
||||
{
|
||||
b.Property<Guid>("EventId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<string>("CommandType")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<Guid?>("CorrelationId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<string>("Data")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<DateTime>("OccurredOn")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<DateTime?>("ProcessedOn")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.HasKey("EventId");
|
||||
|
||||
b.ToTable("InternalMessages", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BuildingBlocks.Outbox.OutboxMessage", b =>
|
||||
{
|
||||
b.Property<Guid>("EventId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<Guid?>("CorrelationId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<string>("Data")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("EventType")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.IsUnicode(false)
|
||||
.HasColumnType("varchar(50)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<DateTime>("OccurredOn")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<DateTime?>("ProcessedOn")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Type")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.HasKey("EventId");
|
||||
|
||||
b.ToTable("OutboxMessages", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Passenger.Passengers.Models.Passenger", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<int>("Age")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<DateTime?>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<long?>("CreatedBy")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<DateTime?>("LastModified")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<long?>("LastModifiedBy")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<int>("PassengerType")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("PassportNumber")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<long>("Version")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Passenger", "dbo");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,86 +0,0 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Passenger.Data.Migrations
|
||||
{
|
||||
public partial class UpdateEventId : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.RenameColumn(
|
||||
name: "Id",
|
||||
table: "OutboxMessages",
|
||||
newName: "EventId");
|
||||
|
||||
migrationBuilder.AlterColumn<long>(
|
||||
name: "LastModifiedBy",
|
||||
schema: "dbo",
|
||||
table: "Passenger",
|
||||
type: "bigint",
|
||||
nullable: true,
|
||||
oldClrType: typeof(int),
|
||||
oldType: "int",
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AlterColumn<long>(
|
||||
name: "CreatedBy",
|
||||
schema: "dbo",
|
||||
table: "Passenger",
|
||||
type: "bigint",
|
||||
nullable: true,
|
||||
oldClrType: typeof(int),
|
||||
oldType: "int",
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "InternalMessages",
|
||||
columns: table => new
|
||||
{
|
||||
EventId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
Name = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
||||
OccurredOn = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
CommandType = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
||||
Data = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
||||
ProcessedOn = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
CorrelationId = table.Column<Guid>(type: "uniqueidentifier", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_InternalMessages", x => x.EventId);
|
||||
});
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "InternalMessages");
|
||||
|
||||
migrationBuilder.RenameColumn(
|
||||
name: "EventId",
|
||||
table: "OutboxMessages",
|
||||
newName: "Id");
|
||||
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "LastModifiedBy",
|
||||
schema: "dbo",
|
||||
table: "Passenger",
|
||||
type: "int",
|
||||
nullable: true,
|
||||
oldClrType: typeof(long),
|
||||
oldType: "bigint",
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "CreatedBy",
|
||||
schema: "dbo",
|
||||
table: "Passenger",
|
||||
type: "int",
|
||||
nullable: true,
|
||||
oldClrType: typeof(long),
|
||||
oldType: "bigint",
|
||||
oldNullable: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -12,8 +12,8 @@ using Passenger.Data;
|
||||
namespace Passenger.Data.Migrations
|
||||
{
|
||||
[DbContext(typeof(PassengerDbContext))]
|
||||
[Migration("20220416172933_Audit")]
|
||||
partial class Audit
|
||||
[Migration("20220523195643_initial")]
|
||||
partial class initial
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
@ -24,44 +24,6 @@ namespace Passenger.Data.Migrations
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder, 1L, 1);
|
||||
|
||||
modelBuilder.Entity("BuildingBlocks.Outbox.OutboxMessage", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<Guid?>("CorrelationId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<string>("Data")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("EventType")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.IsUnicode(false)
|
||||
.HasColumnType("varchar(50)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<DateTime>("OccurredOn")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<DateTime?>("ProcessedOn")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Type")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("OutboxMessages", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Passenger.Passengers.Models.Passenger", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
@ -73,8 +35,8 @@ namespace Passenger.Data.Migrations
|
||||
b.Property<DateTime?>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int?>("CreatedBy")
|
||||
.HasColumnType("int");
|
||||
b.Property<long?>("CreatedBy")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.HasColumnType("bit");
|
||||
@ -82,8 +44,8 @@ namespace Passenger.Data.Migrations
|
||||
b.Property<DateTime?>("LastModified")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int?>("LastModifiedBy")
|
||||
.HasColumnType("int");
|
||||
b.Property<long?>("LastModifiedBy")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
@ -12,24 +12,6 @@ namespace Passenger.Data.Migrations
|
||||
migrationBuilder.EnsureSchema(
|
||||
name: "dbo");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "OutboxMessages",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
Name = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
||||
OccurredOn = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
Type = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
||||
Data = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
||||
ProcessedOn = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
EventType = table.Column<string>(type: "varchar(50)", unicode: false, maxLength: 50, nullable: false),
|
||||
CorrelationId = table.Column<Guid>(type: "uniqueidentifier", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_OutboxMessages", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Passenger",
|
||||
schema: "dbo",
|
||||
@ -40,9 +22,12 @@ namespace Passenger.Data.Migrations
|
||||
Name = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
PassengerType = table.Column<int>(type: "int", nullable: false),
|
||||
Age = table.Column<int>(type: "int", nullable: false),
|
||||
LastModified = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
CreatedAt = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
CreatedBy = table.Column<long>(type: "bigint", nullable: true),
|
||||
LastModified = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
LastModifiedBy = table.Column<long>(type: "bigint", nullable: true),
|
||||
IsDeleted = table.Column<bool>(type: "bit", nullable: false),
|
||||
ModifiedBy = table.Column<int>(type: "int", nullable: true)
|
||||
Version = table.Column<long>(type: "bigint", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
@ -52,9 +37,6 @@ namespace Passenger.Data.Migrations
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "OutboxMessages");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "Passenger",
|
||||
schema: "dbo");
|
||||
@ -22,76 +22,6 @@ namespace Passenger.Data.Migrations
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder, 1L, 1);
|
||||
|
||||
modelBuilder.Entity("BuildingBlocks.InternalProcessor.InternalMessage", b =>
|
||||
{
|
||||
b.Property<Guid>("EventId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<string>("CommandType")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<Guid?>("CorrelationId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<string>("Data")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<DateTime>("OccurredOn")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<DateTime?>("ProcessedOn")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.HasKey("EventId");
|
||||
|
||||
b.ToTable("InternalMessages", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BuildingBlocks.Outbox.OutboxMessage", b =>
|
||||
{
|
||||
b.Property<Guid>("EventId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<Guid?>("CorrelationId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<string>("Data")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("EventType")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.IsUnicode(false)
|
||||
.HasColumnType("varchar(50)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<DateTime>("OccurredOn")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<DateTime?>("ProcessedOn")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Type")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.HasKey("EventId");
|
||||
|
||||
b.ToTable("OutboxMessages", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Passenger.Passengers.Models.Passenger", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
|
||||
@ -19,7 +19,7 @@ public class RegisterNewUserConsumerHandler : IConsumer<UserCreated>
|
||||
{
|
||||
Guard.Against.Null(context.Message, nameof(UserCreated));
|
||||
|
||||
var passenger = Passengers.Models.Passenger.Create(context.Message.Id, context.Message.Name, context.Message.PassportNumber);
|
||||
var passenger = Passengers.Models.Passenger.Create(SnowFlakIdGenerator.NewId(), context.Message.Name, context.Message.PassportNumber);
|
||||
|
||||
await _passengerDbContext.AddAsync(passenger);
|
||||
|
||||
|
||||
@ -13,12 +13,12 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Data\Migrations"/>
|
||||
<Folder Include="Extensions"/>
|
||||
<Folder Include="Data\Migrations" />
|
||||
<Folder Include="Extensions" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\..\BuildingBlocks\BuildingBlocks.csproj"/>
|
||||
<ProjectReference Include="..\..\..\..\BuildingBlocks\BuildingBlocks.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@ -1,8 +1,11 @@
|
||||
using BuildingBlocks.IdsGenerator;
|
||||
using MediatR;
|
||||
using Passenger.Passengers.Dtos;
|
||||
using Passenger.Passengers.Models;
|
||||
|
||||
namespace Passenger.Passengers.Features.CompleteRegisterPassenger;
|
||||
|
||||
public record CompleteRegisterPassengerCommand
|
||||
(string PassportNumber, PassengerType PassengerType, int Age) : IRequest<PassengerResponseDto>;
|
||||
public record CompleteRegisterPassengerCommand(string PassportNumber, PassengerType PassengerType, int Age) : IRequest<PassengerResponseDto>
|
||||
{
|
||||
public long Id { get; set; } = SnowFlakIdGenerator.NewId();
|
||||
}
|
||||
|
||||
@ -24,8 +24,7 @@ public class CompleteRegisterPassengerCommandHandler : IRequestHandler<CompleteR
|
||||
Guard.Against.Null(command, nameof(command));
|
||||
|
||||
var passenger = await _passengerDbContext.Passengers.AsNoTracking().SingleOrDefaultAsync(
|
||||
x => x.PassportNumber == command.PassportNumber,
|
||||
cancellationToken);
|
||||
x => x.PassportNumber == command.PassportNumber, cancellationToken);
|
||||
|
||||
if (passenger is null)
|
||||
throw new PassengerNotExist();
|
||||
|
||||
@ -0,0 +1,18 @@
|
||||
using AutoBogus;
|
||||
using BuildingBlocks.IdsGenerator;
|
||||
using Passenger.Passengers.Features.CompleteRegisterPassenger;
|
||||
using Passenger.Passengers.Models;
|
||||
|
||||
namespace Integration.Test.Fakes;
|
||||
|
||||
public sealed class FakeCompleteRegisterPassengerCommand : AutoFaker<CompleteRegisterPassengerCommand>
|
||||
{
|
||||
public FakeCompleteRegisterPassengerCommand(string passportNumber)
|
||||
{
|
||||
RuleFor(r => r.Id, _ => SnowFlakIdGenerator.NewId());
|
||||
RuleFor(r => r.PassportNumber, _ => passportNumber);
|
||||
RuleFor(r => r.PassengerType, _ => PassengerType.Male);
|
||||
RuleFor(r => r.Age, _ => 30);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,12 @@
|
||||
using BuildingBlocks.Contracts.EventBus.Messages;
|
||||
using BuildingBlocks.IdsGenerator;
|
||||
|
||||
namespace Integration.Test.Fakes;
|
||||
|
||||
public static class FakePassengerCreated
|
||||
{
|
||||
public static global::Passenger.Passengers.Models.Passenger Generate(UserCreated userCreated)
|
||||
{
|
||||
return global::Passenger.Passengers.Models.Passenger.Create(SnowFlakIdGenerator.NewId(), userCreated.Name, userCreated.PassportNumber);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
using AutoBogus;
|
||||
using BuildingBlocks.Contracts.EventBus.Messages;
|
||||
using BuildingBlocks.IdsGenerator;
|
||||
|
||||
namespace Integration.Test.Fakes;
|
||||
|
||||
public class FakeUserCreated : AutoFaker<UserCreated>
|
||||
{
|
||||
public FakeUserCreated()
|
||||
{
|
||||
RuleFor(r => r.Id, _ => SnowFlakIdGenerator.NewId());
|
||||
RuleFor(r => r.Name, _ => "Meysam");
|
||||
RuleFor(r => r.PassportNumber, _ => "1299878");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
using System.Threading.Tasks;
|
||||
using BuildingBlocks.Contracts.EventBus.Messages;
|
||||
using Integration.Test.Fakes;
|
||||
using MassTransit.Testing;
|
||||
using Xunit;
|
||||
|
||||
namespace Integration.Test.Identity.Features;
|
||||
|
||||
[Collection(nameof(TestFixture))]
|
||||
public class RegisterNewUserConsumerTests
|
||||
{
|
||||
private readonly TestFixture _fixture;
|
||||
private readonly ITestHarness _testHarness;
|
||||
|
||||
public RegisterNewUserConsumerTests(TestFixture fixture)
|
||||
{
|
||||
_fixture = fixture;
|
||||
_testHarness = _fixture.TestHarness;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task should_register_new_user_consume_handler_consume_user_created_message()
|
||||
{
|
||||
// // Arrange
|
||||
var message = new FakeUserCreated().Generate();
|
||||
|
||||
// // Act
|
||||
await _testHarness.Bus.Publish(message);
|
||||
|
||||
// // Assert
|
||||
await _testHarness.Consumed.Any<UserCreated>();
|
||||
}
|
||||
}
|
||||
@ -8,10 +8,10 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0"/>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.4"/>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0"/>
|
||||
<PackageReference Include="xunit" Version="2.4.1"/>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.4" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
@ -26,9 +26,4 @@
|
||||
<ProjectReference Include="..\..\src\Passenger.Api\Passenger.Api.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Fakes" />
|
||||
<Folder Include="Passenger\Features" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@ -0,0 +1,45 @@
|
||||
using System.Threading.Tasks;
|
||||
using BuildingBlocks.Contracts.EventBus.Messages;
|
||||
using BuildingBlocks.IdsGenerator;
|
||||
using FluentAssertions;
|
||||
using Integration.Test.Fakes;
|
||||
using MassTransit;
|
||||
using MassTransit.Testing;
|
||||
using Xunit;
|
||||
|
||||
namespace Integration.Test.Passenger.Features;
|
||||
|
||||
[Collection(nameof(TestFixture))]
|
||||
public class CompleteRegisterPassengerTests
|
||||
{
|
||||
private readonly TestFixture _fixture;
|
||||
private readonly ITestHarness _testHarness;
|
||||
|
||||
public CompleteRegisterPassengerTests(TestFixture fixture)
|
||||
{
|
||||
_fixture = fixture;
|
||||
_testHarness = _fixture.TestHarness;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task should_complete_register_passenger_and_update_to_db()
|
||||
{
|
||||
// Arrange
|
||||
var userCreated = new FakeUserCreated().Generate();
|
||||
await _testHarness.Bus.Publish(userCreated);
|
||||
await _testHarness.Consumed.Any<UserCreated>();
|
||||
await _fixture.InsertAsync(FakePassengerCreated.Generate(userCreated));
|
||||
|
||||
var command = new FakeCompleteRegisterPassengerCommand(userCreated.PassportNumber).Generate();
|
||||
|
||||
// Act
|
||||
var response = await _fixture.SendAsync(command);
|
||||
|
||||
// Assert
|
||||
response.Should().NotBeNull();
|
||||
response?.Name.Should().Be(userCreated.Name);
|
||||
response?.PassportNumber.Should().Be(command.PassportNumber);
|
||||
response?.PassengerType.Should().Be(command.PassengerType);
|
||||
response?.Age.Should().Be(command.Age);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
using System.Threading.Tasks;
|
||||
using BuildingBlocks.Contracts.EventBus.Messages;
|
||||
using FluentAssertions;
|
||||
using Integration.Test.Fakes;
|
||||
using MassTransit.Testing;
|
||||
using Passenger.Passengers.Features.GetPassengerById;
|
||||
using Xunit;
|
||||
|
||||
namespace Integration.Test.Passenger.Features;
|
||||
|
||||
[Collection(nameof(TestFixture))]
|
||||
public class GetPassengerByIdTests
|
||||
{
|
||||
private readonly TestFixture _fixture;
|
||||
private readonly ITestHarness _testHarness;
|
||||
|
||||
public GetPassengerByIdTests(TestFixture fixture)
|
||||
{
|
||||
_fixture = fixture;
|
||||
_testHarness = _fixture.TestHarness;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task should_retrive_a_passenger_by_id_currectly()
|
||||
{
|
||||
// Arrange
|
||||
var userCreated = new FakeUserCreated().Generate();
|
||||
await _testHarness.Bus.Publish(userCreated);
|
||||
await _testHarness.Consumed.Any<UserCreated>();
|
||||
var passengerEntity = FakePassengerCreated.Generate(userCreated);
|
||||
await _fixture.InsertAsync(passengerEntity);
|
||||
|
||||
var query = new GetPassengerQueryById(passengerEntity.Id);
|
||||
|
||||
// Act
|
||||
var response = await _fixture.SendAsync(query);
|
||||
|
||||
// Assert
|
||||
response.Should().NotBeNull();
|
||||
response?.Id.Should().Be(passengerEntity.Id);
|
||||
}
|
||||
}
|
||||
@ -1,12 +0,0 @@
|
||||
using Xunit;
|
||||
|
||||
namespace Integration.Test;
|
||||
|
||||
public class UnitTest1
|
||||
{
|
||||
[Fact]
|
||||
public void Test1()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user