Skip to content

Commit

Permalink
Merge pull request #37 from davewalker5/sighting-statistics-report
Browse files Browse the repository at this point in the history
Sighting statistics report
  • Loading branch information
davewalker5 authored Aug 13, 2024
2 parents 44a9196 + 3715767 commit 929f1c6
Show file tree
Hide file tree
Showing 26 changed files with 234 additions and 26 deletions.
4 changes: 2 additions & 2 deletions docker/api/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM mcr.microsoft.com/dotnet/core/aspnet:latest
COPY flightrecorder.api-1.10.0.0 /opt/flightrecorder.api-1.10.0.0
WORKDIR /opt/flightrecorder.api-1.10.0.0/bin
COPY flightrecorder.api-1.11.0.0 /opt/flightrecorder.api-1.11.0.0
WORKDIR /opt/flightrecorder.api-1.11.0.0/bin
ENTRYPOINT [ "./FlightRecorder.Api" ]
4 changes: 2 additions & 2 deletions docker/ui/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM mcr.microsoft.com/dotnet/aspnet:latest AS runtime
COPY flightrecorder.mvc-1.10.0.0 /opt/flightrecorder.mvc-1.10.0.0
WORKDIR /opt/flightrecorder.mvc-1.10.0.0/bin
COPY flightrecorder.mvc-1.11.0.0 /opt/flightrecorder.mvc-1.11.0.0
WORKDIR /opt/flightrecorder.mvc-1.11.0.0/bin
ENTRYPOINT [ "./FlightRecorder.Mvc" ]
36 changes: 30 additions & 6 deletions src/FlightRecorder.Api/Controllers/ReportsController.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
using FlightRecorder.BusinessLogic.Factory;
using FlightRecorder.Api.Entities;
using FlightRecorder.BusinessLogic.Factory;
using FlightRecorder.Entities.Db;
using FlightRecorder.Entities.Reporting;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using System.Web;

namespace FlightRecorder.Api.Controllers
Expand All @@ -27,6 +23,34 @@ public ReportsController(FlightRecorderFactory factory)
_factory = factory;
}

/// <summary>
/// Generate the sighting statistics report
/// </summary>
/// <returns></returns>
[HttpGet]
[Route("sightings")]
public async Task<ActionResult<SightingStatisticsReport>> GetSightingStatistics()
{
var aircraft = await _factory.Aircraft.CountAsync();
var manufacturers = await _factory.Manufacturers.CountAsync();
var models = await _factory.Models.CountAsync();
var airlines = await _factory.Airlines.CountAsync();
var flights = await _factory.Flights.CountAsync();
var sightings = await _factory.Sightings.CountAsync();
var locations = await _factory.Locations.CountAsync();

return new SightingStatisticsReport
(
aircraft,
manufacturers,
models,
airlines,
flights,
sightings,
locations
);
}

/// <summary>
/// Generate the airline statistics report
/// </summary>
Expand Down
16 changes: 16 additions & 0 deletions src/FlightRecorder.Api/Entities/SightingStatisticsReport.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System.Diagnostics.CodeAnalysis;

namespace FlightRecorder.Api.Entities
{
[ExcludeFromCodeCoverage]
public record SightingStatisticsReport
(
int Aircraft,
int Manufacturers,
int Models,
int Airlines,
int Flights,
int Sightings,
int Locations
);
}
6 changes: 3 additions & 3 deletions src/FlightRecorder.Api/FlightRecorder.Api.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ReleaseVersion>1.10.0.0</ReleaseVersion>
<FileVersion>1.10.0.0</FileVersion>
<ProductVersion>1.10.0</ProductVersion>
<ReleaseVersion>1.11.0.0</ReleaseVersion>
<FileVersion>1.11.0.0</FileVersion>
<ProductVersion>1.11.0</ProductVersion>
<ImplicitUsings>enable</ImplicitUsings>
<IsPackable>false</IsPackable>
</PropertyGroup>
Expand Down
7 changes: 7 additions & 0 deletions src/FlightRecorder.BusinessLogic/Database/AircraftManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@ public IAsyncEnumerable<Aircraft> ListAsync(Expression<Func<Aircraft, bool>> pre
return aircraft;
}

