From 391df2fb1daf3a438cc75933e4b828b8d70bcd6e Mon Sep 17 00:00:00 2001 From: David Walker Date: Sun, 10 Mar 2024 08:20:51 +0000 Subject: [PATCH 01/12] Added maintainer management class --- .../DroneFlightLogDbContext.cs | 3 + .../DroneFlightLogDbContext.cs | 3 + ...oneManagerTest.cs => DroneManagerTests.cs} | 2 +- ...htManagerTest.cs => FlightManagerTests.cs} | 2 +- ...rTest.cs => FlightPropertyManagerTests.cs} | 2 +- .../MaintainerManagerTests.cs | 155 ++++++ ...delManagerTest.cs => ModelManagerTests.cs} | 334 ++++++------ .../OperatorManagerTests.cs | 500 +++++++++--------- .../DroneFlightLog.Data.csproj | 4 - src/DroneFlightLog.Data/Entities/Flight.cs | 46 +- .../Entities/Maintainer.cs | 14 + .../Entities/MaintenanceRecord.cs | 20 + .../Exceptions/MaintainerExistsException.cs | 21 + .../Exceptions/MaintainerNotFoundException.cs | 21 + .../Factory/DroneFlightLogFactory.cs | 3 + .../Interfaces/IDroneFlightLogDbContext.cs | 3 + .../Interfaces/IDroneFlightLogFactory.cs | 1 + .../Interfaces/IMaintainerManager.cs | 20 + .../Logic/MaintainerManager.cs | 212 ++++++++ 19 files changed, 919 insertions(+), 447 deletions(-) rename src/DroneFlightLog.Data.Tests/{DroneManagerTest.cs => DroneManagerTests.cs} (99%) rename src/DroneFlightLog.Data.Tests/{FlightManagerTest.cs => FlightManagerTests.cs} (99%) rename src/DroneFlightLog.Data.Tests/{FlightPropertyManagerTest.cs => FlightPropertyManagerTests.cs} (99%) create mode 100644 src/DroneFlightLog.Data.Tests/MaintainerManagerTests.cs rename src/DroneFlightLog.Data.Tests/{ModelManagerTest.cs => ModelManagerTests.cs} (96%) create mode 100644 src/DroneFlightLog.Data/Entities/Maintainer.cs create mode 100644 src/DroneFlightLog.Data/Entities/MaintenanceRecord.cs create mode 100644 src/DroneFlightLog.Data/Exceptions/MaintainerExistsException.cs create mode 100644 src/DroneFlightLog.Data/Exceptions/MaintainerNotFoundException.cs create mode 100644 src/DroneFlightLog.Data/Interfaces/IMaintainerManager.cs create mode 100644 src/DroneFlightLog.Data/Logic/MaintainerManager.cs diff --git a/src/DroneFlightLog.Data.InMemory/DroneFlightLogDbContext.cs b/src/DroneFlightLog.Data.InMemory/DroneFlightLogDbContext.cs index c70320e..1c1fd1c 100644 --- a/src/DroneFlightLog.Data.InMemory/DroneFlightLogDbContext.cs +++ b/src/DroneFlightLog.Data.InMemory/DroneFlightLogDbContext.cs @@ -22,6 +22,9 @@ public class DroneFlightLogDbContext : DbContext, IDroneFlightLogDbContext public DbSet FlightLogUsers { get; set; } + public DbSet Maintainers { get; set; } + public DbSet MaintenanceRecords { get; set; } + public DroneFlightLogDbContext(DbContextOptions options) : base(options) { } diff --git a/src/DroneFlightLog.Data.Sqlite/DroneFlightLogDbContext.cs b/src/DroneFlightLog.Data.Sqlite/DroneFlightLogDbContext.cs index 7be0e7f..95335f2 100644 --- a/src/DroneFlightLog.Data.Sqlite/DroneFlightLogDbContext.cs +++ b/src/DroneFlightLog.Data.Sqlite/DroneFlightLogDbContext.cs @@ -22,6 +22,9 @@ public class DroneFlightLogDbContext : DbContext, IDroneFlightLogDbContext public DbSet FlightLogUsers { get; set; } + public DbSet Maintainers { get; set; } + public DbSet MaintenanceRecords { get; set; } + public DroneFlightLogDbContext(DbContextOptions options) : base(options) { } diff --git a/src/DroneFlightLog.Data.Tests/DroneManagerTest.cs b/src/DroneFlightLog.Data.Tests/DroneManagerTests.cs similarity index 99% rename from src/DroneFlightLog.Data.Tests/DroneManagerTest.cs rename to src/DroneFlightLog.Data.Tests/DroneManagerTests.cs index 79bc13b..448a278 100644 --- a/src/DroneFlightLog.Data.Tests/DroneManagerTest.cs +++ b/src/DroneFlightLog.Data.Tests/DroneManagerTests.cs @@ -11,7 +11,7 @@ namespace DroneFlightLog.Data.Tests { [TestClass] - public class DroneManagerTest + public class DroneManagerTests { private const string ManufacturerName = "Some Manufacturer"; private const string ModelName = "Some Model"; diff --git a/src/DroneFlightLog.Data.Tests/FlightManagerTest.cs b/src/DroneFlightLog.Data.Tests/FlightManagerTests.cs similarity index 99% rename from src/DroneFlightLog.Data.Tests/FlightManagerTest.cs rename to src/DroneFlightLog.Data.Tests/FlightManagerTests.cs index 6c7430b..f172ebf 100644 --- a/src/DroneFlightLog.Data.Tests/FlightManagerTest.cs +++ b/src/DroneFlightLog.Data.Tests/FlightManagerTests.cs @@ -12,7 +12,7 @@ namespace DroneFlightLog.Data.Tests { [TestClass] - public class FlightManagerTest + public class FlightManagerTests { private const string Number = "1"; private const string Street = "Some Street"; diff --git a/src/DroneFlightLog.Data.Tests/FlightPropertyManagerTest.cs b/src/DroneFlightLog.Data.Tests/FlightPropertyManagerTests.cs similarity index 99% rename from src/DroneFlightLog.Data.Tests/FlightPropertyManagerTest.cs rename to src/DroneFlightLog.Data.Tests/FlightPropertyManagerTests.cs index c3250f3..47843f6 100644 --- a/src/DroneFlightLog.Data.Tests/FlightPropertyManagerTest.cs +++ b/src/DroneFlightLog.Data.Tests/FlightPropertyManagerTests.cs @@ -12,7 +12,7 @@ namespace DroneFlightLog.Data.Tests { [TestClass] - public class FlightPropertyManagerTest + public class FlightPropertyManagerTests { private const string Number = "1"; private const string Street = "Some Street"; diff --git a/src/DroneFlightLog.Data.Tests/MaintainerManagerTests.cs b/src/DroneFlightLog.Data.Tests/MaintainerManagerTests.cs new file mode 100644 index 0000000..2d5f8b9 --- /dev/null +++ b/src/DroneFlightLog.Data.Tests/MaintainerManagerTests.cs @@ -0,0 +1,155 @@ +using DroneFlightLog.Data.Entities; +using DroneFlightLog.Data.Exceptions; +using DroneFlightLog.Data.Factory; +using DroneFlightLog.Data.InMemory; +using DroneFlightLog.Data.Interfaces; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace DroneFlightLog.Data.Tests +{ + [TestClass] + public class MaintainerManagerTests + { + private const string AsyncFirstNames = "Async First Names"; + private const string FirstNames = "First Names"; + private const string UpdatedFirstNames = "Updated First Names"; + private const string Surname = "Surname"; + private const string UpdatedSurname = "Updated Surname"; + + private IDroneFlightLogFactory _factory; + private int _maintainerId; + + [TestInitialize] + public void TestInitialize() + { + DroneFlightLogDbContext context = new DroneFlightLogDbContextFactory().CreateDbContext(null); + _factory = new DroneFlightLogFactory(context); + + Maintainer maintainer = _factory.Maintainers.AddMaintainer(FirstNames, Surname); + _factory.Context.SaveChanges(); + _maintainerId = maintainer.Id; + } + + [TestMethod] + public void AddMaintainerTest() + { + // The maintainer has been added during test initialisation. All that needs + // to be done here is to validate it + Assert.AreEqual(1, _factory.Context.Maintainers.Count()); + Assert.AreEqual(FirstNames, _factory.Context.Maintainers.First().FirstNames); + Assert.AreEqual(Surname, _factory.Context.Maintainers.First().Surname); + } + + [TestMethod] + public async Task AddMaintainerAsyncTest() + { + Maintainer maintainer = await _factory.Maintainers.AddMaintainerAsync(AsyncFirstNames, Surname); + await _factory.Context.SaveChangesAsync(); + Assert.AreEqual(2, _factory.Context.Maintainers.Count()); + Assert.AreEqual(AsyncFirstNames, maintainer.FirstNames); + Assert.AreEqual(Surname, maintainer.Surname); + } + + [TestMethod, ExpectedException(typeof(MaintainerExistsException))] + public void AddExistingMaintainerTest() + { + _factory.Maintainers.AddMaintainer(FirstNames, Surname); + } + + [TestMethod] + public void UpdateMaintainerTest() + { + _factory.Maintainers.UpdateMaintainer(_maintainerId, UpdatedFirstNames, UpdatedSurname); + _factory.Context.SaveChanges(); + Maintainer maintainer = _factory.Maintainers.GetMaintainer(_maintainerId); + Assert.AreEqual(UpdatedFirstNames, maintainer.FirstNames); + Assert.AreEqual(UpdatedSurname, maintainer.Surname); + } + + [TestMethod] + public async Task UpdateMaintainerAsyncTest() + { + await _factory.Maintainers.UpdateMaintainerAsync(_maintainerId, UpdatedFirstNames, UpdatedSurname); + await _factory.Context.SaveChangesAsync(); + Maintainer maintainer = await _factory.Maintainers.GetMaintainerAsync(_maintainerId); + Assert.AreEqual(UpdatedFirstNames, maintainer.FirstNames); + Assert.AreEqual(UpdatedSurname, maintainer.Surname); + } + + [TestMethod] + public void GetMaintainerByIdTest() + { + Maintainer maintainer = _factory.Maintainers.GetMaintainer(_maintainerId); + ValidateMaintainer(maintainer, _maintainerId); + } + + [TestMethod] + public async Task GetMaintainerByIdAsyncTest() + { + Maintainer maintainer = await _factory.Maintainers.GetMaintainerAsync(_maintainerId); + ValidateMaintainer(maintainer, _maintainerId); + } + + [TestMethod, ExpectedException(typeof(MaintainerNotFoundException))] + public void GetMissingMaintainerByIdTest() + { + _factory.Maintainers.GetMaintainer(-1); + } + + [TestMethod] + public void GetAllMaintainersTest() + { + IEnumerable maintainers = _factory.Maintainers.GetMaintainers(); + Assert.AreEqual(1, maintainers.Count()); + ValidateMaintainer(maintainers.First(), _maintainerId); + } + + [TestMethod] + public async Task GetAllMaintainersAsyncTest() + { + List maintainers = await _factory.Maintainers.GetMaintainersAsync().ToListAsync(); + Assert.AreEqual(1, maintainers.Count()); + ValidateMaintainer(maintainers.First(), _maintainerId); + } + + [TestMethod] + public void FindMaintainerTest() + { + Maintainer maintainer = _factory.Maintainers.FindMaintainer(FirstNames, Surname); + ValidateMaintainer(maintainer, _maintainerId); + } + + [TestMethod] + public async Task FindMaintainerAsyncTest() + { + Maintainer maintainer = await _factory.Maintainers.FindMaintainerAsync(FirstNames, Surname); + ValidateMaintainer(maintainer, _maintainerId); + } + + [TestMethod] + public void FindMissingMaintainerTest() + { + Maintainer maintainer = _factory.Maintainers.FindMaintainer("", ""); + Assert.IsNull(maintainer); + } + + #region Helpers + /// + /// Validate the specified maintainer + /// + /// + /// + /// + private void ValidateMaintainer(Maintainer maintainer, int expectedMaintainerId) + { + Assert.AreEqual(expectedMaintainerId, maintainer.Id); + Assert.AreEqual(FirstNames, maintainer.FirstNames); + Assert.AreEqual(Surname, maintainer.Surname); + } + #endregion + } +} diff --git a/src/DroneFlightLog.Data.Tests/ModelManagerTest.cs b/src/DroneFlightLog.Data.Tests/ModelManagerTests.cs similarity index 96% rename from src/DroneFlightLog.Data.Tests/ModelManagerTest.cs rename to src/DroneFlightLog.Data.Tests/ModelManagerTests.cs index 0d6e7fc..a329ff4 100644 --- a/src/DroneFlightLog.Data.Tests/ModelManagerTest.cs +++ b/src/DroneFlightLog.Data.Tests/ModelManagerTests.cs @@ -1,168 +1,168 @@ using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using DroneFlightLog.Data.Entities; -using DroneFlightLog.Data.Exceptions; -using DroneFlightLog.Data.Factory; -using DroneFlightLog.Data.InMemory; -using DroneFlightLog.Data.Interfaces; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace DroneFlightLog.Data.Tests -{ - [TestClass] - public class ModelManagerTest - { - private const string ManufacturerName = "Some Manufacturer"; - private const string UpdatedManufacturerName = "Some OtherManufacturer"; - private const string ModelName = "Some Model"; - private const string UpdatedModelName = "Some Other Model"; - private const string AsyncModelName = "Some Async Model"; - - private IDroneFlightLogFactory _factory; - private int _manufacturerId; - private int _modelId; - - [TestInitialize] - public void TestInitialize() - { - DroneFlightLogDbContext context = new DroneFlightLogDbContextFactory().CreateDbContext(null); - _factory = new DroneFlightLogFactory(context); - - Manufacturer manufacturer = _factory.Manufacturers.AddManufacturer(ManufacturerName); - _factory.Context.SaveChanges(); - _manufacturerId = manufacturer.Id; - - Model model = _factory.Models.AddModel(ModelName, _manufacturerId); - _factory.Context.SaveChanges(); - _modelId = model.Id; - } - - [TestMethod] - public void AddModelTest() - { - // The model has been added during test initialisation. All that needs - // to be done here is to validate it - Assert.AreEqual(1, _factory.Context.Models.Count()); - Assert.AreEqual(ModelName, _factory.Context.Models.First().Name); - Assert.AreEqual(_manufacturerId, _factory.Context.Models.First().ManufacturerId); - } - - [TestMethod] - public async Task AddModelAsyncTest() - { - Model model = await _factory.Models.AddModelAsync(AsyncModelName, _manufacturerId); - await _factory.Context.SaveChangesAsync(); - Assert.AreEqual(2, _factory.Context.Models.Count()); - Assert.AreEqual(AsyncModelName, model.Name); - Assert.AreEqual(_manufacturerId, model.ManufacturerId); - } - - [TestMethod, ExpectedException(typeof(ModelExistsException))] - public void AddExistingModelTest() - { - _factory.Models.AddModel(ModelName, _manufacturerId); - } - - [TestMethod, ExpectedException(typeof(ManufacturerNotFoundException))] - public void AddModelForMissingManufacturerTest() - { - _factory.Models.AddModel(ModelName, -1); - } - - [TestMethod] - public void GetModelByIdTest() - { - Model model = _factory.Models.GetModel(_modelId); - ValidateModel(model); - } - - [TestMethod] - public async Task GetModelByIdAsyncTest() - { - Model model = await _factory.Models.GetModelAsync(_modelId); - ValidateModel(model); - } - - [TestMethod, ExpectedException(typeof(ModelNotFoundException))] - public void GetMissingModelByIdTest() - { - _factory.Models.GetModel(-1); - } - - [TestMethod] - public void UpdateModelTest() - { - // To make this a complete test, we need a second manufacturer - Manufacturer manufacturer = _factory.Manufacturers.AddManufacturer(UpdatedManufacturerName); - _factory.Context.SaveChanges(); - - _factory.Models.UpdateModel(_modelId, UpdatedModelName, manufacturer.Id); - _factory.Context.SaveChanges(); - - Model model = _factory.Models.GetModel(_modelId); - Assert.AreEqual(UpdatedModelName, model.Name); - Assert.AreEqual(manufacturer.Id, model.ManufacturerId); - } - - [TestMethod] - public async Task UpdateModelAsyncTest() - { - // To make this a complete test, we need a second manufacturer - Manufacturer manufacturer = await _factory.Manufacturers.AddManufacturerAsync(UpdatedManufacturerName); - await _factory.Context.SaveChangesAsync(); - - await _factory.Models.UpdateModelAsync(_modelId, UpdatedModelName, manufacturer.Id); - await _factory.Context.SaveChangesAsync(); - - Model model = await _factory.Models.GetModelAsync(_modelId); - Assert.AreEqual(UpdatedModelName, model.Name); - Assert.AreEqual(manufacturer.Id, model.ManufacturerId); - } - - [TestMethod] - public void GetAllModelsTest() - { - IEnumerable models = _factory.Models.GetModels(null); - Assert.AreEqual(1, models.Count()); - ValidateModel(models.First()); - } - - [TestMethod] - public async Task GetAllModelsAsyncTest() - { - List models = await _factory.Models.GetModelsAsync(null).ToListAsync(); - Assert.AreEqual(1, models.Count()); - ValidateModel(models.First()); - } - - [TestMethod] - public void GetModelsForManufacturerTest() - { - IEnumerable models = _factory.Models.GetModels(_manufacturerId); - Assert.AreEqual(1, models.Count()); - ValidateModel(models.First()); - } - - [TestMethod] - public void GetModelsForMissingManufacturerTest() - { - IEnumerable models = _factory.Models.GetModels(-1); - Assert.IsFalse(models.Any()); - } - - #region Helpers - /// - /// Check the properties of a model - /// - /// - private void ValidateModel(Model model) - { - Assert.AreEqual(_modelId, model.Id); - Assert.AreEqual(ModelName, model.Name); - Assert.AreEqual(_manufacturerId, model.ManufacturerId); - Assert.AreEqual(ManufacturerName, model.Manufacturer.Name); - } - #endregion - } -} +using System.Linq; +using System.Threading.Tasks; +using DroneFlightLog.Data.Entities; +using DroneFlightLog.Data.Exceptions; +using DroneFlightLog.Data.Factory; +using DroneFlightLog.Data.InMemory; +using DroneFlightLog.Data.Interfaces; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace DroneFlightLog.Data.Tests +{ + [TestClass] + public class ModelManagerTests + { + private const string ManufacturerName = "Some Manufacturer"; + private const string UpdatedManufacturerName = "Some OtherManufacturer"; + private const string ModelName = "Some Model"; + private const string UpdatedModelName = "Some Other Model"; + private const string AsyncModelName = "Some Async Model"; + + private IDroneFlightLogFactory _factory; + private int _manufacturerId; + private int _modelId; + + [TestInitialize] + public void TestInitialize() + { + DroneFlightLogDbContext context = new DroneFlightLogDbContextFactory().CreateDbContext(null); + _factory = new DroneFlightLogFactory(context); + + Manufacturer manufacturer = _factory.Manufacturers.AddManufacturer(ManufacturerName); + _factory.Context.SaveChanges(); + _manufacturerId = manufacturer.Id; + + Model model = _factory.Models.AddModel(ModelName, _manufacturerId); + _factory.Context.SaveChanges(); + _modelId = model.Id; + } + + [TestMethod] + public void AddModelTest() + { + // The model has been added during test initialisation. All that needs + // to be done here is to validate it + Assert.AreEqual(1, _factory.Context.Models.Count()); + Assert.AreEqual(ModelName, _factory.Context.Models.First().Name); + Assert.AreEqual(_manufacturerId, _factory.Context.Models.First().ManufacturerId); + } + + [TestMethod] + public async Task AddModelAsyncTest() + { + Model model = await _factory.Models.AddModelAsync(AsyncModelName, _manufacturerId); + await _factory.Context.SaveChangesAsync(); + Assert.AreEqual(2, _factory.Context.Models.Count()); + Assert.AreEqual(AsyncModelName, model.Name); + Assert.AreEqual(_manufacturerId, model.ManufacturerId); + } + + [TestMethod, ExpectedException(typeof(ModelExistsException))] + public void AddExistingModelTest() + { + _factory.Models.AddModel(ModelName, _manufacturerId); + } + + [TestMethod, ExpectedException(typeof(ManufacturerNotFoundException))] + public void AddModelForMissingManufacturerTest() + { + _factory.Models.AddModel(ModelName, -1); + } + + [TestMethod] + public void GetModelByIdTest() + { + Model model = _factory.Models.GetModel(_modelId); + ValidateModel(model); + } + + [TestMethod] + public async Task GetModelByIdAsyncTest() + { + Model model = await _factory.Models.GetModelAsync(_modelId); + ValidateModel(model); + } + + [TestMethod, ExpectedException(typeof(ModelNotFoundException))] + public void GetMissingModelByIdTest() + { + _factory.Models.GetModel(-1); + } + + [TestMethod] + public void UpdateModelTest() + { + // To make this a complete test, we need a second manufacturer + Manufacturer manufacturer = _factory.Manufacturers.AddManufacturer(UpdatedManufacturerName); + _factory.Context.SaveChanges(); + + _factory.Models.UpdateModel(_modelId, UpdatedModelName, manufacturer.Id); + _factory.Context.SaveChanges(); + + Model model = _factory.Models.GetModel(_modelId); + Assert.AreEqual(UpdatedModelName, model.Name); + Assert.AreEqual(manufacturer.Id, model.ManufacturerId); + } + + [TestMethod] + public async Task UpdateModelAsyncTest() + { + // To make this a complete test, we need a second manufacturer + Manufacturer manufacturer = await _factory.Manufacturers.AddManufacturerAsync(UpdatedManufacturerName); + await _factory.Context.SaveChangesAsync(); + + await _factory.Models.UpdateModelAsync(_modelId, UpdatedModelName, manufacturer.Id); + await _factory.Context.SaveChangesAsync(); + + Model model = await _factory.Models.GetModelAsync(_modelId); + Assert.AreEqual(UpdatedModelName, model.Name); + Assert.AreEqual(manufacturer.Id, model.ManufacturerId); + } + + [TestMethod] + public void GetAllModelsTest() + { + IEnumerable models = _factory.Models.GetModels(null); + Assert.AreEqual(1, models.Count()); + ValidateModel(models.First()); + } + + [TestMethod] + public async Task GetAllModelsAsyncTest() + { + List models = await _factory.Models.GetModelsAsync(null).ToListAsync(); + Assert.AreEqual(1, models.Count()); + ValidateModel(models.First()); + } + + [TestMethod] + public void GetModelsForManufacturerTest() + { + IEnumerable models = _factory.Models.GetModels(_manufacturerId); + Assert.AreEqual(1, models.Count()); + ValidateModel(models.First()); + } + + [TestMethod] + public void GetModelsForMissingManufacturerTest() + { + IEnumerable models = _factory.Models.GetModels(-1); + Assert.IsFalse(models.Any()); + } + + #region Helpers + /// + /// Check the properties of a model + /// + /// + private void ValidateModel(Model model) + { + Assert.AreEqual(_modelId, model.Id); + Assert.AreEqual(ModelName, model.Name); + Assert.AreEqual(_manufacturerId, model.ManufacturerId); + Assert.AreEqual(ManufacturerName, model.Manufacturer.Name); + } + #endregion + } +} diff --git a/src/DroneFlightLog.Data.Tests/OperatorManagerTests.cs b/src/DroneFlightLog.Data.Tests/OperatorManagerTests.cs index ee44347..c3aa21a 100644 --- a/src/DroneFlightLog.Data.Tests/OperatorManagerTests.cs +++ b/src/DroneFlightLog.Data.Tests/OperatorManagerTests.cs @@ -1,251 +1,251 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using DroneFlightLog.Data.Entities; -using DroneFlightLog.Data.Exceptions; -using DroneFlightLog.Data.Factory; -using DroneFlightLog.Data.InMemory; -using DroneFlightLog.Data.Interfaces; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace DroneFlightLog.Data.Tests -{ - [TestClass] - public class OperatorManagerTests - { - private const string Number = "1"; - private const string Street = "Some Street"; - private const string Town = "Some Town"; - private const string County = "Some County"; - private const string Postcode = "AB12 3CD"; - private const string SecondPostcode = "EF12 3GH"; - private const string Country = "Some Country"; - - private const string AsyncFirstNames = "Async First Names"; - private const string FirstNames = "First Names"; - private const string UpdatedFirstNames = "Updated First Names"; - private const string Surname = "Surname"; - private const string UpdatedSurname = "Updated Surname"; - private readonly DateTime DoB = DateTime.Now; - private readonly DateTime UpdatedDoB = DateTime.Now.AddDays(365); - private const string FlyerNumber = "Some Flyer Number"; - private const string UpdatedFlyerNumber = "Updated Flyer Number"; - private const string OperatorNumber = "Some Operator Number"; - private const string UpdatedOperatorNumber = "Updated Operator Number"; - - private IDroneFlightLogFactory _factory; - private int _firstAddressId; - private int _secondAddressId; - private int _operatorId; - - [TestInitialize] - public void TestInitialize() - { - DroneFlightLogDbContext context = new DroneFlightLogDbContextFactory().CreateDbContext(null); - _factory = new DroneFlightLogFactory(context); - - Address firstAddress = _factory.Addresses.AddAddress(Number, Street, Town, County, Postcode, Country); - Address secondAddress = _factory.Addresses.AddAddress(Number, Street, Town, County, SecondPostcode, Country); - _factory.Context.SaveChanges(); - _firstAddressId = firstAddress.Id; - _secondAddressId = secondAddress.Id; - - Operator op = _factory.Operators.AddOperator(FirstNames, Surname, DoB, FlyerNumber, OperatorNumber, _firstAddressId); - _factory.Context.SaveChanges(); - _operatorId = op.Id; - } - - [TestMethod] - public void AddOperatorTest() - { - // The operator has been added during test initialisation. All that needs - // to be done here is to validate it - Assert.AreEqual(1, _factory.Context.Operators.Count()); - Assert.AreEqual(FirstNames, _factory.Context.Operators.First().FirstNames); - Assert.AreEqual(Surname, _factory.Context.Operators.First().Surname); - Assert.AreEqual(DoB, _factory.Context.Operators.First().DoB); - Assert.AreEqual(FlyerNumber, _factory.Context.Operators.First().FlyerNumber); - Assert.AreEqual(OperatorNumber, _factory.Context.Operators.First().OperatorNumber); - Assert.AreEqual(_firstAddressId, _factory.Context.Operators.First().AddressId); - } - - [TestMethod] - public async Task AddOperatorAsyncTest() - { - Operator op = await _factory.Operators.AddOperatorAsync(AsyncFirstNames, Surname, DoB, FlyerNumber, OperatorNumber, _firstAddressId); - await _factory.Context.SaveChangesAsync(); - Assert.AreEqual(2, _factory.Context.Operators.Count()); - Assert.AreEqual(AsyncFirstNames, op.FirstNames); - Assert.AreEqual(Surname, op.Surname); - Assert.AreEqual(DoB, op.DoB); - Assert.AreEqual(FlyerNumber, op.FlyerNumber); - Assert.AreEqual(OperatorNumber, op.OperatorNumber); - Assert.AreEqual(_firstAddressId, op.AddressId); - } - - [TestMethod, ExpectedException(typeof(OperatorExistsException))] - public void AddExistingOperatorTest() - { - _factory.Operators.AddOperator(FirstNames, Surname, DateTime.Now, "", "", _firstAddressId); - } - - [TestMethod] - public void UpdateOperatorTest() - { - _factory.Operators.UpdateOperator(_operatorId, UpdatedFirstNames, UpdatedSurname, UpdatedDoB, UpdatedFlyerNumber, UpdatedOperatorNumber, _secondAddressId); - _factory.Context.SaveChanges(); - Operator op = _factory.Operators.GetOperator(_operatorId); - Assert.AreEqual(UpdatedFirstNames, op.FirstNames); - Assert.AreEqual(UpdatedSurname, op.Surname); - Assert.AreEqual(UpdatedDoB, op.DoB); - Assert.AreEqual(UpdatedFlyerNumber, op.FlyerNumber); - Assert.AreEqual(UpdatedOperatorNumber, op.OperatorNumber); - Assert.AreEqual(_secondAddressId, op.AddressId); - } - - [TestMethod] - public async Task UpdateOperatorAsyncTest() - { - await _factory.Operators.UpdateOperatorAsync(_operatorId, UpdatedFirstNames, UpdatedSurname, UpdatedDoB, UpdatedFlyerNumber, UpdatedOperatorNumber, _secondAddressId); - await _factory.Context.SaveChangesAsync(); - Operator op = await _factory.Operators.GetOperatorAsync(_operatorId); - Assert.AreEqual(UpdatedFirstNames, op.FirstNames); - Assert.AreEqual(UpdatedSurname, op.Surname); - Assert.AreEqual(UpdatedDoB, op.DoB); - Assert.AreEqual(UpdatedFlyerNumber, op.FlyerNumber); - Assert.AreEqual(UpdatedOperatorNumber, op.OperatorNumber); - Assert.AreEqual(_secondAddressId, op.AddressId); - } - - [TestMethod] - public void GetOperatorByIdTest() - { - Operator op = _factory.Operators.GetOperator(_operatorId); - ValidateOperator(op, _operatorId, _firstAddressId); - } - - [TestMethod] - public async Task GetOperatorByIdAsyncTest() - { - Operator op = await _factory.Operators.GetOperatorAsync(_operatorId); - ValidateOperator(op, _operatorId, _firstAddressId); - } - - [TestMethod, ExpectedException(typeof(OperatorNotFoundException))] - public void GetMissingOperatorByIdTest() - { - _factory.Operators.GetOperator(-1); - } - - [TestMethod] - public void GetAllOperatorsTest() - { - IEnumerable operators = _factory.Operators.GetOperators(null); - Assert.AreEqual(1, operators.Count()); - ValidateOperator(operators.First(), _operatorId, _firstAddressId); - } - - [TestMethod] - public async Task GetAllOperatorsAsyncTest() - { - List operators = await _factory.Operators.GetOperatorsAsync(null).ToListAsync(); - Assert.AreEqual(1, operators.Count()); - ValidateOperator(operators.First(), _operatorId, _firstAddressId); - } - - [TestMethod] - public void GetAllOperatorsForAddressTest() - { - IEnumerable operators = _factory.Operators.GetOperators(_firstAddressId); - Assert.AreEqual(1, operators.Count()); - ValidateOperator(operators.First(), _operatorId, _firstAddressId); - } - - [TestMethod] - public void GetAllOperatorsForMissingAddressTest() - { - IEnumerable operators = _factory.Operators.GetOperators(-1); - Assert.AreEqual(0, operators.Count()); - } - - [TestMethod] - public void FindOperatorTest() - { - Operator op = _factory.Operators.FindOperator(FirstNames, Surname, _firstAddressId); - ValidateOperator(op, _operatorId, _firstAddressId); - } - - [TestMethod] - public async Task FindOperatorAsyncTest() - { - Operator op = await _factory.Operators.FindOperatorAsync(FirstNames, Surname, _firstAddressId); - ValidateOperator(op, _operatorId, _firstAddressId); - } - - [TestMethod] - public void FindMissingOperatorTest() - { - Operator op = _factory.Operators.FindOperator("", "", 0); - Assert.IsNull(op); - } - - [TestMethod] - public void SetOperatorAddressTest() - { - _factory.Operators.SetOperatorAddress(_operatorId, _secondAddressId); - _factory.Context.SaveChanges(); - - Operator op = _factory.Operators.FindOperator(FirstNames, Surname, _firstAddressId); - Assert.IsNull(op); - - op = _factory.Operators.FindOperator(FirstNames, Surname, _secondAddressId); - ValidateOperator(op, _operatorId, _secondAddressId); - } - - [TestMethod] - public async Task SetOperatorAddressAsyncTest() - { - await _factory.Operators.SetOperatorAddressAsync(_operatorId, _secondAddressId); - await _factory.Context.SaveChangesAsync(); - - Operator op = await _factory.Operators.FindOperatorAsync(FirstNames, Surname, _firstAddressId); - Assert.IsNull(op); - - op = await _factory.Operators.FindOperatorAsync(FirstNames, Surname, _secondAddressId); - ValidateOperator(op, _operatorId, _secondAddressId); - } - - [TestMethod, ExpectedException(typeof(AddressNotFoundException))] - public void SetOperatorMissingAddressTest() - { - _factory.Operators.SetOperatorAddress(_operatorId, -1); - } - - [TestMethod, ExpectedException(typeof(OperatorNotFoundException))] - public void SetMissingOperatorAddressTest() - { - _factory.Operators.SetOperatorAddress(-1, _secondAddressId); - } - - #region Helpers - /// - /// Validate the specified operator - /// - /// - /// - /// - private void ValidateOperator(Operator op, int expectedOperatorId, int expectedAddressId) - { - Assert.AreEqual(expectedOperatorId, op.Id); - - Assert.AreEqual(FirstNames, op.FirstNames); - Assert.AreEqual(Surname, op.Surname); - Assert.AreEqual(DoB, op.DoB); - Assert.AreEqual(FlyerNumber, op.FlyerNumber); - Assert.AreEqual(OperatorNumber, op.OperatorNumber); - Assert.AreEqual(expectedAddressId, op.AddressId); - } - #endregion - } -} +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using DroneFlightLog.Data.Entities; +using DroneFlightLog.Data.Exceptions; +using DroneFlightLog.Data.Factory; +using DroneFlightLog.Data.InMemory; +using DroneFlightLog.Data.Interfaces; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace DroneFlightLog.Data.Tests +{ + [TestClass] + public class OperatorManagerTests + { + private const string Number = "1"; + private const string Street = "Some Street"; + private const string Town = "Some Town"; + private const string County = "Some County"; + private const string Postcode = "AB12 3CD"; + private const string SecondPostcode = "EF12 3GH"; + private const string Country = "Some Country"; + + private const string AsyncFirstNames = "Async First Names"; + private const string FirstNames = "First Names"; + private const string UpdatedFirstNames = "Updated First Names"; + private const string Surname = "Surname"; + private const string UpdatedSurname = "Updated Surname"; + private readonly DateTime DoB = DateTime.Now; + private readonly DateTime UpdatedDoB = DateTime.Now.AddDays(365); + private const string FlyerNumber = "Some Flyer Number"; + private const string UpdatedFlyerNumber = "Updated Flyer Number"; + private const string OperatorNumber = "Some Operator Number"; + private const string UpdatedOperatorNumber = "Updated Operator Number"; + + private IDroneFlightLogFactory _factory; + private int _firstAddressId; + private int _secondAddressId; + private int _operatorId; + + [TestInitialize] + public void TestInitialize() + { + DroneFlightLogDbContext context = new DroneFlightLogDbContextFactory().CreateDbContext(null); + _factory = new DroneFlightLogFactory(context); + + Address firstAddress = _factory.Addresses.AddAddress(Number, Street, Town, County, Postcode, Country); + Address secondAddress = _factory.Addresses.AddAddress(Number, Street, Town, County, SecondPostcode, Country); + _factory.Context.SaveChanges(); + _firstAddressId = firstAddress.Id; + _secondAddressId = secondAddress.Id; + + Operator op = _factory.Operators.AddOperator(FirstNames, Surname, DoB, FlyerNumber, OperatorNumber, _firstAddressId); + _factory.Context.SaveChanges(); + _operatorId = op.Id; + } + + [TestMethod] + public void AddOperatorTest() + { + // The operator has been added during test initialisation. All that needs + // to be done here is to validate it + Assert.AreEqual(1, _factory.Context.Operators.Count()); + Assert.AreEqual(FirstNames, _factory.Context.Operators.First().FirstNames); + Assert.AreEqual(Surname, _factory.Context.Operators.First().Surname); + Assert.AreEqual(DoB, _factory.Context.Operators.First().DoB); + Assert.AreEqual(FlyerNumber, _factory.Context.Operators.First().FlyerNumber); + Assert.AreEqual(OperatorNumber, _factory.Context.Operators.First().OperatorNumber); + Assert.AreEqual(_firstAddressId, _factory.Context.Operators.First().AddressId); + } + + [TestMethod] + public async Task AddOperatorAsyncTest() + { + Operator op = await _factory.Operators.AddOperatorAsync(AsyncFirstNames, Surname, DoB, FlyerNumber, OperatorNumber, _firstAddressId); + await _factory.Context.SaveChangesAsync(); + Assert.AreEqual(2, _factory.Context.Operators.Count()); + Assert.AreEqual(AsyncFirstNames, op.FirstNames); + Assert.AreEqual(Surname, op.Surname); + Assert.AreEqual(DoB, op.DoB); + Assert.AreEqual(FlyerNumber, op.FlyerNumber); + Assert.AreEqual(OperatorNumber, op.OperatorNumber); + Assert.AreEqual(_firstAddressId, op.AddressId); + } + + [TestMethod, ExpectedException(typeof(OperatorExistsException))] + public void AddExistingOperatorTest() + { + _factory.Operators.AddOperator(FirstNames, Surname, DateTime.Now, "", "", _firstAddressId); + } + + [TestMethod] + public void UpdateOperatorTest() + { + _factory.Operators.UpdateOperator(_operatorId, UpdatedFirstNames, UpdatedSurname, UpdatedDoB, UpdatedFlyerNumber, UpdatedOperatorNumber, _secondAddressId); + _factory.Context.SaveChanges(); + Operator op = _factory.Operators.GetOperator(_operatorId); + Assert.AreEqual(UpdatedFirstNames, op.FirstNames); + Assert.AreEqual(UpdatedSurname, op.Surname); + Assert.AreEqual(UpdatedDoB, op.DoB); + Assert.AreEqual(UpdatedFlyerNumber, op.FlyerNumber); + Assert.AreEqual(UpdatedOperatorNumber, op.OperatorNumber); + Assert.AreEqual(_secondAddressId, op.AddressId); + } + + [TestMethod] + public async Task UpdateOperatorAsyncTest() + { + await _factory.Operators.UpdateOperatorAsync(_operatorId, UpdatedFirstNames, UpdatedSurname, UpdatedDoB, UpdatedFlyerNumber, UpdatedOperatorNumber, _secondAddressId); + await _factory.Context.SaveChangesAsync(); + Operator op = await _factory.Operators.GetOperatorAsync(_operatorId); + Assert.AreEqual(UpdatedFirstNames, op.FirstNames); + Assert.AreEqual(UpdatedSurname, op.Surname); + Assert.AreEqual(UpdatedDoB, op.DoB); + Assert.AreEqual(UpdatedFlyerNumber, op.FlyerNumber); + Assert.AreEqual(UpdatedOperatorNumber, op.OperatorNumber); + Assert.AreEqual(_secondAddressId, op.AddressId); + } + + [TestMethod] + public void GetOperatorByIdTest() + { + Operator op = _factory.Operators.GetOperator(_operatorId); + ValidateOperator(op, _operatorId, _firstAddressId); + } + + [TestMethod] + public async Task GetOperatorByIdAsyncTest() + { + Operator op = await _factory.Operators.GetOperatorAsync(_operatorId); + ValidateOperator(op, _operatorId, _firstAddressId); + } + + [TestMethod, ExpectedException(typeof(OperatorNotFoundException))] + public void GetMissingOperatorByIdTest() + { + _factory.Operators.GetOperator(-1); + } + + [TestMethod] + public void GetAllOperatorsTest() + { + IEnumerable operators = _factory.Operators.GetOperators(null); + Assert.AreEqual(1, operators.Count()); + ValidateOperator(operators.First(), _operatorId, _firstAddressId); + } + + [TestMethod] + public async Task GetAllOperatorsAsyncTest() + { + List operators = await _factory.Operators.GetOperatorsAsync(null).ToListAsync(); + Assert.AreEqual(1, operators.Count()); + ValidateOperator(operators.First(), _operatorId, _firstAddressId); + } + + [TestMethod] + public void GetAllOperatorsForAddressTest() + { + IEnumerable operators = _factory.Operators.GetOperators(_firstAddressId); + Assert.AreEqual(1, operators.Count()); + ValidateOperator(operators.First(), _operatorId, _firstAddressId); + } + + [TestMethod] + public void GetAllOperatorsForMissingAddressTest() + { + IEnumerable operators = _factory.Operators.GetOperators(-1); + Assert.AreEqual(0, operators.Count()); + } + + [TestMethod] + public void FindOperatorTest() + { + Operator op = _factory.Operators.FindOperator(FirstNames, Surname, _firstAddressId); + ValidateOperator(op, _operatorId, _firstAddressId); + } + + [TestMethod] + public async Task FindOperatorAsyncTest() + { + Operator op = await _factory.Operators.FindOperatorAsync(FirstNames, Surname, _firstAddressId); + ValidateOperator(op, _operatorId, _firstAddressId); + } + + [TestMethod] + public void FindMissingOperatorTest() + { + Operator op = _factory.Operators.FindOperator("", "", 0); + Assert.IsNull(op); + } + + [TestMethod] + public void SetOperatorAddressTest() + { + _factory.Operators.SetOperatorAddress(_operatorId, _secondAddressId); + _factory.Context.SaveChanges(); + + Operator op = _factory.Operators.FindOperator(FirstNames, Surname, _firstAddressId); + Assert.IsNull(op); + + op = _factory.Operators.FindOperator(FirstNames, Surname, _secondAddressId); + ValidateOperator(op, _operatorId, _secondAddressId); + } + + [TestMethod] + public async Task SetOperatorAddressAsyncTest() + { + await _factory.Operators.SetOperatorAddressAsync(_operatorId, _secondAddressId); + await _factory.Context.SaveChangesAsync(); + + Operator op = await _factory.Operators.FindOperatorAsync(FirstNames, Surname, _firstAddressId); + Assert.IsNull(op); + + op = await _factory.Operators.FindOperatorAsync(FirstNames, Surname, _secondAddressId); + ValidateOperator(op, _operatorId, _secondAddressId); + } + + [TestMethod, ExpectedException(typeof(AddressNotFoundException))] + public void SetOperatorMissingAddressTest() + { + _factory.Operators.SetOperatorAddress(_operatorId, -1); + } + + [TestMethod, ExpectedException(typeof(OperatorNotFoundException))] + public void SetMissingOperatorAddressTest() + { + _factory.Operators.SetOperatorAddress(-1, _secondAddressId); + } + + #region Helpers + /// + /// Validate the specified operator + /// + /// + /// + /// + private void ValidateOperator(Operator op, int expectedOperatorId, int expectedAddressId) + { + Assert.AreEqual(expectedOperatorId, op.Id); + + Assert.AreEqual(FirstNames, op.FirstNames); + Assert.AreEqual(Surname, op.Surname); + Assert.AreEqual(DoB, op.DoB); + Assert.AreEqual(FlyerNumber, op.FlyerNumber); + Assert.AreEqual(OperatorNumber, op.OperatorNumber); + Assert.AreEqual(expectedAddressId, op.AddressId); + } + #endregion + } +} diff --git a/src/DroneFlightLog.Data/DroneFlightLog.Data.csproj b/src/DroneFlightLog.Data/DroneFlightLog.Data.csproj index 62ef81c..a8b28b0 100644 --- a/src/DroneFlightLog.Data/DroneFlightLog.Data.csproj +++ b/src/DroneFlightLog.Data/DroneFlightLog.Data.csproj @@ -24,10 +24,6 @@ - - - - diff --git a/src/DroneFlightLog.Data/Entities/Flight.cs b/src/DroneFlightLog.Data/Entities/Flight.cs index 4aba308..3cf0603 100644 --- a/src/DroneFlightLog.Data/Entities/Flight.cs +++ b/src/DroneFlightLog.Data/Entities/Flight.cs @@ -1,24 +1,24 @@ using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Diagnostics.CodeAnalysis; - -namespace DroneFlightLog.Data.Entities -{ - [ExcludeFromCodeCoverage] - public class Flight - { - [Key] - public int Id { get; set; } - public int DroneId { get; set; } - public int LocationId { get; set; } - public int OperatorId { get; set; } - public DateTime Start { get; set; } - public DateTime End { get; set; } - - public Drone Drone { get; set; } - public Location Location { get; set; } - public Operator Operator { get; set; } - public IList Properties { get; set; } - } -} +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Diagnostics.CodeAnalysis; + +namespace DroneFlightLog.Data.Entities +{ + [ExcludeFromCodeCoverage] + public class Flight + { + [Key] + public int Id { get; set; } + public int DroneId { get; set; } + public int LocationId { get; set; } + public int OperatorId { get; set; } + public DateTime Start { get; set; } + public DateTime End { get; set; } + + public Drone Drone { get; set; } + public Location Location { get; set; } + public Operator Operator { get; set; } + public IList Properties { get; set; } + } +} diff --git a/src/DroneFlightLog.Data/Entities/Maintainer.cs b/src/DroneFlightLog.Data/Entities/Maintainer.cs new file mode 100644 index 0000000..a677fe1 --- /dev/null +++ b/src/DroneFlightLog.Data/Entities/Maintainer.cs @@ -0,0 +1,14 @@ +using System.ComponentModel.DataAnnotations; +using System.Diagnostics.CodeAnalysis; + +namespace DroneFlightLog.Data.Entities +{ + [ExcludeFromCodeCoverage] + public class Maintainer + { + [Key] + public int Id { get; set; } + public string FirstNames { get; set; } + public string Surname { get; set; } + } +} diff --git a/src/DroneFlightLog.Data/Entities/MaintenanceRecord.cs b/src/DroneFlightLog.Data/Entities/MaintenanceRecord.cs new file mode 100644 index 0000000..0436257 --- /dev/null +++ b/src/DroneFlightLog.Data/Entities/MaintenanceRecord.cs @@ -0,0 +1,20 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.Diagnostics.CodeAnalysis; + +namespace DroneFlightLog.Data.Entities +{ + [ExcludeFromCodeCoverage] + public class MaintenanceRecord + { + [Key] + public int Id { get; set; } + public int MaintainerId { get; set; } + public int DroneId { get; set; } + public DateTime DateCompleted { get; set; } + public string Description { get; set; } + public string Notes { get; set; } + + public Maintainer Maintainer { get; set; } + } +} diff --git a/src/DroneFlightLog.Data/Exceptions/MaintainerExistsException.cs b/src/DroneFlightLog.Data/Exceptions/MaintainerExistsException.cs new file mode 100644 index 0000000..2c5d997 --- /dev/null +++ b/src/DroneFlightLog.Data/Exceptions/MaintainerExistsException.cs @@ -0,0 +1,21 @@ +using System; +using System.Diagnostics.CodeAnalysis; + +namespace DroneFlightLog.Data.Exceptions +{ + [ExcludeFromCodeCoverage] + public class MaintainerExistsException : Exception + { + public MaintainerExistsException() + { + } + + public MaintainerExistsException(string message) : base(message) + { + } + + public MaintainerExistsException(string message, Exception inner) : base(message, inner) + { + } + } +} \ No newline at end of file diff --git a/src/DroneFlightLog.Data/Exceptions/MaintainerNotFoundException.cs b/src/DroneFlightLog.Data/Exceptions/MaintainerNotFoundException.cs new file mode 100644 index 0000000..7d5c259 --- /dev/null +++ b/src/DroneFlightLog.Data/Exceptions/MaintainerNotFoundException.cs @@ -0,0 +1,21 @@ +using System; +using System.Diagnostics.CodeAnalysis; + +namespace DroneFlightLog.Data.Exceptions +{ + [ExcludeFromCodeCoverage] + public class MaintainerNotFoundException : Exception + { + public MaintainerNotFoundException() + { + } + + public MaintainerNotFoundException(string message) : base(message) + { + } + + public MaintainerNotFoundException(string message, Exception inner) : base(message, inner) + { + } + } +} diff --git a/src/DroneFlightLog.Data/Factory/DroneFlightLogFactory.cs b/src/DroneFlightLog.Data/Factory/DroneFlightLogFactory.cs index 68d2d7c..bf6b523 100644 --- a/src/DroneFlightLog.Data/Factory/DroneFlightLogFactory.cs +++ b/src/DroneFlightLog.Data/Factory/DroneFlightLogFactory.cs @@ -16,6 +16,7 @@ public class DroneFlightLogFactory : IDroneFlightLogFactory where T : DbCo private Lazy _locations; private Lazy _flights; private Lazy _users; + private Lazy _maintainers; public DroneFlightLogFactory(T context) { @@ -29,6 +30,7 @@ public DroneFlightLogFactory(T context) _locations = new Lazy(() => new LocationManager(context)); _flights = new Lazy(() => new FlightManager(this)); _users = new Lazy(() => new UserManager(context)); + _maintainers = new Lazy(() => new MaintainerManager(context)); } public T Context { get; private set; } @@ -41,5 +43,6 @@ public DroneFlightLogFactory(T context) public ILocationManager Locations { get { return _locations.Value; } } public IFlightManager Flights { get { return _flights.Value; } } public IUserManager Users { get { return _users.Value; } } + public IMaintainerManager Maintainers { get { return _maintainers.Value; } } } } diff --git a/src/DroneFlightLog.Data/Interfaces/IDroneFlightLogDbContext.cs b/src/DroneFlightLog.Data/Interfaces/IDroneFlightLogDbContext.cs index 216fcb7..c080201 100644 --- a/src/DroneFlightLog.Data/Interfaces/IDroneFlightLogDbContext.cs +++ b/src/DroneFlightLog.Data/Interfaces/IDroneFlightLogDbContext.cs @@ -18,5 +18,8 @@ public interface IDroneFlightLogDbContext DbSet Locations { get; set; } DbSet FlightLogUsers { get; set; } + + DbSet Maintainers { get; set; } + DbSet MaintenanceRecords { get; set; } } } diff --git a/src/DroneFlightLog.Data/Interfaces/IDroneFlightLogFactory.cs b/src/DroneFlightLog.Data/Interfaces/IDroneFlightLogFactory.cs index ac189fe..6994d43 100644 --- a/src/DroneFlightLog.Data/Interfaces/IDroneFlightLogFactory.cs +++ b/src/DroneFlightLog.Data/Interfaces/IDroneFlightLogFactory.cs @@ -14,5 +14,6 @@ public interface IDroneFlightLogFactory where T : DbContext, IDroneFlightLogD IOperatorManager Operators { get; } IFlightManager Flights { get; } IUserManager Users { get; } + IMaintainerManager Maintainers { get; } } } \ No newline at end of file diff --git a/src/DroneFlightLog.Data/Interfaces/IMaintainerManager.cs b/src/DroneFlightLog.Data/Interfaces/IMaintainerManager.cs new file mode 100644 index 0000000..32bc8be --- /dev/null +++ b/src/DroneFlightLog.Data/Interfaces/IMaintainerManager.cs @@ -0,0 +1,20 @@ +using DroneFlightLog.Data.Entities; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace DroneFlightLog.Data.Interfaces +{ + public interface IMaintainerManager + { + Maintainer AddMaintainer(string firstnames, string surname); + Task AddMaintainerAsync(string firstnames, string surname); + Maintainer FindMaintainer(string firstnames, string surname); + Task FindMaintainerAsync(string firstnames, string surname); + Maintainer GetMaintainer(int maintainerId); + Task GetMaintainerAsync(int maintainerId); + IEnumerable GetMaintainers(); + IAsyncEnumerable GetMaintainersAsync(); + Maintainer UpdateMaintainer(int maintainerId, string firstnames, string surname); + Task UpdateMaintainerAsync(int maintainerId, string firstnames, string surname); + } +} \ No newline at end of file diff --git a/src/DroneFlightLog.Data/Logic/MaintainerManager.cs b/src/DroneFlightLog.Data/Logic/MaintainerManager.cs new file mode 100644 index 0000000..82377f0 --- /dev/null +++ b/src/DroneFlightLog.Data/Logic/MaintainerManager.cs @@ -0,0 +1,212 @@ +using DroneFlightLog.Data.Entities; +using DroneFlightLog.Data.Exceptions; +using DroneFlightLog.Data.Extensions; +using DroneFlightLog.Data.Interfaces; +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DroneFlightLog.Data.Logic +{ + internal class MaintainerManager : IMaintainerManager where T : DbContext, IDroneFlightLogDbContext + { + private readonly IDroneFlightLogDbContext _context; + + internal MaintainerManager(IDroneFlightLogDbContext context) + { + _context = context; + } + + /// + /// Return the maintainer with the specified Id + /// + /// + /// + public Maintainer GetMaintainer(int maintainerId) + { + Maintainer maintainer = _context.Maintainers.FirstOrDefault(m => m.Id == maintainerId); + ThrowIfMaintainerNotFound(maintainer, maintainerId); + return maintainer; + } + + /// + /// Return the maintainer with the specified Id + /// + /// + /// + public async Task GetMaintainerAsync(int maintainerId) + { + Maintainer maintainer = await _context.Maintainers.FirstOrDefaultAsync(m => m.Id == maintainerId); + ThrowIfMaintainerNotFound(maintainer, maintainerId); + return maintainer; + } + + /// + /// Get all the current maintainer details + /// + /// + public IEnumerable GetMaintainers() + { + IEnumerable maintainers = _context.Maintainers; + return maintainers; + } + + /// + /// Get all the current maintainer details + /// + public IAsyncEnumerable GetMaintainersAsync() + { + IAsyncEnumerable maintainers = _context.Maintainers.AsAsyncEnumerable(); + return maintainers; + } + + /// + /// Add a maintainer + /// + /// + /// + /// + public Maintainer AddMaintainer(string firstnames, string surname) + { + Maintainer maintainer = FindMaintainer(firstnames, surname); + ThrowIfMaintainerFound(maintainer, firstnames, surname); + + maintainer = new Maintainer + { + FirstNames = firstnames.CleanString(), + Surname = surname.CleanString() + }; + + _context.Maintainers.Add(maintainer); + return maintainer; + } + + /// + /// Add a maintainer + /// + /// + /// + /// + public async Task AddMaintainerAsync(string firstnames, string surname) + { + Maintainer maintainer = await FindMaintainerAsync(firstnames, surname); + ThrowIfMaintainerFound(maintainer, firstnames, surname); + + maintainer = new Maintainer + { + FirstNames = firstnames.CleanString(), + Surname = surname.CleanString() + }; + + await _context.Maintainers.AddAsync(maintainer); + return maintainer; + } + + /// + /// Update a maintainers details + /// + /// + /// + /// + /// + public Maintainer UpdateMaintainer(int maintainerId, string firstnames, string surname) + { + // Check there isn't already a maintainer with those details + Maintainer existing = FindMaintainer(firstnames, surname); + ThrowIfMaintainerFound(existing, firstnames, surname); + + // Get the current maintainer and update their details + Maintainer maintainer = GetMaintainer(maintainerId); + maintainer.FirstNames = firstnames.CleanString(); + maintainer.Surname = surname.CleanString(); + return maintainer; + } + + /// + /// Update a maintainers details + /// + /// + /// + /// + /// + public async Task UpdateMaintainerAsync(int maintainerId, string firstnames, string surname) + { + // Check there isn't already a maintainer with those details + Maintainer existing = await FindMaintainerAsync(firstnames, surname); + ThrowIfMaintainerFound(existing, firstnames, surname); + + // Get the current maintainer and update their details + Maintainer maintainer = await GetMaintainerAsync(maintainerId); + maintainer.FirstNames = firstnames.CleanString(); + maintainer.Surname = surname.CleanString(); + return maintainer; + } + + /// + /// Find a maintainer based on their name + /// + /// + /// + /// + public Maintainer FindMaintainer(string firstnames, string surname) + { + firstnames = firstnames.CleanString(); + surname = surname.CleanString(); + + return _context.Maintainers + .FirstOrDefault(a => (a.FirstNames == firstnames) && + (a.Surname == surname)); + } + + /// + /// Find a maintainer based on their name + /// + /// + /// + /// + public async Task FindMaintainerAsync(string firstnames, string surname) + { + firstnames = firstnames.CleanString(); + surname = surname.CleanString(); + + return await _context.Maintainers + .FirstOrDefaultAsync(a => (a.FirstNames == firstnames) && + (a.Surname == surname)); + } + + /// + /// Throw an exception if a maintainer is not found + /// + /// + /// + [ExcludeFromCodeCoverage] + private static void ThrowIfMaintainerNotFound(Maintainer maintainer, int maintainerId) + { + if (maintainer == null) + { + string message = $"Maintainer with ID {maintainerId} not found"; + throw new MaintainerNotFoundException(message); + } + } + + /// + /// Throw an exception if a maintainer already exists + /// + /// + /// + /// + [ExcludeFromCodeCoverage] + private static void ThrowIfMaintainerFound(Maintainer maintainer, string firstnames, string surname) + { + if (maintainer != null) + { + string message = $"Maintainer {firstnames} {surname} already exists"; + throw new MaintainerExistsException(message); + } + } + } +} From 4085edaf5788359998cbc5bd13ac3a6ecf7dafc1 Mon Sep 17 00:00:00 2001 From: David Walker Date: Sun, 10 Mar 2024 08:57:50 +0000 Subject: [PATCH 02/12] Improved code coverage --- .../DroneFlightLog.Data.Tests.csproj | 13 +- .../FlightManagerTests.cs | 496 +++++++-------- .../FlightPropertyManagerTests.cs | 592 +++++++++--------- .../LocationManagerTests.cs | 280 ++++----- .../OperatorManagerTests.cs | 8 + 5 files changed, 704 insertions(+), 685 deletions(-) diff --git a/src/DroneFlightLog.Data.Tests/DroneFlightLog.Data.Tests.csproj b/src/DroneFlightLog.Data.Tests/DroneFlightLog.Data.Tests.csproj index 3773a55..9720e43 100644 --- a/src/DroneFlightLog.Data.Tests/DroneFlightLog.Data.Tests.csproj +++ b/src/DroneFlightLog.Data.Tests/DroneFlightLog.Data.Tests.csproj @@ -2,17 +2,22 @@ net8.0 - false + + + + - runtime; build; native; contentfiles; analyzers; buildtransitive -all - + + runtime; build; native; contentfiles; analyzers; buildtransitive + + all + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/src/DroneFlightLog.Data.Tests/FlightManagerTests.cs b/src/DroneFlightLog.Data.Tests/FlightManagerTests.cs index f172ebf..5ed7f14 100644 --- a/src/DroneFlightLog.Data.Tests/FlightManagerTests.cs +++ b/src/DroneFlightLog.Data.Tests/FlightManagerTests.cs @@ -1,250 +1,250 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using DroneFlightLog.Data.Entities; -using DroneFlightLog.Data.Exceptions; -using DroneFlightLog.Data.Factory; -using DroneFlightLog.Data.InMemory; -using DroneFlightLog.Data.Interfaces; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace DroneFlightLog.Data.Tests -{ - [TestClass] - public class FlightManagerTests - { - private const string Number = "1"; - private const string Street = "Some Street"; - private const string Town = "Some Town"; - private const string County = "Some County"; - private const string Postcode = "AB12 3CD"; - private const string Country = "Some Country"; - - private const string FirstNames = "First Names"; - private const string SecondFirstNames = "Second Operator First Names"; - private const string Surname = "Surname"; - private readonly DateTime DoB = DateTime.Now; - private const string FlyerNumber = "Some Flyer Number"; - private const string OperatorNumber = "Some Operator Number"; - - private const string LocationName = "My Local Drone Flight Location"; - private const string SecondLocationName = "My Second Local Drone Flight Location"; - - private const string ManufacturerName = "Some Manufacturer"; - private const string ModelName = "Some Model"; - private const string DroneName = "Some Drone"; - private const string SecondDroneName = "Some Other Drone"; - private const string DroneSerialNumber = "1234567890"; - private const string SecondDroneSerialNumber = "0987654321"; - - private readonly DateTime StartDate = DateTime.Now.AddMinutes(-5); - private readonly DateTime EndDate = DateTime.Now.AddMinutes(5); - - private IDroneFlightLogFactory _factory; - private int _operatorId; - private int _secondOperatorId; - private int _locationId; - private int _secondLocationId; - private int _droneId; - private int _secondDroneId; - private int _flightId; - - [TestInitialize] - public void TestInitialize() - { - DroneFlightLogDbContext context = new DroneFlightLogDbContextFactory().CreateDbContext(null); - _factory = new DroneFlightLogFactory(context); - - Address address = _factory.Addresses.AddAddress(Number, Street, Town, County, Postcode, Country); - _factory.Context.SaveChanges(); - - Operator op = _factory.Operators.AddOperator(FirstNames, Surname, DoB, FlyerNumber, OperatorNumber, address.Id); - Operator secondOp = _factory.Operators.AddOperator(SecondFirstNames, Surname, DoB, FlyerNumber, OperatorNumber, address.Id); - _factory.Context.SaveChanges(); - _operatorId = op.Id; - _secondOperatorId = secondOp.Id; - - Location location = _factory.Locations.AddLocation(LocationName); - Location secondLocation = _factory.Locations.AddLocation(SecondLocationName); - _factory.Context.SaveChanges(); - _locationId = location.Id; - _secondLocationId = secondLocation.Id; - - Manufacturer manufacturer = _factory.Manufacturers.AddManufacturer(ManufacturerName); - _factory.Context.SaveChanges(); - - Model model = _factory.Models.AddModel(ModelName, manufacturer.Id); - _factory.Context.SaveChanges(); - - Drone drone = _factory.Drones.AddDrone(DroneName, DroneSerialNumber, model.Id); - Drone secondDrone = _factory.Drones.AddDrone(SecondDroneName, SecondDroneSerialNumber, model.Id); - _factory.Context.SaveChanges(); - _droneId = drone.Id; - _secondDroneId = secondDrone.Id; - - Flight flight = _factory.Flights.AddFlight(op.Id, drone.Id, location.Id, StartDate, EndDate); - _factory.Context.SaveChanges(); - _flightId = flight.Id; - } - - [TestMethod] - public void GetFlightTest() - { - Flight flight = _factory.Flights.GetFlight(_flightId); - Assert.AreEqual(_flightId, flight.Id); - Assert.AreEqual(_droneId, flight.DroneId); - Assert.AreEqual(_locationId, flight.LocationId); - Assert.AreEqual(_operatorId, flight.OperatorId); - Assert.AreEqual(StartDate, flight.Start); - Assert.AreEqual(EndDate, flight.End); - } - - [TestMethod] - public async Task GetFlightAsyncTest() - { - Flight flight = await _factory.Flights.GetFlightAsync(_flightId); - Assert.AreEqual(_flightId, flight.Id); - Assert.AreEqual(_droneId, flight.DroneId); - Assert.AreEqual(_locationId, flight.LocationId); - Assert.AreEqual(_operatorId, flight.OperatorId); - Assert.AreEqual(StartDate, flight.Start); - Assert.AreEqual(EndDate, flight.End); - } - - [TestMethod, ExpectedException(typeof(FlightNotFoundException))] - public void GetMissingFlightByIdTest() - { - _factory.Flights.GetFlight(-1); - } - - [TestMethod] - public void AddFlightTest() - { - // The flight has been added during test initialisation. All that needs - // to be done here is to validate it - Assert.AreEqual(1, _factory.Context.Flights.Count()); - Assert.AreEqual(_flightId, _factory.Context.Flights.First().Id); - Assert.AreEqual(_droneId, _factory.Context.Flights.First().DroneId); - Assert.AreEqual(_locationId, _factory.Context.Flights.First().LocationId); - Assert.AreEqual(_operatorId, _factory.Context.Flights.First().OperatorId); - Assert.AreEqual(StartDate, _factory.Context.Flights.First().Start); - Assert.AreEqual(EndDate, _factory.Context.Flights.First().End); - } - - [TestMethod] - public async Task AddFlightAsyncTest() - { - Flight flight = await _factory.Flights.AddFlightAsync(_operatorId, _droneId, _locationId, StartDate, EndDate); - await _factory.Context.SaveChangesAsync(); - Assert.AreEqual(2, _factory.Context.Flights.Count()); - Assert.AreEqual(_droneId, flight.DroneId); - Assert.AreEqual(_locationId, flight.LocationId); - Assert.AreEqual(_operatorId, flight.OperatorId); - Assert.AreEqual(StartDate, flight.Start); - Assert.AreEqual(EndDate, flight.End); - } - - [TestMethod] - public void UpdateFlightTest() - { - DateTime start = StartDate.AddDays(-1); - DateTime end = EndDate.AddDays(-1); - _factory.Flights.UpdateFlight(_flightId, _secondOperatorId, _secondDroneId, _secondLocationId, start, end); - _factory.Context.SaveChanges(); - - Flight flight = _factory.Flights.GetFlight(_flightId); - Assert.AreEqual(_secondDroneId, flight.DroneId); - Assert.AreEqual(_secondLocationId, flight.LocationId); - Assert.AreEqual(_secondOperatorId, flight.OperatorId); - Assert.AreEqual(start, flight.Start); - Assert.AreEqual(end, flight.End); - } - - [TestMethod] - public async Task UpdateFlightAsyncTest() - { - DateTime start = StartDate.AddDays(-1); - DateTime end = EndDate.AddDays(-1); - await _factory.Flights.UpdateFlightAsync(_flightId, _secondOperatorId, _secondDroneId, _secondLocationId, start, end); - await _factory.Context.SaveChangesAsync(); - - Flight flight = await _factory.Flights.GetFlightAsync(_flightId); - Assert.AreEqual(_secondDroneId, flight.DroneId); - Assert.AreEqual(_secondLocationId, flight.LocationId); - Assert.AreEqual(_secondOperatorId, flight.OperatorId); - Assert.AreEqual(start, flight.Start); - Assert.AreEqual(end, flight.End); - } - - [TestMethod] - public void FindFlightByOperatorIdTest() - { - IEnumerable flights = _factory.Flights.FindFlights(_operatorId, null, null, null, null, 1, 2); - Assert.AreEqual(1, flights.Count()); - ValidateFlight(flights.First()); - } - - [TestMethod] - public async Task FindFlightByOperatorIdAsyncTest() - { - List flights = await _factory.Flights.FindFlightsAsync(_operatorId, null, null, null, null, 1, 2).ToListAsync(); - Assert.AreEqual(1, flights.Count()); - ValidateFlight(flights.First()); - } - - [TestMethod] - public void FindFlightByDroneIdTest() - { - IEnumerable flights = _factory.Flights.FindFlights(null, _droneId, null, null, null, 1, 2); - Assert.AreEqual(1, flights.Count()); - ValidateFlight(flights.First()); - } - - [TestMethod] - public void FindFlightByLocationIdTest() - { - IEnumerable flights = _factory.Flights.FindFlights(null, null, _locationId, null, null, 1, 2); - Assert.AreEqual(1, flights.Count()); - ValidateFlight(flights.First()); - } - - [TestMethod] - public void FindFlightByStartDateTest() - { - IEnumerable flights = _factory.Flights.FindFlights(null, null, null, StartDate, null, 1, 2); - Assert.AreEqual(1, flights.Count()); - ValidateFlight(flights.First()); - } - - [TestMethod] - public void FindFlightByEndDateTest() - { - IEnumerable flights = _factory.Flights.FindFlights(null, null, null, null, EndDate, 1, 2); - Assert.AreEqual(1, flights.Count()); - ValidateFlight(flights.First()); - } - - [TestMethod] - public void FindFlightByMultipleCriteriaTest() - { - IEnumerable flights = _factory.Flights.FindFlights(_operatorId, _droneId, _locationId, StartDate, EndDate, 1, 2); - Assert.AreEqual(1, flights.Count()); - ValidateFlight(flights.First()); - } - - #region Helpers - /// - /// Validate the properties of the specified flight - /// - /// - private void ValidateFlight(Flight flight) - { - Assert.AreEqual(_flightId, flight.Id); - Assert.AreEqual(_droneId, flight.DroneId); - Assert.AreEqual(_locationId, flight.LocationId); - Assert.AreEqual(_operatorId, flight.OperatorId); - } - #endregion - } -} +using System.Linq; +using System.Threading.Tasks; +using DroneFlightLog.Data.Entities; +using DroneFlightLog.Data.Exceptions; +using DroneFlightLog.Data.Factory; +using DroneFlightLog.Data.InMemory; +using DroneFlightLog.Data.Interfaces; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace DroneFlightLog.Data.Tests +{ + [TestClass] + public class FlightManagerTests + { + private const string Number = "1"; + private const string Street = "Some Street"; + private const string Town = "Some Town"; + private const string County = "Some County"; + private const string Postcode = "AB12 3CD"; + private const string Country = "Some Country"; + + private const string FirstNames = "First Names"; + private const string SecondFirstNames = "Second Operator First Names"; + private const string Surname = "Surname"; + private readonly DateTime DoB = DateTime.Now; + private const string FlyerNumber = "Some Flyer Number"; + private const string OperatorNumber = "Some Operator Number"; + + private const string LocationName = "My Local Drone Flight Location"; + private const string SecondLocationName = "My Second Local Drone Flight Location"; + + private const string ManufacturerName = "Some Manufacturer"; + private const string ModelName = "Some Model"; + private const string DroneName = "Some Drone"; + private const string SecondDroneName = "Some Other Drone"; + private const string DroneSerialNumber = "1234567890"; + private const string SecondDroneSerialNumber = "0987654321"; + + private readonly DateTime StartDate = DateTime.Now.AddMinutes(-5); + private readonly DateTime EndDate = DateTime.Now.AddMinutes(5); + + private IDroneFlightLogFactory _factory; + private int _operatorId; + private int _secondOperatorId; + private int _locationId; + private int _secondLocationId; + private int _droneId; + private int _secondDroneId; + private int _flightId; + + [TestInitialize] + public void TestInitialize() + { + DroneFlightLogDbContext context = new DroneFlightLogDbContextFactory().CreateDbContext(null); + _factory = new DroneFlightLogFactory(context); + + Address address = _factory.Addresses.AddAddress(Number, Street, Town, County, Postcode, Country); + _factory.Context.SaveChanges(); + + Operator op = _factory.Operators.AddOperator(FirstNames, Surname, DoB, FlyerNumber, OperatorNumber, address.Id); + Operator secondOp = _factory.Operators.AddOperator(SecondFirstNames, Surname, DoB, FlyerNumber, OperatorNumber, address.Id); + _factory.Context.SaveChanges(); + _operatorId = op.Id; + _secondOperatorId = secondOp.Id; + + Location location = _factory.Locations.AddLocation(LocationName); + Location secondLocation = _factory.Locations.AddLocation(SecondLocationName); + _factory.Context.SaveChanges(); + _locationId = location.Id; + _secondLocationId = secondLocation.Id; + + Manufacturer manufacturer = _factory.Manufacturers.AddManufacturer(ManufacturerName); + _factory.Context.SaveChanges(); + + Model model = _factory.Models.AddModel(ModelName, manufacturer.Id); + _factory.Context.SaveChanges(); + + Drone drone = _factory.Drones.AddDrone(DroneName, DroneSerialNumber, model.Id); + Drone secondDrone = _factory.Drones.AddDrone(SecondDroneName, SecondDroneSerialNumber, model.Id); + _factory.Context.SaveChanges(); + _droneId = drone.Id; + _secondDroneId = secondDrone.Id; + + Flight flight = _factory.Flights.AddFlight(op.Id, drone.Id, location.Id, StartDate, EndDate); + _factory.Context.SaveChanges(); + _flightId = flight.Id; + } + + [TestMethod] + public void GetFlightTest() + { + Flight flight = _factory.Flights.GetFlight(_flightId); + Assert.AreEqual(_flightId, flight.Id); + Assert.AreEqual(_droneId, flight.DroneId); + Assert.AreEqual(_locationId, flight.LocationId); + Assert.AreEqual(_operatorId, flight.OperatorId); + Assert.AreEqual(StartDate, flight.Start); + Assert.AreEqual(EndDate, flight.End); + } + + [TestMethod] + public async Task GetFlightAsyncTest() + { + Flight flight = await _factory.Flights.GetFlightAsync(_flightId); + Assert.AreEqual(_flightId, flight.Id); + Assert.AreEqual(_droneId, flight.DroneId); + Assert.AreEqual(_locationId, flight.LocationId); + Assert.AreEqual(_operatorId, flight.OperatorId); + Assert.AreEqual(StartDate, flight.Start); + Assert.AreEqual(EndDate, flight.End); + } + + [TestMethod, ExpectedException(typeof(FlightNotFoundException))] + public void GetMissingFlightByIdTest() + { + _factory.Flights.GetFlight(-1); + } + + [TestMethod] + public void AddFlightTest() + { + // The flight has been added during test initialisation. All that needs + // to be done here is to validate it + Assert.AreEqual(1, _factory.Context.Flights.Count()); + Assert.AreEqual(_flightId, _factory.Context.Flights.First().Id); + Assert.AreEqual(_droneId, _factory.Context.Flights.First().DroneId); + Assert.AreEqual(_locationId, _factory.Context.Flights.First().LocationId); + Assert.AreEqual(_operatorId, _factory.Context.Flights.First().OperatorId); + Assert.AreEqual(StartDate, _factory.Context.Flights.First().Start); + Assert.AreEqual(EndDate, _factory.Context.Flights.First().End); + } + + [TestMethod] + public async Task AddFlightAsyncTest() + { + Flight flight = await _factory.Flights.AddFlightAsync(_operatorId, _droneId, _locationId, StartDate, EndDate); + await _factory.Context.SaveChangesAsync(); + Assert.AreEqual(2, _factory.Context.Flights.Count()); + Assert.AreEqual(_droneId, flight.DroneId); + Assert.AreEqual(_locationId, flight.LocationId); + Assert.AreEqual(_operatorId, flight.OperatorId); + Assert.AreEqual(StartDate, flight.Start); + Assert.AreEqual(EndDate, flight.End); + } + + [TestMethod] + public void UpdateFlightTest() + { + DateTime start = StartDate.AddDays(-1); + DateTime end = EndDate.AddDays(-1); + _factory.Flights.UpdateFlight(_flightId, _secondOperatorId, _secondDroneId, _secondLocationId, start, end); + _factory.Context.SaveChanges(); + + Flight flight = _factory.Flights.GetFlight(_flightId); + Assert.AreEqual(_secondDroneId, flight.DroneId); + Assert.AreEqual(_secondLocationId, flight.LocationId); + Assert.AreEqual(_secondOperatorId, flight.OperatorId); + Assert.AreEqual(start, flight.Start); + Assert.AreEqual(end, flight.End); + } + + [TestMethod] + public async Task UpdateFlightAsyncTest() + { + DateTime start = StartDate.AddDays(-1); + DateTime end = EndDate.AddDays(-1); + await _factory.Flights.UpdateFlightAsync(_flightId, _secondOperatorId, _secondDroneId, _secondLocationId, start, end); + await _factory.Context.SaveChangesAsync(); + + Flight flight = await _factory.Flights.GetFlightAsync(_flightId); + Assert.AreEqual(_secondDroneId, flight.DroneId); + Assert.AreEqual(_secondLocationId, flight.LocationId); + Assert.AreEqual(_secondOperatorId, flight.OperatorId); + Assert.AreEqual(start, flight.Start); + Assert.AreEqual(end, flight.End); + } + + [TestMethod] + public void FindFlightByOperatorIdTest() + { + IEnumerable flights = _factory.Flights.FindFlights(_operatorId, null, null, null, null, 1, 2); + Assert.AreEqual(1, flights.Count()); + ValidateFlight(flights.First()); + } + + [TestMethod] + public async Task FindFlightByOperatorIdAsyncTest() + { + List flights = await _factory.Flights.FindFlightsAsync(_operatorId, null, null, null, null, 1, 2).ToListAsync(); + Assert.AreEqual(1, flights.Count()); + ValidateFlight(flights.First()); + } + + [TestMethod] + public void FindFlightByDroneIdTest() + { + IEnumerable flights = _factory.Flights.FindFlights(null, _droneId, null, null, null, 1, 2); + Assert.AreEqual(1, flights.Count()); + ValidateFlight(flights.First()); + } + + [TestMethod] + public void FindFlightByLocationIdTest() + { + IEnumerable flights = _factory.Flights.FindFlights(null, null, _locationId, null, null, 1, 2); + Assert.AreEqual(1, flights.Count()); + ValidateFlight(flights.First()); + } + + [TestMethod] + public void FindFlightByStartDateTest() + { + IEnumerable flights = _factory.Flights.FindFlights(null, null, null, StartDate, null, 1, 2); + Assert.AreEqual(1, flights.Count()); + ValidateFlight(flights.First()); + } + + [TestMethod] + public void FindFlightByEndDateTest() + { + IEnumerable flights = _factory.Flights.FindFlights(null, null, null, null, EndDate, 1, 2); + Assert.AreEqual(1, flights.Count()); + ValidateFlight(flights.First()); + } + + [TestMethod] + public void FindFlightByMultipleCriteriaTest() + { + IEnumerable flights = _factory.Flights.FindFlights(_operatorId, _droneId, _locationId, StartDate, EndDate, 1, 2); + Assert.AreEqual(1, flights.Count()); + ValidateFlight(flights.First()); + } + + #region Helpers + /// + /// Validate the properties of the specified flight + /// + /// + private void ValidateFlight(Flight flight) + { + Assert.AreEqual(_flightId, flight.Id); + Assert.AreEqual(_droneId, flight.DroneId); + Assert.AreEqual(_locationId, flight.LocationId); + Assert.AreEqual(_operatorId, flight.OperatorId); + } + #endregion + } +} diff --git a/src/DroneFlightLog.Data.Tests/FlightPropertyManagerTests.cs b/src/DroneFlightLog.Data.Tests/FlightPropertyManagerTests.cs index 47843f6..99728e5 100644 --- a/src/DroneFlightLog.Data.Tests/FlightPropertyManagerTests.cs +++ b/src/DroneFlightLog.Data.Tests/FlightPropertyManagerTests.cs @@ -1,295 +1,301 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using DroneFlightLog.Data.Entities; -using DroneFlightLog.Data.Exceptions; -using DroneFlightLog.Data.Factory; -using DroneFlightLog.Data.InMemory; -using DroneFlightLog.Data.Interfaces; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace DroneFlightLog.Data.Tests -{ - [TestClass] - public class FlightPropertyManagerTests - { - private const string Number = "1"; - private const string Street = "Some Street"; - private const string Town = "Some Town"; - private const string County = "Some County"; - private const string Postcode = "AB12 3CD"; - private const string Country = "Some Country"; - - private const string FirstNames = "First Names"; - private const string Surname = "Surname"; - private readonly DateTime DoB = DateTime.Now; - private const string FlyerNumber = "Some Flyer Number"; - private const string OperatorNumber = "Some Operator Number"; - - private const string LocationName = "My Local Drone Flight Location"; - - private const string ManufacturerName = "Some Manufacturer"; - private const string ModelName = "Some Model"; - private const string DroneName = "Some Drone"; - private const string DroneSerialNumber = "1234567890"; - - private const string PropertyName = "Wind Speed"; - private const string UpdatedPropertyName = "Updated Wind Speed"; - private const FlightPropertyDataType PropertyType = FlightPropertyDataType.Number; - private const decimal PropertyValue = 7.8M; - private const decimal UpdatedPropertyValue = 4.67M; - - private const string MultiInstancePropertyName = "Some Property"; - private const string DatePropertyName = "Some Date Property"; - private const string StringPropertyName = "Some String Property"; - private const string StringPropertyValue = "Some Value"; - - private const string AsyncPropertyName = "Some Async Property"; - private const decimal AsyncPropertyValue = 6.45M; - - private IDroneFlightLogFactory _factory; - private int _flightId; - private int _propertyId; - private int _propertyValueId; - - [TestInitialize] - public void TestInitialize() - { - DroneFlightLogDbContext context = new DroneFlightLogDbContextFactory().CreateDbContext(null); - _factory = new DroneFlightLogFactory(context); - - Address address = _factory.Addresses.AddAddress(Number, Street, Town, County, Postcode, Country); - _factory.Context.SaveChanges(); - - Operator op = _factory.Operators.AddOperator(FirstNames, Surname, DoB, FlyerNumber, OperatorNumber, address.Id); - _factory.Context.SaveChanges(); - - Location location = _factory.Locations.AddLocation(LocationName); - _factory.Context.SaveChanges(); - - Manufacturer manufacturer = _factory.Manufacturers.AddManufacturer(ManufacturerName); - _factory.Context.SaveChanges(); - - Model model = _factory.Models.AddModel(ModelName, manufacturer.Id); - _factory.Context.SaveChanges(); - - Drone drone = _factory.Drones.AddDrone(DroneName, DroneSerialNumber, model.Id); - _factory.Context.SaveChanges(); - - Flight flight = _factory.Flights.AddFlight(op.Id, drone.Id, location.Id, DateTime.Now, DateTime.Now); - _factory.Context.SaveChanges(); - _flightId = flight.Id; - - FlightProperty property = _factory.Properties.AddProperty(PropertyName, PropertyType, true); - _factory.Context.SaveChanges(); - _propertyId = property.Id; - - FlightPropertyValue value = _factory.Properties.AddPropertyValue(_flightId, _propertyId, PropertyValue); - _factory.Context.SaveChanges(); - _propertyValueId = value.Id; - } - - [TestMethod] - public void AddPropertyTest() - { - // The property has been added during test initialisation. All that needs - // to be done here is to validate it - Assert.AreEqual(1, _factory.Context.FlightProperties.Count()); - Assert.AreEqual(PropertyName, _factory.Context.FlightProperties.First().Name); - Assert.AreEqual(PropertyType, _factory.Context.FlightProperties.First().DataType); - Assert.IsTrue(_factory.Context.FlightProperties.First().IsSingleInstance); - } - - [TestMethod] - public async Task AddPropertyAsyncTest() - { - FlightProperty property = await _factory.Properties.AddPropertyAsync(AsyncPropertyName, PropertyType, true); - await _factory.Context.SaveChangesAsync(); - Assert.AreEqual(2, _factory.Context.FlightProperties.Count()); - Assert.AreEqual(AsyncPropertyName, property.Name); - Assert.AreEqual(PropertyType, property.DataType); - Assert.IsTrue(property.IsSingleInstance); - } - - [TestMethod, ExpectedException(typeof(PropertyExistsException))] - public void AddExistingPropertyTest() - { - _factory.Properties.AddProperty(PropertyName, PropertyType, true); - } - - [TestMethod] - public void GetPropertiesTest() - { - IEnumerable properties = _factory.Properties.GetProperties(); - Assert.AreEqual(1, properties.Count()); - Assert.AreEqual(PropertyName, properties.First().Name); - Assert.AreEqual(PropertyType, properties.First().DataType); - Assert.IsTrue(properties.First().IsSingleInstance); - } - - [TestMethod] - public async Task GetPropertiesAsyncTest() - { - List properties = await _factory.Properties.GetPropertiesAsync().ToListAsync(); - Assert.AreEqual(1, properties.Count()); - Assert.AreEqual(PropertyName, properties.First().Name); - Assert.AreEqual(PropertyType, properties.First().DataType); - Assert.IsTrue(properties.First().IsSingleInstance); - } - - [TestMethod] - public void UpdatePropertyTest() - { - _factory.Properties.UpdateProperty(_propertyId, UpdatedPropertyName); - _factory.Context.SaveChanges(); - FlightProperty property = _factory.Properties.GetProperties().First(p => p.Id == _propertyId); - Assert.AreEqual(UpdatedPropertyName, property.Name); - } - - [TestMethod] - public async Task UpdatePropertyAsyncTest() - { - await _factory.Properties.UpdatePropertyAsync(_propertyId, UpdatedPropertyName); - await _factory.Context.SaveChangesAsync(); - FlightProperty property = _factory.Properties.GetProperties().First(p => p.Id == _propertyId); - Assert.AreEqual(UpdatedPropertyName, property.Name); - } - - [TestMethod] - public void AddPropertyValueTest() - { - // The property has been added during test initialisation. All that needs - // to be done here is to validate it - Assert.AreEqual(1, _factory.Context.FlightPropertyValues.Count()); - Assert.AreEqual(_flightId, _factory.Context.FlightPropertyValues.First().FlightId); - Assert.AreEqual(_propertyId, _factory.Context.FlightPropertyValues.First().PropertyId); - Assert.AreEqual(PropertyValue, _factory.Context.FlightPropertyValues.First().NumberValue); - } - - [TestMethod] - public async Task AddPropertyValueAsyncTest() - { - // To allow this to work, we need to make the existing property multi-value - _factory.Context.FlightProperties.First(p => p.Id == _propertyId).IsSingleInstance = false; - await _factory.Context.SaveChangesAsync(); - - FlightPropertyValue value = await _factory.Properties.AddPropertyValueAsync(_flightId, _propertyId, AsyncPropertyValue); - await _factory.Context.SaveChangesAsync(); - Assert.AreEqual(2, _factory.Context.FlightPropertyValues.Count()); - Assert.AreEqual(_flightId, value.FlightId); - Assert.AreEqual(_propertyId, value.PropertyId); - Assert.AreEqual(AsyncPropertyValue, value.NumberValue); - } - - [TestMethod] - public void GetPropertyValueTest() - { - FlightPropertyValue value = _factory.Properties.GetPropertyValue(_propertyValueId); - Assert.AreEqual(_flightId, value.FlightId); - Assert.AreEqual(_propertyId, value.PropertyId); - Assert.AreEqual(PropertyValue, value.NumberValue); - } - - [TestMethod] - public async Task GetPropertyValueAsyncTest() - { - FlightPropertyValue value = await _factory.Properties.GetPropertyValueAsync(_propertyValueId); - Assert.AreEqual(_flightId, value.FlightId); - Assert.AreEqual(_propertyId, value.PropertyId); - Assert.AreEqual(PropertyValue, value.NumberValue); - } - - [TestMethod] - public void UpdatePropertyValueTest() - { - _factory.Properties.UpdatePropertyValue(_propertyValueId, UpdatedPropertyValue); - _factory.Context.SaveChanges(); - FlightPropertyValue value = _factory.Properties.GetPropertyValues(_flightId).First(v => v.Id == _propertyValueId); - Assert.AreEqual(UpdatedPropertyValue, value.NumberValue); - } - - [TestMethod] - public async Task UpdatePropertyValueAsyncTest() - { - await _factory.Properties.UpdatePropertyValueAsync(_propertyValueId, UpdatedPropertyValue); - await _factory.Context.SaveChangesAsync(); - FlightPropertyValue value = await _factory.Properties.GetPropertyValuesAsync(_flightId).FirstAsync(v => v.Id == _propertyValueId); - Assert.AreEqual(UpdatedPropertyValue, value.NumberValue); - } - - [TestMethod, ExpectedException(typeof(ValueExistsException))] - public void AddDuplicateSingleInstanceValueTest() - { - _factory.Properties.AddPropertyValue(_flightId, _propertyId, PropertyValue); - } - - [TestMethod] - public void GetPropertyValuesTest() - { - IEnumerable values = _factory.Properties.GetPropertyValues(_flightId); - Assert.AreEqual(1, values.Count()); - Assert.AreEqual(_flightId, values.First().FlightId); - Assert.AreEqual(_propertyId, values.First().PropertyId); - Assert.AreEqual(PropertyValue, values.First().NumberValue); - } - - [TestMethod] - public async Task GetPropertyValuesAsyncTest() - { - List values = await _factory.Properties.GetPropertyValuesAsync(_flightId).ToListAsync(); - Assert.AreEqual(1, values.Count()); - Assert.AreEqual(_flightId, values.First().FlightId); - Assert.AreEqual(_propertyId, values.First().PropertyId); - Assert.AreEqual(PropertyValue, values.First().NumberValue); - } - - [TestMethod] - public void GetPropertyValuesForMissingFlightTest() - { - IEnumerable values = _factory.Properties.GetPropertyValues(-1); - Assert.IsFalse(values.Any()); - } - - [TestMethod] - public void AddMultiInstancePropertyValuesTest() - { - FlightProperty property = _factory.Properties.AddProperty(MultiInstancePropertyName, PropertyType, false); - _factory.Context.SaveChanges(); - - _factory.Properties.AddPropertyValue(_flightId, property.Id, 1.0M); - _factory.Properties.AddPropertyValue(_flightId, property.Id, 2.0M); - _factory.Context.SaveChanges(); - - IEnumerable values = _factory.Properties.GetPropertyValues(_flightId); - Assert.AreEqual(3, values.Count()); - } - - [TestMethod] - public void AddDatePropertyValueTest() - { - FlightProperty property = _factory.Properties.AddProperty(DatePropertyName, FlightPropertyDataType.Date, true); - _factory.Context.SaveChanges(); - - DateTime date = DateTime.Now; - _factory.Properties.AddPropertyValue(_flightId, property.Id, date); - _factory.Context.SaveChanges(); - - FlightPropertyValue value = _factory.Properties.GetPropertyValues(_flightId).First(v => v.PropertyId == property.Id); - Assert.AreEqual(value.DateValue, date); - } - - [TestMethod] - public void AddStringPropertyValueTest() - { - FlightProperty property = _factory.Properties.AddProperty(StringPropertyName, FlightPropertyDataType.String, true); - _factory.Context.SaveChanges(); - - _factory.Properties.AddPropertyValue(_flightId, property.Id, StringPropertyValue); - _factory.Context.SaveChanges(); - - FlightPropertyValue value = _factory.Properties.GetPropertyValues(_flightId).First(v => v.PropertyId == property.Id); - Assert.AreEqual(value.StringValue, StringPropertyValue); - } - } -} +using System.Linq; +using System.Threading.Tasks; +using DroneFlightLog.Data.Entities; +using DroneFlightLog.Data.Exceptions; +using DroneFlightLog.Data.Factory; +using DroneFlightLog.Data.InMemory; +using DroneFlightLog.Data.Interfaces; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace DroneFlightLog.Data.Tests +{ + [TestClass] + public class FlightPropertyManagerTests + { + private const string Number = "1"; + private const string Street = "Some Street"; + private const string Town = "Some Town"; + private const string County = "Some County"; + private const string Postcode = "AB12 3CD"; + private const string Country = "Some Country"; + + private const string FirstNames = "First Names"; + private const string Surname = "Surname"; + private readonly DateTime DoB = DateTime.Now; + private const string FlyerNumber = "Some Flyer Number"; + private const string OperatorNumber = "Some Operator Number"; + + private const string LocationName = "My Local Drone Flight Location"; + + private const string ManufacturerName = "Some Manufacturer"; + private const string ModelName = "Some Model"; + private const string DroneName = "Some Drone"; + private const string DroneSerialNumber = "1234567890"; + + private const string PropertyName = "Wind Speed"; + private const string UpdatedPropertyName = "Updated Wind Speed"; + private const FlightPropertyDataType PropertyType = FlightPropertyDataType.Number; + private const decimal PropertyValue = 7.8M; + private const decimal UpdatedPropertyValue = 4.67M; + + private const string MultiInstancePropertyName = "Some Property"; + private const string DatePropertyName = "Some Date Property"; + private const string StringPropertyName = "Some String Property"; + private const string StringPropertyValue = "Some Value"; + + private const string AsyncPropertyName = "Some Async Property"; + private const decimal AsyncPropertyValue = 6.45M; + + private IDroneFlightLogFactory _factory; + private int _flightId; + private int _propertyId; + private int _propertyValueId; + + [TestInitialize] + public void TestInitialize() + { + DroneFlightLogDbContext context = new DroneFlightLogDbContextFactory().CreateDbContext(null); + _factory = new DroneFlightLogFactory(context); + + Address address = _factory.Addresses.AddAddress(Number, Street, Town, County, Postcode, Country); + _factory.Context.SaveChanges(); + + Operator op = _factory.Operators.AddOperator(FirstNames, Surname, DoB, FlyerNumber, OperatorNumber, address.Id); + _factory.Context.SaveChanges(); + + Location location = _factory.Locations.AddLocation(LocationName); + _factory.Context.SaveChanges(); + + Manufacturer manufacturer = _factory.Manufacturers.AddManufacturer(ManufacturerName); + _factory.Context.SaveChanges(); + + Model model = _factory.Models.AddModel(ModelName, manufacturer.Id); + _factory.Context.SaveChanges(); + + Drone drone = _factory.Drones.AddDrone(DroneName, DroneSerialNumber, model.Id); + _factory.Context.SaveChanges(); + + Flight flight = _factory.Flights.AddFlight(op.Id, drone.Id, location.Id, DateTime.Now, DateTime.Now); + _factory.Context.SaveChanges(); + _flightId = flight.Id; + + FlightProperty property = _factory.Properties.AddProperty(PropertyName, PropertyType, true); + _factory.Context.SaveChanges(); + _propertyId = property.Id; + + FlightPropertyValue value = _factory.Properties.AddPropertyValue(_flightId, _propertyId, PropertyValue); + _factory.Context.SaveChanges(); + _propertyValueId = value.Id; + } + + [TestMethod] + public void AddPropertyTest() + { + // The property has been added during test initialisation. All that needs + // to be done here is to validate it + Assert.AreEqual(1, _factory.Context.FlightProperties.Count()); + Assert.AreEqual(PropertyName, _factory.Context.FlightProperties.First().Name); + Assert.AreEqual(PropertyType, _factory.Context.FlightProperties.First().DataType); + Assert.IsTrue(_factory.Context.FlightProperties.First().IsSingleInstance); + } + + [TestMethod] + public async Task AddPropertyAsyncTest() + { + FlightProperty property = await _factory.Properties.AddPropertyAsync(AsyncPropertyName, PropertyType, true); + await _factory.Context.SaveChangesAsync(); + Assert.AreEqual(2, _factory.Context.FlightProperties.Count()); + Assert.AreEqual(AsyncPropertyName, property.Name); + Assert.AreEqual(PropertyType, property.DataType); + Assert.IsTrue(property.IsSingleInstance); + } + + [TestMethod, ExpectedException(typeof(PropertyExistsException))] + public void AddExistingPropertyTest() + { + _factory.Properties.AddProperty(PropertyName, PropertyType, true); + } + + [TestMethod] + public void GetPropertiesTest() + { + IEnumerable properties = _factory.Properties.GetProperties(); + Assert.AreEqual(1, properties.Count()); + Assert.AreEqual(PropertyName, properties.First().Name); + Assert.AreEqual(PropertyType, properties.First().DataType); + Assert.IsTrue(properties.First().IsSingleInstance); + } + + [TestMethod] + public async Task GetPropertiesAsyncTest() + { + List properties = await _factory.Properties.GetPropertiesAsync().ToListAsync(); + Assert.AreEqual(1, properties.Count()); + Assert.AreEqual(PropertyName, properties.First().Name); + Assert.AreEqual(PropertyType, properties.First().DataType); + Assert.IsTrue(properties.First().IsSingleInstance); + } + + [TestMethod] + public void UpdatePropertyTest() + { + _factory.Properties.UpdateProperty(_propertyId, UpdatedPropertyName); + _factory.Context.SaveChanges(); + FlightProperty property = _factory.Properties.GetProperties().First(p => p.Id == _propertyId); + Assert.AreEqual(UpdatedPropertyName, property.Name); + } + + [TestMethod] + public async Task UpdatePropertyAsyncTest() + { + await _factory.Properties.UpdatePropertyAsync(_propertyId, UpdatedPropertyName); + await _factory.Context.SaveChangesAsync(); + FlightProperty property = _factory.Properties.GetProperties().First(p => p.Id == _propertyId); + Assert.AreEqual(UpdatedPropertyName, property.Name); + } + + [TestMethod] + public void AddPropertyValueTest() + { + // The property has been added during test initialisation. All that needs + // to be done here is to validate it + Assert.AreEqual(1, _factory.Context.FlightPropertyValues.Count()); + Assert.AreEqual(_flightId, _factory.Context.FlightPropertyValues.First().FlightId); + Assert.AreEqual(_propertyId, _factory.Context.FlightPropertyValues.First().PropertyId); + Assert.AreEqual(PropertyValue, _factory.Context.FlightPropertyValues.First().NumberValue); + } + + [TestMethod] + public async Task AddPropertyValueAsyncTest() + { + // To allow this to work, we need to make the existing property multi-value + _factory.Context.FlightProperties.First(p => p.Id == _propertyId).IsSingleInstance = false; + await _factory.Context.SaveChangesAsync(); + + FlightPropertyValue value = await _factory.Properties.AddPropertyValueAsync(_flightId, _propertyId, AsyncPropertyValue); + await _factory.Context.SaveChangesAsync(); + Assert.AreEqual(2, _factory.Context.FlightPropertyValues.Count()); + Assert.AreEqual(_flightId, value.FlightId); + Assert.AreEqual(_propertyId, value.PropertyId); + Assert.AreEqual(AsyncPropertyValue, value.NumberValue); + } + + [TestMethod] + public void GetPropertyValueTest() + { + FlightPropertyValue value = _factory.Properties.GetPropertyValue(_propertyValueId); + Assert.AreEqual(_flightId, value.FlightId); + Assert.AreEqual(_propertyId, value.PropertyId); + Assert.AreEqual(PropertyValue, value.NumberValue); + } + + [TestMethod] + public async Task GetPropertyValueAsyncTest() + { + FlightPropertyValue value = await _factory.Properties.GetPropertyValueAsync(_propertyValueId); + Assert.AreEqual(_flightId, value.FlightId); + Assert.AreEqual(_propertyId, value.PropertyId); + Assert.AreEqual(PropertyValue, value.NumberValue); + } + + [TestMethod] + public void UpdatePropertyValueTest() + { + _factory.Properties.UpdatePropertyValue(_propertyValueId, UpdatedPropertyValue); + _factory.Context.SaveChanges(); + FlightPropertyValue value = _factory.Properties.GetPropertyValues(_flightId).First(v => v.Id == _propertyValueId); + Assert.AreEqual(UpdatedPropertyValue, value.NumberValue); + } + + [TestMethod] + public async Task UpdatePropertyValueAsyncTest() + { + await _factory.Properties.UpdatePropertyValueAsync(_propertyValueId, UpdatedPropertyValue); + await _factory.Context.SaveChangesAsync(); + FlightPropertyValue value = await _factory.Properties.GetPropertyValuesAsync(_flightId).FirstAsync(v => v.Id == _propertyValueId); + Assert.AreEqual(UpdatedPropertyValue, value.NumberValue); + } + + [TestMethod, ExpectedException(typeof(ValueExistsException))] + public void AddDuplicateSingleInstanceValueTest() + { + _factory.Properties.AddPropertyValue(_flightId, _propertyId, PropertyValue); + } + + [TestMethod, ExpectedException(typeof(ValueExistsException))] + public async Task AddDuplicateSingleInstanceValueAsyncTest() + { + await _factory.Properties.AddPropertyValueAsync(_flightId, _propertyId, PropertyValue); + } + + [TestMethod] + public void GetPropertyValuesTest() + { + IEnumerable values = _factory.Properties.GetPropertyValues(_flightId); + Assert.AreEqual(1, values.Count()); + Assert.AreEqual(_flightId, values.First().FlightId); + Assert.AreEqual(_propertyId, values.First().PropertyId); + Assert.AreEqual(PropertyValue, values.First().NumberValue); + } + + [TestMethod] + public async Task GetPropertyValuesAsyncTest() + { + List values = await _factory.Properties.GetPropertyValuesAsync(_flightId).ToListAsync(); + Assert.AreEqual(1, values.Count()); + Assert.AreEqual(_flightId, values.First().FlightId); + Assert.AreEqual(_propertyId, values.First().PropertyId); + Assert.AreEqual(PropertyValue, values.First().NumberValue); + } + + [TestMethod] + public void GetPropertyValuesForMissingFlightTest() + { + IEnumerable values = _factory.Properties.GetPropertyValues(-1); + Assert.IsFalse(values.Any()); + } + + [TestMethod] + public void AddMultiInstancePropertyValuesTest() + { + FlightProperty property = _factory.Properties.AddProperty(MultiInstancePropertyName, PropertyType, false); + _factory.Context.SaveChanges(); + + _factory.Properties.AddPropertyValue(_flightId, property.Id, 1.0M); + _factory.Properties.AddPropertyValue(_flightId, property.Id, 2.0M); + _factory.Context.SaveChanges(); + + IEnumerable values = _factory.Properties.GetPropertyValues(_flightId); + Assert.AreEqual(3, values.Count()); + } + + [TestMethod] + public void AddDatePropertyValueTest() + { + FlightProperty property = _factory.Properties.AddProperty(DatePropertyName, FlightPropertyDataType.Date, true); + _factory.Context.SaveChanges(); + + DateTime date = DateTime.Now; + _factory.Properties.AddPropertyValue(_flightId, property.Id, date); + _factory.Context.SaveChanges(); + + FlightPropertyValue value = _factory.Properties.GetPropertyValues(_flightId).First(v => v.PropertyId == property.Id); + Assert.AreEqual(value.DateValue, date); + } + + [TestMethod] + public void AddStringPropertyValueTest() + { + FlightProperty property = _factory.Properties.AddProperty(StringPropertyName, FlightPropertyDataType.String, true); + _factory.Context.SaveChanges(); + + _factory.Properties.AddPropertyValue(_flightId, property.Id, StringPropertyValue); + _factory.Context.SaveChanges(); + + FlightPropertyValue value = _factory.Properties.GetPropertyValues(_flightId).First(v => v.PropertyId == property.Id); + Assert.AreEqual(value.StringValue, StringPropertyValue); + } + } +} diff --git a/src/DroneFlightLog.Data.Tests/LocationManagerTests.cs b/src/DroneFlightLog.Data.Tests/LocationManagerTests.cs index d7d2149..df095d0 100644 --- a/src/DroneFlightLog.Data.Tests/LocationManagerTests.cs +++ b/src/DroneFlightLog.Data.Tests/LocationManagerTests.cs @@ -1,141 +1,141 @@ using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using DroneFlightLog.Data.Entities; -using DroneFlightLog.Data.Exceptions; -using DroneFlightLog.Data.Factory; -using DroneFlightLog.Data.InMemory; -using DroneFlightLog.Data.Interfaces; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace DroneFlightLog.Data.Tests -{ - [TestClass] - public class LocationManagerTests - { - private const string Name = "My Local Drone Flight Location"; - private const string UpdatedName = "My Other Local Drone Flight Location"; - private const string AsyncName = "My Local Async Drone Flight Location"; - - private IDroneFlightLogFactory _factory; - private int _locationId; - - [TestInitialize] - public void TestInitialize() - { - DroneFlightLogDbContext context = new DroneFlightLogDbContextFactory().CreateDbContext(null); - _factory = new DroneFlightLogFactory(context); - - Location location = _factory.Locations.AddLocation(Name); - _factory.Context.SaveChanges(); - _locationId = location.Id; - } - - [TestMethod] - public void AddLocationTest() - { - // The location has been added during test initialisation. All that needs - // to be done here is to validate it - Assert.AreEqual(1, _factory.Context.Locations.Count()); - Assert.AreEqual(Name, _factory.Context.Locations.First().Name); - } - - [TestMethod] - public async Task AddLocationAsyncTest() - { - Location location = _factory.Locations.AddLocation(AsyncName); - await _factory.Context.SaveChangesAsync(); - Assert.AreEqual(2, _factory.Context.Locations.Count()); - Assert.AreEqual(AsyncName, location.Name); - } - - [TestMethod, ExpectedException(typeof(LocationExistsException))] - public void AddExistingLocationTest() - { - _factory.Locations.AddLocation(Name); - } - - [TestMethod] - public void GetLocationByIdTest() - { - Location location = _factory.Locations.GetLocation(_locationId); - Assert.AreEqual(_locationId, location.Id); - Assert.AreEqual(Name, location.Name); - } - - [TestMethod] - public async Task GetLocationByIdAsyncTest() - { - Location location = await _factory.Locations.GetLocationAsync(_locationId); - Assert.AreEqual(_locationId, location.Id); - Assert.AreEqual(Name, location.Name); - } - - [TestMethod, ExpectedException(typeof(LocationNotFoundException))] - public void GetMissingLocationByIdTest() - { - _factory.Locations.GetLocation(-1); - } - - [TestMethod] - public void UpdateLocationTest() - { - _factory.Locations.UpdateLocation(_locationId, UpdatedName); - _factory.Context.SaveChanges(); - Location location = _factory.Locations.GetLocation(_locationId); - Assert.AreEqual(_locationId, location.Id); - Assert.AreEqual(UpdatedName, location.Name); - } - - [TestMethod] - public async Task UpdateManufacturerAsyncTest() - { - await _factory.Locations.UpdateLocationAsync(_locationId, UpdatedName); - await _factory.Context.SaveChangesAsync(); - Location location = await _factory.Locations.GetLocationAsync(_locationId); - Assert.AreEqual(_locationId, location.Id); - Assert.AreEqual(UpdatedName, location.Name); - } - - [TestMethod] - public void GetAllLocationsTest() - { - IEnumerable locations = _factory.Locations.GetLocations(); - Assert.AreEqual(1, locations.Count()); - int locationId = _factory.Context.Locations.First().Id; - Assert.AreEqual(locationId, locations.First().Id); - Assert.AreEqual(Name, locations.First().Name); - } - - [TestMethod] - public async Task GetAllLocationsAsyncTest() - { - List locations = await _factory.Locations.GetLocationsAsync().ToListAsync(); - Assert.AreEqual(1, locations.Count()); - int locationId = _factory.Context.Locations.First().Id; - Assert.AreEqual(locationId, locations.First().Id); - Assert.AreEqual(Name, locations.First().Name); - } - - [TestMethod] - public void FindLocationTest() - { - Location location = _factory.Locations.FindLocation(Name); - Assert.AreEqual(location.Name, Name); - } - - [TestMethod] - public async Task FindLocationAsyncTest() - { - Location location = await _factory.Locations.FindLocationAsync(Name); - Assert.AreEqual(location.Name, Name); - } - - [TestMethod] - public void FindMissingLocationTest() - { - Location location = _factory.Locations.FindLocation("Missing"); - Assert.IsNull(location); - } - } -} +using System.Linq; +using System.Threading.Tasks; +using DroneFlightLog.Data.Entities; +using DroneFlightLog.Data.Exceptions; +using DroneFlightLog.Data.Factory; +using DroneFlightLog.Data.InMemory; +using DroneFlightLog.Data.Interfaces; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace DroneFlightLog.Data.Tests +{ + [TestClass] + public class LocationManagerTests + { + private const string Name = "My Local Drone Flight Location"; + private const string UpdatedName = "My Other Local Drone Flight Location"; + private const string AsyncName = "My Local Async Drone Flight Location"; + + private IDroneFlightLogFactory _factory; + private int _locationId; + + [TestInitialize] + public void TestInitialize() + { + DroneFlightLogDbContext context = new DroneFlightLogDbContextFactory().CreateDbContext(null); + _factory = new DroneFlightLogFactory(context); + + Location location = _factory.Locations.AddLocation(Name); + _factory.Context.SaveChanges(); + _locationId = location.Id; + } + + [TestMethod] + public void AddLocationTest() + { + // The location has been added during test initialisation. All that needs + // to be done here is to validate it + Assert.AreEqual(1, _factory.Context.Locations.Count()); + Assert.AreEqual(Name, _factory.Context.Locations.First().Name); + } + + [TestMethod] + public async Task AddLocationAsyncTest() + { + Location location = await _factory.Locations.AddLocationAsync(AsyncName); + await _factory.Context.SaveChangesAsync(); + Assert.AreEqual(2, _factory.Context.Locations.Count()); + Assert.AreEqual(AsyncName, location.Name); + } + + [TestMethod, ExpectedException(typeof(LocationExistsException))] + public void AddExistingLocationTest() + { + _factory.Locations.AddLocation(Name); + } + + [TestMethod] + public void GetLocationByIdTest() + { + Location location = _factory.Locations.GetLocation(_locationId); + Assert.AreEqual(_locationId, location.Id); + Assert.AreEqual(Name, location.Name); + } + + [TestMethod] + public async Task GetLocationByIdAsyncTest() + { + Location location = await _factory.Locations.GetLocationAsync(_locationId); + Assert.AreEqual(_locationId, location.Id); + Assert.AreEqual(Name, location.Name); + } + + [TestMethod, ExpectedException(typeof(LocationNotFoundException))] + public void GetMissingLocationByIdTest() + { + _factory.Locations.GetLocation(-1); + } + + [TestMethod] + public void UpdateLocationTest() + { + _factory.Locations.UpdateLocation(_locationId, UpdatedName); + _factory.Context.SaveChanges(); + Location location = _factory.Locations.GetLocation(_locationId); + Assert.AreEqual(_locationId, location.Id); + Assert.AreEqual(UpdatedName, location.Name); + } + + [TestMethod] + public async Task UpdateManufacturerAsyncTest() + { + await _factory.Locations.UpdateLocationAsync(_locationId, UpdatedName); + await _factory.Context.SaveChangesAsync(); + Location location = await _factory.Locations.GetLocationAsync(_locationId); + Assert.AreEqual(_locationId, location.Id); + Assert.AreEqual(UpdatedName, location.Name); + } + + [TestMethod] + public void GetAllLocationsTest() + { + IEnumerable locations = _factory.Locations.GetLocations(); + Assert.AreEqual(1, locations.Count()); + int locationId = _factory.Context.Locations.First().Id; + Assert.AreEqual(locationId, locations.First().Id); + Assert.AreEqual(Name, locations.First().Name); + } + + [TestMethod] + public async Task GetAllLocationsAsyncTest() + { + List locations = await _factory.Locations.GetLocationsAsync().ToListAsync(); + Assert.AreEqual(1, locations.Count()); + int locationId = _factory.Context.Locations.First().Id; + Assert.AreEqual(locationId, locations.First().Id); + Assert.AreEqual(Name, locations.First().Name); + } + + [TestMethod] + public void FindLocationTest() + { + Location location = _factory.Locations.FindLocation(Name); + Assert.AreEqual(location.Name, Name); + } + + [TestMethod] + public async Task FindLocationAsyncTest() + { + Location location = await _factory.Locations.FindLocationAsync(Name); + Assert.AreEqual(location.Name, Name); + } + + [TestMethod] + public void FindMissingLocationTest() + { + Location location = _factory.Locations.FindLocation("Missing"); + Assert.IsNull(location); + } + } +} diff --git a/src/DroneFlightLog.Data.Tests/OperatorManagerTests.cs b/src/DroneFlightLog.Data.Tests/OperatorManagerTests.cs index c3aa21a..faa9a0e 100644 --- a/src/DroneFlightLog.Data.Tests/OperatorManagerTests.cs +++ b/src/DroneFlightLog.Data.Tests/OperatorManagerTests.cs @@ -162,6 +162,14 @@ public void GetAllOperatorsForAddressTest() ValidateOperator(operators.First(), _operatorId, _firstAddressId); } + [TestMethod] + public async Task GetAllOperatorsForAddressAsyncTest() + { + IEnumerable operators = await _factory.Operators.GetOperatorsAsync(_firstAddressId).ToListAsync(); + Assert.AreEqual(1, operators.Count()); + ValidateOperator(operators.First(), _operatorId, _firstAddressId); + } + [TestMethod] public void GetAllOperatorsForMissingAddressTest() { From b29a503bfd7b03ddfcca6e6b1a51fb6ddb514ca5 Mon Sep 17 00:00:00 2001 From: Dave Walker Date: Mon, 11 Mar 2024 16:29:47 +0000 Subject: [PATCH 03/12] Added the maintenance record management class --- .../MaintenanceRecordManagerTests.cs | 301 +++++++ .../Entities/MaintenanceRecord.cs | 1 + .../Entities/MaintenanceRecordType.cs | 8 + .../MaintenanceRecordNotFoundException.cs | 21 + .../Factory/DroneFlightLogFactory.cs | 3 + .../Interfaces/IDroneFlightLogFactory.cs | 1 + .../Interfaces/IMaintenanceRecordManager.cs | 19 + .../Logic/FlightPropertyManager.cs | 746 +++++++++--------- .../Logic/MaintenanceRecordManager.cs | 223 ++++++ src/DroneFlightLog.Data/Logic/UserManager.cs | 478 +++++------ 10 files changed, 1189 insertions(+), 612 deletions(-) create mode 100644 src/DroneFlightLog.Data.Tests/MaintenanceRecordManagerTests.cs create mode 100644 src/DroneFlightLog.Data/Entities/MaintenanceRecordType.cs create mode 100644 src/DroneFlightLog.Data/Exceptions/MaintenanceRecordNotFoundException.cs create mode 100644 src/DroneFlightLog.Data/Interfaces/IMaintenanceRecordManager.cs create mode 100644 src/DroneFlightLog.Data/Logic/MaintenanceRecordManager.cs diff --git a/src/DroneFlightLog.Data.Tests/MaintenanceRecordManagerTests.cs b/src/DroneFlightLog.Data.Tests/MaintenanceRecordManagerTests.cs new file mode 100644 index 0000000..955dba1 --- /dev/null +++ b/src/DroneFlightLog.Data.Tests/MaintenanceRecordManagerTests.cs @@ -0,0 +1,301 @@ +using DroneFlightLog.Data.Entities; +using DroneFlightLog.Data.Exceptions; +using DroneFlightLog.Data.Factory; +using DroneFlightLog.Data.InMemory; +using DroneFlightLog.Data.Interfaces; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DroneFlightLog.Data.Tests +{ + [TestClass] + public class MaintenanceRecordManagerTests + { + private const string MaintainerFirstNames = "A"; + private const string SecondMaintainerFirstNames = "Another"; + private const string MaintainerSurname = "Maintainer"; + + private const string MaintenanceRecordDescription = "Some Maintenance Work"; + private const string MaintenanceRecordNotes = "Did some maintenance work"; + + private const string ModificationRecordDescription = "A Modification"; + private const string ModificationRecordNotes = "Did some modification work"; + + private const string ManufacturerName = "Holy Stone"; + private const string ModelName = "HS165"; + private const string DroneName = "My Drone"; + private const string DroneSerialNumber = "0123456789"; + + private IDroneFlightLogFactory _factory; + private int _droneId; + private int _firstMaintainerId; + private int _secondMaintainerId; + private int _maintenanceRecordId; + + [TestInitialize] + public void TestInitialise() + { + var context = new DroneFlightLogDbContextFactory().CreateDbContext(null); + _factory = new DroneFlightLogFactory(context); + + var manufacturer = _factory.Manufacturers.AddManufacturer(ManufacturerName); + _factory.Context.SaveChanges(); + + var model = _factory.Models.AddModel(ModelName, manufacturer.Id); + _factory.Context.SaveChanges(); + + var drone = _factory.Drones.AddDrone(DroneName, DroneSerialNumber, model.Id); + _factory.Context.SaveChanges(); + _droneId = drone.Id; + + var maintainer = _factory.Maintainers.AddMaintainer(MaintainerFirstNames, MaintainerSurname); + _factory.Context.SaveChanges(); + _firstMaintainerId = maintainer.Id; + + maintainer = _factory.Maintainers.AddMaintainer(SecondMaintainerFirstNames, MaintainerSurname); + _factory.Context.SaveChanges(); + _secondMaintainerId = maintainer.Id; + + var maintenanceRecord = _factory.MaintenanceRecords.AddMaintenanceRecord(_firstMaintainerId, _droneId, MaintenanceRecordType.Maintenance, DateTime.Now, MaintenanceRecordDescription, MaintenanceRecordNotes); + _factory.Context.SaveChanges(); + _maintenanceRecordId = maintenanceRecord.Id; + } + + [TestMethod] + public void AddMaintenanceRecordTest() + { + // The maintainer has been added during test initialisation. All that needs + // to be done here is to validate it + Assert.AreEqual(1, _factory.Context.MaintenanceRecords.Count()); + Assert.AreEqual(_firstMaintainerId, _factory.Context.MaintenanceRecords.First().MaintainerId); + Assert.AreEqual(_droneId, _factory.Context.MaintenanceRecords.First().DroneId); + Assert.AreEqual(MaintenanceRecordType.Maintenance, _factory.Context.MaintenanceRecords.First().RecordType); + Assert.AreEqual(MaintenanceRecordDescription, _factory.Context.MaintenanceRecords.First().Description); + Assert.AreEqual(MaintenanceRecordNotes, _factory.Context.MaintenanceRecords.First().Notes); + } + + [TestMethod] + public async Task AddMaintenanceRecordAsyncTest() + { + var maintenanceRecord = await _factory.MaintenanceRecords.AddMaintenanceRecordAsync(_secondMaintainerId, _droneId, MaintenanceRecordType.Modification, DateTime.Now, ModificationRecordDescription, ModificationRecordNotes); + await _factory.Context.SaveChangesAsync(); + + Assert.AreEqual(2, _factory.Context.MaintenanceRecords.Count()); + Assert.AreEqual(_secondMaintainerId, maintenanceRecord.MaintainerId); + Assert.AreEqual(_droneId, maintenanceRecord.DroneId); + Assert.AreEqual(MaintenanceRecordType.Modification, maintenanceRecord.RecordType); + Assert.AreEqual(ModificationRecordDescription, maintenanceRecord.Description); + Assert.AreEqual(ModificationRecordNotes, maintenanceRecord.Notes); + } + + [TestMethod] + [ExpectedException(typeof(MaintainerNotFoundException))] + public void AddMaintenanceRecordInvalidMaintainerTest() + { + _factory.MaintenanceRecords.AddMaintenanceRecord(0, _droneId, MaintenanceRecordType.Maintenance, DateTime.Now, MaintenanceRecordDescription, MaintenanceRecordNotes); + } + + [TestMethod] + [ExpectedException(typeof(MaintainerNotFoundException))] + public async Task AddMaintenanceRecordInvalidMaintainerAsyncTest() + { + await _factory.MaintenanceRecords.AddMaintenanceRecordAsync(0, _droneId, MaintenanceRecordType.Maintenance, DateTime.Now, MaintenanceRecordDescription, MaintenanceRecordNotes); + } + + [TestMethod] + [ExpectedException(typeof(DroneNotFoundException))] + public void AddMaintenanceRecordInvalidDroneTest() + { + _factory.MaintenanceRecords.AddMaintenanceRecord(_firstMaintainerId, 0, MaintenanceRecordType.Maintenance, DateTime.Now, MaintenanceRecordDescription, MaintenanceRecordNotes); + } + + [TestMethod] + [ExpectedException(typeof(DroneNotFoundException))] + public async Task AddMaintenanceRecordInvalidDroneAsyncTest() + { + await _factory.MaintenanceRecords.AddMaintenanceRecordAsync(_firstMaintainerId, 0, MaintenanceRecordType.Maintenance, DateTime.Now, MaintenanceRecordDescription, MaintenanceRecordNotes); + } + + [TestMethod] + public void GetMaintenanceRecordTest() + { + var maintenanceRecord = _factory.MaintenanceRecords.GetMaintenanceRecord(_firstMaintainerId); + Assert.AreEqual(_firstMaintainerId, maintenanceRecord.MaintainerId); + Assert.AreEqual(_droneId, maintenanceRecord.DroneId); + Assert.AreEqual(MaintenanceRecordType.Maintenance, maintenanceRecord.RecordType); + Assert.AreEqual(MaintenanceRecordDescription, maintenanceRecord.Description); + Assert.AreEqual(MaintenanceRecordNotes, maintenanceRecord.Notes); + } + + [TestMethod] + public async Task GetMaintenanceRecordAsyncTest() + { + var maintenanceRecord = await _factory.MaintenanceRecords.GetMaintenanceRecordAsync(_firstMaintainerId); + Assert.AreEqual(_firstMaintainerId, maintenanceRecord.MaintainerId); + Assert.AreEqual(_droneId, maintenanceRecord.DroneId); + Assert.AreEqual(MaintenanceRecordType.Maintenance, maintenanceRecord.RecordType); + Assert.AreEqual(MaintenanceRecordDescription, maintenanceRecord.Description); + Assert.AreEqual(MaintenanceRecordNotes, maintenanceRecord.Notes); + } + + [TestMethod] + [ExpectedException(typeof(MaintenanceRecordNotFoundException))] + public void GetMaintenanceRecordInvalidTest() + { + _factory.MaintenanceRecords.GetMaintenanceRecord(0); + } + + [TestMethod] + [ExpectedException(typeof(MaintenanceRecordNotFoundException))] + public async Task GetMaintenanceRecordInvalidAsyncTest() + { + await _factory.MaintenanceRecords.GetMaintenanceRecordAsync(0); + } + + [TestMethod] + public void UpdateMaintenanceRecordTest() + { + _factory.MaintenanceRecords.UpdateMaintenanceRecord(_maintenanceRecordId, _secondMaintainerId, _droneId, MaintenanceRecordType.Modification, DateTime.Now, ModificationRecordDescription, ModificationRecordNotes); + _factory.Context.SaveChanges(); + + Assert.AreEqual(1, _factory.Context.MaintenanceRecords.Count()); + Assert.AreEqual(_secondMaintainerId, _factory.Context.MaintenanceRecords.First().MaintainerId); + Assert.AreEqual(_droneId, _factory.Context.MaintenanceRecords.First().DroneId); + Assert.AreEqual(MaintenanceRecordType.Modification, _factory.Context.MaintenanceRecords.First().RecordType); + Assert.AreEqual(ModificationRecordDescription, _factory.Context.MaintenanceRecords.First().Description); + Assert.AreEqual(ModificationRecordNotes, _factory.Context.MaintenanceRecords.First().Notes); + } + + [TestMethod] + public async Task UpdateMaintenanceRecordAsyncTest() + { + await _factory.MaintenanceRecords.UpdateMaintenanceRecordAsync(_maintenanceRecordId, _secondMaintainerId, _droneId, MaintenanceRecordType.Modification, DateTime.Now, ModificationRecordDescription, ModificationRecordNotes); + await _factory.Context.SaveChangesAsync(); + + Assert.AreEqual(1, _factory.Context.MaintenanceRecords.Count()); + Assert.AreEqual(_secondMaintainerId, _factory.Context.MaintenanceRecords.First().MaintainerId); + Assert.AreEqual(_droneId, _factory.Context.MaintenanceRecords.First().DroneId); + Assert.AreEqual(MaintenanceRecordType.Modification, _factory.Context.MaintenanceRecords.First().RecordType); + Assert.AreEqual(ModificationRecordDescription, _factory.Context.MaintenanceRecords.First().Description); + Assert.AreEqual(ModificationRecordNotes, _factory.Context.MaintenanceRecords.First().Notes); + } + + [TestMethod] + [ExpectedException(typeof(MaintenanceRecordNotFoundException))] + public void UpdateMaintenanceRecordInvalidTest() + { + _factory.MaintenanceRecords.UpdateMaintenanceRecord(0, _secondMaintainerId, _droneId, MaintenanceRecordType.Modification, DateTime.Now, ModificationRecordDescription, ModificationRecordNotes); + } + + [TestMethod] + [ExpectedException(typeof(MaintenanceRecordNotFoundException))] + public async Task UpdateMaintenanceRecordInvalidAsyncTest() + { + await _factory.MaintenanceRecords.UpdateMaintenanceRecordAsync(0, _secondMaintainerId, _droneId, MaintenanceRecordType.Modification, DateTime.Now, ModificationRecordDescription, ModificationRecordNotes); + } + + [TestMethod] + [ExpectedException(typeof(MaintainerNotFoundException))] + public void UpdateMaintenanceRecordInvalidMaintainerTest() + { + _factory.MaintenanceRecords.UpdateMaintenanceRecord(_maintenanceRecordId, 0, _droneId, MaintenanceRecordType.Modification, DateTime.Now, ModificationRecordDescription, ModificationRecordNotes); + } + + [TestMethod] + [ExpectedException(typeof(MaintainerNotFoundException))] + public async Task UpdateMaintenanceRecordInvalidMaintainerAsyncTest() + { + await _factory.MaintenanceRecords.UpdateMaintenanceRecordAsync(_maintenanceRecordId, 0, _droneId, MaintenanceRecordType.Modification, DateTime.Now, ModificationRecordDescription, ModificationRecordNotes); + } + + [TestMethod] + [ExpectedException(typeof(DroneNotFoundException))] + public void UpdateMaintenanceRecordInvalidDroneTest() + { + _factory.MaintenanceRecords.UpdateMaintenanceRecord(_maintenanceRecordId, _secondMaintainerId, 0, MaintenanceRecordType.Modification, DateTime.Now, ModificationRecordDescription, ModificationRecordNotes); + } + + [TestMethod] + [ExpectedException(typeof(DroneNotFoundException))] + public async Task UpdateMaintenanceRecordInvalidDroneAsyncTest() + { + await _factory.MaintenanceRecords.UpdateMaintenanceRecordAsync(_maintenanceRecordId, _secondMaintainerId, 0, MaintenanceRecordType.Modification, DateTime.Now, ModificationRecordDescription, ModificationRecordNotes); + } + + [TestMethod] + public void FindMaintenanceRecordsByMaintainerTest() + { + IEnumerable maintenanceRecords = _factory.MaintenanceRecords.FindMaintenanceRecords(_firstMaintainerId, null, null, null, 1, int.MaxValue); + Assert.AreEqual(1, maintenanceRecords.Count()); + Assert.AreEqual(_firstMaintainerId, maintenanceRecords.First().MaintainerId); + Assert.AreEqual(_droneId, maintenanceRecords.First().DroneId); + Assert.AreEqual(MaintenanceRecordType.Maintenance, maintenanceRecords.First().RecordType); + Assert.AreEqual(MaintenanceRecordDescription, maintenanceRecords.First().Description); + Assert.AreEqual(MaintenanceRecordNotes, maintenanceRecords.First().Notes); + } + + [TestMethod] + public async Task FindMaintenanceRecordsByMaintainerAsyncTest() + { + IEnumerable maintenanceRecords = await _factory.MaintenanceRecords.FindMaintenanceRecordsAsync(_firstMaintainerId, null, null, null, 1, int.MaxValue).ToListAsync(); + Assert.AreEqual(1, maintenanceRecords.Count()); + Assert.AreEqual(_firstMaintainerId, maintenanceRecords.First().MaintainerId); + Assert.AreEqual(_droneId, maintenanceRecords.First().DroneId); + Assert.AreEqual(MaintenanceRecordType.Maintenance, maintenanceRecords.First().RecordType); + Assert.AreEqual(MaintenanceRecordDescription, maintenanceRecords.First().Description); + Assert.AreEqual(MaintenanceRecordNotes, maintenanceRecords.First().Notes); + } + + [TestMethod] + public void FindMaintenanceRecordsByDroneTest() + { + IEnumerable maintenanceRecords = _factory.MaintenanceRecords.FindMaintenanceRecords(null, _droneId, null, null, 1, int.MaxValue); + Assert.AreEqual(1, maintenanceRecords.Count()); + Assert.AreEqual(_firstMaintainerId, maintenanceRecords.First().MaintainerId); + Assert.AreEqual(_droneId, maintenanceRecords.First().DroneId); + Assert.AreEqual(MaintenanceRecordType.Maintenance, maintenanceRecords.First().RecordType); + Assert.AreEqual(MaintenanceRecordDescription, maintenanceRecords.First().Description); + Assert.AreEqual(MaintenanceRecordNotes, maintenanceRecords.First().Notes); + } + + [TestMethod] + public async Task FindMaintenanceRecordsByDroneAsyncTest() + { + IEnumerable maintenanceRecords = await _factory.MaintenanceRecords.FindMaintenanceRecordsAsync(null, _droneId, null, null, 1, int.MaxValue).ToListAsync(); + Assert.AreEqual(1, maintenanceRecords.Count()); + Assert.AreEqual(_firstMaintainerId, maintenanceRecords.First().MaintainerId); + Assert.AreEqual(_droneId, maintenanceRecords.First().DroneId); + Assert.AreEqual(MaintenanceRecordType.Maintenance, maintenanceRecords.First().RecordType); + Assert.AreEqual(MaintenanceRecordDescription, maintenanceRecords.First().Description); + Assert.AreEqual(MaintenanceRecordNotes, maintenanceRecords.First().Notes); + } + + [TestMethod] + public void FindMaintenanceRecordsByDateRangeTest() + { + IEnumerable maintenanceRecords = _factory.MaintenanceRecords.FindMaintenanceRecords(null, null, DateTime.Now.AddDays(-1), DateTime.Now.AddDays(1), 1, int.MaxValue); + Assert.AreEqual(1, maintenanceRecords.Count()); + Assert.AreEqual(_firstMaintainerId, maintenanceRecords.First().MaintainerId); + Assert.AreEqual(_droneId, maintenanceRecords.First().DroneId); + Assert.AreEqual(MaintenanceRecordType.Maintenance, maintenanceRecords.First().RecordType); + Assert.AreEqual(MaintenanceRecordDescription, maintenanceRecords.First().Description); + Assert.AreEqual(MaintenanceRecordNotes, maintenanceRecords.First().Notes); + } + + [TestMethod] + public async Task FindMaintenanceRecordsByDateRangeAsyncTest() + { + IEnumerable maintenanceRecords = await _factory.MaintenanceRecords.FindMaintenanceRecordsAsync(null, null, DateTime.Now.AddDays(-1), DateTime.Now.AddDays(1), 1, int.MaxValue).ToListAsync(); + Assert.AreEqual(1, maintenanceRecords.Count()); + Assert.AreEqual(_firstMaintainerId, maintenanceRecords.First().MaintainerId); + Assert.AreEqual(_droneId, maintenanceRecords.First().DroneId); + Assert.AreEqual(MaintenanceRecordType.Maintenance, maintenanceRecords.First().RecordType); + Assert.AreEqual(MaintenanceRecordDescription, maintenanceRecords.First().Description); + Assert.AreEqual(MaintenanceRecordNotes, maintenanceRecords.First().Notes); + } + } +} diff --git a/src/DroneFlightLog.Data/Entities/MaintenanceRecord.cs b/src/DroneFlightLog.Data/Entities/MaintenanceRecord.cs index 0436257..cd13099 100644 --- a/src/DroneFlightLog.Data/Entities/MaintenanceRecord.cs +++ b/src/DroneFlightLog.Data/Entities/MaintenanceRecord.cs @@ -12,6 +12,7 @@ public class MaintenanceRecord public int MaintainerId { get; set; } public int DroneId { get; set; } public DateTime DateCompleted { get; set; } + public MaintenanceRecordType RecordType { get; set; } public string Description { get; set; } public string Notes { get; set; } diff --git a/src/DroneFlightLog.Data/Entities/MaintenanceRecordType.cs b/src/DroneFlightLog.Data/Entities/MaintenanceRecordType.cs new file mode 100644 index 0000000..2d380db --- /dev/null +++ b/src/DroneFlightLog.Data/Entities/MaintenanceRecordType.cs @@ -0,0 +1,8 @@ +namespace DroneFlightLog.Data.Entities +{ + public enum MaintenanceRecordType + { + Maintenance, + Modification + } +} diff --git a/src/DroneFlightLog.Data/Exceptions/MaintenanceRecordNotFoundException.cs b/src/DroneFlightLog.Data/Exceptions/MaintenanceRecordNotFoundException.cs new file mode 100644 index 0000000..2dbe4ed --- /dev/null +++ b/src/DroneFlightLog.Data/Exceptions/MaintenanceRecordNotFoundException.cs @@ -0,0 +1,21 @@ +using System; +using System.Diagnostics.CodeAnalysis; + +namespace DroneFlightLog.Data.Exceptions +{ + [ExcludeFromCodeCoverage] + public class MaintenanceRecordNotFoundException : Exception + { + public MaintenanceRecordNotFoundException() + { + } + + public MaintenanceRecordNotFoundException(string message) : base(message) + { + } + + public MaintenanceRecordNotFoundException(string message, Exception inner) : base(message, inner) + { + } + } +} \ No newline at end of file diff --git a/src/DroneFlightLog.Data/Factory/DroneFlightLogFactory.cs b/src/DroneFlightLog.Data/Factory/DroneFlightLogFactory.cs index bf6b523..3029fab 100644 --- a/src/DroneFlightLog.Data/Factory/DroneFlightLogFactory.cs +++ b/src/DroneFlightLog.Data/Factory/DroneFlightLogFactory.cs @@ -17,6 +17,7 @@ public class DroneFlightLogFactory : IDroneFlightLogFactory where T : DbCo private Lazy _flights; private Lazy _users; private Lazy _maintainers; + private Lazy _maintenanceRecords; public DroneFlightLogFactory(T context) { @@ -31,6 +32,7 @@ public DroneFlightLogFactory(T context) _flights = new Lazy(() => new FlightManager(this)); _users = new Lazy(() => new UserManager(context)); _maintainers = new Lazy(() => new MaintainerManager(context)); + _maintenanceRecords = new Lazy(() => new MaintenanceRecordManager(this)); } public T Context { get; private set; } @@ -44,5 +46,6 @@ public DroneFlightLogFactory(T context) public IFlightManager Flights { get { return _flights.Value; } } public IUserManager Users { get { return _users.Value; } } public IMaintainerManager Maintainers { get { return _maintainers.Value; } } + public IMaintenanceRecordManager MaintenanceRecords { get { return _maintenanceRecords.Value; } } } } diff --git a/src/DroneFlightLog.Data/Interfaces/IDroneFlightLogFactory.cs b/src/DroneFlightLog.Data/Interfaces/IDroneFlightLogFactory.cs index 6994d43..cc2b54e 100644 --- a/src/DroneFlightLog.Data/Interfaces/IDroneFlightLogFactory.cs +++ b/src/DroneFlightLog.Data/Interfaces/IDroneFlightLogFactory.cs @@ -15,5 +15,6 @@ public interface IDroneFlightLogFactory where T : DbContext, IDroneFlightLogD IFlightManager Flights { get; } IUserManager Users { get; } IMaintainerManager Maintainers { get; } + IMaintenanceRecordManager MaintenanceRecords { get; } } } \ No newline at end of file diff --git a/src/DroneFlightLog.Data/Interfaces/IMaintenanceRecordManager.cs b/src/DroneFlightLog.Data/Interfaces/IMaintenanceRecordManager.cs new file mode 100644 index 0000000..5028474 --- /dev/null +++ b/src/DroneFlightLog.Data/Interfaces/IMaintenanceRecordManager.cs @@ -0,0 +1,19 @@ +using DroneFlightLog.Data.Entities; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace DroneFlightLog.Data.Interfaces +{ + public interface IMaintenanceRecordManager + { + MaintenanceRecord AddMaintenanceRecord(int maintainerId, int droneId, MaintenanceRecordType type, DateTime completed, string description, string notes); + Task AddMaintenanceRecordAsync(int maintainerId, int droneId, MaintenanceRecordType type, DateTime completed, string description, string notes); + IEnumerable FindMaintenanceRecords(int? maintainerId, int? droneId, DateTime? start, DateTime? end, int pageNumber, int pageSize); + IAsyncEnumerable FindMaintenanceRecordsAsync(int? maintainerId, int? droneId, DateTime? start, DateTime? end, int pageNumber, int pageSize); + MaintenanceRecord GetMaintenanceRecord(int id); + Task GetMaintenanceRecordAsync(int id); + MaintenanceRecord UpdateMaintenanceRecord(int id, int maintainerId, int droneId, MaintenanceRecordType type, DateTime completed, string description, string notes); + Task UpdateMaintenanceRecordAsync(int id, int maintainerId, int droneId, MaintenanceRecordType type, DateTime completed, string description, string notes); + } +} \ No newline at end of file diff --git a/src/DroneFlightLog.Data/Logic/FlightPropertyManager.cs b/src/DroneFlightLog.Data/Logic/FlightPropertyManager.cs index 6a4bd48..29f557d 100644 --- a/src/DroneFlightLog.Data/Logic/FlightPropertyManager.cs +++ b/src/DroneFlightLog.Data/Logic/FlightPropertyManager.cs @@ -1,374 +1,374 @@ using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Threading.Tasks; -using DroneFlightLog.Data.Entities; -using DroneFlightLog.Data.Exceptions; -using DroneFlightLog.Data.Extensions; -using DroneFlightLog.Data.Interfaces; -using Microsoft.EntityFrameworkCore; - -namespace DroneFlightLog.Data.Logic -{ - internal class FlightPropertyManager : IFlightPropertyManager where T : DbContext, IDroneFlightLogDbContext - { - private readonly T _context; - - internal FlightPropertyManager(T context) - { - _context = context; - } - - /// - /// Add a new flight property definition - /// - /// - /// - /// - public FlightProperty AddProperty(string name, FlightPropertyDataType type, bool isSingleInstance) - { - FlightProperty property = _context.FlightProperties.FirstOrDefault(p => p.Name == name); - ThrowIfPropertyFound(property, name); - - property = new FlightProperty - { - Name = name, - DataType = type, - IsSingleInstance = isSingleInstance - }; - - _context.FlightProperties.Add(property); - return property; - } - - /// - /// Add a new flight property definition - /// - /// - /// - /// - /// - public async Task AddPropertyAsync(string name, FlightPropertyDataType type, bool isSingleInstance) - { - FlightProperty property = await _context.FlightProperties.FirstOrDefaultAsync(p => p.Name == name); - ThrowIfPropertyFound(property, name); - - property = new FlightProperty - { - Name = name, - DataType = type, - IsSingleInstance = isSingleInstance - }; - - await _context.FlightProperties.AddAsync(property); - return property; - } - - /// - /// Update an existing flight property definition - /// - /// - /// - /// - public FlightProperty UpdateProperty(int id, string name) - { - name = name.CleanString(); - FlightProperty existing = _context.FlightProperties.FirstOrDefault(p => p.Name == name); - ThrowIfPropertyFound(existing, name); - - FlightProperty property = _context.FlightProperties.FirstOrDefault(p => p.Id == id); - ThrowIfPropertyNotFound(property, id); - - // The only property that can be updated without running the risk of invalidating - // existing data is the name - property.Name = name; - return property; - } - - /// - /// Update an existing flight property definition - /// - /// - /// - /// - public async Task UpdatePropertyAsync(int id, string name) - { - name = name.CleanString(); - FlightProperty existing = await _context.FlightProperties.FirstOrDefaultAsync(p => p.Name == name); - ThrowIfPropertyFound(existing, name); - - FlightProperty property = await _context.FlightProperties.FirstOrDefaultAsync(p => p.Id == id); - ThrowIfPropertyNotFound(property, id); - - // The only property that can be updated without running the risk of invalidating - // existing data is the name - property.Name = name; - return property; - } - - /// - /// Add a value for a property to a flight - /// - /// - /// - /// - public FlightPropertyValue AddPropertyValue(int flightId, int propertyId, object value) - { - FlightProperty definition = _context.FlightProperties.First(p => p.Id == propertyId); - FlightPropertyValue propertyValue; - - if (definition.IsSingleInstance) - { - propertyValue = _context.FlightPropertyValues.FirstOrDefault(v => (v.FlightId == flightId) && (v.PropertyId == propertyId)); - ThrowIfPropertyValueFound(propertyValue, definition.Name, flightId); - } - - propertyValue = CreatePropertyValue(definition, flightId, propertyId, value); - _context.FlightPropertyValues.Add(propertyValue); - return propertyValue; - } - - /// - /// Add a value for a property to a flight - /// - /// - /// - /// - public async Task AddPropertyValueAsync(int flightId, int propertyId, object value) - { - FlightProperty definition = await _context.FlightProperties.FirstAsync(p => p.Id == propertyId); - FlightPropertyValue propertyValue; - - if (definition.IsSingleInstance) - { - propertyValue = await _context.FlightPropertyValues.FirstOrDefaultAsync(v => (v.FlightId == flightId) && (v.PropertyId == propertyId)); - ThrowIfPropertyValueFound(propertyValue, definition.Name, flightId); - } - - propertyValue = CreatePropertyValue(definition, flightId, propertyId, value); - await _context.FlightPropertyValues.AddAsync(propertyValue); - return propertyValue; - } - - /// - /// Update an existing flight property definition - /// - /// - /// - /// - public FlightPropertyValue UpdatePropertyValue(int id, object value) - { - FlightPropertyValue propertyValue = _context.FlightPropertyValues.FirstOrDefault(p => p.Id == id); - ThrowIfPropertyValueNotFound(propertyValue, id); - - FlightProperty definition = _context.FlightProperties.First(p => p.Id == propertyValue.PropertyId); - SetPropertyValue(definition, propertyValue, value); - return propertyValue; - } - - /// - /// Update an existing flight property definition - /// - /// - /// - /// - public async Task UpdatePropertyValueAsync(int id, object value) - { - FlightPropertyValue propertyValue = await _context.FlightPropertyValues.FirstOrDefaultAsync(p => p.Id == id); - ThrowIfPropertyValueNotFound(propertyValue, id); - - FlightProperty definition = await _context.FlightProperties.FirstAsync(p => p.Id == propertyValue.PropertyId); - SetPropertyValue(definition, propertyValue, value); - return propertyValue; - } - - /// - /// Get all the current property definitions - /// - public IEnumerable GetProperties() => - _context.FlightProperties; - - /// - /// Get all the current property definitions - /// - public IAsyncEnumerable GetPropertiesAsync() => - _context.FlightProperties.AsAsyncEnumerable(); - - /// - /// Return the property values for a specified flight - /// - /// - public IEnumerable GetPropertyValues(int flightId) => - _context.FlightPropertyValues - .Include(v => v.Property) - .Where(v => v.FlightId == flightId); - - /// - /// Return the property values for a specified flight - /// - /// - public IAsyncEnumerable GetPropertyValuesAsync(int flightId) => - _context.FlightPropertyValues - .Include(v => v.Property) - .Where(v => v.FlightId == flightId) - .AsAsyncEnumerable(); - - /// - /// Return the specified flight property value - /// - /// - /// - public FlightPropertyValue GetPropertyValue(int id) - { - FlightPropertyValue value = _context.FlightPropertyValues - .Include(v => v.Property) - .FirstOrDefault(v => v.Id == id); - ThrowIfPropertyValueNotFound(value, id); - return value; - } - - /// - /// Return the specified flight property value - /// - /// - /// - public async Task GetPropertyValueAsync(int id) - { - FlightPropertyValue value = await _context.FlightPropertyValues - .Include(v => v.Property) - .FirstOrDefaultAsync(v => v.Id == id); - ThrowIfPropertyValueNotFound(value, id); - return value; - } - - /// - /// Create a new property value - /// - /// - /// - /// - /// - /// - [ExcludeFromCodeCoverage] - private FlightPropertyValue CreatePropertyValue(FlightProperty definition, int flightId, int propertyId, object value) - { - FlightPropertyValue propertyValue = null; - switch (definition.DataType) - { - case FlightPropertyDataType.Date: - propertyValue = new FlightPropertyValue - { - FlightId = flightId, - PropertyId = propertyId - }; - break; - case FlightPropertyDataType.Number: - propertyValue = new FlightPropertyValue - { - FlightId = flightId, - PropertyId = propertyId - }; - break; - case FlightPropertyDataType.String: - propertyValue = new FlightPropertyValue - { - FlightId = flightId, - PropertyId = propertyId - }; - break; - default: - break; - } - - SetPropertyValue(definition, propertyValue, value); - return propertyValue; - } - - /// - /// Set the value field on an existing property value object - /// - /// - /// - /// - /// - [ExcludeFromCodeCoverage] - private void SetPropertyValue(FlightProperty definition, FlightPropertyValue propertyValue, object value) - { - switch (definition.DataType) - { - case FlightPropertyDataType.Date: - propertyValue.DateValue = (DateTime)value; - break; - case FlightPropertyDataType.Number: - propertyValue.NumberValue = (decimal)value; - break; - case FlightPropertyDataType.String: - propertyValue.StringValue = (string)value; - break; - default: - break; - } - } - - /// - /// Throw an error if a property already exists - /// - /// - /// - [ExcludeFromCodeCoverage] - private void ThrowIfPropertyFound(FlightProperty property, string name) - { - if (property != null) - { - string message = $"Property {name} already exists"; - throw new PropertyExistsException(message); - } - } - - /// - /// Throw an exception if a flight property does not exist - /// - /// - /// - [ExcludeFromCodeCoverage] - private void ThrowIfPropertyNotFound(FlightProperty property, int id) - { - if (property == null) - { - string message = $"Flight property with ID {id} not found"; - throw new PropertyNotFoundException(message); - } - } - - /// - /// Throw an error if a single-instance property value already exists - /// - /// - /// - [ExcludeFromCodeCoverage] - private void ThrowIfPropertyValueFound(FlightPropertyValue propertyValue, string propertyName, int flightId) - { - if (propertyValue != null) - { - string message = $"Single instance property {propertyName} already has a value for flight Id {flightId}"; - throw new ValueExistsException(message); - } - } - - /// - /// Throw an exception if a flight property value does not exist - /// - /// - /// - [ExcludeFromCodeCoverage] - private void ThrowIfPropertyValueNotFound(FlightPropertyValue value, int id) - { - if (value == null) - { - string message = $"Flight property value with ID {id} not found"; - throw new PropertyValueNotFoundException(message); - } - } - } -} +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Threading.Tasks; +using DroneFlightLog.Data.Entities; +using DroneFlightLog.Data.Exceptions; +using DroneFlightLog.Data.Extensions; +using DroneFlightLog.Data.Interfaces; +using Microsoft.EntityFrameworkCore; + +namespace DroneFlightLog.Data.Logic +{ + internal class FlightPropertyManager : IFlightPropertyManager where T : DbContext, IDroneFlightLogDbContext + { + private readonly T _context; + + internal FlightPropertyManager(T context) + { + _context = context; + } + + /// + /// Add a new flight property definition + /// + /// + /// + /// + public FlightProperty AddProperty(string name, FlightPropertyDataType type, bool isSingleInstance) + { + FlightProperty property = _context.FlightProperties.FirstOrDefault(p => p.Name == name); + ThrowIfPropertyFound(property, name); + + property = new FlightProperty + { + Name = name, + DataType = type, + IsSingleInstance = isSingleInstance + }; + + _context.FlightProperties.Add(property); + return property; + } + + /// + /// Add a new flight property definition + /// + /// + /// + /// + /// + public async Task AddPropertyAsync(string name, FlightPropertyDataType type, bool isSingleInstance) + { + FlightProperty property = await _context.FlightProperties.FirstOrDefaultAsync(p => p.Name == name); + ThrowIfPropertyFound(property, name); + + property = new FlightProperty + { + Name = name, + DataType = type, + IsSingleInstance = isSingleInstance + }; + + await _context.FlightProperties.AddAsync(property); + return property; + } + + /// + /// Update an existing flight property definition + /// + /// + /// + /// + public FlightProperty UpdateProperty(int id, string name) + { + name = name.CleanString(); + FlightProperty existing = _context.FlightProperties.FirstOrDefault(p => p.Name == name); + ThrowIfPropertyFound(existing, name); + + FlightProperty property = _context.FlightProperties.FirstOrDefault(p => p.Id == id); + ThrowIfPropertyNotFound(property, id); + + // The only property that can be updated without running the risk of invalidating + // existing data is the name + property.Name = name; + return property; + } + + /// + /// Update an existing flight property definition + /// + /// + /// + /// + public async Task UpdatePropertyAsync(int id, string name) + { + name = name.CleanString(); + FlightProperty existing = await _context.FlightProperties.FirstOrDefaultAsync(p => p.Name == name); + ThrowIfPropertyFound(existing, name); + + FlightProperty property = await _context.FlightProperties.FirstOrDefaultAsync(p => p.Id == id); + ThrowIfPropertyNotFound(property, id); + + // The only property that can be updated without running the risk of invalidating + // existing data is the name + property.Name = name; + return property; + } + + /// + /// Add a value for a property to a flight + /// + /// + /// + /// + public FlightPropertyValue AddPropertyValue(int flightId, int propertyId, object value) + { + FlightProperty definition = _context.FlightProperties.First(p => p.Id == propertyId); + FlightPropertyValue propertyValue; + + if (definition.IsSingleInstance) + { + propertyValue = _context.FlightPropertyValues.FirstOrDefault(v => (v.FlightId == flightId) && (v.PropertyId == propertyId)); + ThrowIfPropertyValueFound(propertyValue, definition.Name, flightId); + } + + propertyValue = CreatePropertyValue(definition, flightId, propertyId, value); + _context.FlightPropertyValues.Add(propertyValue); + return propertyValue; + } + + /// + /// Add a value for a property to a flight + /// + /// + /// + /// + public async Task AddPropertyValueAsync(int flightId, int propertyId, object value) + { + FlightProperty definition = await _context.FlightProperties.FirstAsync(p => p.Id == propertyId); + FlightPropertyValue propertyValue; + + if (definition.IsSingleInstance) + { + propertyValue = await _context.FlightPropertyValues.FirstOrDefaultAsync(v => (v.FlightId == flightId) && (v.PropertyId == propertyId)); + ThrowIfPropertyValueFound(propertyValue, definition.Name, flightId); + } + + propertyValue = CreatePropertyValue(definition, flightId, propertyId, value); + await _context.FlightPropertyValues.AddAsync(propertyValue); + return propertyValue; + } + + /// + /// Update an existing flight property definition + /// + /// + /// + /// + public FlightPropertyValue UpdatePropertyValue(int id, object value) + { + FlightPropertyValue propertyValue = _context.FlightPropertyValues.FirstOrDefault(p => p.Id == id); + ThrowIfPropertyValueNotFound(propertyValue, id); + + FlightProperty definition = _context.FlightProperties.First(p => p.Id == propertyValue.PropertyId); + SetPropertyValue(definition, propertyValue, value); + return propertyValue; + } + + /// + /// Update an existing flight property definition + /// + /// + /// + /// + public async Task UpdatePropertyValueAsync(int id, object value) + { + FlightPropertyValue propertyValue = await _context.FlightPropertyValues.FirstOrDefaultAsync(p => p.Id == id); + ThrowIfPropertyValueNotFound(propertyValue, id); + + FlightProperty definition = await _context.FlightProperties.FirstAsync(p => p.Id == propertyValue.PropertyId); + SetPropertyValue(definition, propertyValue, value); + return propertyValue; + } + + /// + /// Get all the current property definitions + /// + public IEnumerable GetProperties() => + _context.FlightProperties; + + /// + /// Get all the current property definitions + /// + public IAsyncEnumerable GetPropertiesAsync() => + _context.FlightProperties.AsAsyncEnumerable(); + + /// + /// Return the property values for a specified flight + /// + /// + public IEnumerable GetPropertyValues(int flightId) => + _context.FlightPropertyValues + .Include(v => v.Property) + .Where(v => v.FlightId == flightId); + + /// + /// Return the property values for a specified flight + /// + /// + public IAsyncEnumerable GetPropertyValuesAsync(int flightId) => + _context.FlightPropertyValues + .Include(v => v.Property) + .Where(v => v.FlightId == flightId) + .AsAsyncEnumerable(); + + /// + /// Return the specified flight property value + /// + /// + /// + public FlightPropertyValue GetPropertyValue(int id) + { + FlightPropertyValue value = _context.FlightPropertyValues + .Include(v => v.Property) + .FirstOrDefault(v => v.Id == id); + ThrowIfPropertyValueNotFound(value, id); + return value; + } + + /// + /// Return the specified flight property value + /// + /// + /// + public async Task GetPropertyValueAsync(int id) + { + FlightPropertyValue value = await _context.FlightPropertyValues + .Include(v => v.Property) + .FirstOrDefaultAsync(v => v.Id == id); + ThrowIfPropertyValueNotFound(value, id); + return value; + } + + /// + /// Create a new property value + /// + /// + /// + /// + /// + /// + [ExcludeFromCodeCoverage] + private FlightPropertyValue CreatePropertyValue(FlightProperty definition, int flightId, int propertyId, object value) + { + FlightPropertyValue propertyValue = null; + switch (definition.DataType) + { + case FlightPropertyDataType.Date: + propertyValue = new FlightPropertyValue + { + FlightId = flightId, + PropertyId = propertyId + }; + break; + case FlightPropertyDataType.Number: + propertyValue = new FlightPropertyValue + { + FlightId = flightId, + PropertyId = propertyId + }; + break; + case FlightPropertyDataType.String: + propertyValue = new FlightPropertyValue + { + FlightId = flightId, + PropertyId = propertyId + }; + break; + default: + break; + } + + SetPropertyValue(definition, propertyValue, value); + return propertyValue; + } + + /// + /// Set the value field on an existing property value object + /// + /// + /// + /// + /// + [ExcludeFromCodeCoverage] + private void SetPropertyValue(FlightProperty definition, FlightPropertyValue propertyValue, object value) + { + switch (definition.DataType) + { + case FlightPropertyDataType.Date: + propertyValue.DateValue = (DateTime)value; + break; + case FlightPropertyDataType.Number: + propertyValue.NumberValue = (decimal)value; + break; + case FlightPropertyDataType.String: + propertyValue.StringValue = (string)value; + break; + default: + break; + } + } + + /// + /// Throw an error if a property already exists + /// + /// + /// + [ExcludeFromCodeCoverage] + private void ThrowIfPropertyFound(FlightProperty property, string name) + { + if (property != null) + { + string message = $"Property {name} already exists"; + throw new PropertyExistsException(message); + } + } + + /// + /// Throw an exception if a flight property does not exist + /// + /// + /// + [ExcludeFromCodeCoverage] + private void ThrowIfPropertyNotFound(FlightProperty property, int id) + { + if (property == null) + { + string message = $"Flight property with ID {id} not found"; + throw new PropertyNotFoundException(message); + } + } + + /// + /// Throw an error if a single-instance property value already exists + /// + /// + /// + [ExcludeFromCodeCoverage] + private void ThrowIfPropertyValueFound(FlightPropertyValue propertyValue, string propertyName, int flightId) + { + if (propertyValue != null) + { + string message = $"Single instance property {propertyName} already has a value for flight Id {flightId}"; + throw new ValueExistsException(message); + } + } + + /// + /// Throw an exception if a flight property value does not exist + /// + /// + /// + [ExcludeFromCodeCoverage] + private void ThrowIfPropertyValueNotFound(FlightPropertyValue value, int id) + { + if (value == null) + { + string message = $"Flight property value with ID {id} not found"; + throw new PropertyValueNotFoundException(message); + } + } + } +} diff --git a/src/DroneFlightLog.Data/Logic/MaintenanceRecordManager.cs b/src/DroneFlightLog.Data/Logic/MaintenanceRecordManager.cs new file mode 100644 index 0000000..d5df736 --- /dev/null +++ b/src/DroneFlightLog.Data/Logic/MaintenanceRecordManager.cs @@ -0,0 +1,223 @@ +using DroneFlightLog.Data.Entities; +using DroneFlightLog.Data.Exceptions; +using DroneFlightLog.Data.Interfaces; +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Threading.Tasks; + +namespace DroneFlightLog.Data.Logic +{ + internal class MaintenanceRecordManager : IMaintenanceRecordManager where T : DbContext, IDroneFlightLogDbContext + { + private readonly IDroneFlightLogFactory _factory; + + internal MaintenanceRecordManager(IDroneFlightLogFactory factory) + { + _factory = factory; + } + + /// + /// Add a new maintenance record + /// + /// + /// + /// + /// + /// + /// + /// + public MaintenanceRecord AddMaintenanceRecord(int maintainerId, int droneId, MaintenanceRecordType type, DateTime completed, string description, string? notes) + { + // These will throw exceptions if the corresponding entities do not exist + _factory.Maintainers.GetMaintainer(maintainerId); + _factory.Drones.GetDrone(droneId); + + MaintenanceRecord maintenanceRecord = new() + { + MaintainerId = maintainerId, + DroneId = droneId, + RecordType = type, + DateCompleted = completed, + Description = description, + Notes = notes + }; + + _factory.Context.MaintenanceRecords.Add(maintenanceRecord); + return maintenanceRecord; + } + + /// + /// Add a new maintenance record + /// + /// + /// + /// + /// + /// + /// + /// + public async Task AddMaintenanceRecordAsync(int maintainerId, int droneId, MaintenanceRecordType type, DateTime completed, string description, string? notes) + { + // These will throw exceptions if the corresponding entities do not exist + await _factory.Maintainers.GetMaintainerAsync(maintainerId); + await _factory.Drones.GetDroneAsync(droneId); + + MaintenanceRecord maintenanceRecord = new() + { + MaintainerId = maintainerId, + DroneId = droneId, + RecordType = type, + DateCompleted = completed, + Description = description, + Notes = notes + }; + + await _factory.Context.MaintenanceRecords.AddAsync(maintenanceRecord); + return maintenanceRecord; + } + + /// + /// Get the maintenance record with the specified Id + /// + /// + /// + public MaintenanceRecord GetMaintenanceRecord(int id) + { + MaintenanceRecord maintenanceRecord = _factory.Context.MaintenanceRecords.FirstOrDefault(m => m.Id == id); + ThrowIfMaintenanceRecordNotFound(maintenanceRecord, id); + return maintenanceRecord; + } + + /// + /// Get the maintenance record with the specified Id + /// + /// + /// + public async Task GetMaintenanceRecordAsync(int id) + { + MaintenanceRecord maintenanceRecord = await _factory.Context.MaintenanceRecords.FirstOrDefaultAsync(m => m.Id == id); + ThrowIfMaintenanceRecordNotFound(maintenanceRecord, id); + return maintenanceRecord; + } + + /// + /// Update the maintenance record with the specified Id + /// + /// + /// + /// + /// + /// + /// + /// + /// + public MaintenanceRecord UpdateMaintenanceRecord(int id, int maintainerId, int droneId, MaintenanceRecordType type, DateTime completed, string description, string? notes) + { + // These will throw exceptions if the corresponding entities do not exist + _factory.Maintainers.GetMaintainer(maintainerId); + _factory.Drones.GetDrone(droneId); + + MaintenanceRecord maintenanceRecord = GetMaintenanceRecord(id); + maintenanceRecord.MaintainerId = maintainerId; + maintenanceRecord.DroneId = droneId; + maintenanceRecord.RecordType = type; + maintenanceRecord.DateCompleted = completed; + maintenanceRecord.Description = description; + maintenanceRecord.Notes = notes; + + return maintenanceRecord; + } + + /// + /// Update the maintenance record with the specified Id + /// + /// + /// + /// + /// + /// + /// + /// + /// + public async Task UpdateMaintenanceRecordAsync(int id, int maintainerId, int droneId, MaintenanceRecordType type, DateTime completed, string description, string? notes) + { + // These will throw exceptions if the corresponding entities do not exist + await _factory.Maintainers.GetMaintainerAsync(maintainerId); + await _factory.Drones.GetDroneAsync(droneId); + + MaintenanceRecord maintenanceRecord = await GetMaintenanceRecordAsync(id); + maintenanceRecord.MaintainerId = maintainerId; + maintenanceRecord.DroneId = droneId; + maintenanceRecord.RecordType = type; + maintenanceRecord.DateCompleted = completed; + maintenanceRecord.Description = description; + maintenanceRecord.Notes = notes; + + return maintenanceRecord; + } + + /// + /// Find maintenance records for a maintainer, drone and date range + /// + /// + /// + /// + /// + /// + /// + /// + public IEnumerable FindMaintenanceRecords(int? maintainerId, int? droneId, DateTime? start, DateTime? end, int pageNumber, int pageSize) + { + IEnumerable maintenanceRecords = _factory.Context + .MaintenanceRecords + .Include(m => m.Maintainer) + .Where(m => ((maintainerId == null) || (maintainerId == m.MaintainerId)) && + ((droneId == null) || (droneId == m.DroneId)) && + ((start == null) || (m.DateCompleted >= start)) && + ((end == null) || (m.DateCompleted <= end))) + .Skip((pageNumber - 1) * pageSize) + .Take(pageSize); + + return maintenanceRecords; + } + + /// + /// Find maintenance records for a maintainer, drone and date range + /// + /// + /// + /// + public IAsyncEnumerable FindMaintenanceRecordsAsync(int? maintainerId, int? droneId, DateTime? start, DateTime? end, int pageNumber, int pageSize) + { + IAsyncEnumerable maintenanceRecords = _factory.Context + .MaintenanceRecords + .Include(m => m.Maintainer) + .Where(m => ((maintainerId == null) || (maintainerId == m.MaintainerId)) && + ((droneId == null) || (droneId == m.DroneId)) && + ((start == null) || (m.DateCompleted >= start)) && + ((end == null) || (m.DateCompleted <= end))) + .Skip((pageNumber - 1) * pageSize) + .Take(pageSize) + .AsAsyncEnumerable(); + return maintenanceRecords; + } + + /// + /// Throw an error if a maintenance record does not exist + /// + /// + /// + [ExcludeFromCodeCoverage] + private void ThrowIfMaintenanceRecordNotFound(MaintenanceRecord maintenanceRecord, int maintenanceRecordId) + { + if (maintenanceRecord == null) + { + string message = $"Maintenance record with ID {maintenanceRecordId} not found"; + throw new MaintenanceRecordNotFoundException(message); + } + } + } +} diff --git a/src/DroneFlightLog.Data/Logic/UserManager.cs b/src/DroneFlightLog.Data/Logic/UserManager.cs index 1ab1d82..498342c 100644 --- a/src/DroneFlightLog.Data/Logic/UserManager.cs +++ b/src/DroneFlightLog.Data/Logic/UserManager.cs @@ -1,240 +1,240 @@ using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Threading.Tasks; -using DroneFlightLog.Data.Entities; -using DroneFlightLog.Data.Exceptions; -using DroneFlightLog.Data.Interfaces; -using Microsoft.EntityFrameworkCore; -using Microsoft.AspNetCore.Identity; - -namespace DroneFlightLog.Data.Logic -{ - public class UserManager : IUserManager where T : DbContext, IDroneFlightLogDbContext - { - private Lazy> _hasher; - private readonly T _context; - - public UserManager(T context) - { - _hasher = new Lazy>(() => new PasswordHasher()); - _context = context; - } - - /// - /// Return the user with the specified Id - /// - /// - /// - public FlightLogUser GetUser(int userId) - { - FlightLogUser user = _context.FlightLogUsers.FirstOrDefault(u => u.Id == userId); - ThrowIfUserNotFound(user, userId); - return user; - } - - /// - /// Return the user with the specified Id - /// - /// - /// - public async Task GetUserAsync(int userId) - { - FlightLogUser user = await _context.FlightLogUsers.FirstOrDefaultAsync(u => u.Id == userId); - ThrowIfUserNotFound(user, userId); - return user; - } - - /// - /// Return the user with the specified Id - /// - /// - /// - public FlightLogUser GetUser(string userName) - { - FlightLogUser user = _context.FlightLogUsers.FirstOrDefault(u => u.UserName == userName); - ThrowIfUserNotFound(user, userName); - return user; - } - - /// - /// Return the user with the specified Id - /// - /// - /// - public async Task GetUserAsync(string userName) - { - FlightLogUser user = await _context.FlightLogUsers.FirstOrDefaultAsync(u => u.UserName == userName); - ThrowIfUserNotFound(user, userName); - return user; - } - - /// - /// Get all the current user details - /// - public IEnumerable GetUsers() => - _context.FlightLogUsers; - - /// - /// Get all the current user details - /// - public IAsyncEnumerable GetUsersAsync() => - _context.FlightLogUsers.AsAsyncEnumerable(); - - /// - /// Add a new user, given their details - /// - /// - /// - /// - public FlightLogUser AddUser(string userName, string password) - { - FlightLogUser user = _context.FlightLogUsers.FirstOrDefault(u => u.UserName == userName); - ThrowIfUserFound(user, userName); - - user = new FlightLogUser - { - UserName = userName, - Password = _hasher.Value.HashPassword(userName, password) - }; - - _context.FlightLogUsers.Add(user); - _context.SaveChanges(); - return user; - } - - /// - /// Add a new user, given their details - /// - /// - /// - /// - public async Task AddUserAsync(string userName, string password) - { - FlightLogUser user = await _context.FlightLogUsers.FirstOrDefaultAsync(u => u.UserName == userName); - ThrowIfUserFound(user, userName); - - user = new FlightLogUser - { - UserName = userName, - Password = _hasher.Value.HashPassword(userName, password) - }; - - await _context.FlightLogUsers.AddAsync(user); - await _context.SaveChangesAsync(); - return user; - } - - /// - /// Authenticate the specified user - /// - /// - /// - /// - public bool Authenticate(string userName, string password) - { - FlightLogUser user = GetUser(userName); - PasswordVerificationResult result = _hasher.Value.VerifyHashedPassword(userName, user.Password, password); - if (result == PasswordVerificationResult.SuccessRehashNeeded) - { - user.Password = _hasher.Value.HashPassword(userName, password); - _context.SaveChanges(); - } - return result != PasswordVerificationResult.Failed; - } - - /// - /// Authenticate the specified user - /// - /// - /// - /// - public async Task AuthenticateAsync(string userName, string password) - { - FlightLogUser user = await GetUserAsync(userName); - PasswordVerificationResult result = _hasher.Value.VerifyHashedPassword(userName, user.Password, password); - if (result == PasswordVerificationResult.SuccessRehashNeeded) - { - user.Password = _hasher.Value.HashPassword(userName, password); - await _context.SaveChangesAsync(); - } - return result != PasswordVerificationResult.Failed; - } - - /// - /// Set the password for the specified user - /// - /// - /// - public void SetPassword(string userName, string password) - { - FlightLogUser user = GetUser(userName); - user.Password = _hasher.Value.HashPassword(userName, password); - _context.SaveChanges(); - } - - /// - /// Set the password for the specified user - /// - /// - /// - public async Task SetPasswordAsync(string userName, string password) - { - FlightLogUser user = await GetUserAsync(userName); - user.Password = _hasher.Value.HashPassword(userName, password); - await _context.SaveChangesAsync(); - } - - /// - /// Delete the specified user - /// - /// - public void DeleteUser(string userName) - { - FlightLogUser user = GetUser(userName); - _context.FlightLogUsers.Remove(user); - _context.SaveChanges(); - } - - /// - /// Delete the specified user - /// - /// - public async Task DeleteUserAsync(string userName) - { - FlightLogUser user = await GetUserAsync(userName); - _context.FlightLogUsers.Remove(user); - await _context.SaveChangesAsync(); - } - - /// - /// Throw an exception if a user doesn't exist - /// - /// - /// - [ExcludeFromCodeCoverage] - private void ThrowIfUserNotFound(FlightLogUser user, object userId) - { - if (user == null) - { - string message = $"User {userId} not found"; - throw new UserNotFoundException(message); - } - } - - /// - /// Throw an exception if a user already exists - /// - /// - /// - [ExcludeFromCodeCoverage] - private void ThrowIfUserFound(FlightLogUser user, object userId) - { - if (user != null) - { - throw new UserExistsException($"User {userId} already exists"); - } - } - } -} +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Threading.Tasks; +using DroneFlightLog.Data.Entities; +using DroneFlightLog.Data.Exceptions; +using DroneFlightLog.Data.Interfaces; +using Microsoft.EntityFrameworkCore; +using Microsoft.AspNetCore.Identity; + +namespace DroneFlightLog.Data.Logic +{ + public class UserManager : IUserManager where T : DbContext, IDroneFlightLogDbContext + { + private Lazy> _hasher; + private readonly T _context; + + public UserManager(T context) + { + _hasher = new Lazy>(() => new PasswordHasher()); + _context = context; + } + + /// + /// Return the user with the specified Id + /// + /// + /// + public FlightLogUser GetUser(int userId) + { + FlightLogUser user = _context.FlightLogUsers.FirstOrDefault(u => u.Id == userId); + ThrowIfUserNotFound(user, userId); + return user; + } + + /// + /// Return the user with the specified Id + /// + /// + /// + public async Task GetUserAsync(int userId) + { + FlightLogUser user = await _context.FlightLogUsers.FirstOrDefaultAsync(u => u.Id == userId); + ThrowIfUserNotFound(user, userId); + return user; + } + + /// + /// Return the user with the specified Id + /// + /// + /// + public FlightLogUser GetUser(string userName) + { + FlightLogUser user = _context.FlightLogUsers.FirstOrDefault(u => u.UserName == userName); + ThrowIfUserNotFound(user, userName); + return user; + } + + /// + /// Return the user with the specified Id + /// + /// + /// + public async Task GetUserAsync(string userName) + { + FlightLogUser user = await _context.FlightLogUsers.FirstOrDefaultAsync(u => u.UserName == userName); + ThrowIfUserNotFound(user, userName); + return user; + } + + /// + /// Get all the current user details + /// + public IEnumerable GetUsers() => + _context.FlightLogUsers; + + /// + /// Get all the current user details + /// + public IAsyncEnumerable GetUsersAsync() => + _context.FlightLogUsers.AsAsyncEnumerable(); + + /// + /// Add a new user, given their details + /// + /// + /// + /// + public FlightLogUser AddUser(string userName, string password) + { + FlightLogUser user = _context.FlightLogUsers.FirstOrDefault(u => u.UserName == userName); + ThrowIfUserFound(user, userName); + + user = new FlightLogUser + { + UserName = userName, + Password = _hasher.Value.HashPassword(userName, password) + }; + + _context.FlightLogUsers.Add(user); + _context.SaveChanges(); + return user; + } + + /// + /// Add a new user, given their details + /// + /// + /// + /// + public async Task AddUserAsync(string userName, string password) + { + FlightLogUser user = await _context.FlightLogUsers.FirstOrDefaultAsync(u => u.UserName == userName); + ThrowIfUserFound(user, userName); + + user = new FlightLogUser + { + UserName = userName, + Password = _hasher.Value.HashPassword(userName, password) + }; + + await _context.FlightLogUsers.AddAsync(user); + await _context.SaveChangesAsync(); + return user; + } + + /// + /// Authenticate the specified user + /// + /// + /// + /// + public bool Authenticate(string userName, string password) + { + FlightLogUser user = GetUser(userName); + PasswordVerificationResult result = _hasher.Value.VerifyHashedPassword(userName, user.Password, password); + if (result == PasswordVerificationResult.SuccessRehashNeeded) + { + user.Password = _hasher.Value.HashPassword(userName, password); + _context.SaveChanges(); + } + return result != PasswordVerificationResult.Failed; + } + + /// + /// Authenticate the specified user + /// + /// + /// + /// + public async Task AuthenticateAsync(string userName, string password) + { + FlightLogUser user = await GetUserAsync(userName); + PasswordVerificationResult result = _hasher.Value.VerifyHashedPassword(userName, user.Password, password); + if (result == PasswordVerificationResult.SuccessRehashNeeded) + { + user.Password = _hasher.Value.HashPassword(userName, password); + await _context.SaveChangesAsync(); + } + return result != PasswordVerificationResult.Failed; + } + + /// + /// Set the password for the specified user + /// + /// + /// + public void SetPassword(string userName, string password) + { + FlightLogUser user = GetUser(userName); + user.Password = _hasher.Value.HashPassword(userName, password); + _context.SaveChanges(); + } + + /// + /// Set the password for the specified user + /// + /// + /// + public async Task SetPasswordAsync(string userName, string password) + { + FlightLogUser user = await GetUserAsync(userName); + user.Password = _hasher.Value.HashPassword(userName, password); + await _context.SaveChangesAsync(); + } + + /// + /// Delete the specified user + /// + /// + public void DeleteUser(string userName) + { + FlightLogUser user = GetUser(userName); + _context.FlightLogUsers.Remove(user); + _context.SaveChanges(); + } + + /// + /// Delete the specified user + /// + /// + public async Task DeleteUserAsync(string userName) + { + FlightLogUser user = await GetUserAsync(userName); + _context.FlightLogUsers.Remove(user); + await _context.SaveChangesAsync(); + } + + /// + /// Throw an exception if a user doesn't exist + /// + /// + /// + [ExcludeFromCodeCoverage] + private void ThrowIfUserNotFound(FlightLogUser user, object userId) + { + if (user == null) + { + string message = $"User {userId} not found"; + throw new UserNotFoundException(message); + } + } + + /// + /// Throw an exception if a user already exists + /// + /// + /// + [ExcludeFromCodeCoverage] + private void ThrowIfUserFound(FlightLogUser user, object userId) + { + if (user != null) + { + throw new UserExistsException($"User {userId} already exists"); + } + } + } +} From 1c6f3a19fc03e64e6f0f264900b8b0842a76f85a Mon Sep 17 00:00:00 2001 From: Dave Walker Date: Mon, 11 Mar 2024 18:34:31 +0000 Subject: [PATCH 04/12] Added the maintainers controller and database migrations --- .../Controllers/MaintainersController.cs | 116 +++++ .../Controllers/OperatorsController.cs | 2 +- .../DroneFlightLog.Api.csproj | 10 +- .../DroneFlightLog.Data.InMemory.csproj | 12 +- .../DroneFlightLog.Data.Sqlite.csproj | 12 +- .../20240311181826_MaintenanceLog.Designer.cs | 396 ++++++++++++++++++ .../20240311181826_MaintenanceLog.cs | 78 ++++ .../DroneFlightLogDbContextModelSnapshot.cs | 88 +++- .../DroneFlightLog.Data.Tests.csproj | 13 +- .../DroneFlightLog.Data.csproj | 8 +- .../Logic/MaintenanceRecordManager.cs | 8 +- .../DroneFlightLog.Importer.csproj | 10 +- .../DroneFlightLog.Manager.csproj | 14 +- src/DroneFlightLog.Manager/appsettings.json | 2 +- .../DroneFlightLog.Mvc.csproj | 10 +- src/DroneFlightLog.Mvc/Startup.cs | 2 +- 16 files changed, 726 insertions(+), 55 deletions(-) create mode 100644 src/DroneFlightLog.Api/Controllers/MaintainersController.cs create mode 100644 src/DroneFlightLog.Data.Sqlite/Migrations/20240311181826_MaintenanceLog.Designer.cs create mode 100644 src/DroneFlightLog.Data.Sqlite/Migrations/20240311181826_MaintenanceLog.cs diff --git a/src/DroneFlightLog.Api/Controllers/MaintainersController.cs b/src/DroneFlightLog.Api/Controllers/MaintainersController.cs new file mode 100644 index 0000000..999d013 --- /dev/null +++ b/src/DroneFlightLog.Api/Controllers/MaintainersController.cs @@ -0,0 +1,116 @@ +using DroneFlightLog.Data.Entities; +using DroneFlightLog.Data.Exceptions; +using DroneFlightLog.Data.Interfaces; +using DroneFlightLog.Data.Sqlite; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Web; + +namespace DroneFlightLog.Api.Controllers +{ + [Authorize] + [ApiController] + [ApiConventionType(typeof(DefaultApiConventions))] + [Route("[controller]")] + public class MaintainersController : Controller + { + private readonly IDroneFlightLogFactory _factory; + + public MaintainersController(IDroneFlightLogFactory factory) + { + _factory = factory; + } + + [HttpGet] + [Route("{id}")] + public async Task> GetMaintainerAsync(int id) + { + Maintainer maintainer; + + try + { + maintainer = await _factory.Maintainers.GetMaintainerAsync(id); + } + catch (MaintainerNotFoundException) + { + return NotFound(); + } + + return maintainer; + } + + [HttpGet] + [Route("")] + public async Task>> GetMaintainersAsync() + { + List maintainers = await _factory.Maintainers.GetMaintainersAsync().ToListAsync(); + + if (!maintainers.Any()) + { + return NoContent(); + } + + return maintainers; + } + + [HttpGet] + [Route("{firstNames}/{surname}")] + public async Task> FindMaintainerAsync(string firstNames, string surname) + { + string decodedFirstNames = HttpUtility.UrlDecode(firstNames); + string decodedSurname = HttpUtility.UrlDecode(surname); + Maintainer maintainer = await _factory.Maintainers.FindMaintainerAsync(decodedFirstNames, decodedSurname); + + if (maintainer == null) + { + return NotFound(); + } + + return maintainer; + } + + [HttpPut] + [Route("")] + public async Task> UpdateMaintainerAsync([FromBody] Maintainer template) + { + Maintainer maintainer; + + try + { + maintainer = await _factory.Maintainers.UpdateMaintainerAsync(template.Id, + template.FirstNames, + template.Surname); + await _factory.Context.SaveChangesAsync(); + } + catch (MaintainerNotFoundException) + { + return NotFound(); + } + + return maintainer; + } + + [HttpPost] + [Route("")] + public async Task> CreateMaintainerAsync([FromBody] Maintainer template) + { + Maintainer maintainer; + + try + { + maintainer = await _factory.Maintainers.AddMaintainerAsync(template.FirstNames, + template.Surname); + await _factory.Context.SaveChangesAsync(); + } + catch (MaintainerExistsException) + { + return BadRequest(); + } + + return maintainer; + } + } +} diff --git a/src/DroneFlightLog.Api/Controllers/OperatorsController.cs b/src/DroneFlightLog.Api/Controllers/OperatorsController.cs index c737364..72d3ba0 100644 --- a/src/DroneFlightLog.Api/Controllers/OperatorsController.cs +++ b/src/DroneFlightLog.Api/Controllers/OperatorsController.cs @@ -34,7 +34,7 @@ public async Task> GetOperatorAsync(int id) { op = await _factory.Operators.GetOperatorAsync(id); } - catch (LocationNotFoundException) + catch (OperatorNotFoundException) { return NotFound(); } diff --git a/src/DroneFlightLog.Api/DroneFlightLog.Api.csproj b/src/DroneFlightLog.Api/DroneFlightLog.Api.csproj index fe946e7..7e76809 100644 --- a/src/DroneFlightLog.Api/DroneFlightLog.Api.csproj +++ b/src/DroneFlightLog.Api/DroneFlightLog.Api.csproj @@ -20,11 +20,11 @@ - - - - - + + + + + diff --git a/src/DroneFlightLog.Data.InMemory/DroneFlightLog.Data.InMemory.csproj b/src/DroneFlightLog.Data.InMemory/DroneFlightLog.Data.InMemory.csproj index 616cd21..e216247 100644 --- a/src/DroneFlightLog.Data.InMemory/DroneFlightLog.Data.InMemory.csproj +++ b/src/DroneFlightLog.Data.InMemory/DroneFlightLog.Data.InMemory.csproj @@ -3,10 +3,10 @@ net8.0 DroneFlightLog.Data.InMemory - 1.1.1.0 + 1.1.2.0 true Dave Walker - Copyright (c) 2020, 2021, 2022, 2023 Dave Walker + Copyright (c) 2020, 2021, 2022, 2023, 2024 Dave Walker Dave Walker NuGet package and framework updates Drone Flight Logging In Memory Database Layer @@ -16,16 +16,16 @@ https://github.com/davewalker5/DroneFlightLogDb MIT false - 1.1.1.0 + 1.1.2.0 - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/src/DroneFlightLog.Data.Sqlite/DroneFlightLog.Data.Sqlite.csproj b/src/DroneFlightLog.Data.Sqlite/DroneFlightLog.Data.Sqlite.csproj index 95f9643..c17e550 100644 --- a/src/DroneFlightLog.Data.Sqlite/DroneFlightLog.Data.Sqlite.csproj +++ b/src/DroneFlightLog.Data.Sqlite/DroneFlightLog.Data.Sqlite.csproj @@ -3,10 +3,10 @@ net8.0 DroneFlightLog.Data.Sqlite - 1.1.1.0 + 1.1.2.0 true Dave Walker - Copyright (c) 2020, 2021, 2022, 2023 Dave Walker + Copyright (c) 2020, 2021, 2022, 2023, 2024 Dave Walker Dave Walker NuGet package and framework updates Drone Flight Logging SQLite Database Layer @@ -16,19 +16,19 @@ https://github.com/davewalker5/DroneFlightLogDb MIT false - 1.1.1.0 + 1.1.2.0 - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + diff --git a/src/DroneFlightLog.Data.Sqlite/Migrations/20240311181826_MaintenanceLog.Designer.cs b/src/DroneFlightLog.Data.Sqlite/Migrations/20240311181826_MaintenanceLog.Designer.cs new file mode 100644 index 0000000..142df3f --- /dev/null +++ b/src/DroneFlightLog.Data.Sqlite/Migrations/20240311181826_MaintenanceLog.Designer.cs @@ -0,0 +1,396 @@ +// +using System; +using DroneFlightLog.Data.Sqlite; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace DroneFlightLog.Data.Sqlite.Migrations +{ + [DbContext(typeof(DroneFlightLogDbContext))] + [Migration("20240311181826_MaintenanceLog")] + partial class MaintenanceLog + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "8.0.2"); + + modelBuilder.Entity("DroneFlightLog.Data.Entities.Address", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Country") + .HasColumnType("TEXT"); + + b.Property("County") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("TEXT"); + + b.Property("Postcode") + .HasColumnType("TEXT"); + + b.Property("Street") + .HasColumnType("TEXT"); + + b.Property("Town") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Addresses"); + }); + + modelBuilder.Entity("DroneFlightLog.Data.Entities.Drone", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ModelId") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("SerialNumber") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ModelId"); + + b.ToTable("Drones"); + }); + + modelBuilder.Entity("DroneFlightLog.Data.Entities.Flight", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DroneId") + .HasColumnType("INTEGER"); + + b.Property("End") + .HasColumnType("TEXT"); + + b.Property("LocationId") + .HasColumnType("INTEGER"); + + b.Property("OperatorId") + .HasColumnType("INTEGER"); + + b.Property("Start") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DroneId"); + + b.HasIndex("LocationId"); + + b.HasIndex("OperatorId"); + + b.ToTable("Flights"); + }); + + modelBuilder.Entity("DroneFlightLog.Data.Entities.FlightLogUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Password") + .HasColumnType("TEXT"); + + b.Property("UserName") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("FlightLogUsers"); + }); + + modelBuilder.Entity("DroneFlightLog.Data.Entities.FlightProperty", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DataType") + .HasColumnType("INTEGER"); + + b.Property("IsSingleInstance") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("FlightProperties"); + }); + + modelBuilder.Entity("DroneFlightLog.Data.Entities.FlightPropertyValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateValue") + .HasColumnType("TEXT"); + + b.Property("FlightId") + .HasColumnType("INTEGER"); + + b.Property("NumberValue") + .HasColumnType("TEXT"); + + b.Property("PropertyId") + .HasColumnType("INTEGER"); + + b.Property("StringValue") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("FlightId"); + + b.HasIndex("PropertyId"); + + b.ToTable("FlightPropertyValues"); + }); + + modelBuilder.Entity("DroneFlightLog.Data.Entities.Location", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Locations"); + }); + + modelBuilder.Entity("DroneFlightLog.Data.Entities.Maintainer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("FirstNames") + .HasColumnType("TEXT"); + + b.Property("Surname") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Maintainers"); + }); + + modelBuilder.Entity("DroneFlightLog.Data.Entities.MaintenanceRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateCompleted") + .HasColumnType("TEXT"); + + b.Property("Description") + .HasColumnType("TEXT"); + + b.Property("DroneId") + .HasColumnType("INTEGER"); + + b.Property("MaintainerId") + .HasColumnType("INTEGER"); + + b.Property("Notes") + .HasColumnType("TEXT"); + + b.Property("RecordType") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("MaintainerId"); + + b.ToTable("MaintenanceRecords"); + }); + + modelBuilder.Entity("DroneFlightLog.Data.Entities.Manufacturer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Manufacturers"); + }); + + modelBuilder.Entity("DroneFlightLog.Data.Entities.Model", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ManufacturerId") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ManufacturerId"); + + b.ToTable("Models"); + }); + + modelBuilder.Entity("DroneFlightLog.Data.Entities.Operator", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AddressId") + .HasColumnType("INTEGER"); + + b.Property("DoB") + .HasColumnType("TEXT"); + + b.Property("FirstNames") + .HasColumnType("TEXT"); + + b.Property("FlyerNumber") + .HasColumnType("TEXT"); + + b.Property("OperatorNumber") + .HasColumnType("TEXT"); + + b.Property("Surname") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AddressId"); + + b.ToTable("Operators"); + }); + + modelBuilder.Entity("DroneFlightLog.Data.Entities.Drone", b => + { + b.HasOne("DroneFlightLog.Data.Entities.Model", "Model") + .WithMany() + .HasForeignKey("ModelId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Model"); + }); + + modelBuilder.Entity("DroneFlightLog.Data.Entities.Flight", b => + { + b.HasOne("DroneFlightLog.Data.Entities.Drone", "Drone") + .WithMany() + .HasForeignKey("DroneId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("DroneFlightLog.Data.Entities.Location", "Location") + .WithMany() + .HasForeignKey("LocationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("DroneFlightLog.Data.Entities.Operator", "Operator") + .WithMany() + .HasForeignKey("OperatorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Drone"); + + b.Navigation("Location"); + + b.Navigation("Operator"); + }); + + modelBuilder.Entity("DroneFlightLog.Data.Entities.FlightPropertyValue", b => + { + b.HasOne("DroneFlightLog.Data.Entities.Flight", "Flight") + .WithMany("Properties") + .HasForeignKey("FlightId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("DroneFlightLog.Data.Entities.FlightProperty", "Property") + .WithMany() + .HasForeignKey("PropertyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Flight"); + + b.Navigation("Property"); + }); + + modelBuilder.Entity("DroneFlightLog.Data.Entities.MaintenanceRecord", b => + { + b.HasOne("DroneFlightLog.Data.Entities.Maintainer", "Maintainer") + .WithMany() + .HasForeignKey("MaintainerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Maintainer"); + }); + + modelBuilder.Entity("DroneFlightLog.Data.Entities.Model", b => + { + b.HasOne("DroneFlightLog.Data.Entities.Manufacturer", "Manufacturer") + .WithMany() + .HasForeignKey("ManufacturerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Manufacturer"); + }); + + modelBuilder.Entity("DroneFlightLog.Data.Entities.Operator", b => + { + b.HasOne("DroneFlightLog.Data.Entities.Address", "Address") + .WithMany() + .HasForeignKey("AddressId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Address"); + }); + + modelBuilder.Entity("DroneFlightLog.Data.Entities.Flight", b => + { + b.Navigation("Properties"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/DroneFlightLog.Data.Sqlite/Migrations/20240311181826_MaintenanceLog.cs b/src/DroneFlightLog.Data.Sqlite/Migrations/20240311181826_MaintenanceLog.cs new file mode 100644 index 0000000..b54b103 --- /dev/null +++ b/src/DroneFlightLog.Data.Sqlite/Migrations/20240311181826_MaintenanceLog.cs @@ -0,0 +1,78 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace DroneFlightLog.Data.Sqlite.Migrations +{ + /// + public partial class MaintenanceLog : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "Token", + table: "FlightLogUsers"); + + migrationBuilder.CreateTable( + name: "Maintainers", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + FirstNames = table.Column(type: "TEXT", nullable: true), + Surname = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Maintainers", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "MaintenanceRecords", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + MaintainerId = table.Column(type: "INTEGER", nullable: false), + DroneId = table.Column(type: "INTEGER", nullable: false), + DateCompleted = table.Column(type: "TEXT", nullable: false), + RecordType = table.Column(type: "INTEGER", nullable: false), + Description = table.Column(type: "TEXT", nullable: true), + Notes = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_MaintenanceRecords", x => x.Id); + table.ForeignKey( + name: "FK_MaintenanceRecords_Maintainers_MaintainerId", + column: x => x.MaintainerId, + principalTable: "Maintainers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_MaintenanceRecords_MaintainerId", + table: "MaintenanceRecords", + column: "MaintainerId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "MaintenanceRecords"); + + migrationBuilder.DropTable( + name: "Maintainers"); + + migrationBuilder.AddColumn( + name: "Token", + table: "FlightLogUsers", + type: "TEXT", + nullable: true); + } + } +} diff --git a/src/DroneFlightLog.Data.Sqlite/Migrations/DroneFlightLogDbContextModelSnapshot.cs b/src/DroneFlightLog.Data.Sqlite/Migrations/DroneFlightLogDbContextModelSnapshot.cs index 2e4730e..7d16791 100644 --- a/src/DroneFlightLog.Data.Sqlite/Migrations/DroneFlightLogDbContextModelSnapshot.cs +++ b/src/DroneFlightLog.Data.Sqlite/Migrations/DroneFlightLogDbContextModelSnapshot.cs @@ -5,6 +5,8 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +#nullable disable + namespace DroneFlightLog.Data.Sqlite.Migrations { [DbContext(typeof(DroneFlightLogDbContext))] @@ -13,8 +15,7 @@ partial class DroneFlightLogDbContextModelSnapshot : ModelSnapshot protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "3.1.1"); + modelBuilder.HasAnnotation("ProductVersion", "8.0.2"); modelBuilder.Entity("DroneFlightLog.Data.Entities.Address", b => { @@ -108,9 +109,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Password") .HasColumnType("TEXT"); - b.Property("Token") - .HasColumnType("TEXT"); - b.Property("UserName") .HasColumnType("TEXT"); @@ -183,6 +181,54 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("Locations"); }); + modelBuilder.Entity("DroneFlightLog.Data.Entities.Maintainer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("FirstNames") + .HasColumnType("TEXT"); + + b.Property("Surname") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Maintainers"); + }); + + modelBuilder.Entity("DroneFlightLog.Data.Entities.MaintenanceRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateCompleted") + .HasColumnType("TEXT"); + + b.Property("Description") + .HasColumnType("TEXT"); + + b.Property("DroneId") + .HasColumnType("INTEGER"); + + b.Property("MaintainerId") + .HasColumnType("INTEGER"); + + b.Property("Notes") + .HasColumnType("TEXT"); + + b.Property("RecordType") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("MaintainerId"); + + b.ToTable("MaintenanceRecords"); + }); + modelBuilder.Entity("DroneFlightLog.Data.Entities.Manufacturer", b => { b.Property("Id") @@ -254,6 +300,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasForeignKey("ModelId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("Model"); }); modelBuilder.Entity("DroneFlightLog.Data.Entities.Flight", b => @@ -275,6 +323,12 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasForeignKey("OperatorId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("Drone"); + + b.Navigation("Location"); + + b.Navigation("Operator"); }); modelBuilder.Entity("DroneFlightLog.Data.Entities.FlightPropertyValue", b => @@ -290,6 +344,21 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasForeignKey("PropertyId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("Flight"); + + b.Navigation("Property"); + }); + + modelBuilder.Entity("DroneFlightLog.Data.Entities.MaintenanceRecord", b => + { + b.HasOne("DroneFlightLog.Data.Entities.Maintainer", "Maintainer") + .WithMany() + .HasForeignKey("MaintainerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Maintainer"); }); modelBuilder.Entity("DroneFlightLog.Data.Entities.Model", b => @@ -299,6 +368,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasForeignKey("ManufacturerId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("Manufacturer"); }); modelBuilder.Entity("DroneFlightLog.Data.Entities.Operator", b => @@ -308,6 +379,13 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasForeignKey("AddressId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("Address"); + }); + + modelBuilder.Entity("DroneFlightLog.Data.Entities.Flight", b => + { + b.Navigation("Properties"); }); #pragma warning restore 612, 618 } diff --git a/src/DroneFlightLog.Data.Tests/DroneFlightLog.Data.Tests.csproj b/src/DroneFlightLog.Data.Tests/DroneFlightLog.Data.Tests.csproj index 9720e43..20dabcd 100644 --- a/src/DroneFlightLog.Data.Tests/DroneFlightLog.Data.Tests.csproj +++ b/src/DroneFlightLog.Data.Tests/DroneFlightLog.Data.Tests.csproj @@ -10,15 +10,14 @@ - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/src/DroneFlightLog.Data/DroneFlightLog.Data.csproj b/src/DroneFlightLog.Data/DroneFlightLog.Data.csproj index a8b28b0..7d6b14c 100644 --- a/src/DroneFlightLog.Data/DroneFlightLog.Data.csproj +++ b/src/DroneFlightLog.Data/DroneFlightLog.Data.csproj @@ -3,10 +3,10 @@ net8.0 DroneFlightLog.Data - 1.1.1.0 + 1.1.2.0 true Dave Walker - Copyright (c) 2020, 2021, 2022, 2023 Dave Walker + Copyright (c) 2020, 2021, 2022, 2023, 2024 Dave Walker Dave Walker NuGet package and framework updates Drone Flight Logging Database Layer @@ -16,11 +16,11 @@ https://github.com/davewalker5/DroneFlightLogDb MIT false - 1.1.1.0 + 1.1.2.0 - + diff --git a/src/DroneFlightLog.Data/Logic/MaintenanceRecordManager.cs b/src/DroneFlightLog.Data/Logic/MaintenanceRecordManager.cs index d5df736..5cd2238 100644 --- a/src/DroneFlightLog.Data/Logic/MaintenanceRecordManager.cs +++ b/src/DroneFlightLog.Data/Logic/MaintenanceRecordManager.cs @@ -29,7 +29,7 @@ internal MaintenanceRecordManager(IDroneFlightLogFactory factory) /// /// /// - public MaintenanceRecord AddMaintenanceRecord(int maintainerId, int droneId, MaintenanceRecordType type, DateTime completed, string description, string? notes) + public MaintenanceRecord AddMaintenanceRecord(int maintainerId, int droneId, MaintenanceRecordType type, DateTime completed, string description, string notes) { // These will throw exceptions if the corresponding entities do not exist _factory.Maintainers.GetMaintainer(maintainerId); @@ -59,7 +59,7 @@ public MaintenanceRecord AddMaintenanceRecord(int maintainerId, int droneId, Mai /// /// /// - public async Task AddMaintenanceRecordAsync(int maintainerId, int droneId, MaintenanceRecordType type, DateTime completed, string description, string? notes) + public async Task AddMaintenanceRecordAsync(int maintainerId, int droneId, MaintenanceRecordType type, DateTime completed, string description, string notes) { // These will throw exceptions if the corresponding entities do not exist await _factory.Maintainers.GetMaintainerAsync(maintainerId); @@ -114,7 +114,7 @@ public async Task GetMaintenanceRecordAsync(int id) /// /// /// - public MaintenanceRecord UpdateMaintenanceRecord(int id, int maintainerId, int droneId, MaintenanceRecordType type, DateTime completed, string description, string? notes) + public MaintenanceRecord UpdateMaintenanceRecord(int id, int maintainerId, int droneId, MaintenanceRecordType type, DateTime completed, string description, string notes) { // These will throw exceptions if the corresponding entities do not exist _factory.Maintainers.GetMaintainer(maintainerId); @@ -142,7 +142,7 @@ public MaintenanceRecord UpdateMaintenanceRecord(int id, int maintainerId, int d /// /// /// - public async Task UpdateMaintenanceRecordAsync(int id, int maintainerId, int droneId, MaintenanceRecordType type, DateTime completed, string description, string? notes) + public async Task UpdateMaintenanceRecordAsync(int id, int maintainerId, int droneId, MaintenanceRecordType type, DateTime completed, string description, string notes) { // These will throw exceptions if the corresponding entities do not exist await _factory.Maintainers.GetMaintainerAsync(maintainerId); diff --git a/src/DroneFlightLog.Importer/DroneFlightLog.Importer.csproj b/src/DroneFlightLog.Importer/DroneFlightLog.Importer.csproj index ba6b06f..5222c76 100644 --- a/src/DroneFlightLog.Importer/DroneFlightLog.Importer.csproj +++ b/src/DroneFlightLog.Importer/DroneFlightLog.Importer.csproj @@ -3,9 +3,9 @@ Exe net8.0 - 1.1.1.0 - 1.1.1.0 - 1.1.1.0 + 1.1.2.0 + 1.1.2.0 + 1.1.2.0 Release;Debug enable false @@ -24,8 +24,8 @@ - - + + diff --git a/src/DroneFlightLog.Manager/DroneFlightLog.Manager.csproj b/src/DroneFlightLog.Manager/DroneFlightLog.Manager.csproj index 98e3c3a..d34e87d 100644 --- a/src/DroneFlightLog.Manager/DroneFlightLog.Manager.csproj +++ b/src/DroneFlightLog.Manager/DroneFlightLog.Manager.csproj @@ -1,11 +1,11 @@ - + Exe net8.0 - 1.1.1.0 - 1.1.1.0 - 1.1.1 + 1.1.2.0 + 1.1.2.0 + 1.1.2 enable false @@ -19,7 +19,11 @@ - + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/src/DroneFlightLog.Manager/appsettings.json b/src/DroneFlightLog.Manager/appsettings.json index 2c1c79d..3f3f214 100644 --- a/src/DroneFlightLog.Manager/appsettings.json +++ b/src/DroneFlightLog.Manager/appsettings.json @@ -1,5 +1,5 @@ { "ConnectionStrings": { - "DroneLogDb": "Data Source=droneflightlog.db" + "DroneLogDb": "Data Source=C:\\MyApps\\DroneFlightLog\\droneflightlog_dev.db" } } diff --git a/src/DroneFlightLog.Mvc/DroneFlightLog.Mvc.csproj b/src/DroneFlightLog.Mvc/DroneFlightLog.Mvc.csproj index 67164db..73c42df 100644 --- a/src/DroneFlightLog.Mvc/DroneFlightLog.Mvc.csproj +++ b/src/DroneFlightLog.Mvc/DroneFlightLog.Mvc.csproj @@ -2,9 +2,9 @@ net8.0 - 1.1.4.0 - 1.1.4.0 - 1.1.4.0 + 1.1.5.0 + 1.1.5.0 + 1.1.5.0 Release;Debug false @@ -38,8 +38,8 @@ - - + + diff --git a/src/DroneFlightLog.Mvc/Startup.cs b/src/DroneFlightLog.Mvc/Startup.cs index 2cb915a..68114df 100644 --- a/src/DroneFlightLog.Mvc/Startup.cs +++ b/src/DroneFlightLog.Mvc/Startup.cs @@ -117,7 +117,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) string token = context.Session.GetString(LoginController.TokenSessionKey); if (!string.IsNullOrEmpty(token)) { - context.Request.Headers.Add("Authorization", "Bearer " + token); + context.Request.Headers.Append("Authorization", "Bearer " + token); } await next(); }); From 3b01a3fa6f3671375c72201548bcdd56d020f1c3 Mon Sep 17 00:00:00 2001 From: Dave Walker Date: Tue, 12 Mar 2024 08:34:40 +0000 Subject: [PATCH 05/12] Added maintainer maintenance UI --- docker/api/Dockerfile | 4 +- .../DroneFlightLog.Api.csproj | 6 +- .../Api/MaintainersClient.cs | 100 ++++++++++++++++ src/DroneFlightLog.Mvc/Api/OperatorClient.cs | 2 - .../Controllers/MaintainersController.cs | 107 ++++++++++++++++++ .../DroneFlightLog.Mvc.csproj | 2 - src/DroneFlightLog.Mvc/Entities/Maintainer.cs | 18 +++ .../Models/AddMaintainerViewModel.cs | 6 + .../Models/EditMaintainerViewModel.cs | 6 + .../Models/MaintainerViewModelBase.cs | 21 ++++ src/DroneFlightLog.Mvc/Startup.cs | 1 + .../Views/Maintainers/Add.cshtml | 30 +++++ .../Views/Maintainers/Edit.cshtml | 20 ++++ .../Views/Maintainers/Index.cshtml | 47 ++++++++ .../Views/Maintainers/Maintainer.cshtml | 38 +++++++ .../Views/Operators/Index.cshtml | 2 +- .../Views/Shared/_Layout.cshtml | 6 +- src/DroneFlightLog.Mvc/appsettings.json | 6 +- 18 files changed, 409 insertions(+), 13 deletions(-) create mode 100644 src/DroneFlightLog.Mvc/Api/MaintainersClient.cs create mode 100644 src/DroneFlightLog.Mvc/Controllers/MaintainersController.cs create mode 100644 src/DroneFlightLog.Mvc/Entities/Maintainer.cs create mode 100644 src/DroneFlightLog.Mvc/Models/AddMaintainerViewModel.cs create mode 100644 src/DroneFlightLog.Mvc/Models/EditMaintainerViewModel.cs create mode 100644 src/DroneFlightLog.Mvc/Models/MaintainerViewModelBase.cs create mode 100644 src/DroneFlightLog.Mvc/Views/Maintainers/Add.cshtml create mode 100644 src/DroneFlightLog.Mvc/Views/Maintainers/Edit.cshtml create mode 100644 src/DroneFlightLog.Mvc/Views/Maintainers/Index.cshtml create mode 100644 src/DroneFlightLog.Mvc/Views/Maintainers/Maintainer.cshtml diff --git a/docker/api/Dockerfile b/docker/api/Dockerfile index 65a7adc..a8c04ce 100644 --- a/docker/api/Dockerfile +++ b/docker/api/Dockerfile @@ -1,4 +1,4 @@ FROM mcr.microsoft.com/dotnet/core/aspnet:latest -COPY droneflightlog.api-1.2.1.0 /opt/droneflightlog.api-1.2.1.0 -WORKDIR /opt/droneflightlog.api-1.2.1.0/bin +COPY droneflightlog.api-1.2.2.0 /opt/droneflightlog.api-1.2.2.0 +WORKDIR /opt/droneflightlog.api-1.2.2.0/bin ENTRYPOINT [ "./DroneFlightLog.Api" ] diff --git a/src/DroneFlightLog.Api/DroneFlightLog.Api.csproj b/src/DroneFlightLog.Api/DroneFlightLog.Api.csproj index 7e76809..001ec8c 100644 --- a/src/DroneFlightLog.Api/DroneFlightLog.Api.csproj +++ b/src/DroneFlightLog.Api/DroneFlightLog.Api.csproj @@ -2,9 +2,9 @@ net8.0 - 1.2.1.0 - 1.2.1.0 - 1.2.1.0 + 1.2.2.0 + 1.2.2.0 + 1.2.2.0 Release;Debug false diff --git a/src/DroneFlightLog.Mvc/Api/MaintainersClient.cs b/src/DroneFlightLog.Mvc/Api/MaintainersClient.cs new file mode 100644 index 0000000..c0d66d9 --- /dev/null +++ b/src/DroneFlightLog.Mvc/Api/MaintainersClient.cs @@ -0,0 +1,100 @@ +using DroneFlightLog.Mvc.Configuration; +using DroneFlightLog.Mvc.Entities; +using DroneFlightLog.Mvc.Interfaces; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Options; +using Newtonsoft.Json; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Threading.Tasks; + +namespace DroneFlightLog.Mvc.Api +{ + public class MaintainersClient : DroneFlightLogClientBase + { + private const string RouteKey = "Maintainers"; + private const string CacheKey = "Maintainers"; + + public MaintainersClient(HttpClient client, IOptions settings, IHttpContextAccessor accessor, ICacheWrapper cache) + : base(client, settings, accessor, cache) + { + } + + /// + /// Return a list of maintainer details + /// + /// + public async Task> GetMaintainersAsync() + { + List maintainers = _cache.Get>(CacheKey); + if (maintainers == null) + { + string json = await SendIndirectAsync(RouteKey, null, HttpMethod.Get); + maintainers = JsonConvert.DeserializeObject>(json); + _cache.Set(CacheKey, maintainers, _settings.Value.CacheLifetimeSeconds); + } + return maintainers; + } + + /// + /// Return the maintainer with the specified Id + /// + /// + /// + public async Task GetMaintainerAsync(int id) + { + List maintainers = await GetMaintainersAsync(); + Maintainer maintainer = maintainers.First(l => l.Id == id); + return maintainer; + } + + /// + /// Create a new maintainer + /// + /// + /// + /// + public async Task AddMaintainerAsync(string firstNames, string surname) + { + _cache.Remove(CacheKey); + + dynamic template = new + { + FirstNames = firstNames, + Surname = surname + }; + + string data = JsonConvert.SerializeObject(template); + string json = await SendIndirectAsync(RouteKey, data, HttpMethod.Post); + + Maintainer maintainer = JsonConvert.DeserializeObject(json); + return maintainer; + } + + /// + /// Update an existing maintainer + /// + /// + /// + /// + /// + public async Task UpdateMaintainerAsync(int id, string firstNames, string surname) + { + _cache.Remove(CacheKey); + + dynamic template = new + { + Id = id, + FirstNames = firstNames, + Surname = surname + }; + + string data = JsonConvert.SerializeObject(template); + string json = await SendIndirectAsync(RouteKey, data, HttpMethod.Put); + + Maintainer maintainer = JsonConvert.DeserializeObject(json); + return maintainer; + } + } +} diff --git a/src/DroneFlightLog.Mvc/Api/OperatorClient.cs b/src/DroneFlightLog.Mvc/Api/OperatorClient.cs index cd3a48c..7626b5b 100644 --- a/src/DroneFlightLog.Mvc/Api/OperatorClient.cs +++ b/src/DroneFlightLog.Mvc/Api/OperatorClient.cs @@ -45,8 +45,6 @@ public async Task> GetOperatorsAsync() /// public async Task GetOperatorAsync(int id) { - // TODO : This needs to be replaced with a call to retrieve a single - // operator by Id. For now, retrieve them all then pick the one required List operators = await GetOperatorsAsync(); Operator op = operators.First(l => l.Id == id); return op; diff --git a/src/DroneFlightLog.Mvc/Controllers/MaintainersController.cs b/src/DroneFlightLog.Mvc/Controllers/MaintainersController.cs new file mode 100644 index 0000000..45981e4 --- /dev/null +++ b/src/DroneFlightLog.Mvc/Controllers/MaintainersController.cs @@ -0,0 +1,107 @@ +using DroneFlightLog.Mvc.Api; +using DroneFlightLog.Mvc.Entities; +using DroneFlightLog.Mvc.Models; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace DroneFlightLog.Mvc.Controllers +{ + [Authorize] + public class MaintainersController : Controller + { + private readonly MaintainersClient _operators; + + public MaintainersController(MaintainersClient maintainers) + { + _operators = maintainers; + } + + /// + /// Serve the maintainers list page + /// + /// + [HttpGet] + public async Task Index() + { + List operators = await _operators.GetMaintainersAsync(); + return View(operators); + } + + /// + /// Serve the page to add a new maintainer + /// + /// + [HttpGet] + public IActionResult Add() + { + return View(new AddMaintainerViewModel()); + } + + /// + /// Handle POST events to save new maintainers + /// + /// + /// + [HttpPost] + [ValidateAntiForgeryToken] + public async Task Add(AddMaintainerViewModel model) + { + if (ModelState.IsValid) + { + Maintainer maintainer = await _operators.AddMaintainerAsync( + model.Maintainer.FirstNames, + model.Maintainer.Surname); + + ModelState.Clear(); + model.Clear(); + model.Message = $"Maintainer '{maintainer.FirstNames} {maintainer.Surname}' added successfully"; + } + + return View(model); + } + + /// + /// Serve the page to edit an existing maintainer + /// + /// + /// + [HttpGet] + public async Task Edit(int id) + { + Maintainer maintainer = await _operators.GetMaintainerAsync(id); + EditMaintainerViewModel model = new EditMaintainerViewModel(); + model.Maintainer = maintainer; + return View(model); + } + + /// + /// Handle POST events to update existing maintainers + /// + /// + /// + [HttpPost] + [ValidateAntiForgeryToken] + public async Task Edit(EditMaintainerViewModel model) + { + IActionResult result; + + if (ModelState.IsValid) + { + Maintainer maintainer = await _operators.UpdateMaintainerAsync( + model.Maintainer.Id, + model.Maintainer.FirstNames, + model.Maintainer.Surname); + + result = RedirectToAction("Index"); + } + else + { + result = View(model); + } + + return result; + } + } +} diff --git a/src/DroneFlightLog.Mvc/DroneFlightLog.Mvc.csproj b/src/DroneFlightLog.Mvc/DroneFlightLog.Mvc.csproj index 73c42df..d2eebcb 100644 --- a/src/DroneFlightLog.Mvc/DroneFlightLog.Mvc.csproj +++ b/src/DroneFlightLog.Mvc/DroneFlightLog.Mvc.csproj @@ -15,9 +15,7 @@ - - diff --git a/src/DroneFlightLog.Mvc/Entities/Maintainer.cs b/src/DroneFlightLog.Mvc/Entities/Maintainer.cs new file mode 100644 index 0000000..65c7b68 --- /dev/null +++ b/src/DroneFlightLog.Mvc/Entities/Maintainer.cs @@ -0,0 +1,18 @@ +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; + +namespace DroneFlightLog.Mvc.Entities +{ + public class Maintainer + { + public int Id { get; set; } + + [DisplayName("First Names")] + [Required(ErrorMessage = "You must provide a first name")] + public string FirstNames { get; set; } + + [DisplayName("Surname")] + [Required(ErrorMessage = "You must provide a surname")] + public string Surname { get; set; } + } +} diff --git a/src/DroneFlightLog.Mvc/Models/AddMaintainerViewModel.cs b/src/DroneFlightLog.Mvc/Models/AddMaintainerViewModel.cs new file mode 100644 index 0000000..9161736 --- /dev/null +++ b/src/DroneFlightLog.Mvc/Models/AddMaintainerViewModel.cs @@ -0,0 +1,6 @@ +namespace DroneFlightLog.Mvc.Models +{ + public class AddMaintainerViewModel : MaintainerViewModelBase + { + } +} diff --git a/src/DroneFlightLog.Mvc/Models/EditMaintainerViewModel.cs b/src/DroneFlightLog.Mvc/Models/EditMaintainerViewModel.cs new file mode 100644 index 0000000..3868029 --- /dev/null +++ b/src/DroneFlightLog.Mvc/Models/EditMaintainerViewModel.cs @@ -0,0 +1,6 @@ +namespace DroneFlightLog.Mvc.Models +{ + public class EditMaintainerViewModel : MaintainerViewModelBase + { + } +} diff --git a/src/DroneFlightLog.Mvc/Models/MaintainerViewModelBase.cs b/src/DroneFlightLog.Mvc/Models/MaintainerViewModelBase.cs new file mode 100644 index 0000000..399df8d --- /dev/null +++ b/src/DroneFlightLog.Mvc/Models/MaintainerViewModelBase.cs @@ -0,0 +1,21 @@ +using DroneFlightLog.Mvc.Entities; + +namespace DroneFlightLog.Mvc.Models +{ + public abstract class MaintainerViewModelBase + { + public Maintainer Maintainer { get; set; } + public string Message { get; set; } + + public MaintainerViewModelBase() + { + Clear(); + } + + public virtual void Clear() + { + Maintainer = new Maintainer(); + Message = ""; + } + } +} diff --git a/src/DroneFlightLog.Mvc/Startup.cs b/src/DroneFlightLog.Mvc/Startup.cs index 68114df..2e82ef4 100644 --- a/src/DroneFlightLog.Mvc/Startup.cs +++ b/src/DroneFlightLog.Mvc/Startup.cs @@ -58,6 +58,7 @@ public void ConfigureServices(IServiceCollection services) services.AddHttpClient(); services.AddHttpClient(); services.AddHttpClient(); + services.AddHttpClient(); // Configure session state for token storage services.AddSession(options => diff --git a/src/DroneFlightLog.Mvc/Views/Maintainers/Add.cshtml b/src/DroneFlightLog.Mvc/Views/Maintainers/Add.cshtml new file mode 100644 index 0000000..05c1fa8 --- /dev/null +++ b/src/DroneFlightLog.Mvc/Views/Maintainers/Add.cshtml @@ -0,0 +1,30 @@ +@model DroneFlightLog.Mvc.Models.AddMaintainerViewModel + +@{ + ViewData["Title"] = "Add Maintainer"; +} + +
+ @using (Html.BeginForm()) + { +
+
+ Add Maintainer +
+
+
+ + @if (!string.IsNullOrEmpty(Model.Message)) + { +
+
+ @Html.Raw(Model.Message) +
+
+
+ } + + @await Html.PartialAsync("Maintainer", Model) + ; + } +
diff --git a/src/DroneFlightLog.Mvc/Views/Maintainers/Edit.cshtml b/src/DroneFlightLog.Mvc/Views/Maintainers/Edit.cshtml new file mode 100644 index 0000000..7525950 --- /dev/null +++ b/src/DroneFlightLog.Mvc/Views/Maintainers/Edit.cshtml @@ -0,0 +1,20 @@ +@model DroneFlightLog.Mvc.Models.EditMaintainerViewModel + +@{ + ViewData["Title"] = "Edit Maintainer"; +} + +
+ @using (Html.BeginForm()) + { +
+
+ Edit Maintainer +
+
+
+ + @await Html.PartialAsync("Maintainer", Model) + ; + } +
diff --git a/src/DroneFlightLog.Mvc/Views/Maintainers/Index.cshtml b/src/DroneFlightLog.Mvc/Views/Maintainers/Index.cshtml new file mode 100644 index 0000000..a3311d0 --- /dev/null +++ b/src/DroneFlightLog.Mvc/Views/Maintainers/Index.cshtml @@ -0,0 +1,47 @@ +@using System.Collections.Generic +@using DroneFlightLog.Mvc.Entities +@model List + +@{ + ViewData["Title"] = "Maintainer Details"; +} + +

+ + Maintainer Details + +
+ + + Manage maintainer details + + +

+ + + + + + + @if (Model != null) + { + foreach (var maintainer in Model) + { + + + + + + } + } +
First NamesSurname +
@maintainer.FirstNames@maintainer.Surname + + + +
+ +
+

+ Add +

diff --git a/src/DroneFlightLog.Mvc/Views/Maintainers/Maintainer.cshtml b/src/DroneFlightLog.Mvc/Views/Maintainers/Maintainer.cshtml new file mode 100644 index 0000000..7e257d1 --- /dev/null +++ b/src/DroneFlightLog.Mvc/Views/Maintainers/Maintainer.cshtml @@ -0,0 +1,38 @@ +@model DroneFlightLog.Mvc.Models.MaintainerViewModelBase + +@Html.AntiForgeryToken() +@Html.HiddenFor(m => m.Maintainer.Id) + + +
+
+ Maintainer Details +
+
+
+ +
+
+ @Html.LabelFor(m => m.Maintainer.FirstNames) +
+ @Html.EditorFor(m => m.Maintainer.FirstNames, new { @class = "form-control" }) +
+ @Html.ValidationMessageFor(m => m.Maintainer.FirstNames, "", new { @class = "text-danger" }) +
+
+ @Html.LabelFor(m => m.Maintainer.Surname) +
+ @Html.EditorFor(m => m.Maintainer.Surname, new { @class = "form-control" }) +
+ @Html.ValidationMessageFor(m => m.Maintainer.Surname, "", new { @class = "text-danger" }) +
+
+
+ +
+
+
+ +
+
+
diff --git a/src/DroneFlightLog.Mvc/Views/Operators/Index.cshtml b/src/DroneFlightLog.Mvc/Views/Operators/Index.cshtml index effe64f..1e18a3a 100644 --- a/src/DroneFlightLog.Mvc/Views/Operators/Index.cshtml +++ b/src/DroneFlightLog.Mvc/Views/Operators/Index.cshtml @@ -3,7 +3,7 @@ @model List @{ - ViewData["Title"] = "Flight Properties"; + ViewData["Title"] = "Operator Details"; }

diff --git a/src/DroneFlightLog.Mvc/Views/Shared/_Layout.cshtml b/src/DroneFlightLog.Mvc/Views/Shared/_Layout.cshtml index 430ffde..5e9c02f 100644 --- a/src/DroneFlightLog.Mvc/Views/Shared/_Layout.cshtml +++ b/src/DroneFlightLog.Mvc/Views/Shared/_Layout.cshtml @@ -54,8 +54,10 @@ Drones

Flight Locations - Flight Properties - Operators + Flight Properties + Operators + + Maintainers