diff --git a/FreeTubeSync/Database/DataContext.cs b/FreeTubeSync/Database/DataContext.cs index e6f8165..7f9f879 100644 --- a/FreeTubeSync/Database/DataContext.cs +++ b/FreeTubeSync/Database/DataContext.cs @@ -65,6 +65,17 @@ public class DataContext : DbContext .OrderByDescending(cl => cl.ChangeTime) .FirstOrDefaultAsync(ct); } + + public async Task CleanupChangeLogAsync(CancellationToken ct = default) + { + var logs = await ChangeLogs.ToListAsync(ct); + if (logs.Count < 50) return; + for (var i = 0; i < (logs.Count - 50); i++) + { + ChangeLogs.Remove(logs[i]); + } + await base.SaveChangesAsync(ct); + } public DbSet Histories { get; set; } public DbSet Playlists { get; set; } diff --git a/FreeTubeSync/Database/MapData.cs b/FreeTubeSync/Database/MapData.cs deleted file mode 100644 index ef8b010..0000000 --- a/FreeTubeSync/Database/MapData.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System.Collections; - -namespace FreeTubeSync.Database; - -public static class MapData -{ - public static void MapFrom(this object obj2, object obj1) - { - var props = new Dictionary(); - var t1Type = obj1.GetType(); - var t2Type = obj2.GetType(); - - var properties = t1Type.GetProperties(); - foreach (var property in properties) - { - props[property.Name] = property.GetValue(obj1); - } - properties = t2Type.GetProperties(); - foreach (var property in properties) - { - if (props.ContainsKey(property.Name)) - { - var value = props[property.Name]; - if (value is string || value is not IEnumerable) - property.SetValue(obj2, value); - } - } - } - - public static void MapTo(this IEnumerable obj1, IList obj2) - where T1 : class where T2 : class, new() - { - foreach (var obj in obj1) - { - var newObj = new T2(); - newObj.MapFrom(obj); - obj2.Add(newObj); - } - } -} \ No newline at end of file diff --git a/FreeTubeSync/EndPoints/HistoryEndpoint.cs b/FreeTubeSync/EndPoints/HistoryEndpoint.cs index bf98d12..2e88b4e 100644 --- a/FreeTubeSync/EndPoints/HistoryEndpoint.cs +++ b/FreeTubeSync/EndPoints/HistoryEndpoint.cs @@ -32,25 +32,22 @@ public static class HistoryEndpoint { try { + logger.LogInformation("History {id} does not exist, adding it to the database Thread: {thread}", + history._id, Thread.CurrentThread.ManagedThreadId); await repository.AddAsync(history, ct); } catch (Exception ex) { - logger.LogError(ex, "Failed to create history {json}", history._id); + logger.LogError("Failed to create history {json}", history._id); return Results.StatusCode(500); } } else { - try - { - await repository.UpdateAsync(history, ct); - } - catch (Exception ex) - { - logger.LogError(ex, "Failed to update history {json}", history._id); - return Results.StatusCode(500); - } + logger.LogInformation("History {id} exists, updating the database. Thread: {thread}", history._id, + Thread.CurrentThread.ManagedThreadId); + results.UpdateFrom(history); + await repository.UpdateAsync(results, ct); } return Results.Ok(); } diff --git a/FreeTubeSync/EndPoints/PingEndpoint.cs b/FreeTubeSync/EndPoints/PingEndpoint.cs index 2460ee7..3f5ee4d 100644 --- a/FreeTubeSync/EndPoints/PingEndpoint.cs +++ b/FreeTubeSync/EndPoints/PingEndpoint.cs @@ -7,10 +7,10 @@ public static class PingEndpoint public static void MapPingEndpoints(this WebApplication app) { var group = app.MapGroup("ping"); - group.MapGet("/", async (CancellationToken token) => + group.MapGet("/", async (DataContext dbContext, CancellationToken token) => { - await Task.Delay(10); - var dict = new { AppVersion = "0.1.4" }; + await dbContext.CleanupChangeLogAsync(token); + var dict = new { AppVersion = "0.1.5" }; return Results.Ok(dict); }); @@ -22,6 +22,7 @@ public static class PingEndpoint return Results.NotFound(); var dict = new { LastUpdated = log.ChangeTime }; + await dbContext.CleanupChangeLogAsync(token); return Results.Ok(dict); }); } diff --git a/FreeTubeSync/EndPoints/PlaylistEndpoint.cs b/FreeTubeSync/EndPoints/PlaylistEndpoint.cs index f3aeb7c..a9c5713 100644 --- a/FreeTubeSync/EndPoints/PlaylistEndpoint.cs +++ b/FreeTubeSync/EndPoints/PlaylistEndpoint.cs @@ -34,24 +34,21 @@ public static class PlaylistEndpoint { try { + logger.LogInformation("Playlist {id} does not exist, adding it to the database", playlist._id); await repository.AddAsync(playlist, ct); } - catch (Exception ex) + catch (Exception) { - logger.LogError(ex, "Failed to create Playlist {playlist}", playlist._id); + logger.LogError("Failed to create Playlist {playlist}", playlist._id); return Results.StatusCode(500); } } else { - // Add Update Code here + logger.LogInformation("Playlist {id} exists, updating the databsae.", playlist._id); + results.UpdateFrom(playlist); var toRemove = results.videos.Where(vid => !playlist.videos.Any(x => x.playlistItemId == vid.playlistItemId)).ToList(); - results.lastUpdatedAt = playlist.lastUpdatedAt; - results.@protected = playlist.@protected; - results.playlistName = playlist.playlistName; - results.createdAt = playlist.createdAt; - foreach (var vid in toRemove) results.videos.Remove(vid); diff --git a/FreeTubeSync/EndPoints/ProfileEndpoint.cs b/FreeTubeSync/EndPoints/ProfileEndpoint.cs index 4d97ca1..27cd98a 100644 --- a/FreeTubeSync/EndPoints/ProfileEndpoint.cs +++ b/FreeTubeSync/EndPoints/ProfileEndpoint.cs @@ -33,22 +33,21 @@ public static class ProfileEndpoint { try { + logger.LogInformation("Profile {id} does not exist, adding it to the database", profile._id); await repository.AddAsync(profile, ct); } - catch (Exception ex) + catch (Exception) { - logger.LogError(ex, "Failed to create profile {json}", profile._id); + logger.LogError("Failed to create profile {json}", profile._id); return Results.StatusCode(500); } } else { + logger.LogInformation("Profile {id} exists, updating the database.", profile._id); + res.UpdateFrom(profile); var toRemove = res.subscriptions.Where(sub => !profile.subscriptions.Any(x => x.id == sub.id)).ToList(); - res.name = profile.name; - res.textColor = profile.textColor; - res.bgColor = profile.bgColor; - foreach (var sub in toRemove) res.subscriptions.Remove(sub); diff --git a/FreeTubeSync/EndPoints/SearchHistoryEndpoint.cs b/FreeTubeSync/EndPoints/SearchHistoryEndpoint.cs index c9b0f3f..35b3203 100644 --- a/FreeTubeSync/EndPoints/SearchHistoryEndpoint.cs +++ b/FreeTubeSync/EndPoints/SearchHistoryEndpoint.cs @@ -34,25 +34,20 @@ public static class SearchHistoryEndpoint { try { + logger.LogInformation("SearchHistory {id} does not exist, adding it to the database", history._id); await repository.AddAsync(history, ct); } - catch (Exception e) + catch (Exception) { - logger.LogError(e, "Failed to update history {json}", history._id); + logger.LogError("Failed to update history {json}", history._id); return Results.StatusCode(500); } } else { - try - { - await repository.UpdateAsync(history, ct); - } - catch (Exception e) - { - logger.LogError(e, "Failed to update history {json}", history._id); - return Results.StatusCode(500); - } + logger.LogInformation("SearchHistory {id} exists, updating the database.", history._id); + result.UpdateFrom(history); + await repository.UpdateAsync(result, ct); } return Results.Ok(); diff --git a/FreeTubeSync/EndPoints/SettingEndpoint.cs b/FreeTubeSync/EndPoints/SettingEndpoint.cs index bd21d2e..543dc0c 100644 --- a/FreeTubeSync/EndPoints/SettingEndpoint.cs +++ b/FreeTubeSync/EndPoints/SettingEndpoint.cs @@ -33,25 +33,20 @@ public static class SettingEndpoint { try { + logger.LogInformation("Setting {id} does not exist, adding it to the database", setting._id); await repository.AddAsync(setting, ct); } - catch (Exception ex) + catch (Exception) { - logger.LogError(ex, "Failed to add setting {setting}", setting._id); + logger.LogError("Failed to add setting {setting}", setting._id); return Results.StatusCode(500); } } else { - try - { - await repository.UpdateAsync(setting, ct); - } - catch (Exception ex) - { - logger.LogError(ex, "Failed to update setting {setting}", setting._id); - return Results.StatusCode(500); - } + logger.LogInformation("Setting {id} exists, updating the database.", setting._id); + res.UpdateFrom(setting); + await repository.UpdateAsync(res, ct); } return Results.Ok(); } diff --git a/FreeTubeSync/Migrations/20250808221748_UpdateNewLayout.Designer.cs b/FreeTubeSync/Migrations/20250808221748_UpdateNewLayout.Designer.cs new file mode 100644 index 0000000..95ab779 --- /dev/null +++ b/FreeTubeSync/Migrations/20250808221748_UpdateNewLayout.Designer.cs @@ -0,0 +1,257 @@ +// +using System; +using FreeTubeSync.Database; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace FreeTubeSync.Migrations +{ + [DbContext(typeof(DataContext))] + [Migration("20250808221748_UpdateNewLayout")] + partial class UpdateNewLayout + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "9.0.7"); + + modelBuilder.Entity("FreeTubeSync.Model.ChangeLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChangeTime") + .HasColumnType("TEXT"); + + b.Property("ChangeType") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("TableName") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("ChangeLogs"); + }); + + modelBuilder.Entity("FreeTubeSync.Model.History", b => + { + b.Property("_id") + .HasColumnType("TEXT"); + + b.Property("author") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("authorId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("description") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("isLive") + .HasColumnType("INTEGER"); + + b.Property("lastViewedPlaylistItemId") + .HasColumnType("TEXT"); + + b.Property("lastViewedPlaylistType") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("lengthSeconds") + .HasColumnType("INTEGER"); + + b.Property("published") + .HasColumnType("INTEGER"); + + b.Property("timeWatched") + .HasColumnType("INTEGER"); + + b.Property("title") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("type") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("videoId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("viewCount") + .HasColumnType("INTEGER"); + + b.Property("watchProgress") + .HasColumnType("REAL"); + + b.HasKey("_id"); + + b.ToTable("Histories"); + }); + + modelBuilder.Entity("FreeTubeSync.Model.Playlist", b => + { + b.Property("_id") + .HasColumnType("TEXT"); + + b.Property("createdAt") + .HasColumnType("INTEGER"); + + b.Property("lastUpdatedAt") + .HasColumnType("INTEGER"); + + b.Property("playlistName") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("protected") + .HasColumnType("INTEGER"); + + b.HasKey("_id"); + + b.ToTable("Playlists"); + }); + + modelBuilder.Entity("FreeTubeSync.Model.Profile", b => + { + b.Property("_id") + .HasColumnType("TEXT"); + + b.Property("bgColor") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("textColor") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("_id"); + + b.ToTable("Profiles"); + }); + + modelBuilder.Entity("FreeTubeSync.Model.SearchHistory", b => + { + b.Property("_id") + .HasColumnType("TEXT"); + + b.Property("lastUpdatedAt") + .HasColumnType("INTEGER"); + + b.HasKey("_id"); + + b.ToTable("SearchHistories"); + }); + + modelBuilder.Entity("FreeTubeSync.Model.Setting", b => + { + b.Property("_id") + .HasColumnType("TEXT"); + + b.Property("value") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("_id"); + + b.ToTable("Settings"); + }); + + modelBuilder.Entity("FreeTubeSync.Model.Playlist", b => + { + b.OwnsMany("FreeTubeSync.Model.Video", "videos", b1 => + { + b1.Property("Playlist_id") + .HasColumnType("TEXT"); + + b1.Property("videoId") + .HasColumnType("TEXT"); + + b1.Property("author") + .IsRequired() + .HasColumnType("TEXT"); + + b1.Property("authorId") + .IsRequired() + .HasColumnType("TEXT"); + + b1.Property("lengthSeconds") + .IsRequired() + .HasColumnType("TEXT"); + + b1.Property("playlistItemId") + .IsRequired() + .HasColumnType("TEXT"); + + b1.Property("published") + .HasColumnType("INTEGER"); + + b1.Property("timeAdded") + .HasColumnType("INTEGER"); + + b1.Property("title") + .IsRequired() + .HasColumnType("TEXT"); + + b1.Property("type") + .IsRequired() + .HasColumnType("TEXT"); + + b1.HasKey("Playlist_id", "videoId"); + + b1.ToTable("Video"); + + b1.WithOwner() + .HasForeignKey("Playlist_id"); + }); + + b.Navigation("videos"); + }); + + modelBuilder.Entity("FreeTubeSync.Model.Profile", b => + { + b.OwnsMany("FreeTubeSync.Model.Subscription", "subscriptions", b1 => + { + b1.Property("Profile_id") + .HasColumnType("TEXT"); + + b1.Property("id") + .HasColumnType("TEXT"); + + b1.Property("name") + .IsRequired() + .HasColumnType("TEXT"); + + b1.Property("thumbnail") + .HasColumnType("TEXT"); + + b1.HasKey("Profile_id", "id"); + + b1.ToTable("Subscription"); + + b1.WithOwner() + .HasForeignKey("Profile_id"); + }); + + b.Navigation("subscriptions"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/FreeTubeSync/Migrations/20250808221748_UpdateNewLayout.cs b/FreeTubeSync/Migrations/20250808221748_UpdateNewLayout.cs new file mode 100644 index 0000000..995bf7a --- /dev/null +++ b/FreeTubeSync/Migrations/20250808221748_UpdateNewLayout.cs @@ -0,0 +1,130 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace FreeTubeSync.Migrations +{ + /// + public partial class UpdateNewLayout : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Subscriptions"); + + migrationBuilder.DropTable( + name: "Videos"); + + migrationBuilder.CreateTable( + name: "Subscription", + columns: table => new + { + id = table.Column(type: "TEXT", nullable: false), + Profile_id = table.Column(type: "TEXT", nullable: false), + name = table.Column(type: "TEXT", nullable: false), + thumbnail = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Subscription", x => new { x.Profile_id, x.id }); + table.ForeignKey( + name: "FK_Subscription_Profiles_Profile_id", + column: x => x.Profile_id, + principalTable: "Profiles", + principalColumn: "_id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "Video", + columns: table => new + { + videoId = table.Column(type: "TEXT", nullable: false), + Playlist_id = table.Column(type: "TEXT", nullable: false), + title = table.Column(type: "TEXT", nullable: false), + author = table.Column(type: "TEXT", nullable: false), + authorId = table.Column(type: "TEXT", nullable: false), + lengthSeconds = table.Column(type: "TEXT", nullable: false), + published = table.Column(type: "INTEGER", nullable: false), + timeAdded = table.Column(type: "INTEGER", nullable: false), + playlistItemId = table.Column(type: "TEXT", nullable: false), + type = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Video", x => new { x.Playlist_id, x.videoId }); + table.ForeignKey( + name: "FK_Video_Playlists_Playlist_id", + column: x => x.Playlist_id, + principalTable: "Playlists", + principalColumn: "_id", + onDelete: ReferentialAction.Cascade); + }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Subscription"); + + migrationBuilder.DropTable( + name: "Video"); + + migrationBuilder.CreateTable( + name: "Subscriptions", + columns: table => new + { + id = table.Column(type: "TEXT", nullable: false), + Profile_id = table.Column(type: "TEXT", nullable: true), + name = table.Column(type: "TEXT", nullable: false), + thumbnail = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Subscriptions", x => x.id); + table.ForeignKey( + name: "FK_Subscriptions_Profiles_Profile_id", + column: x => x.Profile_id, + principalTable: "Profiles", + principalColumn: "_id"); + }); + + migrationBuilder.CreateTable( + name: "Videos", + columns: table => new + { + playlistItemId = table.Column(type: "TEXT", nullable: false), + Playlist_id = table.Column(type: "TEXT", nullable: true), + author = table.Column(type: "TEXT", nullable: false), + authorId = table.Column(type: "TEXT", nullable: false), + lengthSeconds = table.Column(type: "TEXT", nullable: false), + pubished = table.Column(type: "INTEGER", nullable: false), + timeAdded = table.Column(type: "INTEGER", nullable: false), + title = table.Column(type: "TEXT", nullable: false), + type = table.Column(type: "TEXT", nullable: false), + videoId = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Videos", x => x.playlistItemId); + table.ForeignKey( + name: "FK_Videos_Playlists_Playlist_id", + column: x => x.Playlist_id, + principalTable: "Playlists", + principalColumn: "_id"); + }); + + migrationBuilder.CreateIndex( + name: "IX_Subscriptions_Profile_id", + table: "Subscriptions", + column: "Profile_id"); + + migrationBuilder.CreateIndex( + name: "IX_Videos_Playlist_id", + table: "Videos", + column: "Playlist_id"); + } + } +} diff --git a/FreeTubeSync/Migrations/DataContextModelSnapshot.cs b/FreeTubeSync/Migrations/DataContextModelSnapshot.cs index 0076d0a..b3b960a 100644 --- a/FreeTubeSync/Migrations/DataContextModelSnapshot.cs +++ b/FreeTubeSync/Migrations/DataContextModelSnapshot.cs @@ -17,7 +17,7 @@ namespace FreeTubeSync.Migrations #pragma warning disable 612, 618 modelBuilder.HasAnnotation("ProductVersion", "9.0.7"); - modelBuilder.Entity("FreeTubeSync.Model.Database.ChangeLog", b => + modelBuilder.Entity("FreeTubeSync.Model.ChangeLog", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -39,7 +39,7 @@ namespace FreeTubeSync.Migrations b.ToTable("ChangeLogs"); }); - modelBuilder.Entity("FreeTubeSync.Model.Database.History", b => + modelBuilder.Entity("FreeTubeSync.Model.History", b => { b.Property("_id") .HasColumnType("TEXT"); @@ -98,7 +98,7 @@ namespace FreeTubeSync.Migrations b.ToTable("Histories"); }); - modelBuilder.Entity("FreeTubeSync.Model.Database.Playlist", b => + modelBuilder.Entity("FreeTubeSync.Model.Playlist", b => { b.Property("_id") .HasColumnType("TEXT"); @@ -121,7 +121,7 @@ namespace FreeTubeSync.Migrations b.ToTable("Playlists"); }); - modelBuilder.Entity("FreeTubeSync.Model.Database.Profile", b => + modelBuilder.Entity("FreeTubeSync.Model.Profile", b => { b.Property("_id") .HasColumnType("TEXT"); @@ -143,7 +143,7 @@ namespace FreeTubeSync.Migrations b.ToTable("Profiles"); }); - modelBuilder.Entity("FreeTubeSync.Model.Database.SearchHistory", b => + modelBuilder.Entity("FreeTubeSync.Model.SearchHistory", b => { b.Property("_id") .HasColumnType("TEXT"); @@ -156,7 +156,7 @@ namespace FreeTubeSync.Migrations b.ToTable("SearchHistories"); }); - modelBuilder.Entity("FreeTubeSync.Model.Database.Setting", b => + modelBuilder.Entity("FreeTubeSync.Model.Setting", b => { b.Property("_id") .HasColumnType("TEXT"); @@ -170,94 +170,82 @@ namespace FreeTubeSync.Migrations b.ToTable("Settings"); }); - modelBuilder.Entity("FreeTubeSync.Model.Database.Subscription", b => + modelBuilder.Entity("FreeTubeSync.Model.Playlist", b => { - b.Property("id") - .HasColumnType("TEXT"); + b.OwnsMany("FreeTubeSync.Model.Video", "videos", b1 => + { + b1.Property("Playlist_id") + .HasColumnType("TEXT"); - b.Property("Profile_id") - .HasColumnType("TEXT"); + b1.Property("videoId") + .HasColumnType("TEXT"); - b.Property("name") - .IsRequired() - .HasColumnType("TEXT"); + b1.Property("author") + .IsRequired() + .HasColumnType("TEXT"); - b.Property("thumbnail") - .HasColumnType("TEXT"); + b1.Property("authorId") + .IsRequired() + .HasColumnType("TEXT"); - b.HasKey("id"); + b1.Property("lengthSeconds") + .IsRequired() + .HasColumnType("TEXT"); - b.HasIndex("Profile_id"); + b1.Property("playlistItemId") + .IsRequired() + .HasColumnType("TEXT"); - b.ToTable("Subscriptions"); - }); + b1.Property("published") + .HasColumnType("INTEGER"); - modelBuilder.Entity("FreeTubeSync.Model.Database.Video", b => - { - b.Property("playlistItemId") - .HasColumnType("TEXT"); + b1.Property("timeAdded") + .HasColumnType("INTEGER"); - b.Property("Playlist_id") - .HasColumnType("TEXT"); + b1.Property("title") + .IsRequired() + .HasColumnType("TEXT"); - b.Property("author") - .IsRequired() - .HasColumnType("TEXT"); + b1.Property("type") + .IsRequired() + .HasColumnType("TEXT"); - b.Property("authorId") - .IsRequired() - .HasColumnType("TEXT"); + b1.HasKey("Playlist_id", "videoId"); - b.Property("lengthSeconds") - .IsRequired() - .HasColumnType("TEXT"); + b1.ToTable("Video"); - b.Property("pubished") - .HasColumnType("INTEGER"); + b1.WithOwner() + .HasForeignKey("Playlist_id"); + }); - b.Property("timeAdded") - .HasColumnType("INTEGER"); - - b.Property("title") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("type") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("videoId") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("playlistItemId"); - - b.HasIndex("Playlist_id"); - - b.ToTable("Videos"); - }); - - modelBuilder.Entity("FreeTubeSync.Model.Database.Subscription", b => - { - b.HasOne("FreeTubeSync.Model.Database.Profile", null) - .WithMany("subscriptions") - .HasForeignKey("Profile_id"); - }); - - modelBuilder.Entity("FreeTubeSync.Model.Database.Video", b => - { - b.HasOne("FreeTubeSync.Model.Database.Playlist", null) - .WithMany("videos") - .HasForeignKey("Playlist_id"); - }); - - modelBuilder.Entity("FreeTubeSync.Model.Database.Playlist", b => - { b.Navigation("videos"); }); - modelBuilder.Entity("FreeTubeSync.Model.Database.Profile", b => + modelBuilder.Entity("FreeTubeSync.Model.Profile", b => { + b.OwnsMany("FreeTubeSync.Model.Subscription", "subscriptions", b1 => + { + b1.Property("Profile_id") + .HasColumnType("TEXT"); + + b1.Property("id") + .HasColumnType("TEXT"); + + b1.Property("name") + .IsRequired() + .HasColumnType("TEXT"); + + b1.Property("thumbnail") + .HasColumnType("TEXT"); + + b1.HasKey("Profile_id", "id"); + + b1.ToTable("Subscription"); + + b1.WithOwner() + .HasForeignKey("Profile_id"); + }); + b.Navigation("subscriptions"); }); #pragma warning restore 612, 618 diff --git a/FreeTubeSync/Model/BaseModel.cs b/FreeTubeSync/Model/BaseModel.cs new file mode 100644 index 0000000..9f7aebe --- /dev/null +++ b/FreeTubeSync/Model/BaseModel.cs @@ -0,0 +1,17 @@ +using System.Collections; + +namespace FreeTubeSync.Model; + +public class BaseModel +{ + public void UpdateFrom(object other) + { + foreach (var prop in other.GetType().GetProperties()) + { + if (prop.Name == "_id" || prop.Name == "id" || prop.Name == "Id" || prop.Name == "subscriptions" || prop.Name == "videos") + continue; + var val = prop.GetValue(other); + prop.SetValue(this, val); + } + } +} \ No newline at end of file diff --git a/FreeTubeSync/Model/ChangeLog.cs b/FreeTubeSync/Model/ChangeLog.cs index d1e6734..d6b7e40 100644 --- a/FreeTubeSync/Model/ChangeLog.cs +++ b/FreeTubeSync/Model/ChangeLog.cs @@ -1,6 +1,6 @@ namespace FreeTubeSync.Model; -public class ChangeLog +public class ChangeLog : BaseModel { public int Id { get; set; } public string TableName { get; set; } = string.Empty; diff --git a/FreeTubeSync/Model/History.cs b/FreeTubeSync/Model/History.cs index 09ecba2..13c915d 100644 --- a/FreeTubeSync/Model/History.cs +++ b/FreeTubeSync/Model/History.cs @@ -2,7 +2,7 @@ using System.ComponentModel.DataAnnotations; namespace FreeTubeSync.Model; -public class History +public class History : BaseModel { [Key] public string _id { get; set; } = string.Empty; diff --git a/FreeTubeSync/Model/Playlist.cs b/FreeTubeSync/Model/Playlist.cs index 83d6bf7..4322ad1 100644 --- a/FreeTubeSync/Model/Playlist.cs +++ b/FreeTubeSync/Model/Playlist.cs @@ -2,7 +2,7 @@ using System.ComponentModel.DataAnnotations; namespace FreeTubeSync.Model; -public class Playlist +public class Playlist : BaseModel { [Key] public string _id { get; set; } = string.Empty; diff --git a/FreeTubeSync/Model/Profile.cs b/FreeTubeSync/Model/Profile.cs index 658c21d..751304f 100644 --- a/FreeTubeSync/Model/Profile.cs +++ b/FreeTubeSync/Model/Profile.cs @@ -2,7 +2,7 @@ using System.ComponentModel.DataAnnotations; namespace FreeTubeSync.Model; -public class Profile +public class Profile : BaseModel { [Key] public string _id { get; set; } = string.Empty; diff --git a/FreeTubeSync/Model/SearchHistory.cs b/FreeTubeSync/Model/SearchHistory.cs index e4c4080..2e48a20 100644 --- a/FreeTubeSync/Model/SearchHistory.cs +++ b/FreeTubeSync/Model/SearchHistory.cs @@ -2,7 +2,7 @@ using System.ComponentModel.DataAnnotations; namespace FreeTubeSync.Model; -public class SearchHistory +public class SearchHistory : BaseModel { [Key] public string _id { get; set; } = string.Empty; diff --git a/FreeTubeSync/Model/Setting.cs b/FreeTubeSync/Model/Setting.cs index 6c8992c..e53ee9a 100644 --- a/FreeTubeSync/Model/Setting.cs +++ b/FreeTubeSync/Model/Setting.cs @@ -2,7 +2,7 @@ using System.ComponentModel.DataAnnotations; namespace FreeTubeSync.Model; -public class Setting +public class Setting : BaseModel { [Key] public string _id { get; set; } diff --git a/FreeTubeSync/Model/Subscription.cs b/FreeTubeSync/Model/Subscription.cs index 8a5f84b..5756d61 100644 --- a/FreeTubeSync/Model/Subscription.cs +++ b/FreeTubeSync/Model/Subscription.cs @@ -3,7 +3,7 @@ using Microsoft.EntityFrameworkCore; namespace FreeTubeSync.Model; [Owned] -public class Subscription +public class Subscription : BaseModel { public string id { get; set; } = string.Empty; public string name { get; set; } = string.Empty; diff --git a/FreeTubeSync/Model/Video.cs b/FreeTubeSync/Model/Video.cs index fc0a5cd..02e7491 100644 --- a/FreeTubeSync/Model/Video.cs +++ b/FreeTubeSync/Model/Video.cs @@ -3,7 +3,7 @@ using Microsoft.EntityFrameworkCore; namespace FreeTubeSync.Model; [Owned] -public class Video +public class Video : BaseModel { public string videoId { get; set; } = string.Empty; public string title { get; set; } = string.Empty; diff --git a/FreeTubeSync/Repository.cs b/FreeTubeSync/Repository.cs index 286e7c3..c25a7e5 100644 --- a/FreeTubeSync/Repository.cs +++ b/FreeTubeSync/Repository.cs @@ -23,8 +23,11 @@ public class Repository : IRepository where TEntity : class public async Task UpdateAsync(TEntity entity, CancellationToken ct, bool sync = true) { - _dbSet.Attach(entity); - _context.Entry(entity).State = EntityState.Modified; + if (!_dbSet.Local.Contains(entity)) + { + _dbSet.Attach(entity); + _context.Entry(entity).State = EntityState.Modified; + } if (sync) await _context.SaveChangesAsync(ct); } diff --git a/FreeTubeSync/appsettings.Development.json b/FreeTubeSync/appsettings.Development.json index 2bb5f2c..0a76cd5 100644 --- a/FreeTubeSync/appsettings.Development.json +++ b/FreeTubeSync/appsettings.Development.json @@ -5,7 +5,8 @@ "Logging": { "LogLevel": { "Default": "Information", - "Microsoft.AspNetCore": "Warning" + "Microsoft.AspNetCore": "Warning", + "Microsoft.EntityFrameworkCore": "Warning" } } } diff --git a/FreeTubeSync/appsettings.json b/FreeTubeSync/appsettings.json index cbd653d..acd8c04 100644 --- a/FreeTubeSync/appsettings.json +++ b/FreeTubeSync/appsettings.json @@ -5,7 +5,8 @@ "Logging": { "LogLevel": { "Default": "Information", - "Microsoft.AspNetCore": "Warning" + "Microsoft.AspNetCore": "Warning", + "Microsoft.EntityFrameworkCore": "Warning" } }, "AllowedHosts": "*"