/// <summary>
/// Return the number of aircraft in the database
/// </summary>
/// <returns></returns>
public async Task<int> CountAsync()
=> await _factory.Context.Aircraft.CountAsync();

/// <summary>
/// Get the aircraft of a specified model
/// </summary>
Expand Down
7 changes: 7 additions & 0 deletions src/FlightRecorder.BusinessLogic/Database/AirlineManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,13 @@ public IAsyncEnumerable<Airline> ListAsync(Expression<Func<Airline, bool>> predi
return results;
}

/// <summary>
/// Return the number of airlines in the database
/// </summary>
/// <returns></returns>
public async Task<int> CountAsync()
=> await _context.Airlines.CountAsync();

/// <summary>
/// Add a named airline, if it doesn't already exist
/// </summary>
Expand Down
7 changes: 7 additions & 0 deletions src/FlightRecorder.BusinessLogic/Database/FlightManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,13 @@ public IAsyncEnumerable<Flight> ListAsync(Expression<Func<Flight, bool>> predica
return flights;
}

/// <summary>
/// Return the number of flights in the database
/// </summary>
/// <returns></returns>
public async Task<int> CountAsync()
=> await _factory.Context.Flights.CountAsync();

/// <summary>
/// Get the flights for a named airline
/// </summary>
Expand Down
7 changes: 7 additions & 0 deletions src/FlightRecorder.BusinessLogic/Database/LocationManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,13 @@ public virtual IAsyncEnumerable<Location> ListAsync(Expression<Func<Location, bo
return results;
}

/// <summary>
/// Return the number of locations in the database
/// </summary>
/// <returns></returns>
public async Task<int> CountAsync()
=> await _context.Locations.CountAsync();

/// <summary>
/// Add a named location, if it doesn't already exist
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,13 @@ public IAsyncEnumerable<Manufacturer> ListAsync(Expression<Func<Manufacturer, bo
return results;
}

/// <summary>
/// Return the number of manufacturers in the database
/// </summary>
/// <returns></returns>
public async Task<int> CountAsync()
=> await _context.Manufacturers.CountAsync();

/// <summary>
/// Add a named manufacturer, if it doesn't already exist
/// </summary>
Expand Down
7 changes: 7 additions & 0 deletions src/FlightRecorder.BusinessLogic/Database/ModelManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,13 @@ public IAsyncEnumerable<Model> ListAsync(Expression<Func<Model, bool>> predicate
return models;
}

/// <summary>
/// Return the number of aircraft models in the database
/// </summary>
/// <returns></returns>
public async Task<int> CountAsync()
=> await _factory.Context.Models.CountAsync();

/// <summary>
/// Get the models for a named manufacturer
/// </summary>
Expand Down
7 changes: 7 additions & 0 deletions src/FlightRecorder.BusinessLogic/Database/SightingManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,13 @@ public IAsyncEnumerable<Sighting> ListAsync(Expression<Func<Sighting, bool>> pre
return sightings;
}

/// <summary>
/// Return the number of sightings in the database
/// </summary>
/// <returns></returns>
public async Task<int> CountAsync()
=> await _factory.Context.Sightings.CountAsync();

