API færdig

Der er lavet følgende på API:
Modtage tag
Fjernt tag
Log

Der er lavet database til samme
This commit is contained in:
2026-07-19 22:00:58 +02:00
parent 90882b8042
commit 589a8c477d
20 changed files with 450 additions and 12 deletions

View File

@@ -0,0 +1,32 @@
using System.Text.Json.Serialization;
using fgs.api.models;
using fgs.database.Context;
using fgs.database.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace fgs.api.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class LogController(FilamentguardContext dbContext) : ControllerBase
{
[HttpPost]
[Route("create")]
public void Logging(LogRequest logRequest)
{
Log log = new Log();
log.Category = logRequest.Category;
log.Data = logRequest.Data;
log.DeviceId = logRequest.deviceId;
log.FirmwareVersion = logRequest.FirmwareVersion;
log.Hostname = logRequest.Hostname;
log.Level = logRequest.Level;
log.Message = logRequest.Message;
log.UptimeMilliseconds = (long)logRequest.UptimeMilliseconds;
log.TagUid = logRequest.tagUid;
dbContext.Logs.Add(log);
dbContext.SaveChanges();
}
}
}

View File

@@ -0,0 +1,76 @@
using fgs.api.models;
using fgs.database.Context;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Tag = fgs.database.Models.Tag;
namespace fgs.api.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class TagController(FilamentguardContext dbContext) : ControllerBase
{
[HttpPost]
[Route("detected")]
public IActionResult Detected([FromBody] OpenPrintTag openPrintTag)
{
Tag? currentTag = dbContext.Tags
.SingleOrDefault(c => c.DeviceId.Equals(openPrintTag.device.deviceId) && c.TagUid.Equals(openPrintTag.tag.tagUid));
if (currentTag == null)
{
currentTag = new Tag();
dbContext.Tags.Add(currentTag);
}
currentTag.DeviceId = openPrintTag.device?.deviceId;
currentTag.HostName = openPrintTag.device?.hostname;
currentTag.TagUid = openPrintTag.tag.tagUid;
currentTag.InstanceUid = openPrintTag.tag.instanceUuid;
currentTag.MaterialName = openPrintTag.tag.materialName;
currentTag.MaterialType = openPrintTag.tag.materialType;
currentTag.Brand = openPrintTag.tag.brand;
currentTag.ColorHex = openPrintTag.tag.colorHex;
currentTag.ActualWeightGrams = openPrintTag.tag.actualWeightGrams;
currentTag.NominalWeightGrams = openPrintTag.tag.nominalWeightGrams;
currentTag.SpoolWeightGrams = openPrintTag.tag.spoolWeightGrams;
currentTag.ConsumedWeightGrams = openPrintTag.tag.consumedWeightGrams;
currentTag.RemainingWeightGrams = openPrintTag.tag.remainingWeightGrams;
currentTag.HasActualWeight = openPrintTag.tag.hasActualWeight;
currentTag.HasNominalWeight = openPrintTag.tag.hasNominalWeight;
currentTag.HasSpoolWeight = openPrintTag.tag.hasSpoolWeight;
currentTag.HasConsumedWeight = openPrintTag.tag.hasConsumedWeight;
currentTag.IsActive = true;
dbContext.SaveChanges();
return Ok();
}
[HttpPost]
[Route("removed")]
public IActionResult Removed([FromBody] OpenPrintTagRemoved openPrintTagRemoved)
{
Tag? currentTag = dbContext.Tags
.SingleOrDefault(c => c.DeviceId.Equals(openPrintTagRemoved.device.deviceId) && c.TagUid.Equals(openPrintTagRemoved.tag.tagUid));
if (currentTag != null)
{
currentTag.IsActive = false;
dbContext.SaveChanges();
return Ok(new
{
message = "Tag removal received, tag removed",
tagUid = openPrintTagRemoved.tag.tagUid,
deviceId = openPrintTagRemoved.device?.deviceId
});
}
else
{
return Ok(new
{
message = "Tag removal received, but no tag to remove"
});
}
}
}
}

