diff --git a/Environment/Service/Controllers/DeviceController.cs b/Environment/Service/Controllers/DeviceController.cs new file mode 100644 index 0000000..dbd376a --- /dev/null +++ b/Environment/Service/Controllers/DeviceController.cs @@ -0,0 +1,45 @@ +using ChrisKaczor.HomeMonitor.Environment.Service.Data; +using ChrisKaczor.HomeMonitor.Environment.Service.Models.Device; +using Microsoft.AspNetCore.Mvc; + +namespace ChrisKaczor.HomeMonitor.Environment.Service.Controllers; + +[Route("[controller]")] +[ApiController] +public class DeviceController(Database database, IConfiguration configuration) : ControllerBase +{ + [HttpGet()] + public async Task>> GetDevices() + { + return (await database.GetDevicesAsync()).ToList(); + } + + [HttpGet("{name}")] + public async Task> GetDevice(string name) + { + var device = await database.GetDeviceAsync(name); + + if (device == null) + return NotFound(); + + return device; + } + + [HttpPost()] + public async Task AddDevice(Device device) + { + HttpContext.Request.Headers.TryGetValue("Authorization", out var authorizationHeader); + + if (authorizationHeader != "Bearer " + configuration["AuthorizationToken"]) + return Unauthorized(); + + var existingDevice = await database.GetDeviceAsync(device.Name); + + if (existingDevice != null) + return BadRequest("Device already exists"); + + await database.SetDeviceLastUpdatedAsync(device.Name, device.LastUpdated); + + return Ok(); + } +} \ No newline at end of file diff --git a/Environment/Service/Data/Database.cs b/Environment/Service/Data/Database.cs index 2f1b3e2..ca3f62f 100644 --- a/Environment/Service/Data/Database.cs +++ b/Environment/Service/Data/Database.cs @@ -1,4 +1,5 @@ using ChrisKaczor.HomeMonitor.Environment.Service.Models; +using ChrisKaczor.HomeMonitor.Environment.Service.Models.Device; using ChrisKaczor.HomeMonitor.Environment.Service.Models.Indoor; using Dapper; using DbUp; @@ -80,4 +81,31 @@ public class Database(IConfiguration configuration) return await connection.QueryAsync(query, new { Start = start, End = end }).ConfigureAwait(false); } + + public async Task> GetDevicesAsync() + { + await using var connection = CreateConnection(); + + var query = ResourceReader.GetString("ChrisKaczor.HomeMonitor.Environment.Service.Data.Queries.GetDevices.psql"); + + return await connection.QueryAsync(query).ConfigureAwait(false); + } + + public async Task GetDeviceAsync(string deviceName) + { + await using var connection = CreateConnection(); + + var query = ResourceReader.GetString("ChrisKaczor.HomeMonitor.Environment.Service.Data.Queries.GetDevice.psql"); + + return await connection.QueryFirstOrDefaultAsync(query, new { Name = deviceName }).ConfigureAwait(false); + } + + public async Task SetDeviceLastUpdatedAsync(string deviceName, DateTimeOffset? lastUpdated) + { + await using var connection = CreateConnection(); + + var query = ResourceReader.GetString("ChrisKaczor.HomeMonitor.Environment.Service.Data.Queries.SetDeviceLastUpdated.psql"); + + await connection.ExecuteAsync(query, new { Name = deviceName, LastUpdated = lastUpdated }).ConfigureAwait(false); + } } \ No newline at end of file diff --git a/Environment/Service/Data/Queries/GetDevice.psql b/Environment/Service/Data/Queries/GetDevice.psql new file mode 100644 index 0000000..a559988 --- /dev/null +++ b/Environment/Service/Data/Queries/GetDevice.psql @@ -0,0 +1,7 @@ +SELECT + name AS Name, + last_updated AS LastUpdated +FROM + device +WHERE + name = @Name \ No newline at end of file diff --git a/Environment/Service/Data/Queries/GetDevices.psql b/Environment/Service/Data/Queries/GetDevices.psql new file mode 100644 index 0000000..b369e62 --- /dev/null +++ b/Environment/Service/Data/Queries/GetDevices.psql @@ -0,0 +1,5 @@ +SELECT + name AS Name, + last_updated AS LastUpdated +FROM + device \ No newline at end of file diff --git a/Environment/Service/Data/Queries/SetDeviceLastUpdated.psql b/Environment/Service/Data/Queries/SetDeviceLastUpdated.psql new file mode 100644 index 0000000..4743393 --- /dev/null +++ b/Environment/Service/Data/Queries/SetDeviceLastUpdated.psql @@ -0,0 +1,11 @@ +INSERT INTO device( + name, + last_updated +) +VALUES ( + @Name, + @LastUpdated +) +ON CONFLICT (name) + DO UPDATE + SET last_updated = EXCLUDED.last_updated \ No newline at end of file diff --git a/Environment/Service/Data/Schema/2-Device Table.psql b/Environment/Service/Data/Schema/2-Device Table.psql new file mode 100644 index 0000000..c91705a --- /dev/null +++ b/Environment/Service/Data/Schema/2-Device Table.psql @@ -0,0 +1,5 @@ +CREATE TABLE device( + name text NOT NULL, + last_updated timestamptz NULL, + CONSTRAINT device_pk PRIMARY KEY (name) +); diff --git a/Environment/Service/Environment.http b/Environment/Service/Environment.http index 1b88651..444fe24 100644 --- a/Environment/Service/Environment.http +++ b/Environment/Service/Environment.http @@ -16,4 +16,56 @@ Accept: application/json ### GET {{Environment_HostAddress}}/readings/aggregate?start=2024-03-11T00:00&end=2024-03-12T00:00 -Accept: application/json \ No newline at end of file +Accept: application/json + +### + +GET {{Environment_HostAddress}}/device +Accept: application/json + +### + +GET {{Environment_HostAddress}}/device/main +Accept: application/json + +### + +GET {{Environment_HostAddress}}/device/test +Accept: application/json + +### + +POST {{Environment_HostAddress}}/device +Content-Type: application/json +Authorization: Bearer test-token +Accept: application/json + +{ "name": "test" } + +### + +POST {{Environment_HostAddress}}/device +Content-Type: application/json +Authorization: Bearer test-token +Accept: application/json + +{ } + +### + +POST {{Environment_HostAddress}}/device +Content-Type: application/json +Authorization: Bearer foo +Accept: application/json + +{ "name": "test" } + +### + +POST {{Environment_HostAddress}}/device +Content-Type: application/json +Accept: application/json + +{ "name": "test" } + +### \ No newline at end of file diff --git a/Environment/Service/MessageHandler.cs b/Environment/Service/MessageHandler.cs index b14b8e4..55a5c07 100644 --- a/Environment/Service/MessageHandler.cs +++ b/Environment/Service/MessageHandler.cs @@ -77,6 +77,8 @@ public class MessageHandler : IHostedService await _database.StoreMessageAsync(message); + await _database.SetDeviceLastUpdatedAsync(message.Name, message.Timestamp); + await SendMessage(message); } diff --git a/Environment/Service/Models/Device/Device.cs b/Environment/Service/Models/Device/Device.cs new file mode 100644 index 0000000..782b542 --- /dev/null +++ b/Environment/Service/Models/Device/Device.cs @@ -0,0 +1,7 @@ +namespace ChrisKaczor.HomeMonitor.Environment.Service.Models.Device; + +public class Device +{ + public required string Name { get; set; } + public DateTimeOffset? LastUpdated { get; set; } +} diff --git a/Environment/Service/Service.csproj b/Environment/Service/Service.csproj index 0d3d65c..75e4955 100644 --- a/Environment/Service/Service.csproj +++ b/Environment/Service/Service.csproj @@ -14,7 +14,11 @@ + + + + @@ -22,7 +26,11 @@ + + + + diff --git a/Environment/Service/appsettings.Development.json b/Environment/Service/appsettings.Development.json index b51e18b..1dc206b 100644 --- a/Environment/Service/appsettings.Development.json +++ b/Environment/Service/appsettings.Development.json @@ -11,14 +11,15 @@ "Environment": { "Database": { "Host": "localhost", - "User": "sa", - "Password": "newpassword", - "Port": 1433, + "User": "postgres", + "Password": "postgres", + "Port": 5432, "Name": "Environment", "TrustServerCertificate": true }, "Hub": { "Url": "http://localhost:8080/environment" } - } + }, + "AuthorizationToken": "test-token" } diff --git a/Environment/Service/deploy/manifest.yaml b/Environment/Service/deploy/manifest.yaml index 112cb7c..41407b9 100644 --- a/Environment/Service/deploy/manifest.yaml +++ b/Environment/Service/deploy/manifest.yaml @@ -112,6 +112,11 @@ spec: key: password - name: Environment__Hub__Url value: http://hub-service/environment + - name: AuthorizationToken + valueFrom: + secretKeyRef: + name: authorization + key: token resources: limits: cpu: 1000m