drop the deigner.cs

This commit is contained in:
Paul Schneider 2026-07-04 16:06:02 +01:00
commit 90dfe9c13f
4 changed files with 60 additions and 109 deletions

View file

@ -1,82 +0,0 @@
// ------------------------------------------------------------------------------
// <autogenerated>
// This code was generated by a tool.
// Mono Runtime Version: 4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </autogenerated>
// ------------------------------------------------------------------------------
namespace Yavsc {
using System;
using System.Reflection;
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public partial class ChatHubLabels {
private static System.Resources.ResourceManager resourceMan;
private static System.Globalization.CultureInfo resourceCulture;
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
public static System.Resources.ResourceManager ResourceManager {
get {
if (object.Equals(null, resourceMan)) {
System.Resources.ResourceManager temp = new System.Resources.ResourceManager(("Yavsc.Abstract.Resources." + "Yavsc.ChatHub"), typeof(ChatHubLabels).GetTypeInfo().Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
public static System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
public static string Authenticated_chat_user {
get {
return ResourceManager.GetString("Authenticated chat user", resourceCulture);
}
}
public static string LabnoJoinNoSend {
get {
return ResourceManager.GetString("LabnoJoinNoSend", resourceCulture);
}
}
public static string InvalidRoomName {
get {
return ResourceManager.GetString("InvalidRoomName", resourceCulture);
}
}
public static string InvalidUserName {
get {
return ResourceManager.GetString("InvalidUserName", resourceCulture);
}
}
public static string InvalidMessage {
get {
return ResourceManager.GetString("InvalidMessage", resourceCulture);
}
}
public static string InvalidReason {
get {
return ResourceManager.GetString("InvalidReason", resourceCulture);
}
}
}
}

View file

@ -264,21 +264,53 @@ namespace Yavsc.ApiControllers
return BadRequest(new { Error = "file write failed", Detail = ex.Message }); return BadRequest(new { Error = "file write failed", Detail = ex.Message });
} }
// Now persist the database row. The int[] is round- // Find-or-add: the (EstimateId, Type) pair is
// tripped via Npgsql's native int[] mapping; the // unique, so a second POST for the same side of the
// migration (separate commit) introduces the column // estimate replaces the previous signature. EF
// and the index. // translates this into a single UPDATE when the
var signature = new Signature // row exists and an INSERT otherwise; the unique
// index in ApplicationDbContext is the
// database-level guarantee that the contract
// holds if two requests race.
var signature = await dbContext.Signatures
.FirstOrDefaultAsync(s => s.EstimateId == id && s.Type == type, token);
if (signature is null)
{ {
EstimateId = id, signature = new Signature
SignerId = userId, {
Type = type, EstimateId = id,
CoordinateMax = payload.CoordinateMax, SignerId = userId,
Strokes = payload.Strokes, Type = type,
CapturedAtUtc = payload.CapturedAtUtc, };
FilePath = Path.Combine(fi.DestDir, fi.FileName), dbContext.Signatures.Add(signature);
}; }
dbContext.Signatures.Add(signature); else
{
// Roll the signer's quota back by the size of
// the file we're about to orphan: the old
// FilePath is no longer referenced once we
// overwrite FilePath below.
try
{
var orphan = new FileInfo(signature.FilePath);
if (orphan.Exists)
{
var signerForOrphan = await dbContext.Users
.FirstOrDefaultAsync(u => u.Id == userId, token);
if (signerForOrphan is not null)
signerForOrphan.DiskUsage =
Math.Max(0, signerForOrphan.DiskUsage - orphan.Length);
}
}
catch { /* best effort — the file is being replaced anyway */ }
}
signature.SignerId = userId;
signature.CoordinateMax = payload.CoordinateMax;
signature.Strokes = payload.Strokes;
signature.CapturedAtUtc = payload.CapturedAtUtc;
signature.FilePath = Path.Combine(fi.DestDir, fi.FileName);
// Bump the signer's quota. The Signature row's // Bump the signer's quota. The Signature row's
// SignerId is the IdentityUser.Id (a string), so we // SignerId is the IdentityUser.Id (a string), so we

View file

@ -35,7 +35,7 @@ namespace Yavsc.Server.Hubs
{ {
bool valid = ValidateStringLength(roomName,1,25); bool valid = ValidateStringLength(roomName,1,25);
if (valid) valid = IsLetterOrDigit(roomName); if (valid) valid = IsLetterOrDigit(roomName);
if (!valid) NotifyUser(NotificationTypes.Error, "roomName", _locator.GetString(ChatHubLabels.InvalidRoomName)); if (!valid) NotifyUser(NotificationTypes.Error, "roomName", _locator.GetString("InvalidRoomName"));
return valid; return valid;
} }
public bool ValidateUserName (string userName) public bool ValidateUserName (string userName)
@ -52,14 +52,14 @@ namespace Yavsc.Server.Hubs
NotifyUser( NotifyUser(
NotificationTypes.Error, NotificationTypes.Error,
"userName", "userName",
_locator.GetString(ChatHubLabels.InvalidUserName)); _locator.GetString("InvalidUserName)"));
return valid; return valid;
} }
public bool ValidateMessage (string message) public bool ValidateMessage (string message)
{ {
if (!ValidateStringLength(message, 1, 10240)) if (!ValidateStringLength(message, 1, 10240))
{ {
NotifyUser(NotificationTypes.Error, "message", _locator.GetString(ChatHubLabels.InvalidMessage)); NotifyUser(NotificationTypes.Error, "message", _locator.GetString("InvalidMessage"));
return false; return false;
} }
return true; return true;
@ -68,7 +68,7 @@ namespace Yavsc.Server.Hubs
{ {
if (!ValidateStringLength(reason, 1,240)) if (!ValidateStringLength(reason, 1,240))
{ {
NotifyUser(NotificationTypes.Error, "reason", ChatHubLabels.InvalidReason); NotifyUser(NotificationTypes.Error, "reason", "InvalidReason");
return false; return false;
} }
return true; return true;

View file

@ -69,16 +69,17 @@ namespace Yavsc.Models
builder.Entity<DeviceDeclaration>().Property(x => x.DeclarationDate).HasDefaultValueSql(NOW_SQL); builder.Entity<DeviceDeclaration>().Property(x => x.DeclarationDate).HasDefaultValueSql(NOW_SQL);
builder.Entity<BlogTag>().HasKey(x => new { x.PostId, x.TagId }); builder.Entity<BlogTag>().HasKey(x => new { x.PostId, x.TagId });
// Signature: composite index (EstimateId, Type, // Signature: unique constraint on (EstimateId, Type)
// CapturedAtUtc DESC) to support the controller's // — the most recent version replaces the previous
// "most recent signature per type" read pattern // one, so a partial unique index (not a regular one)
// without an extra ORDER BY cost. The default // is the right shape. The controller does a
// EF-generated FK index on EstimateId alone is // Find-or-Add so EF translates an upsert into a
// replaced by the composite to avoid duplicate // single UPDATE when the row already exists; the
// indexes. // unique index is the database-level guarantee that
// the contract holds.
builder.Entity<Signature>() builder.Entity<Signature>()
.HasIndex(s => new { s.EstimateId, s.Type, s.CapturedAtUtc }) .HasIndex(s => new { s.EstimateId, s.Type })
.IsDescending(false, false, true); .IsUnique();
builder.Entity<Signature>() builder.Entity<Signature>()
.HasOne(s => s.Estimate) .HasOne(s => s.Estimate)
.WithMany(e => e.Signatures) .WithMany(e => e.Signatures)