зеркало из https://github.com/Azure/Sia-Gateway.git
Refactor/simplify gateway controllers (#58)
Restructuring to reduce responsibility of Controllers by delegating to more specific classes
This commit is contained in:
Родитель
d99a460f68
Коммит
064de55863
2
domain
2
domain
|
@ -1 +1 @@
|
|||
Subproject commit 1af7202242b329206cc58d2534687b12e7a94809
|
||||
Subproject commit e45d43973339e0208c429d9f40f676db656f514f
|
|
@ -23,20 +23,16 @@ namespace Sia.Gateway.Controllers
|
|||
public async Task<IActionResult> Get([FromRoute]long incidentId, [FromRoute]long id)
|
||||
{
|
||||
var result = await _mediator
|
||||
.Send(new GetEngagementRequest(incidentId, id, authContext))
|
||||
.Send(new GetEngagementRequest(incidentId, id, AuthContext))
|
||||
.ConfigureAwait(continueOnCapturedContext: false);
|
||||
if (result == null)
|
||||
{
|
||||
return NotFound(notFoundMessage);
|
||||
}
|
||||
return Ok(result);
|
||||
return OkIfFound(result);
|
||||
}
|
||||
|
||||
[HttpPost()]
|
||||
public async Task<IActionResult> Post([FromRoute]long incidentId, [FromBody]NewEngagement newEngagement)
|
||||
{
|
||||
var result = await _mediator
|
||||
.Send(new PostEngagementRequest(incidentId, newEngagement, authContext))
|
||||
.Send(new PostEngagementRequest(incidentId, newEngagement, AuthContext))
|
||||
.ConfigureAwait(continueOnCapturedContext: false);
|
||||
if (result == null)
|
||||
{
|
||||
|
@ -49,7 +45,7 @@ namespace Sia.Gateway.Controllers
|
|||
public async Task<IActionResult> Put([FromRoute]long incidentId, [FromRoute]long engagementId, [FromBody]UpdateEngagement updatedEngagement)
|
||||
{
|
||||
await _mediator
|
||||
.Send(new PutEngagementRequest(incidentId, engagementId, updatedEngagement, authContext))
|
||||
.Send(new PutEngagementRequest(incidentId, engagementId, updatedEngagement, AuthContext))
|
||||
.ConfigureAwait(continueOnCapturedContext: false);
|
||||
return Ok();
|
||||
}
|
||||
|
|
|
@ -13,134 +13,80 @@ using Sia.Core.Protocol;
|
|||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Sia.Gateway.Links;
|
||||
using Sia.Core.Validation;
|
||||
using Sia.Domain;
|
||||
|
||||
namespace Sia.Gateway.Controllers
|
||||
{
|
||||
public class EventsController : BaseController
|
||||
{
|
||||
private const string notFoundMessage = "Incident or event not found";
|
||||
private readonly HubConnectionBuilder _hubConnectionBuilder;
|
||||
private readonly ILogger<EventsController> _logger;
|
||||
public EventLinksProvider Links { get; }
|
||||
|
||||
public EventsController(IMediator mediator,
|
||||
AzureActiveDirectoryAuthenticationInfo authConfig,
|
||||
HubConnectionBuilder hubConnectionBuilder,
|
||||
IUrlHelper urlHelper,
|
||||
ILoggerFactory loggerFactory)
|
||||
EventLinksProvider links)
|
||||
: base(mediator, authConfig, urlHelper)
|
||||
{
|
||||
_hubConnectionBuilder = hubConnectionBuilder;
|
||||
_logger = loggerFactory.CreateLogger<EventsController>();
|
||||
Links = links;
|
||||
}
|
||||
|
||||
public LinksHeader CreateLinks(string id, string incidentId, EventFilters filter, PaginationMetadata pagination, string routeName)
|
||||
{
|
||||
var _operationLinks = new OperationLinks()
|
||||
{
|
||||
Single = new SingleOperationLinks()
|
||||
{
|
||||
Get = _urlHelper.Link(GetSingleRouteName, new { id }),
|
||||
Post = _urlHelper.Link(PostSingleRouteName, new { })
|
||||
|
||||
},
|
||||
Multiple = new MultipleOperationLinks()
|
||||
{
|
||||
Get = _urlHelper.Link(GetMultipleRouteName, new { })
|
||||
}
|
||||
};
|
||||
var _relationLinks = new RelationLinks()
|
||||
{
|
||||
Parent = new RelatedParentLinks()
|
||||
{
|
||||
Incident = _urlHelper.Link(IncidentsController.GetSingleRouteName, new { id = incidentId })
|
||||
}
|
||||
};
|
||||
return new LinksHeader(filter, pagination, _urlHelper, routeName, _operationLinks, _relationLinks);
|
||||
}
|
||||
|
||||
public const string GetMultipleRouteName = "GetEvents";
|
||||
[HttpGet("incidents/{incidentId}/events", Name = GetMultipleRouteName)]
|
||||
|
||||
[HttpGet("incidents/{incidentId}/events", Name = EventRoutesByIncident.GetMultiple)]
|
||||
public async Task<IActionResult> GetEvents([FromRoute]long incidentId,
|
||||
[FromQuery]PaginationMetadata pagination,
|
||||
[FromQuery]EventFilters filter)
|
||||
{
|
||||
var result = await _mediator
|
||||
.Send(new GetEventsRequest(incidentId, pagination, filter, authContext))
|
||||
.Send(new GetEventsRequest(incidentId, pagination, filter, AuthContext))
|
||||
.ConfigureAwait(continueOnCapturedContext: false);
|
||||
|
||||
Response.Headers.AddLinksHeader(CreateLinks(null, incidentId.ToPathTokenString(), filter, pagination, GetMultipleRouteName));
|
||||
var links = Links.CreatePaginatedLinks(EventRoutesByIncident.GetMultiple, pagination, filter, incidentId);
|
||||
|
||||
return Ok(result);
|
||||
return OkIfFound(result, links);
|
||||
}
|
||||
|
||||
public const string GetSingleRouteName = "GetEvent";
|
||||
[HttpGet("incidents/{incidentId}/events/{id}", Name = GetSingleRouteName)]
|
||||
public async Task<IActionResult> Get([FromRoute]long incidentId, [FromRoute]long id)
|
||||
[HttpGet("incidents/{incidentId}/events/{eventId}", Name = EventRoutesByIncident.GetSingle)]
|
||||
public async Task<IActionResult> Get([FromRoute]long incidentId, [FromRoute]long eventId)
|
||||
{
|
||||
var result = await _mediator
|
||||
.Send(new GetEventRequest(incidentId, id, authContext))
|
||||
.Send(new GetEventRequest(incidentId, eventId, AuthContext))
|
||||
.ConfigureAwait(continueOnCapturedContext: false);
|
||||
|
||||
Response.Headers.AddLinksHeader(CreateLinks(id.ToPathTokenString(), incidentId.ToPathTokenString(), null, null, GetSingleRouteName));
|
||||
if (result == null)
|
||||
{
|
||||
return NotFound(notFoundMessage);
|
||||
}
|
||||
var links = Links.CreateLinks(incidentId, eventId);
|
||||
|
||||
return Ok(result);
|
||||
return OkIfFound(result, links);
|
||||
}
|
||||
|
||||
public const string PostSingleRouteName = "PostEvent";
|
||||
[HttpPost("incidents/{incidentId}/events", Name = PostSingleRouteName)]
|
||||
[HttpPost("incidents/{incidentId}/events", Name = EventRoutesByIncident.PostSingle)]
|
||||
public async Task<IActionResult> Post([FromRoute]long incidentId, [FromBody]NewEvent newEvent)
|
||||
{
|
||||
var result = await _mediator
|
||||
.Send(new PostEventRequest(incidentId, newEvent, authContext))
|
||||
.Send(new PostEventRequest(incidentId, newEvent, AuthContext, new Lazy<string>(() => GetTokenFromHeaders()), Request.Host.Port))
|
||||
.ConfigureAwait(continueOnCapturedContext: false);
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
return NotFound(notFoundMessage);
|
||||
}
|
||||
ILinksHeader getLinks(Event res) =>
|
||||
Links.CreateLinks(incidentId, res.Id);
|
||||
|
||||
await SendEventToSubscribers(result).ConfigureAwait(continueOnCapturedContext: false);
|
||||
Uri getRetrievalRoute(Event res) =>
|
||||
new Uri(_urlHelper.Link(EventRoutesByIncident.GetSingle, new { incidentId, eventId = res.Id }));
|
||||
|
||||
var newUrl = new Uri(_urlHelper.Link(GetSingleRouteName, new { id = result.Id }));
|
||||
|
||||
Response.Headers.AddLinksHeader(CreateLinks(result.Id.ToPathTokenString(), incidentId.ToPathTokenString(), null, null, PostSingleRouteName));
|
||||
return Created(newUrl, result);
|
||||
return CreatedIfExists(result, getRetrievalRoute, getLinks);
|
||||
}
|
||||
|
||||
public const string GetMultipleUncorrelatedRouteName = "GetUncorrelatedEvent";
|
||||
[HttpGet("events", Name = GetMultipleUncorrelatedRouteName)]
|
||||
public async Task<IActionResult> GetUncorrelatedEvents([FromQuery]PaginationMetadata pagination,
|
||||
[FromQuery]EventFilters filter)
|
||||
[HttpGet("events", Name = EventRoutes.GetMultiple)]
|
||||
public async Task<IActionResult> GetUncorrelatedEvents(
|
||||
[FromQuery]PaginationMetadata pagination,
|
||||
[FromQuery]EventFilters filter
|
||||
)
|
||||
{
|
||||
var result = await _mediator
|
||||
.Send(new GetUncorrelatedEventsRequest(pagination, filter, authContext))
|
||||
.Send(new GetUncorrelatedEventsRequest(pagination, filter, AuthContext))
|
||||
.ConfigureAwait(continueOnCapturedContext: false);
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
var links = Links.CreatePaginatedLinks(EventRoutes.GetMultiple, pagination, filter);
|
||||
|
||||
private async Task SendEventToSubscribers(Domain.Event result)
|
||||
{
|
||||
var url = $"http://localhost:{Request.Host.Port}{EventsHub.HubPath}";
|
||||
try
|
||||
{
|
||||
string token = GetTokenFromHeaders();
|
||||
var eventHubConnection = _hubConnectionBuilder
|
||||
.WithAccessToken(() => token)
|
||||
.WithUrl(url)
|
||||
.Build();
|
||||
await eventHubConnection.StartAsync().ConfigureAwait(continueOnCapturedContext: false);
|
||||
await eventHubConnection.SendAsync("Send", result).ConfigureAwait(continueOnCapturedContext: false);
|
||||
await eventHubConnection.DisposeAsync().ConfigureAwait(continueOnCapturedContext: false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, $"Encountered exception when attempting to send posted event to SignalR subscribers, url: {url}");
|
||||
}
|
||||
return OkIfFound(result, links);
|
||||
}
|
||||
|
||||
private string GetTokenFromHeaders()
|
||||
|
|
|
@ -8,97 +8,64 @@ using Sia.Core.Controllers;
|
|||
using Sia.Core.Protocol;
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
using Sia.Core.Validation;
|
||||
using Sia.Gateway.Links;
|
||||
|
||||
namespace Sia.Gateway.Controllers
|
||||
{
|
||||
[Route("[controller]")]
|
||||
public class IncidentsController : BaseController
|
||||
{
|
||||
public IncidentsController(IMediator mediator, AzureActiveDirectoryAuthenticationInfo authConfig, IUrlHelper urlHelper)
|
||||
public IncidentsController(
|
||||
IMediator mediator,
|
||||
AzureActiveDirectoryAuthenticationInfo authConfig,
|
||||
IUrlHelper urlHelper,
|
||||
IncidentLinksProvider links)
|
||||
: base(mediator, authConfig, urlHelper)
|
||||
{
|
||||
Links = links;
|
||||
}
|
||||
|
||||
public LinksHeader CreateLinks(string id, PaginationMetadata pagination, string routeName)
|
||||
{
|
||||
var _operationLinks = new OperationLinks()
|
||||
{
|
||||
Single = new SingleOperationLinks()
|
||||
{
|
||||
Get = _urlHelper.Link(GetSingleRouteName, new { id }),
|
||||
Post = _urlHelper.Link(PostSingleRouteName, new { })
|
||||
},
|
||||
Multiple = new MultipleOperationLinks()
|
||||
{
|
||||
Get = _urlHelper.Link(GetMultipleRouteName, new { })
|
||||
}
|
||||
protected IncidentLinksProvider Links { get; }
|
||||
|
||||
};
|
||||
RelationLinks _relationLinks = null;
|
||||
if (id != null)
|
||||
{
|
||||
_relationLinks = new RelationLinks()
|
||||
{
|
||||
Children = new RelatedChildLinks()
|
||||
{
|
||||
Events = _urlHelper.Link(EventsController.GetMultipleRouteName, new { incidentId = id })
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return new LinksHeader(null, pagination, _urlHelper, routeName, _operationLinks, _relationLinks);
|
||||
}
|
||||
|
||||
public const string GetSingleRouteName = "GetIncident";
|
||||
[HttpGet("{id}", Name = GetSingleRouteName)]
|
||||
public async Task<IActionResult> Get(long id)
|
||||
[HttpGet("{incidentId}", Name = IncidentRoutes.GetSingle)]
|
||||
public async Task<IActionResult> Get(long incidentId)
|
||||
{
|
||||
var result = await _mediator
|
||||
.Send(new GetIncidentRequest(id, authContext))
|
||||
.Send(new GetIncidentRequest(incidentId, AuthContext))
|
||||
.ConfigureAwait(continueOnCapturedContext: false);
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
return NotFound($"{nameof(Incident)} not found");
|
||||
}
|
||||
Response.Headers.AddLinksHeader(CreateLinks(id.ToPathTokenString(), null, GetSingleRouteName));
|
||||
|
||||
return Ok(result);
|
||||
var links = Links.CreateLinks(incidentId);
|
||||
|
||||
return OkIfFound(result, links);
|
||||
}
|
||||
|
||||
public const string GetMultipleRouteName = "GetIncidents";
|
||||
[HttpGet(Name = GetMultipleRouteName)]
|
||||
[HttpGet(Name = IncidentRoutes.GetMultiple)]
|
||||
public async Task<IActionResult> Get([FromQuery] PaginationMetadata pagination)
|
||||
{
|
||||
var result = await _mediator
|
||||
.Send(new GetIncidentsRequest(pagination, authContext))
|
||||
.Send(new GetIncidentsRequest(pagination, AuthContext))
|
||||
.ConfigureAwait(continueOnCapturedContext: false);
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
return NotFound($"{nameof(Incident)}s not found");
|
||||
}
|
||||
Response.Headers.AddLinksHeader(CreateLinks(null, pagination, GetSingleRouteName));
|
||||
return Ok(result);
|
||||
var links = Links.CreatePaginatedLinks(IncidentRoutes.GetSingle, pagination);
|
||||
|
||||
return OkIfFound(result, links);
|
||||
}
|
||||
|
||||
public const string PostSingleRouteName = "PostIncident";
|
||||
[HttpPost(Name = PostSingleRouteName)]
|
||||
[HttpPost(Name = IncidentRoutes.PostSingle)]
|
||||
public async Task<IActionResult> Post([FromBody]NewIncident incident)
|
||||
{
|
||||
var result = await _mediator
|
||||
.Send(new PostIncidentRequest(incident, authContext))
|
||||
.Send(new PostIncidentRequest(incident, AuthContext))
|
||||
.ConfigureAwait(continueOnCapturedContext: false);
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
return NotFound($"{nameof(Incident)} not found");
|
||||
}
|
||||
var newUrl = new Uri(_urlHelper.Link(EventsController.GetMultipleRouteName, new { incidentId = result.Id }));
|
||||
Response.Headers.AddLinksHeader(CreateLinks(result.Id.ToPathTokenString(), null, PostSingleRouteName));
|
||||
return Created(newUrl, result);
|
||||
ILinksHeader getLinks(Incident res) =>
|
||||
Links.CreateLinks(res.Id);
|
||||
|
||||
Uri getRetrievalRoute(Incident res) =>
|
||||
new Uri(_urlHelper.Link(IncidentRoutes.GetSingle, new { incidentId = res.Id }));
|
||||
|
||||
return CreatedIfExists(result, getRetrievalRoute, getLinks);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,13 +23,13 @@ namespace Sia.Gateway.Controllers
|
|||
[HttpGet(Name = nameof(GetAll) + nameof(EventType))]
|
||||
public async Task<IActionResult> GetAll()
|
||||
=> OkIfFound(await _mediator
|
||||
.Send(new GetEventTypesRequest(authContext))
|
||||
.Send(new GetEventTypesRequest(AuthContext))
|
||||
.ConfigureAwait(continueOnCapturedContext: false));
|
||||
|
||||
[HttpGet("{id}", Name = nameof(Get) + nameof(EventType))]
|
||||
public async Task<IActionResult> Get(long id)
|
||||
=> OkIfFound(await _mediator
|
||||
.Send(new GetEventTypeRequest(id, authContext))
|
||||
.Send(new GetEventTypeRequest(id, AuthContext))
|
||||
.ConfigureAwait(continueOnCapturedContext: false));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ namespace Sia.Gateway.Controllers
|
|||
[HttpGet(Name = nameof(GetAll) + "Global" + nameof(Domain.Playbook.Action))]
|
||||
public async Task<IActionResult> GetAll()
|
||||
=> OkIfFound(await _mediator
|
||||
.Send(new GetGlobalActionsRequest(authContext))
|
||||
.Send(new GetGlobalActionsRequest(AuthContext))
|
||||
.ConfigureAwait(continueOnCapturedContext: false));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace Sia.Gateway.Controllers
|
|||
public async Task<IActionResult> Get(string id)
|
||||
{
|
||||
var result = await _mediator
|
||||
.Send(new GetIncidentsByTicketCreateIfNeededRequest(id, authContext))
|
||||
.Send(new GetIncidentsByTicketCreateIfNeededRequest(id, AuthContext))
|
||||
.ConfigureAwait(continueOnCapturedContext: false);
|
||||
return Ok(result);
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ using System.Reflection;
|
|||
using System.Runtime.Loader;
|
||||
using System.Threading.Tasks;
|
||||
using System.Globalization;
|
||||
using Sia.Gateway.Links;
|
||||
|
||||
namespace Sia.Gateway.Initialization
|
||||
{
|
||||
|
@ -46,7 +47,8 @@ namespace Sia.Gateway.Initialization
|
|||
.AddAuth(config)
|
||||
.AddDatabase(env, config)
|
||||
.AddTicketingConnector(env, rawConfig, config?.Connector?.Ticket)
|
||||
.AddMicroserviceProxies(config);
|
||||
.AddMicroserviceProxies(config)
|
||||
.AddRouteHelpers();
|
||||
|
||||
public static IServiceCollection AddAuth(this IServiceCollection services, GatewayConfiguration config)
|
||||
{
|
||||
|
@ -160,8 +162,11 @@ namespace Sia.Gateway.Initialization
|
|||
GetGlobalActionsShortCircuit.RegisterMe(services)));
|
||||
return services;
|
||||
}
|
||||
|
||||
|
||||
public static IServiceCollection AddRouteHelpers(this IServiceCollection services)
|
||||
=> services
|
||||
.AddScoped<IncidentLinksProvider>()
|
||||
.AddScoped<EventLinksProvider>();
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
using Microsoft.AspNetCore.Mvc;
|
||||
using Sia.Core.Protocol;
|
||||
using Sia.Core.Validation;
|
||||
using Sia.Gateway.Filters;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Sia.Gateway.Links
|
||||
{
|
||||
public static class EventRoutes
|
||||
{
|
||||
public const string GetMultiple = "GetUncorrelatedEvent";
|
||||
}
|
||||
|
||||
public static class EventRoutesByIncident
|
||||
{
|
||||
public const string GetMultiple = "GetEvents";
|
||||
public const string GetSingle = "GetEvent";
|
||||
public const string PostSingle = "PostEvent";
|
||||
}
|
||||
|
||||
public class EventLinksProvider : LinksProvider
|
||||
{
|
||||
public EventLinksProvider(IUrlHelper urlHelper)
|
||||
: base(urlHelper) { }
|
||||
|
||||
protected override OperationLinks GetOperationLinks(object routeValues)
|
||||
=> new OperationLinks()
|
||||
{
|
||||
Single = new SingleOperationLinks()
|
||||
{
|
||||
Get = UrlHelper.Link(EventRoutesByIncident.GetSingle, routeValues),
|
||||
Post = UrlHelper.Link(EventRoutesByIncident.PostSingle, routeValues)
|
||||
|
||||
},
|
||||
Multiple = new MultipleOperationLinks()
|
||||
{
|
||||
Get = UrlHelper.Link(EventRoutesByIncident.GetMultiple, routeValues)
|
||||
}
|
||||
};
|
||||
|
||||
public ILinksHeader CreatePaginatedLinks(string routeName, PaginationMetadata pagination, EventFilters filter, long incidentId = default(long))
|
||||
{
|
||||
ThrowIf.NullOrWhiteSpace(routeName, nameof(routeName));
|
||||
var routeValues = (incidentId == default(long))
|
||||
? (object)new { }
|
||||
: new { incidentId = incidentId.ToPathTokenString() };
|
||||
var route = UrlHelper.Link(routeName, routeValues);
|
||||
|
||||
var operationLinks = GetOperationLinks(routeValues);
|
||||
RelationLinks relationLinks = null;
|
||||
|
||||
return new PaginatedLinksHeader(route, operationLinks, relationLinks, pagination, filter);
|
||||
}
|
||||
|
||||
public ILinksHeader CreateLinks(long incidentId, long eventId)
|
||||
{
|
||||
var routeValues = new
|
||||
{
|
||||
incidentId = incidentId.ToPathTokenString(),
|
||||
eventId = eventId.ToPathTokenString()
|
||||
};
|
||||
|
||||
var operationLinks = GetOperationLinks(routeValues);
|
||||
var relationLinks = new RelationLinks()
|
||||
{
|
||||
Parent = new EventParentLinks()
|
||||
{
|
||||
Incident = UrlHelper.Link(IncidentRoutes.GetSingle, new { incidentId })
|
||||
}
|
||||
};
|
||||
|
||||
return new CrudLinksHeader(operationLinks, relationLinks);
|
||||
}
|
||||
}
|
||||
|
||||
public class EventParentLinks
|
||||
{
|
||||
public string Incident { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Routing;
|
||||
using Sia.Core.Protocol;
|
||||
using Sia.Core.Validation;
|
||||
|
||||
namespace Sia.Gateway.Links
|
||||
{
|
||||
public static class IncidentRoutes
|
||||
{
|
||||
public const string GetSingle = "GetIncident";
|
||||
public const string GetMultiple = "GetIncidents";
|
||||
public const string PostSingle = "PostIncident";
|
||||
}
|
||||
public class IncidentLinksProvider : LinksProvider
|
||||
{
|
||||
public IncidentLinksProvider(IUrlHelper urlHelper)
|
||||
: base(urlHelper) { }
|
||||
|
||||
protected override OperationLinks GetOperationLinks(object routeValues)
|
||||
=> new OperationLinks()
|
||||
{
|
||||
Single = new SingleOperationLinks()
|
||||
{
|
||||
Get = UrlHelper.Link(IncidentRoutes.GetSingle, routeValues),
|
||||
Post = UrlHelper.Link(IncidentRoutes.PostSingle, routeValues)
|
||||
},
|
||||
Multiple = new MultipleOperationLinks()
|
||||
{
|
||||
Get = UrlHelper.Link(IncidentRoutes.GetMultiple, routeValues)
|
||||
}
|
||||
};
|
||||
public ILinksHeader CreatePaginatedLinks(string routeName, PaginationMetadata pagination)
|
||||
{
|
||||
ThrowIf.NullOrWhiteSpace(routeName, nameof(routeName));
|
||||
var routeValues = new { };
|
||||
var route = UrlHelper.Link(routeName, routeValues);
|
||||
|
||||
var operationLinks = GetOperationLinks(routeValues);
|
||||
RelationLinks relationLinks = null;
|
||||
|
||||
return new PaginatedLinksHeader(route, operationLinks, relationLinks, pagination);
|
||||
}
|
||||
|
||||
public ILinksHeader CreateLinks(long incidentId)
|
||||
{
|
||||
var routeValues = new { incidentId = incidentId.ToPathTokenString() };
|
||||
var operationLinks = GetOperationLinks(routeValues);
|
||||
var relationLinks = new RelationLinks()
|
||||
{
|
||||
Children = new IncidentChildLinks()
|
||||
{
|
||||
Events = UrlHelper.Link(EventRoutesByIncident.GetMultiple, routeValues)
|
||||
}
|
||||
};
|
||||
|
||||
return new CrudLinksHeader(operationLinks, relationLinks);
|
||||
}
|
||||
}
|
||||
public class IncidentChildLinks
|
||||
{
|
||||
public string Events { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
using Microsoft.AspNetCore.Mvc;
|
||||
using Sia.Core.Protocol;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Sia.Gateway.Links
|
||||
{
|
||||
public abstract class LinksProvider
|
||||
{
|
||||
protected IUrlHelper UrlHelper { get; }
|
||||
protected LinksProvider(IUrlHelper urlHelper)
|
||||
{
|
||||
UrlHelper = urlHelper;
|
||||
}
|
||||
protected abstract OperationLinks GetOperationLinks(object routeValues);
|
||||
}
|
||||
}
|
|
@ -43,11 +43,13 @@ namespace Sia.Gateway.Requests.Events
|
|||
}
|
||||
public override async Task<IEnumerable<Event>> Handle(GetEventsRequest request, CancellationToken cancellationToken)
|
||||
=> await _context.Events
|
||||
.Where(ev => ev.IncidentId == request.IncidentId)
|
||||
.WithFilter(request.Filter)
|
||||
.WithPagination(request.Pagination)
|
||||
.ProjectTo<Event>()
|
||||
.ToListAsync(cancellationToken)
|
||||
.ConfigureAwait(continueOnCapturedContext: false);
|
||||
.Include(ev => ev.Incident)
|
||||
.ThenInclude(inc => inc.Tickets)
|
||||
.Where(ev => ev.IncidentId == request.IncidentId)
|
||||
.WithFilter(request.Filter)
|
||||
.WithPagination(request.Pagination)
|
||||
.ProjectTo<Event>()
|
||||
.ToListAsync(cancellationToken)
|
||||
.ConfigureAwait(continueOnCapturedContext: false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,27 +12,50 @@ using System.Collections.Generic;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Sia.Core.Validation;
|
||||
using Sia.Gateway.Hubs;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.AspNetCore.SignalR.Client;
|
||||
|
||||
namespace Sia.Gateway.Requests
|
||||
{
|
||||
public class PostEventRequest : AuthenticatedRequest<Event>
|
||||
{
|
||||
public PostEventRequest(long incidentId, NewEvent newEvent, AuthenticatedUserContext userContext)
|
||||
:base(userContext)
|
||||
public PostEventRequest(
|
||||
long incidentId,
|
||||
NewEvent newEvent,
|
||||
AuthenticatedUserContext userContext,
|
||||
Lazy<string> lazyToken,
|
||||
int? port
|
||||
) : base(userContext)
|
||||
{
|
||||
IncidentId = incidentId;
|
||||
NewEvent = ThrowIf.Null(newEvent, nameof(newEvent));
|
||||
LazyToken = ThrowIf.Null(lazyToken, nameof(lazyToken));
|
||||
Port = port;
|
||||
}
|
||||
public NewEvent NewEvent { get; }
|
||||
public long IncidentId { get; }
|
||||
public Lazy<string> LazyToken { get; }
|
||||
public int? Port { get; }
|
||||
}
|
||||
|
||||
public class HubConnectionInfo
|
||||
{
|
||||
public int Port { get; set; }
|
||||
}
|
||||
|
||||
public class PostEventHandler : IncidentContextHandler<PostEventRequest, Event>
|
||||
{
|
||||
public PostEventHandler(IncidentContext context)
|
||||
: base(context)
|
||||
private ILogger Logger { get; }
|
||||
private HubConnectionBuilder EventHubConnectionBuilder { get; }
|
||||
public PostEventHandler(
|
||||
IncidentContext context,
|
||||
HubConnectionBuilder hubConnectionBuilder,
|
||||
ILoggerFactory loggerFactory
|
||||
) : base(context)
|
||||
{
|
||||
|
||||
EventHubConnectionBuilder = hubConnectionBuilder;
|
||||
Logger = loggerFactory.CreateLogger<IncidentContextHandler<PostEventRequest, Event>>();
|
||||
}
|
||||
public override async Task<Event> Handle(PostEventRequest request, CancellationToken cancellationToken)
|
||||
{
|
||||
|
@ -48,7 +71,30 @@ namespace Sia.Gateway.Requests
|
|||
dataIncident.Events.Add(dataEvent);
|
||||
await _context.SaveChangesAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
|
||||
|
||||
return Mapper.Map<Event>(dataEvent);
|
||||
var result = Mapper.Map<Event>(dataEvent);
|
||||
|
||||
await SendEventToSubscribers(request, result, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task SendEventToSubscribers(PostEventRequest request, Event result, CancellationToken cancellationToken)
|
||||
{
|
||||
var url = $"http://localhost:{request.Port}{EventsHub.HubPath}";
|
||||
try
|
||||
{
|
||||
var eventHubConnection = EventHubConnectionBuilder
|
||||
.WithAccessToken(() => request.LazyToken.Value)
|
||||
.WithUrl(url)
|
||||
.Build();
|
||||
await eventHubConnection.StartAsync().ConfigureAwait(continueOnCapturedContext: false);
|
||||
await eventHubConnection.SendAsync("Send", result, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
|
||||
await eventHubConnection.DisposeAsync().ConfigureAwait(continueOnCapturedContext: false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex, $"Encountered exception when attempting to send posted event to SignalR subscribers, url: {url}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@ using Newtonsoft.Json;
|
|||
using Sia.Data.Incidents.Models;
|
||||
using Sia.Gateway.Filters;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
||||
namespace Sia.Gateway.Tests.Filters
|
||||
{
|
||||
|
|
|
@ -15,4 +15,4 @@
|
|||
"CA1707:Identifiers should not contain underscores",
|
||||
Justification = "Test methods are more readable with underscores",
|
||||
Scope = "module"
|
||||
)]
|
||||
)]
|
||||
|
|
|
@ -17,7 +17,7 @@ namespace Sia.Gateway.Tests.Requests
|
|||
=> AutoMapperStartup.InitializeAutomapper();
|
||||
|
||||
[TestMethod]
|
||||
public async Task HandleWhenEFReturnsSuccessfulReturnCorrectEngagement()
|
||||
public async Task Handle_WhenEFReturnsSuccessful_ReturnCorrectEngagement()
|
||||
{
|
||||
var expectedEngagement = new Engagement
|
||||
{
|
||||
|
@ -35,7 +35,7 @@ namespace Sia.Gateway.Tests.Requests
|
|||
|
||||
var serviceUnderTest = new GetEngagementHandler(
|
||||
await MockFactory
|
||||
.IncidentContext(nameof(HandleWhenEFReturnsSuccessfulReturnCorrectEngagement))
|
||||
.IncidentContext(nameof(Handle_WhenEFReturnsSuccessful_ReturnCorrectEngagement))
|
||||
.ConfigureAwait(continueOnCapturedContext: false)
|
||||
);
|
||||
var request = new GetEngagementRequest(1, 1, new DummyAuthenticatedUserContext());
|
||||
|
|
|
@ -5,6 +5,7 @@ using Sia.Gateway.Controllers;
|
|||
using Sia.Gateway.Tests.TestDoubles;
|
||||
using Sia.Core.Protocol;
|
||||
using System.Collections.Generic;
|
||||
using Sia.Gateway.Links;
|
||||
|
||||
namespace Sia.Gateway.Tests.Requests.Events
|
||||
{
|
||||
|
@ -39,55 +40,20 @@ namespace Sia.Gateway.Tests.Requests.Events
|
|||
//Arrange
|
||||
methods.Clear();
|
||||
ids.Clear();
|
||||
var eventsController = new EventsController(null, null, null, urlHelperMock.Object, new StubLoggerFactory());
|
||||
var eventLinksProvider = new EventLinksProvider(urlHelperMock.Object);
|
||||
// Act
|
||||
eventsController.CreateLinks("1", "2", null,null,"");
|
||||
eventLinksProvider.CreateLinks(2, 1);
|
||||
|
||||
// Assert
|
||||
urlHelperMock.Verify(foo => foo.Link(EventsController.GetSingleRouteName, It.IsAny<object>()), Times.Exactly(1));
|
||||
urlHelperMock.Verify(foo => foo.Link(EventsController.PostSingleRouteName, It.IsAny<object>()), Times.Exactly(1));
|
||||
urlHelperMock.Verify(foo => foo.Link(EventsController.GetMultipleRouteName, It.IsAny<object>()), Times.Exactly(1));
|
||||
urlHelperMock.Verify(foo => foo.Link(IncidentsController.GetSingleRouteName, It.IsAny<object>()), Times.Exactly(1));
|
||||
urlHelperMock.Verify(foo => foo.Link(EventRoutesByIncident.GetSingle, It.IsAny<object>()), Times.Exactly(1));
|
||||
urlHelperMock.Verify(foo => foo.Link(EventRoutesByIncident.PostSingle, It.IsAny<object>()), Times.Exactly(1));
|
||||
urlHelperMock.Verify(foo => foo.Link(EventRoutesByIncident.GetMultiple, It.IsAny<object>()), Times.Exactly(1));
|
||||
urlHelperMock.Verify(foo => foo.Link(IncidentRoutes.GetSingle, It.IsAny<object>()), Times.Exactly(1));
|
||||
|
||||
Assert.AreEqual(GetProperty(ids[0], "id"), "1");
|
||||
Assert.AreEqual(GetProperty(ids[1], "id"), "");
|
||||
Assert.AreEqual(GetProperty(ids[2], "id"), "");
|
||||
Assert.AreEqual(GetProperty(ids[3], "id"), "2");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GetHeaderValues_AssignsMetadataAndPaginationAsNull_WhenNoMetaDataPassedIn()
|
||||
{
|
||||
//Arrange
|
||||
methods.Clear();
|
||||
ids.Clear();
|
||||
var pagination = new PaginationMetadata()
|
||||
{
|
||||
PageNumber = 2,
|
||||
PageSize = 2,
|
||||
TotalRecords = 10
|
||||
|
||||
};
|
||||
|
||||
var linksHeaderWithoutMetadata = new LinksHeader(null, null, urlHelperMock.Object, "EventsController", null,
|
||||
null);
|
||||
var linksHeaderWithMetadata = new LinksHeader(null, pagination, urlHelperMock.Object, "EventsController", null,
|
||||
null);
|
||||
|
||||
//Act
|
||||
var linksWithoutMetadata = linksHeaderWithoutMetadata.GetHeaderValues();
|
||||
var linksWithMetadata = linksHeaderWithMetadata.GetHeaderValues();
|
||||
|
||||
//Assert
|
||||
Assert.IsNull(linksWithoutMetadata.Metadata);
|
||||
Assert.IsNull(linksWithoutMetadata.Links.Pagination);
|
||||
|
||||
Assert.IsNotNull(linksWithMetadata.Metadata);
|
||||
Assert.IsNotNull(linksWithMetadata.Links.Pagination);
|
||||
urlHelperMock.Verify(foo => foo.Link("EventsController", It.IsAny<object>()), Times.Exactly(2));
|
||||
|
||||
Assert.AreEqual(GetProperty(ids[0], "id"), "");
|
||||
Assert.AreEqual(GetProperty(ids[1], "id"), "");
|
||||
Assert.AreEqual(GetProperty(ids[0], "eventId"), "1");
|
||||
Assert.AreEqual(GetProperty(ids[1], "eventId"), "1");
|
||||
Assert.AreEqual(GetProperty(ids[2], "eventId"), "1");
|
||||
Assert.AreEqual(GetProperty(ids[3], "incidentId"), "2");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ using Moq;
|
|||
using Sia.Gateway.Controllers;
|
||||
using Sia.Core.Protocol;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Sia.Gateway.Links;
|
||||
|
||||
namespace Sia.Gateway.Tests.Requests.Incidents
|
||||
{
|
||||
|
@ -49,57 +49,21 @@ namespace Sia.Gateway.Tests.Requests.Incidents
|
|||
ids.Add(o);
|
||||
}
|
||||
);
|
||||
var incidentsController = new IncidentsController(null, null, urlHelperMock.Object);
|
||||
var incidentLinksProvider = new IncidentLinksProvider(urlHelperMock.Object);
|
||||
|
||||
// Act
|
||||
incidentsController.CreateLinks("1", null, "");
|
||||
incidentLinksProvider.CreateLinks(1);
|
||||
|
||||
// Assert
|
||||
urlHelperMock.Verify(foo => foo.Link(IncidentsController.GetSingleRouteName, It.IsAny<object>()), Times.Exactly(1));
|
||||
urlHelperMock.Verify(foo => foo.Link(IncidentsController.PostSingleRouteName, It.IsAny<object>()), Times.Exactly(1));
|
||||
urlHelperMock.Verify(foo => foo.Link(IncidentsController.GetMultipleRouteName, It.IsAny<object>()), Times.Exactly(1));
|
||||
urlHelperMock.Verify(foo => foo.Link(EventsController.GetMultipleRouteName, It.IsAny<object>()), Times.Exactly(1));
|
||||
urlHelperMock.Verify(foo => foo.Link(IncidentRoutes.GetSingle, It.IsAny<object>()), Times.Exactly(1));
|
||||
urlHelperMock.Verify(foo => foo.Link(IncidentRoutes.PostSingle, It.IsAny<object>()), Times.Exactly(1));
|
||||
urlHelperMock.Verify(foo => foo.Link(IncidentRoutes.GetMultiple, It.IsAny<object>()), Times.Exactly(1));
|
||||
urlHelperMock.Verify(foo => foo.Link(EventRoutesByIncident.GetMultiple, It.IsAny<object>()), Times.Exactly(1));
|
||||
|
||||
Assert.AreEqual(GetProperty(ids[0], "id"), "1");
|
||||
Assert.AreEqual(GetProperty(ids[1], "id"), "");
|
||||
Assert.AreEqual(GetProperty(ids[2], "id"), "");
|
||||
Assert.AreEqual(GetProperty(ids[0], "incidentId"), "1");
|
||||
Assert.AreEqual(GetProperty(ids[1], "incidentId"), "1");
|
||||
Assert.AreEqual(GetProperty(ids[2], "incidentId"), "1");
|
||||
Assert.AreEqual(GetProperty(ids[3], "incidentId"), "1");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GetHeaderValues_AssignsMetadataAndPaginationAsNull_WhenNoMetaDataPassedIn()
|
||||
{
|
||||
//Arrange
|
||||
methods.Clear();
|
||||
ids.Clear();
|
||||
|
||||
var pagination = new PaginationMetadata()
|
||||
{
|
||||
PageNumber = 2,
|
||||
PageSize = 2,
|
||||
TotalRecords = 10
|
||||
|
||||
};
|
||||
|
||||
var linksHeaderWithoutMetadata = new LinksHeader(null, null, urlHelperMock.Object, "IncidentsController", null,
|
||||
null);
|
||||
var linksHeaderWithMetadata = new LinksHeader(null, pagination, urlHelperMock.Object, "IncidentsController", null,
|
||||
null);
|
||||
|
||||
//Act
|
||||
var linksWithoutMetadata = linksHeaderWithoutMetadata.GetHeaderValues();
|
||||
var linksWithMetadata = linksHeaderWithMetadata.GetHeaderValues();
|
||||
|
||||
//Assert
|
||||
Assert.IsNull(linksWithoutMetadata.Metadata);
|
||||
Assert.IsNull(linksWithoutMetadata.Links.Pagination);
|
||||
|
||||
Assert.IsNotNull(linksWithMetadata.Metadata);
|
||||
Assert.IsNotNull(linksWithMetadata.Links.Pagination);
|
||||
urlHelperMock.Verify(foo => foo.Link("IncidentsController", It.IsAny<object>()), Times.Exactly(2));
|
||||
|
||||
Assert.AreEqual(GetProperty(ids[0], "id"), "");
|
||||
Assert.AreEqual(GetProperty(ids[1], "id"), "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче