Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added filtering to request list on itinerary details. #1615

Merged
merged 3 commits into from Dec 16, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -50,15 +50,15 @@ public void ControllerHasAreaAuthorizeAttributeWithCorrectPolicy()
}

[Fact]
public void DetailsHasHttpGetAttribute()
public void DetailsGet_HasHttpGetAttribute()
{
var sut = new ItineraryController(null, null);
var attribute = sut.GetAttributesOn(x => x.Details(It.IsAny<int>())).OfType<HttpGetAttribute>().SingleOrDefault();
Assert.NotNull(attribute);
}

[Fact]
public void DetailsHasRouteAttributeWithCorrectRoute()
public void DetailsGet_HasRouteAttributeWithCorrectRoute()
{
var sut = new ItineraryController(null, null);
var routeAttribute = sut.GetAttributesOn(x => x.Details(It.IsAny<int>())).OfType<RouteAttribute>().SingleOrDefault();
Expand All @@ -67,7 +67,7 @@ public void DetailsHasRouteAttributeWithCorrectRoute()
}

[Fact]
public async Task DetailsSendsEventDetailQueryWithCorrectEventId()
public async Task DetailsGet_SendsEventDetailQueryWithCorrectEventId()
{
var mockMediator = new Mock<IMediator>();
mockMediator.Setup(mock => mock.SendAsync(It.IsAny<ItineraryDetailQuery>())).ReturnsAsync(null).Verifiable();
Expand All @@ -79,7 +79,7 @@ public async Task DetailsSendsEventDetailQueryWithCorrectEventId()
}

[Fact]
public async Task DetailsReturnsHttpNotFoundResultWhenEventIsNull()
public async Task DetailsGet_ReturnsHttpNotFoundResultWhenEventIsNull()
{
var mockMediator = new Mock<IMediator>();
mockMediator.Setup(mock => mock.SendAsync(It.IsAny<ItineraryDetailQuery>())).ReturnsAsync(null).Verifiable();
Expand All @@ -89,7 +89,7 @@ public async Task DetailsReturnsHttpNotFoundResultWhenEventIsNull()
}

[Fact]
public async Task DetailsReturnsHttpUnauthorizedResultWhenUserIsNotOrgAdmin()
public async Task DetailsGet_ReturnsHttpUnauthorizedResultWhenUserIsNotOrgAdmin()
{
var mediator = new Mock<IMediator>();
mediator.Setup(x => x.SendAsync(It.IsAny<ItineraryDetailQuery>())).ReturnsAsync(new ItineraryDetailsViewModel());
Expand All @@ -101,7 +101,7 @@ public async Task DetailsReturnsHttpUnauthorizedResultWhenUserIsNotOrgAdmin()
}

[Fact]
public async Task DetailsReturnsCorrectViewAndViewModelWhenEventIsNotNullAndUserIsOrgAdmin()
public async Task DetailsGet_ReturnsCorrectViewAndViewModelWhenEventIsNotNullAndUserIsOrgAdmin()
{
const int orgId = 1;
var viewModel = new ItineraryDetailsViewModel { OrganizationId = orgId };
Expand All @@ -121,6 +121,125 @@ public async Task DetailsReturnsCorrectViewAndViewModelWhenEventIsNotNullAndUser
Assert.Equal(resultViewModel, viewModel);
}

[Fact]
public void DetailsPost_HasHttpPostAttribute()
{
var sut = new ItineraryController(null, null);
var attribute = sut.GetAttributesOn(x => x.Details(It.IsAny<int>(), It.IsAny<string>(), It.IsAny<RequestStatus?>()))
.OfType<HttpPostAttribute>().SingleOrDefault();
Assert.NotNull(attribute);
}

[Fact]
public void DetailsPost_HasRouteAttributeWithCorrectRoute()
{
var sut = new ItineraryController(null, null);
var routeAttribute = sut.GetAttributesOn(x => x.Details(It.IsAny<int>(), It.IsAny<string>(), It.IsAny<RequestStatus?>()))
.OfType<RouteAttribute>().SingleOrDefault();
Assert.NotNull(routeAttribute);
Assert.Equal(routeAttribute.Template, "Admin/Itinerary/Details/{id}");
}

[Fact]
public async Task DetailsPost_SendsEventDetailQueryWithCorrectEventId()
{
var mockMediator = new Mock<IMediator>();
mockMediator.Setup(mock => mock.SendAsync(It.IsAny<ItineraryDetailQuery>())).ReturnsAsync(null).Verifiable();

var sut = new ItineraryController(mockMediator.Object, null);
await sut.Details(1, null, null);

mockMediator.Verify(x => x.SendAsync(It.IsAny<ItineraryDetailQuery>()), Times.Once);
}