/// <summary>
/// Add a new sighting
/// </summary>
Expand Down
1 change: 1 addition & 0 deletions src/FlightRecorder.Entities/Interfaces/IAircraftManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public interface IAircraftManager
Task<Aircraft> AddAsync(string registration, string serialNumber, long? yearOfManufacture, string modelName, string manufacturerName);
Task<Aircraft> GetAsync(Expression<Func<Aircraft, bool>> predicate);
IAsyncEnumerable<Aircraft> ListAsync(Expression<Func<Aircraft, bool>> predicate, int pageNumber, int pageSize);
Task<int> CountAsync();
Task<IAsyncEnumerable<Aircraft>> ListByModelAsync(string modelName, int pageNumber, int pageSize);
Task<IAsyncEnumerable<Aircraft>> ListByManufacturerAsync(string manufacturerName, int pageNumber, int pageSize);
}
Expand Down
3 changes: 2 additions & 1 deletion src/FlightRecorder.Entities/Interfaces/IAirlineManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public interface IAirlineManager
{
Task<Airline> AddAsync(string name);
Task<Airline> GetAsync(Expression<Func<Airline, bool>> predicate);
IAsyncEnumerable<Airline> ListAsync(Expression<Func<Airline, bool>> predicate, int pageNumber, int pageSize);
IAsyncEnumerable<Airline> ListAsync(Expression<Func<Airline, bool>> predicate, int pageNumber, int pageSize);
Task<int> CountAsync();
}
}
1 change: 1 addition & 0 deletions src/FlightRecorder.Entities/Interfaces/IFlightManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public interface IFlightManager
Task<Flight> AddAsync(string number, string embarkation, string destination, string airlineName);
Task<Flight> GetAsync(Expression<Func<Flight, bool>> predicate);
IAsyncEnumerable<Flight> ListAsync(Expression<Func<Flight, bool>> predicate, int pageNumber, int pageSize);
Task<int> CountAsync();
Task<IAsyncEnumerable<Flight>> ListByAirlineAsync(string airlineName, int pageNumber, int pageSize);
}
}
3 changes: 2 additions & 1 deletion src/FlightRecorder.Entities/Interfaces/ILocationManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public interface ILocationManager
{
Task<Location> AddAsync(string name);
Task<Location> GetAsync(Expression<Func<Location, bool>> predicate);
IAsyncEnumerable<Location> ListAsync(Expression<Func<Location, bool>> predicate, int pageNumber, int pageSize);
IAsyncEnumerable<Location> ListAsync(Expression<Func<Location, bool>> predicate, int pageNumber, int pageSize);
Task<int> CountAsync();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public interface IManufacturerManager
{
Task<Manufacturer> AddAsync(string name);
Task<Manufacturer> GetAsync(Expression<Func<Manufacturer, bool>> predicate);
IAsyncEnumerable<Manufacturer> ListAsync(Expression<Func<Manufacturer, bool>> predicate, int pageNumber, int pageSize);
IAsyncEnumerable<Manufacturer> ListAsync(Expression<Func<Manufacturer, bool>> predicate, int pageNumber, int pageSize);
Task<int> CountAsync();
}
}
1 change: 1 addition & 0 deletions src/FlightRecorder.Entities/Interfaces/IModelManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public interface IModelManager
Task<Model> AddAsync(string name, string manufacturerName);
Task<Model> GetAsync(Expression<Func<Model, bool>> predicate);
IAsyncEnumerable<Model> ListAsync(Expression<Func<Model, bool>> predicate, int pageNumber, int pageSize);
Task<int> CountAsync();
IAsyncEnumerable<Model> ListByManufacturerAsync(string manufacturerName, int pageNumber, int pageSize);
}
}
1 change: 1 addition & 0 deletions src/FlightRecorder.Entities/Interfaces/ISightingManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public interface ISightingManager
Task<Sighting> AddAsync(FlattenedSighting flattened);
Task<Sighting> GetAsync(Expression<Func<Sighting, bool>> predicate);
IAsyncEnumerable<Sighting> ListAsync(Expression<Func<Sighting, bool>> predicate, int pageNumber, int pageSize);
Task<int> CountAsync();
Task<IAsyncEnumerable<Sighting>> ListByAircraftAsync(string registration, int pageNumber, int pageSize);
Task<IAsyncEnumerable<Sighting>> ListByRouteAsync(string embarkation, string destination, int pageNumber, int pageSize);
Task<IAsyncEnumerable<Sighting>> ListByAirlineAsync(string airlineName, int pageNumber, int pageSize);
Expand Down
22 changes: 16 additions & 6 deletions src/FlightRecorder.Mvc/Api/ReportsClient.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
using FlightRecorder.Mvc.Configuration;
using FlightRecorder.Mvc.Entities;
using FlightRecorder.Mvc.Interfaces;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;

