Skip to content

Commit

Permalink
Merge pull request #27 from MissouriMRDT/feature/customization
Browse files Browse the repository at this point in the history
Feature/customization
  • Loading branch information
bwestley authored Oct 27, 2024
2 parents cc395f8 + 9499175 commit bac9c43
Show file tree
Hide file tree
Showing 54 changed files with 5,069 additions and 1,023 deletions.
25 changes: 22 additions & 3 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
"--name",
"Basestation_Software",
// Configure container to use the same network stack as the host machine.
"--network",
"host",
// "--network",
// "host",
// Grants permission to the container to access USBs.
"--privileged"
],
Expand Down Expand Up @@ -41,7 +41,26 @@
// "features": {},

// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
"forwardPorts": [
11000,
12000
],

"portsAttributes": {
"11000": {
"label": "RoveComm UDP",
"onAutoForward": "notify"
},
"12000": {
"label": "RoveComm TCP",
"onAutoForward": "notify"
}
},

"appPort": [
"11000:11000/udp",
"12000:12000/tcp"
],

// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": "dotnet tool install --global dotnet-ef --verbosity diagnostic && dotnet tool install --global dotnet-aspnet-codegenerator --verbosity diagnostic",
Expand Down
69 changes: 69 additions & 0 deletions Basestation_Software.Api/Controllers/ConfigController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using Basestation_Software.Api.Entities;
using Basestation_Software.Models.Config;
using Microsoft.AspNetCore.Mvc;

namespace Basestation_Software.Api.Controllers;

[Route("api/[controller]")]
[ApiController]
public class ConfigController : ControllerBase
{
// Declare member variables.
private readonly IConfigRepository _ConfigRepository;

private static readonly Guid _DefaultGuid = new("00000000-0000-0000-0000-000000000001");

/// <summary>
/// Constructor
/// </summary>
/// <param name="IConfigRepository">Implicitly passed in.</param>
public ConfigController(IConfigRepository ConfigRepository) => _ConfigRepository = ConfigRepository;

/// <summary>
/// IN-Code API Endpoint for adding a config to the DB.
/// </summary>
/// <param name="config">The config object.</param>
/// <returns>The API response object.</returns>
[HttpPut]
public async Task<IActionResult> AddConfig(Config config) {
Guid? id = await _ConfigRepository.AddConfig(config);
return id is not null ? Ok(id) : BadRequest();
}

/// <summary>
/// IN-Code API Endpoint for removing a config from the DB.
/// </summary>
/// <param name="id">The config id.</param>
/// <returns>The API response object.</returns>
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteConfig(Guid id) => id.Equals(_DefaultGuid) || (await _ConfigRepository.DeleteConfig(id)) is null ? Ok() : NotFound();

/// <summary>
/// IN-Code API Endpoint for getting a waypoint to the DB.
/// </summary>
/// <param name="id">The config id.</param>
/// <returns>The API response object.</returns>
[HttpGet("{id}")]
public async Task<IActionResult> GetConfig(Guid id)
{
Config? config = await _ConfigRepository.GetConfig(id);
return config is not null ? Ok(config) : NotFound();
}

/// <summary>
/// IN-Code API Endpoint for getting all configs from the DB.
/// </summary>
/// <returns>The API response object.</returns>
[HttpGet]
public async Task<IActionResult> GetAllConfigs() => Ok(await _ConfigRepository.GetAllConfigs());

/// <summary>
/// IN-Code API Endpoint for updating a config in the DB.
/// </summary>
/// <param name="id">The config id.</param>
/// <param name="config">The config object.</param>
/// <returns>The API response object.</returns>
[HttpPost("{id}")]
public async Task<IActionResult> UpdateConfig(Guid id, Config config) => (await _ConfigRepository.UpdateConfig(id, config)) is not null ? Ok() : NotFound();

}
4 changes: 2 additions & 2 deletions Basestation_Software.Api/Data/data.db
Git LFS file not shown
114 changes: 114 additions & 0 deletions Basestation_Software.Api/Entities/ConfigRepository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
using Basestation_Software.Models.Config;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.EntityFrameworkCore;
using System.Reflection;
using System.Text.Json;

namespace Basestation_Software.Api.Entities;