View File

@@ -1,4 +1,9 @@
using fgs.database.Context;
using fgs.database.Models;
using Microsoft.EntityFrameworkCore;
using Scalar.AspNetCore;
namespace fgs.api namespace fgs.api
{ {
public class Program public class Program
@@ -13,15 +18,23 @@ namespace fgs.api
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi // Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
builder.Services.AddOpenApi(); builder.Services.AddOpenApi();
builder.Services.AddDbContext<FilamentguardContext>(options =>
options.UseSqlServer(
builder.Configuration.GetConnectionString("FilamentGuardDatabase")));
var app = builder.Build(); var app = builder.Build();
// Configure the HTTP request pipeline. // Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment()) if (app.Environment.IsDevelopment())
{ {
app.MapOpenApi(); app.MapOpenApi();
app.MapScalarApiReference();
} }
app.UseHttpsRedirection(); if (!app.Environment.IsDevelopment())
{
app.UseHttpsRedirection();
}
app.UseAuthorization(); app.UseAuthorization();

View File

@@ -6,7 +6,7 @@
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
}, },
"dotnetRunMessages": true, "dotnetRunMessages": true,
"applicationUrl": "http://localhost:5011" "applicationUrl": "http://0.0.0.0:5011"
}, },
"https": { "https": {
"commandName": "Project", "commandName": "Project",
@@ -14,7 +14,7 @@
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
}, },
"dotnetRunMessages": true, "dotnetRunMessages": true,
"applicationUrl": "https://localhost:7157;http://localhost:5011" "applicationUrl": "https://0.0.0.0:7157;http://0.0.0.0:5011"
}, },
"Container (Dockerfile)": { "Container (Dockerfile)": {
"commandName": "Docker", "commandName": "Docker",

View File

@@ -4,5 +4,9 @@
"Default": "Information", "Default": "Information",
"Microsoft.AspNetCore": "Warning" "Microsoft.AspNetCore": "Warning"
} }
},
"ConnectionStrings": {
"FilamentGuardDatabase": "Server=192.168.3.2;Database=filamentguard;User Id=filamentguard;Password=rlsBN2TJMp5WWGW0lm;TrustServerCertificate=True;"
} }
} }

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net10.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
@@ -10,7 +10,13 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.10" /> <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="10.0.10" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.23.0" /> <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.23.0" />
<PackageReference Include="Scalar.AspNetCore" Version="2.16.15" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\fgs.database\fgs.database.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -4,3 +4,18 @@ GET {{fgs.api_HostAddress}}/weatherforecast/
Accept: application/json Accept: application/json
### ###
POST {{fgs.api_HostAddress}}/api/Log/create
Content-Type: application/json
Accept: application/json
{
"DeviceId": "ESP32-B4EDF8F57630",
"Hostname": "filamentguard-f57630",
"FirmwareVersion": "1.0.1",
"Level": "Info",
"Category": "NfcReader",
"Message": "OpenPrintTag registreret.",
"Data": "",
"UptimeMilliseconds": 45231
}

View File

@@ -0,0 +1,23 @@
namespace fgs.api.models
{
public class LogRequest
{
public required string deviceId { get; init; }
public required string tagUid { get; init; }
public required string Hostname { get; init; }
public required string FirmwareVersion { get; init; }
public required string Level { get; init; }
public required string Category { get; init; }
public required string Message { get; init; }
public string? Data { get; init; }
public ulong UptimeMilliseconds { get; init; }
}
}

View File

@@ -0,0 +1,33 @@
namespace fgs.api.models
{
public class OpenPrintTag
{
public Device device { get; set; }
public Tag tag { get; set; }
}
public class Device
{
public string deviceId { get; set; }
public string hostname { get; set; }
}
public class Tag
{
public string tagUid { get; set; }
public string instanceUuid { get; set; }
public string materialName { get; set; }
public string materialType { get; set; }
public string brand { get; set; }
public string colorHex { get; set; }
public int actualWeightGrams { get; set; }
public int nominalWeightGrams { get; set; }
public int spoolWeightGrams { get; set; }
public int consumedWeightGrams { get; set; }
public int remainingWeightGrams { get; set; }
public bool hasActualWeight { get; set; }
public bool hasNominalWeight { get; set; }
public bool hasSpoolWeight { get; set; }
public bool hasConsumedWeight { get; set; }
}
}

