Ejemplo n.º 1
0
        public async Task <IEnumerable <TeachingEvent> > SearchTeachingEventsAsync(TeachingEventSearchRequest request)
        {
            IQueryable <TeachingEvent> teachingEvents = _dbContext.TeachingEvents
                                                        .Include(te => te.Building)
                                                        .OrderBy(te => te.StartAt);

            if (request.TypeId != null)
            {
                teachingEvents = teachingEvents.Where(te => te.TypeId == request.TypeId);
            }

            if (request.StartAfter != null)
            {
                teachingEvents = teachingEvents.Where(te => request.StartAfter < te.StartAt);
            }

            if (request.StartBefore != null)
            {
                teachingEvents = teachingEvents.Where(te => request.StartBefore > te.StartAt);
            }

            if (request.Radius == null)
            {
                return(await teachingEvents.ToListAsync());
            }

            return(await FilterTeachingEventsByRadius(teachingEvents, request));
        }
        public async Task <IActionResult> SearchGroupedByType(
            [FromQuery, SwaggerParameter("Event search criteria.", Required = true)] TeachingEventSearchRequest request,
            [FromQuery, SwaggerParameter("Quantity to return (per type).")] int quantityPerType = 3)
        {
            if (!ModelState.IsValid)
            {
                return(BadRequest(this.ModelState));
            }

            if (request.Postcode != null)
            {
                _logger.LogInformation($"SearchGroupedByType: {request.Postcode}");
            }

            var teachingEvents = await _store.SearchTeachingEventsAsync(request);

            _metrics.TeachingEventSearchResults
            .WithLabels(request.TypeId.ToString(), request.Radius.ToString())
            .Observe(teachingEvents.Count());

            var inPesonTeachingEvents = teachingEvents.Where(e => e.IsInPerson);

            _metrics.InPersonTeachingEventResults
            .WithLabels(request.TypeId.ToString(), request.Radius.ToString())
            .Observe(inPesonTeachingEvents.Count());

            return(Ok(GroupTeachingEventsByType(teachingEvents, quantityPerType)));
        }
        private async Task<IEnumerable<TeachingEvent>> OnlineEventsMatchingRequest(TeachingEventSearchRequest originalRequest)
        {
            var request = originalRequest.Clone(te => { te.Radius = null; });
            var result = await SearchTeachingEventsAsync(request);

            return result.Where(te => te.IsOnline && !te.IsVirtual);
        }
        public async void SearchGroupedByType_ValidRequest_ReturnsTeachingEventsByType()
        {
            var request = new TeachingEventSearchRequest()
            {
                Postcode = "KY12 8FG"
            };
            var mockEvents = MockEvents();

            _mockStore.Setup(mock => mock.SearchTeachingEventsAsync(request)).ReturnsAsync(mockEvents);

            var response = await _controller.SearchGroupedByType(request);

            var ok     = response.Should().BeOfType <OkObjectResult>().Subject;
            var result = (IEnumerable <TeachingEventsByType>)ok.Value;

            result.First().TypeId.Should().Be(123);
            result.First().TeachingEvents.Count().Should().Be(3);
            result.Last().TypeId.Should().Be(456);
            result.Last().TeachingEvents.Count().Should().Be(1);

            _mockLogger.VerifyInformationWasCalled("SearchGroupedByType: KY12 8FG");

            _metrics.TeachingEventSearchResults.WithLabels(new[] { request.TypeId.ToString(), request.Radius.ToString() }).Count.Should().Be(1);
            _metrics.TeachingEventSearchResults.WithLabels(new[] { request.TypeId.ToString(), request.Radius.ToString() }).Count.Should().Be(1);
        }
Ejemplo n.º 5
0
        public void StatusId_DefaultValue_IsOpenAndClsoedEvents()
        {
            var request          = new TeachingEventSearchRequest();
            var expectedDefaults = new int[] { (int)TeachingEvent.Status.Open, (int)TeachingEvent.Status.Closed };

            request.StatusIds.Should().Equal(expectedDefaults);
        }
Ejemplo n.º 6
0
        public void Clone_WithBlock_ClonesAndCallsBlock()
        {
            var request = new TeachingEventSearchRequest()
            {
                Radius = 10, TypeId = 123
            };
            var clone = request.Clone((te) => te.Radius = 100);

            clone.Radius.Should().Be(100);
            clone.TypeId.Should().Be(request.TypeId);
        }
