Add 'Modified' tracking for Prospect entity
Introduce a 'Modified' field to track the last modification date of prospects. Automatically update this field on changes and integrate it in UI display for better transparency.
This commit is contained in:
@@ -42,6 +42,11 @@ namespace FoodsharingSiegen.Contracts.Entity
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string? Memo { get; set; }
|
public string? Memo { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the value indicating the last modification date and time.
|
||||||
|
/// </summary>
|
||||||
|
public DateTime? Modified { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the value of the name (ab)
|
/// Gets or sets the value of the name (ab)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -45,7 +45,7 @@
|
|||||||
</Alert>
|
</Alert>
|
||||||
}
|
}
|
||||||
|
|
||||||
<table style="width: 100%;">
|
<table class="flex-column" style="width: 100%;">
|
||||||
|
|
||||||
<InteractionRow
|
<InteractionRow
|
||||||
Prospect="Prospect"
|
Prospect="Prospect"
|
||||||
@@ -149,5 +149,7 @@
|
|||||||
|
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<div class="flex-grow-1"></div>
|
||||||
|
|
||||||
|
<small class="text-center" style="margin-top: .5rem;">Zuletzt geändert: @Prospect?.Modified?.ToLocalTime()</small>
|
||||||
</div>
|
</div>
|
||||||
@@ -72,7 +72,7 @@ namespace FoodsharingSiegen.Server.Controls
|
|||||||
|
|
||||||
private async Task EditProspectAsync()
|
private async Task EditProspectAsync()
|
||||||
{
|
{
|
||||||
await EditProspectDialog.ShowAsync(ModalService, () => InvokeAsync(StateHasChanged), Prospect);
|
await EditProspectDialog.ShowAsync(ModalService, OnDataChanged ?? (async () => await Task.CompletedTask), Prospect);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
@@ -14,13 +14,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.pc-main {
|
.pc-main {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
flex-basis: 0;
|
flex-basis: 0;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
max-width: 480px;
|
max-width: 480px;
|
||||||
border: 1px solid #533a20;
|
border: 1px solid #533a20;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
margin: 5px;
|
margin: 5px;
|
||||||
padding: 16px;
|
padding: .5rem .5rem 0 .5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pc-main.warning {
|
.pc-main.warning {
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ namespace FoodsharingSiegen.Server.Data.Service
|
|||||||
interaction.Created = DateTime.UtcNow;
|
interaction.Created = DateTime.UtcNow;
|
||||||
|
|
||||||
targetProspect.Interactions.Add(interaction);
|
targetProspect.Interactions.Add(interaction);
|
||||||
|
targetProspect.Modified = DateTime.UtcNow;
|
||||||
|
|
||||||
await Context.SaveChangesAsync();
|
await Context.SaveChangesAsync();
|
||||||
|
|
||||||
@@ -77,6 +78,7 @@ namespace FoodsharingSiegen.Server.Data.Service
|
|||||||
if (prospect == null) return new(new Exception("Cannot be empty"));
|
if (prospect == null) return new(new Exception("Cannot be empty"));
|
||||||
|
|
||||||
prospect.Created = DateTime.UtcNow;
|
prospect.Created = DateTime.UtcNow;
|
||||||
|
prospect.Modified = DateTime.UtcNow;
|
||||||
prospect.Id = Guid.Empty;
|
prospect.Id = Guid.Empty;
|
||||||
|
|
||||||
await Context.Prospects!.AddAsync(prospect);
|
await Context.Prospects!.AddAsync(prospect);
|
||||||
@@ -142,9 +144,20 @@ namespace FoodsharingSiegen.Server.Data.Service
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Context.Interactions!.Remove(new() { Id = interactionId });
|
var interaction = await Context.Interactions!.AsNoTracking().FirstOrDefaultAsync(x => x.Id == interactionId);
|
||||||
|
if(interaction == null) return new(new Exception("Interaction not found"));
|
||||||
|
|
||||||
|
Context.Interactions!.Remove(new() { Id = interaction.Id });
|
||||||
await Context.SaveChangesAsync();
|
await Context.SaveChangesAsync();
|
||||||
|
|
||||||
|
// Update prospect modified date
|
||||||
|
var prospect = await Context.Prospects!.FirstOrDefaultAsync(x => x.Id == interaction.ProspectID);
|
||||||
|
if (prospect != null)
|
||||||
|
{
|
||||||
|
prospect.Modified = DateTime.UtcNow;
|
||||||
|
await Context.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
await AuditService.Insert(AuditType.RemoveInteraction, "?");
|
await AuditService.Insert(AuditType.RemoveInteraction, "?");
|
||||||
|
|
||||||
return new();
|
return new();
|
||||||
@@ -176,6 +189,7 @@ namespace FoodsharingSiegen.Server.Data.Service
|
|||||||
entityProspect.FsId = prospect.FsId;
|
entityProspect.FsId = prospect.FsId;
|
||||||
entityProspect.Warning = prospect.Warning;
|
entityProspect.Warning = prospect.Warning;
|
||||||
entityProspect.RecordState = prospect.RecordState;
|
entityProspect.RecordState = prospect.RecordState;
|
||||||
|
entityProspect.Modified = DateTime.UtcNow;
|
||||||
|
|
||||||
var saveR = await Context.SaveChangesAsync();
|
var saveR = await Context.SaveChangesAsync();
|
||||||
|
|
||||||
|
|||||||
208
FoodsharingSiegen.Server/Migrations/20250330182300_Proposal-Modified.Designer.cs
generated
Normal file
208
FoodsharingSiegen.Server/Migrations/20250330182300_Proposal-Modified.Designer.cs
generated
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using FoodsharingSiegen.Server.Data;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace FoodsharingSiegen.Server.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(FsContext))]
|
||||||
|
[Migration("20250330182300_Proposal-Modified")]
|
||||||
|
partial class ProposalModified
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder.HasAnnotation("ProductVersion", "9.0.3");
|
||||||
|
|
||||||
|
modelBuilder.Entity("FoodsharingSiegen.Contracts.Entity.Audit", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Created")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Data1")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Data2")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Type")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<Guid?>("UserID")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserID");
|
||||||
|
|
||||||
|
b.ToTable("Audits");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("FoodsharingSiegen.Contracts.Entity.Interaction", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("Alert")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Created")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Date")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Info")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("NotNeeded")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProspectID")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Type")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<Guid>("UserID")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ProspectID");
|
||||||
|
|
||||||
|
b.HasIndex("UserID");
|
||||||
|
|
||||||
|
b.ToTable("Interactions");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("FoodsharingSiegen.Contracts.Entity.Prospect", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Created")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("FsId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Memo")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("Modified")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("RecordState")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("Warning")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Prospects");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("FoodsharingSiegen.Contracts.Entity.User", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Created")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("EncryptedPassword")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("ForceLogout")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Groups")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Mail")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Memo")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Network")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Type")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("Verified")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Users");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("FoodsharingSiegen.Contracts.Entity.Audit", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("FoodsharingSiegen.Contracts.Entity.User", "User")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserID");
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("FoodsharingSiegen.Contracts.Entity.Interaction", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("FoodsharingSiegen.Contracts.Entity.Prospect", "Prospect")
|
||||||
|
.WithMany("Interactions")
|
||||||
|
.HasForeignKey("ProspectID")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("FoodsharingSiegen.Contracts.Entity.User", "User")
|
||||||
|
.WithMany("Interactions")
|
||||||
|
.HasForeignKey("UserID")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Prospect");
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("FoodsharingSiegen.Contracts.Entity.Prospect", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Interactions");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("FoodsharingSiegen.Contracts.Entity.User", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Interactions");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace FoodsharingSiegen.Server.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class ProposalModified : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "Modified",
|
||||||
|
table: "Prospects",
|
||||||
|
type: "TEXT",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
// Fill Modified column of existing rows
|
||||||
|
migrationBuilder.Sql(@"
|
||||||
|
UPDATE Prospects
|
||||||
|
SET Modified = COALESCE(
|
||||||
|
(SELECT MAX(Created)
|
||||||
|
FROM Interactions
|
||||||
|
WHERE Interactions.ProspectID = Prospects.Id),
|
||||||
|
Prospects.Created
|
||||||
|
);
|
||||||
|
");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "Modified",
|
||||||
|
table: "Prospects");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -99,6 +99,9 @@ namespace FoodsharingSiegen.Server.Migrations
|
|||||||
b.Property<string>("Memo")
|
b.Property<string>("Memo")
|
||||||
.HasColumnType("TEXT");
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("Modified")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
b.Property<string>("Name")
|
b.Property<string>("Name")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasColumnType("TEXT");
|
.HasColumnType("TEXT");
|
||||||
|
|||||||
Reference in New Issue
Block a user