View File

@@ -0,0 +1,19 @@
namespace fgs.api.models
{
public class OpenPrintTagRemoved
{
public DeviceRemoved device { get; set; }
public TagRemoved tag { get; set; }
}
public class DeviceRemoved
{
public string deviceId { get; set; }
public string hostname { get; set; }
}
public class TagRemoved
{
public string tagUid { get; set; }
}
}

1
fgs.api/models/json.cs Normal file
View File

@@ -0,0 +1 @@

View File

@@ -1,7 +1,31 @@
using System.Net;
using System.Net.Sockets;
var builder = DistributedApplication.CreateBuilder(args); var builder = DistributedApplication.CreateBuilder(args);
builder.AddProject<Projects.fgs_web>("fgs-web"); builder.AddProject<Projects.fgs_web>("fgs-web");
builder.AddProject<Projects.fgs_api>("fgs-api"); string ipAddress = Dns.GetHostEntry(Dns.GetHostName())
.AddressList
.First(address =>
address.AddressFamily == AddressFamily.InterNetwork &&
!IPAddress.IsLoopback(address))
.ToString();
int port = 5051;
builder.AddProject<Projects.fgs_api>("fgs-api")
.WithEndpoint("http", endpoint =>
{
endpoint.Port = port;
endpoint.IsExternal = true;
})
.WithUrlForEndpoint(
"http",
url =>
{
url.Url = "/scalar/v1";
url.DisplayText = $"http://{ipAddress}:{port}/{url.Url}";
});
builder.Build().Run(); builder.Build().Run();

View File

@@ -8,6 +8,10 @@
<UserSecretsId>0879501a-f55f-4876-aa9f-cae6c0e16786</UserSecretsId> <UserSecretsId>0879501a-f55f-4876-aa9f-cae6c0e16786</UserSecretsId>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="MessagePack" Version="3.1.8" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\fgs.api\fgs.api.csproj" /> <ProjectReference Include="..\fgs.api\fgs.api.csproj" />
<ProjectReference Include="..\fgs.web\fgs.web.csproj" /> <ProjectReference Include="..\fgs.web\fgs.web.csproj" />

View File

@@ -1,7 +0,0 @@
namespace fgs.database
{
public class Class1
{
}
}

View File

@@ -0,0 +1,27 @@
// <auto-generated> This file has been auto generated by EF Core Power Tools. </auto-generated>
#nullable disable
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
using fgs.database.Models;
namespace fgs.database.Context;
public partial class FilamentguardContext : DbContext
{
public FilamentguardContext(DbContextOptions<FilamentguardContext> options)
: base(options)
{
}
public virtual DbSet<Log> Logs { get; set; }
public virtual DbSet<Tag> Tags { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
OnModelCreatingPartial(modelBuilder);
}
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
}

View File

@@ -0,0 +1,50 @@
// <auto-generated> This file has been auto generated by EF Core Power Tools. </auto-generated>
#nullable disable
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;
namespace fgs.database.Models;
[Table("Log")]
public partial class Log
{
[Key]
public int Id { get; set; }
[Required]
[Column("deviceId", TypeName = "text")]
public string DeviceId { get; set; }
[Required]
[Column("tagUid", TypeName = "text")]
public string TagUid { get; set; }
[Required]
[Column("hostname", TypeName = "text")]
public string Hostname { get; set; }
[Required]
[Column("firmwareVersion", TypeName = "text")]
public string FirmwareVersion { get; set; }
[Required]
[Column("level", TypeName = "text")]
public string Level { get; set; }
[Required]
[Column("category", TypeName = "text")]
public string Category { get; set; }
[Required]
[Column("message", TypeName = "text")]
public string Message { get; set; }
[Column("data", TypeName = "text")]
public string Data { get; set; }
[Column("uptimeMilliseconds")]
public long UptimeMilliseconds { get; set; }
}