Ejemplo n.º 7
0
        public void Validate_RadiusIsNotNullAndPostcodeIsNull_HasError()
        {
            var request = new TeachingEventSearchRequest()
            {
                Radius   = 10,
                Postcode = null,
            };

            var result = _validator.TestValidate(request);

            result.ShouldHaveValidationErrorFor(request => request.Postcode);
        }
Ejemplo n.º 8
0
        public void Validate_StartBeforeAndNoStartAfter_HasNoError()
        {
            var request = new TeachingEventSearchRequest()
            {
                StartBefore = DateTime.UtcNow.AddDays(1),
                StartAfter  = null,
            };

            var result = _validator.TestValidate(request);

            result.ShouldNotHaveAnyValidationErrors();
        }
Ejemplo n.º 9
0
        public void Validate_StartAfterLaterThanStartBefore_HasError()
        {
            var request = new TeachingEventSearchRequest()
            {
                StartAfter  = DateTime.UtcNow.AddDays(1),
                StartBefore = DateTime.UtcNow
            };

            var result = _validator.TestValidate(request);

            result.ShouldHaveValidationErrorFor(request => request).WithErrorMessage("Start after must be earlier than start before.");
        }
        public async void SearchTeachingEvents_FilteredByDefaultStatusId_ReturnsOpenAndClosedEvents()
        {
            await SeedMockTeachingEventsAndBuildingsAsync();

            var request = new TeachingEventSearchRequest();

            var result = await _store.SearchTeachingEventsAsync(request);

            result.Select(e => e.Name).Should()
            .Contain(
                new string[] { "Event 1", "Event 2", "Event 3", "Event 4", "Event 5", "Event 6", "Event 7" });
        }
Ejemplo n.º 11
0
        public async void SearchTeachingEvents_FilteredByStartBefore_ReturnsMatching()
        {
            await SeedMockTeachingEventsAndBuildingsAsync();

            var request = new TeachingEventSearchRequest()
            {
                StartBefore = DateTime.UtcNow.AddDays(6)
            };

            var result = await _store.SearchTeachingEventsAsync(request);

            result.Select(e => e.Name).Should().BeEquivalentTo(new string[] { "Event 7", "Event 2", "Event 4", "Event 1" },
                                                               options => options.WithStrictOrdering());
        }
Ejemplo n.º 12
0
        public async void SearchTeachingEvents_WithoutFilters_ReturnsAll()
        {
            await SeedMockTeachingEventsAndBuildingsAsync();

            var request = new TeachingEventSearchRequest()
            {
            };

            var result = await _store.SearchTeachingEventsAsync(request);

            result.Select(e => e.Name).Should().BeEquivalentTo(
                new string[] { "Event 7", "Event 2", "Event 4", "Event 1", "Event 3", "Event 5", "Event 6" },
                options => options.WithStrictOrdering());
        }
Ejemplo n.º 13
0
        public async void SearchTeachingEvents_FilteredByRadiusWithFailedPostcodeGeocoding_ReturnsEmpty()
        {
            SeedMockLocations();
            await SeedMockTeachingEventsAndBuildingsAsync();

            var request = new TeachingEventSearchRequest()
            {
                Postcode = "TE7 1NG", Radius = 15
            };

            var result = await _store.SearchTeachingEventsAsync(request);

            result.Should().BeEmpty();
        }
Ejemplo n.º 14
0
        public async void SearchTeachingEvents_FilteredByRadiusWithOutwardOnlyPostcode_ReturnsMatchingAndOnlineEvents()
        {
            SeedMockLocations();
            await SeedMockTeachingEventsAndBuildingsAsync();

            var request = new TeachingEventSearchRequest()
            {
                Postcode = "KY6", Radius = 15
            };

            var result = await _store.SearchTeachingEventsAsync(request);

            result.Select(e => e.Name).Should().BeEquivalentTo(new string[] { "Event 2", "Event 3", "Event 1", "Event 5" },
                                                               options => options.WithStrictOrdering());
        }