[Fact]
public async Task DetailsPost_ReturnsHttpNotFoundResultWhenEventIsNull()
{
var mockMediator = new Mock<IMediator>();
mockMediator.Setup(mock => mock.SendAsync(It.IsAny<ItineraryDetailQuery>())).ReturnsAsync(null).Verifiable();

var controller = new ItineraryController(mockMediator.Object, null);
Assert.IsType<NotFoundResult>(await controller.Details(It.IsAny<int>(), It.IsAny<string>(), It.IsAny<RequestStatus?>()));
}

[Fact]
public async Task DetailsPost_ReturnsHttpUnauthorizedResultWhenUserIsNotOrgAdmin()
{
var mediator = new Mock<IMediator>();
mediator.Setup(x => x.SendAsync(It.IsAny<ItineraryDetailQuery>())).ReturnsAsync(new ItineraryDetailsViewModel());

var sut = new ItineraryController(mediator.Object, null);
sut.MakeUserNotAnOrgAdmin();

Assert.IsType<UnauthorizedResult>(await sut.Details(It.IsAny<int>(), It.IsAny<string>(), It.IsAny<RequestStatus?>()));
}

[Fact]
public async Task DetailsPost_ReturnsCorrectViewAndViewModelWhenEventIsNotNullAndUserIsOrgAdmin()
{
const int orgId = 1;
var viewModel = new ItineraryDetailsViewModel { OrganizationId = orgId };

var mediator = new Mock<IMediator>();
mediator.Setup(x => x.SendAsync(It.IsAny<ItineraryDetailQuery>())).ReturnsAsync(viewModel);

var sut = new ItineraryController(mediator.Object, null);
sut.MakeUserAnOrgAdmin(orgId.ToString());

var result = await sut.Details(It.IsAny<int>(), It.IsAny<string>(), It.IsAny<RequestStatus?>()) as ViewResult;
Assert.Equal(result.ViewName, "Details");

var resultViewModel = result.ViewData.Model;
Assert.IsType<ItineraryDetailsViewModel>(resultViewModel);

Assert.Equal(resultViewModel, viewModel);
}

[Fact]
public async Task DetailsPost_SendsRequestListQueryWithCorrectData()
{
const int orgId = 1;
const int itineraryId = 2;
const string keywords = "search";
const RequestStatus status = RequestStatus.Assigned;
var viewModel = new ItineraryDetailsViewModel { OrganizationId = orgId, Id = 2 };
var requestList = new List<RequestListViewModel>();

var mediator = new Mock<IMediator>();
mediator.Setup(x => x.SendAsync(It.IsAny<ItineraryDetailQuery>())).ReturnsAsync(viewModel);
mediator.Setup(x => x.SendAsync(It.IsAny<RequestListItemsQuery>())).ReturnsAsync(requestList);

var sut = new ItineraryController(mediator.Object, null);
sut.MakeUserAnOrgAdmin(orgId.ToString());
await sut.Details(itineraryId, keywords, status);

mediator.Verify(x => x.SendAsync(It.Is<RequestListItemsQuery>(
y => y.Criteria.ItineraryId == itineraryId &&
y.Criteria.Keywords == keywords &&
y.Criteria.Status == status)), Times.Once);
}

[Fact]
public async Task DetailsPost_ReturnsViewModelWithCorrectRequestListData()
{
const int orgId = 1;
var fullList = new List<RequestListViewModel> {new RequestListViewModel {Id = Guid.NewGuid()}};
var filteredList = new List<RequestListViewModel> {new RequestListViewModel {Id = Guid.NewGuid()}};
var viewModel = new ItineraryDetailsViewModel { OrganizationId = orgId, Requests = fullList};

var mediator = new Mock<IMediator>();
mediator.Setup(x => x.SendAsync(It.IsAny<ItineraryDetailQuery>())).ReturnsAsync(viewModel);
mediator.Setup(x => x.SendAsync(It.IsAny<RequestListItemsQuery>())).ReturnsAsync(filteredList);

var sut = new ItineraryController(mediator.Object, null);
sut.MakeUserAnOrgAdmin(orgId.ToString());
var result = await sut.Details(It.IsAny<int>(), It.IsAny<string>(), It.IsAny<RequestStatus?>()) as ViewResult;

var model = (ItineraryDetailsViewModel) result.ViewData.Model;

Assert.Equal(model.Requests, filteredList);
}

[Fact]
public void CreateHasHttpPostAttribute()
{
Expand Down Expand Up @@ -449,7 +568,7 @@ public async Task EditGet_ReturnsViewResult_WhenUserIsSiteAdmin()
// Assert
var viewResult = Assert.IsType<ViewResult>(await sut.Edit(1));
var model = viewResult.Model as ItineraryEditViewModel;

model.ShouldNotBeNull();
model.Name.ShouldBe("Test");
}
Expand Down Expand Up @@ -514,7 +633,7 @@ public async Task EditPost_ReturnsHttpUnauthorizedResult_WhenUserIsNotOrgAdminFo