View File

@@ -0,0 +1,55 @@
// <auto-generated> This file has been auto generated by EF Core Power Tools. </auto-generated>
#nullable disable
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;
namespace fgs.database.Models;
[Table("Tag")]
public partial class Tag
{
[Key]
public int Id { get; set; }
[Required]
public string DeviceId { get; set; }
public bool IsActive { get; set; }
[Required]
public string TagUid { get; set; }
[Required]
public string HostName { get; set; }
public string InstanceUid { get; set; }
public string MaterialName { get; set; }
public string MaterialType { get; set; }
public string Brand { get; set; }
public string ColorHex { get; set; }
public int? ActualWeightGrams { get; set; }
public int? NominalWeightGrams { get; set; }
public int? SpoolWeightGrams { get; set; }
public int? ConsumedWeightGrams { get; set; }
public int? RemainingWeightGrams { get; set; }
public bool HasActualWeight { get; set; }
public bool HasNominalWeight { get; set; }
public bool HasSpoolWeight { get; set; }
public bool HasConsumedWeight { get; set; }
}

View File

@@ -0,0 +1,58 @@
{
"CodeGenerationMode": 6,
"ContextClassName": "FilamentguardContext",
"ContextNamespace": null,
"FilterSchemas": false,
"IncludeConnectionString": false,
"IrregularWords": null,
"MinimumProductVersion": "2.6.1604",
"ModelNamespace": null,
"OutputContextPath": "Context",
"OutputPath": "Models",
"PluralRules": null,
"PreserveCasingWithRegex": true,
"ProjectRootNamespace": "fgs.database",
"Schemas": null,
"SelectedHandlebarsLanguage": 2,
"SelectedToBeGenerated": 0,
"SingularRules": null,
"T4TemplatePath": null,
"Tables": [
{
"Name": "[dbo].[Log]",
"ObjectType": 0
},
{
"Name": "[dbo].[Tag]",
"ObjectType": 0
}
],
"UiHint": null,
"UncountableWords": null,
"UseAsyncStoredProcedureCalls": true,
"UseBoolPropertiesWithoutDefaultSql": false,
"UseDatabaseNames": false,
"UseDatabaseNamesForRoutines": true,
"UseDateOnlyTimeOnly": true,
"UseDbContextSplitting": false,
"UseDecimalDataAnnotationForSprocResult": true,
"UseFluentApiOnly": false,
"UseHandleBars": false,
"UseHierarchyId": false,
"UseInflector": true,
"UseInternalAccessModifiersForSprocsAndFunctions": false,
"UseLegacyPluralizer": false,
"UseManyToManyEntity": false,
"UseNoDefaultConstructor": false,
"UseNoNavigations": false,
"UseNoObjectFilter": false,
"UseNodaTime": false,
"UseNullableReferences": false,
"UsePrefixNavigationNaming": false,
"UseSchemaFolders": false,
"UseSchemaNamespaces": false,
"UseSpatial": false,
"UseT4": false,
"UseT4Split": false,
"UseTypedTvpParameters": true
}

View File

@@ -6,4 +6,8 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="10.0.10" />
</ItemGroup>
</Project> </Project>

View File

@@ -8,6 +8,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="10.0.10" />
<PackageReference Include="Microsoft.FluentUI.AspNetCore.Components" Version="5.0.0-rc.4-26180.1" /> <PackageReference Include="Microsoft.FluentUI.AspNetCore.Components" Version="5.0.0-rc.4-26180.1" />
<PackageReference Include="Microsoft.FluentUI.AspNetCore.Components.Icons" Version="4.14.3" /> <PackageReference Include="Microsoft.FluentUI.AspNetCore.Components.Icons" Version="4.14.3" />
</ItemGroup> </ItemGroup>