Ejemplo n.º 15
0
        public async void SearchTeachingEvents_FilteredByType_ReturnsMatching()
        {
            SeedMockLocations();
            await SeedMockTeachingEventsAndBuildingsAsync();

            var request = new TeachingEventSearchRequest()
            {
                TypeId = (int)TeachingEvent.EventType.ApplicationWorkshop
            };

            var result = await _store.SearchTeachingEventsAsync(request);

            result.Select(e => e.Name).Should().BeEquivalentTo(new string[] { "Event 2" },
                                                               options => options.WithStrictOrdering());
        }
        public async void SearchTeachingEvents_FilteredByMultipleStatusIds_ReturnsMatching()
        {
            await SeedMockTeachingEventsAndBuildingsAsync();

            var request = new TeachingEventSearchRequest()
            {
                StatusIds = new int[] { (int)TeachingEvent.Status.Open, (int)TeachingEvent.Status.Pending }
            };

            var result = await _store.SearchTeachingEventsAsync(request);

            result.Select(e => e.Name).Should()
            .Contain(
                new string[] { "Event 1", "Event 2", "Event 3", "Event 4", "Event 5", "Event 6", "Event 8" });
        }
        public async void SearchGroupedByType_InvalidRequest_RespondsWithValidationErrors()
        {
            var request = new TeachingEventSearchRequest()
            {
                Postcode = null
            };

            _controller.ModelState.AddModelError("Postcode", "Postcode must be specified.");

            var response = await _controller.SearchGroupedByType(request);

            var badRequest = response.Should().BeOfType <BadRequestObjectResult>().Subject;
            var errors     = badRequest.Value.Should().BeOfType <SerializableError>().Subject;

            errors.Should().ContainKey("Postcode").WhichValue.Should().BeOfType <string[]>().Which.Should().Contain("Postcode must be specified.");
        }
Ejemplo n.º 18
0
        public async void SearchTeachingEvents_WithFilters_ExcludesEventNarrowlyOutOfRange()
        {
            SeedMockLocations();
            await SeedMockTeachingEventsAndBuildingsAsync();

            var request = new TeachingEventSearchRequest()
            {
                Postcode    = "KY6 2NJ",
                Radius      = 12,
                TypeId      = (int)TeachingEvent.EventType.ApplicationWorkshop,
                StartAfter  = DateTime.UtcNow,
                StartBefore = DateTime.UtcNow.AddDays(3)
            };

            var result = await _store.SearchTeachingEventsAsync(request);

            result.Select(e => e.Name).Should().BeEmpty();
        }
Ejemplo n.º 19
0
        public async void SearchTeachingEvents_WithFilters_ReturnsEventNarrowlyInRange()
        {
            SeedMockLocations();
            await SeedMockTeachingEventsAndBuildingsAsync();

            var request = new TeachingEventSearchRequest()
            {
                Postcode    = "KY6 2NJ",
                Radius      = 13,
                TypeId      = (int)TeachingEvent.EventType.ApplicationWorkshop,
                StartAfter  = DateTime.UtcNow,
                StartBefore = DateTime.UtcNow.AddDays(3)
            };

            var result = await _store.SearchTeachingEventsAsync(request);

            result.Select(e => e.Name).Should().BeEquivalentTo(
                new string[] { "Event 2" },
                options => options.WithStrictOrdering());
        }
Ejemplo n.º 20
0
        public void Validate_WhenValid_HasNoErrors()
        {
            var mockPickListItem = new PickListItem {
                Id = 123
            };

            _mockStore
            .Setup(mock => mock.GetPickListItems("msevtmgt_event", "dfe_event_type"))
            .Returns(new[] { mockPickListItem }.AsQueryable());

            var request = new TeachingEventSearchRequest()
            {
                Postcode    = "KY11 9HF",
                Radius      = 10,
                TypeId      = mockPickListItem.Id,
                StartAfter  = DateTime.UtcNow.AddDays(-1),
                StartBefore = DateTime.UtcNow.AddDays(1)
            };

            var result = _validator.TestValidate(request);

            result.IsValid.Should().BeTrue();
        }
Ejemplo n.º 21
0
        private async Task <IEnumerable <TeachingEvent> > FilterTeachingEventsByRadius(
            IQueryable <TeachingEvent> teachingEvents, TeachingEventSearchRequest request)
        {
            var origin = await CoordinateForPostcode(request.Postcode);

            // If we can't locate them, return no results.
            if (origin == null)
            {
                return(new List <TeachingEvent>());
            }

            // Exclude events we don't have a location for.
            teachingEvents = teachingEvents.Where(te => te.Building != null && te.Building.Coordinate != null);

            // Filter events by distance in database
            var result = teachingEvents.Where(teachingEvent => teachingEvent.Building.Coordinate.Distance(origin)
                                              < request.RadiusInKm() * 1000).AsEnumerable();

            // We need to include the various 'online' event types in distance based search results.
            result = result.Concat(await OnlineEventsMatchingRequest(request));

            return(result);
        }