public class ConfigRepository : IConfigRepository
{
// Declare member variables.
private readonly REDDatabase _REDDatabase;

/// <summary>
/// Constructor
/// </summary>
/// <param name="db">Implicitly passed in.</param>
public ConfigRepository(REDDatabase db) => _REDDatabase = db;

/// <summary>
/// Add a configuration to the database.
/// </summary>
/// <param name="config">The new configuration.</param>
/// <returns>New id if insertion successful.</returns>
public async Task<Guid?> AddConfig(Config config)
{
Guid id = Guid.NewGuid();
// Add new row to database table.
var result = await _REDDatabase.Configs.AddAsync(new ConfigEntity {
ID = id,
Data = JsonSerializer.Serialize(config)
});
await _REDDatabase.SaveChangesAsync();
// Return the inserted value.
return result is not null ? id : null;
}

/// <summary>
/// Remove a configuration from the database.
/// </summary>
/// <param name="id">The id of the configuration to remove.</param>
public async Task<ConfigEntity?> DeleteConfig(Guid id)
{
// Find the first waypoint with the same ID.
ConfigEntity? result = await _REDDatabase.Configs.FindAsync(id);
// Check if it was found.
if (result is not null)
{
// Remove the row from the database.
_REDDatabase.Configs.Remove(result);
await _REDDatabase.SaveChangesAsync();
}
return result;
}

/// <summary>
/// Get all configs in the DB.
/// </summary>
/// <returns>A list of Config objects.</returns>
public async Task<Dictionary<Guid, Config>> GetAllConfigs()
{
// Deserialize config entries and sort out null values.
#pragma warning disable CS8619 // Nullability of reference types in value doesn't match target type.
return (await _REDDatabase.Configs.ToListAsync()).ToDictionary(
x => x.ID,
x => JsonSerializer.Deserialize<Config>(x.Data)
).Where(x => x.Value is not null).ToDictionary(x => x.Key, x => x.Value);
#pragma warning restore CS8619 // Nullability of reference types in value doesn't match target type.
}

/// <summary>
/// Get a config from the DB.
/// </summary>
/// <param name="id">The id of the config to return.</param>
/// <returns>A Config object, null if not found.</returns>
public async Task<Config?> GetConfig(Guid id)
{
ConfigEntity? result = await _REDDatabase.Configs.FindAsync(id);
return result is not null ? JsonSerializer.Deserialize<Config>(result.Data) : null;
}

/// <summary>
/// Update the data for a Config in the DB or add it if it does not exist.
/// </summary>
/// <param name="id">The id of the config to update.</param>
/// <param name="config">A Config object containing the new data.</param>
/// <returns>The object stored in the database.</returns>
public async Task<ConfigEntity?> UpdateConfig(Guid id, Config config)
{
ConfigEntity? result = await _REDDatabase.Configs.FindAsync(id);
if (result is null)
{
// Add new row to database table.
result = (await _REDDatabase.Configs.AddAsync(new ConfigEntity
{
ID = id,
Data = JsonSerializer.Serialize(config)
})).Entity;
await _REDDatabase.SaveChangesAsync();
// Return the inserted value.
return result;
}
else
{
// Update data
result.Data = JsonSerializer.Serialize(config);

// Save changes to DB.
await _REDDatabase.SaveChangesAsync();
}

return result;
}
}
12 changes: 12 additions & 0 deletions Basestation_Software.Api/Entities/IConfigRepository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Basestation_Software.Models.Config;

namespace Basestation_Software.Api.Entities;

public interface IConfigRepository
{
Task<Guid?> AddConfig(Config config);
Task<ConfigEntity?> DeleteConfig(Guid id);
Task<Dictionary<Guid, Config>> GetAllConfigs();
Task<Config?> GetConfig(Guid id);
Task<ConfigEntity?> UpdateConfig(Guid id, Config config);
}
33 changes: 33 additions & 0 deletions Basestation_Software.Api/Entities/REDDatabase.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using Basestation_Software.Models.Geospatial;
using Basestation_Software.Models.Config;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using System.Xml.Linq;

namespace Basestation_Software.Api.Entities;

Expand Down Expand Up @@ -32,9 +34,19 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
/// entities in a context. In this case is corresponds to a database table.
/// </summary>
/// <value></value>
public DbSet<ConfigEntity> Configs { get; set; }
public DbSet<GPSWaypoint> Waypoints { get; set; }
public DbSet<MapTile> MapTiles { get; set; }

public void Configure(EntityTypeBuilder<ConfigEntity> modelBuilder)
{
modelBuilder.HasKey(x => x.ID);
modelBuilder.Property(x => x.ID)
.HasColumnName(@"ID")
.IsRequired()
;
}

/// <summary>
/// Configure the primary key for the Waypoints table.
/// </summary>
Expand All @@ -49,6 +61,11 @@ public void Configure(EntityTypeBuilder<GPSWaypoint> modelBuilder)
.ValueGeneratedOnAdd()
;
}

/// <summary>
/// Configure the primary key for the MapTile table.
/// </summary>
/// <param name="modelBuilder"></param>
public void Configure(EntityTypeBuilder<MapTile> modelBuilder)
{
modelBuilder.HasKey(x => x.ID);
Expand Down Expand Up @@ -95,5 +112,21 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
Type = WaypointType.Navigation
}
);

// Add the default layout to the Config table.
modelBuilder.Entity<ConfigEntity>().HasData(
new ConfigEntity
{
// Can't use Guid default (Guid.Empty) because Entity Framework thinks Guid.Empty is null.
// ID=Guid.Empty works perfectly fine when manually added using SQLite but not through Entity Framework.
// Error when creating a migration:
// The seed entity for entity type 'ConfigEntity' cannot be added because a default value
// was provided for the required property 'ID'. Please provide a value different from
// '00000000-0000-0000-0000-000000000000'.
// Workaround: hardcode a default guid here and at the top of MainLayout.Razor.
ID = Guid.Parse("00000000-0000-0000-0000-000000000001"),
Data = System.Text.Json.JsonSerializer.Serialize(new Config { Name = "Default" })
}
);
}
}
Loading

0 comments on commit bac9c43

Please sign in to comment.