namespace FlightRecorder.Mvc.Api
{
Expand All @@ -19,6 +13,22 @@ public ReportsClient(HttpClient client, IOptions<AppSettings> settings, IHttpCon
{
}

/// <summary>
/// Return the sighting statistics report
/// </summary>
/// <returns></returns>
public async Task<SightingStatistics> SightingStatisticsAsync()
{
// Construct the route
string route = Settings.Value.ApiRoutes.First(r => r.Name == "SightingStatistics").Route;

// Call the endpoint and decode the response
string json = await SendDirectAsync(route, null, HttpMethod.Get);
var records = JsonConvert.DeserializeObject<SightingStatistics>(json, JsonSettings);

return records;
}

/// <summary>
/// Return the airline statistics report
/// </summary>
Expand Down
34 changes: 34 additions & 0 deletions src/FlightRecorder.Mvc/Controllers/SightingStatisticsController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using FlightRecorder.Mvc.Api;
using FlightRecorder.Mvc.Configuration;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;

namespace FlightRecorder.Mvc.Controllers
{
[Authorize]
public class SightingStatisticsController : Controller
{
private readonly ReportsClient _reportsClient;
private readonly IOptions<AppSettings> _settings;

public SightingStatisticsController(
ReportsClient reportsClient,
IOptions<AppSettings> settings)
{
_reportsClient = reportsClient;
_settings = settings;
}

/// <summary>
/// Retrieve and serve the report
/// </summary>
/// <returns></returns>
[HttpGet]
public async Task<IActionResult> Index()
{
var report = await _reportsClient.SightingStatisticsAsync();
return View(report);
}
}
}
13 changes: 13 additions & 0 deletions src/FlightRecorder.Mvc/Entities/SightingStatistics.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace FlightRecorder.Mvc.Entities
{
public record SightingStatistics
(
int Aircraft,
int Manufacturers,
int Models,
int Airlines,
int Flights,
int Sightings,
int Locations
);
}
6 changes: 3 additions & 3 deletions src/FlightRecorder.Mvc/FlightRecorder.Mvc.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ReleaseVersion>1.10.0.0</ReleaseVersion>
<FileVersion>1.10.0.0</FileVersion>
<ProductVersion>1.10.0</ProductVersion>
<ReleaseVersion>1.11.0.0</ReleaseVersion>
<FileVersion>1.11.0.0</FileVersion>
<ProductVersion>1.11.0</ProductVersion>
<ImplicitUsings>enable</ImplicitUsings>
<IsPackable>false</IsPackable>
</PropertyGroup>
Expand Down
3 changes: 2 additions & 1 deletion src/FlightRecorder.Mvc/Views/Shared/_Layout.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
Reports
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" asp-area="" asp-controller="SightingStatistics" asp-action="Index">Sighting Statistics</a>
<a class="dropdown-item" asp-area="" asp-controller="AirlineStatistics" asp-action="Index">Airline Statistics</a>
<a class="dropdown-item" asp-area="" asp-controller="FlightsByMonth" asp-action="Index">Flights By Month</a>
<a class="dropdown-item" asp-area="" asp-controller="LocationStatistics" asp-action="Index">Location Statistics</a>
Expand Down Expand Up @@ -109,7 +110,7 @@

<footer class="border-top footer text-muted">
<div class="container">
&copy; 2020, 2021, 2022, 2023, 2024 - Flight Recorder
&copy; 2020, 2021, 2022, 2023, 2024 - David Walker
</div>
</footer>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
Expand Down
Loading

0 comments on commit 929f1c6

Please sign in to comment.