Assert.IsType<UnauthorizedResult>(await sut.Edit(new ItineraryEditViewModel { Id = 50 }));
}

[Fact]
public async Task EditPost_CallsValidator_WithCorrectProperties()
{
Expand All @@ -532,7 +651,7 @@ public async Task EditPost_CallsValidator_WithCorrectProperties()
Id = 1,
Name = "Itinerary",
OrganizationId = 1,
EventSummary = new EventSummaryViewModel {
EventSummary = new EventSummaryViewModel {
StartDateTime = new DateTimeOffset(new DateTime(2016, 01, 01)),
EndDateTime = new DateTimeOffset(new DateTime(2016, 12, 31))
}
Expand Down Expand Up @@ -1639,4 +1758,4 @@ private List<RequestListViewModel> GetRequestsForSelectRequestHappyPathTests()
};
}
}
}
}
Expand Up @@ -51,6 +51,37 @@ public async Task<IActionResult> Details(int id)
return View("Details", itinerary);
}

[HttpPost]
[Route("Admin/Itinerary/Details/{id}")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Details(int id, string requestKeywords, RequestStatus? requestStatus)
{
var itinerary = await _mediator.SendAsync(new ItineraryDetailQuery {ItineraryId = id});
if (itinerary == null)
{
return NotFound();
}

if (!User.IsOrganizationAdmin(itinerary.OrganizationId))
{
return Unauthorized();
}

var filteredRequests = await _mediator.SendAsync(new RequestListItemsQuery
{
Criteria = new RequestSearchCriteria
{
ItineraryId = itinerary.Id,
Keywords = requestKeywords,
Status = requestStatus
}
});

itinerary.Requests = filteredRequests;

return View("Details", itinerary);
}

[HttpPost]
[Route("Admin/Itinerary/Create")]
[ValidateAntiForgeryToken]
Expand Down Expand Up @@ -141,9 +172,9 @@ public async Task<IActionResult> Edit(ItineraryEditViewModel model)

await _mediator.SendAsync(new EditItineraryCommand { Itinerary = model });

return RedirectToAction(nameof(Details), new { area = "Admin", id = model.Id });
return RedirectToAction(nameof(Details), new { area = "Admin", id = model.Id });
}

[HttpPost]
[Route("Admin/Itinerary/AddTeamMember")]
[ValidateAntiForgeryToken]
Expand Down Expand Up @@ -294,7 +325,7 @@ public async Task<IActionResult> ConfirmRemoveRequest(int itineraryId, Guid requ
public async Task<IActionResult> RemoveRequest(RequestSummaryViewModel viewModel)
{
if(!viewModel.UserIsOrgAdmin)
{
{
return Unauthorized();
}

Expand Down Expand Up @@ -388,7 +419,7 @@ public async Task<IActionResult> OptimizeRoute(int itineraryId, OptimizeRouteInp
}

var result = await _mediator.SendAsync(new OptimizeRouteCommand { ItineraryId = itineraryId });

return RedirectToAction("Details", new { id = itineraryId, startAddress = model.StartAddress, endAddress = model.EndAddress });
}

Expand Down Expand Up @@ -433,4 +464,4 @@ private async Task<int> GetOrganizationIdBy(int intinerayId)
return await _mediator.SendAsync(new OrganizationIdQuery { ItineraryId = intinerayId });
}
}
}
}
Expand Up @@ -42,6 +42,11 @@ public async Task<List<RequestListViewModel>> Handle(RequestListItemsQuery messa
results = results.Where(r => r.EventId == message.Criteria.EventId.Value);
}

if (message.Criteria.ItineraryId.HasValue)
{
results = results.Where(r => r.Itineraries.Any(i => i.ItineraryId == message.Criteria.ItineraryId.Value));
}

if (message.Criteria.Status.HasValue)
{
results = results.Where(r => r.Status == message.Criteria.Status); ;
Expand Down
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using AllReady.Models;
using Microsoft.AspNetCore.Mvc.Rendering;

namespace AllReady.Areas.Admin.ViewModels.Itinerary
Expand Down Expand Up @@ -58,5 +59,9 @@ public class ItineraryDetailsViewModel
/// A URL to the bing maps site with parameters needed to generate a driving route
/// </summary>
public string BingMapUrl { get; set; }

public string RequestKeywords { get; set; }

public RequestStatus? RequestStatus { get; set; }
}
}
Expand Up @@ -9,6 +9,7 @@ public class RequestSearchCriteria
public bool IncludeAssigned { get; set; } = false;
public bool IncludeCanceled { get; set; } = false;
public int? EventId { get; set; }
public int? ItineraryId { get; set; }

public string Keywords { get; set; }
public RequestStatus? Status { get; set; }
Expand Down