From 253b06dfaa091d986a8714c081fd1e01679f538a Mon Sep 17 00:00:00 2001 From: crupest Date: Wed, 10 Feb 2021 02:03:06 +0800 Subject: ... --- BackEnd/Timeline/Entities/DatabaseContext.cs | 1 + 1 file changed, 1 insertion(+) (limited to 'BackEnd/Timeline/Entities/DatabaseContext.cs') diff --git a/BackEnd/Timeline/Entities/DatabaseContext.cs b/BackEnd/Timeline/Entities/DatabaseContext.cs index 513cdc95..a0b59d1f 100644 --- a/BackEnd/Timeline/Entities/DatabaseContext.cs +++ b/BackEnd/Timeline/Entities/DatabaseContext.cs @@ -28,6 +28,7 @@ namespace Timeline.Entities public DbSet UserPermission { get; set; } = default!; public DbSet Timelines { get; set; } = default!; public DbSet TimelinePosts { get; set; } = default!; + public DbSet TimelinePostData { get; set; } = default!; public DbSet TimelineMembers { get; set; } = default!; public DbSet HighlightTimelines { get; set; } = default!; public DbSet BookmarkTimelines { get; set; } = default!; -- cgit v1.2.3 From 83de31a999132b052f1ccec75eb664c9e4a18e87 Mon Sep 17 00:00:00 2001 From: crupest Date: Fri, 12 Feb 2021 22:10:56 +0800 Subject: feat: Add databse custom migration service. --- BackEnd/Timeline/Entities/DatabaseContext.cs | 2 + BackEnd/Timeline/Entities/MigrationEntity.cs | 15 +++++ BackEnd/Timeline/Entities/TimelinePostEntity.cs | 3 + BackEnd/Timeline/Program.cs | 19 +++--- .../Services/Migration/CustomMigrationManager.cs | 55 +++++++++++++++++ .../Services/Migration/ICustomMigration.cs | 11 ++++ .../MigationServiceCollectionExtensions.cs | 14 +++++ .../TimelinePostContentToDataMigration.cs | 69 ++++++++++++++++++++++ BackEnd/Timeline/Startup.cs | 3 + 9 files changed, 181 insertions(+), 10 deletions(-) create mode 100644 BackEnd/Timeline/Entities/MigrationEntity.cs create mode 100644 BackEnd/Timeline/Services/Migration/CustomMigrationManager.cs create mode 100644 BackEnd/Timeline/Services/Migration/ICustomMigration.cs create mode 100644 BackEnd/Timeline/Services/Migration/MigationServiceCollectionExtensions.cs create mode 100644 BackEnd/Timeline/Services/Migration/TimelinePostContentToDataMigration.cs (limited to 'BackEnd/Timeline/Entities/DatabaseContext.cs') diff --git a/BackEnd/Timeline/Entities/DatabaseContext.cs b/BackEnd/Timeline/Entities/DatabaseContext.cs index a0b59d1f..8ccdabb5 100644 --- a/BackEnd/Timeline/Entities/DatabaseContext.cs +++ b/BackEnd/Timeline/Entities/DatabaseContext.cs @@ -35,5 +35,7 @@ namespace Timeline.Entities public DbSet JwtToken { get; set; } = default!; public DbSet Data { get; set; } = default!; + + public DbSet Migrations { get; set; } = default!; } } diff --git a/BackEnd/Timeline/Entities/MigrationEntity.cs b/BackEnd/Timeline/Entities/MigrationEntity.cs new file mode 100644 index 00000000..0472f24e --- /dev/null +++ b/BackEnd/Timeline/Entities/MigrationEntity.cs @@ -0,0 +1,15 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Timeline.Entities +{ + [Table("migrations")] + public class MigrationEntity + { + [Column("id"), Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public long Id { get; set; } + + [Column("name"), Required] + public string Name { get; set; } = default!; + } +} diff --git a/BackEnd/Timeline/Entities/TimelinePostEntity.cs b/BackEnd/Timeline/Entities/TimelinePostEntity.cs index 317d43fc..451f56cd 100644 --- a/BackEnd/Timeline/Entities/TimelinePostEntity.cs +++ b/BackEnd/Timeline/Entities/TimelinePostEntity.cs @@ -26,12 +26,15 @@ namespace Timeline.Entities [ForeignKey(nameof(AuthorId))] public UserEntity? Author { get; set; } = default!; + [Obsolete("Use post data instead.")] [Column("content_type")] public string? ContentType { get; set; } + [Obsolete("Use post data instead.")] [Column("content")] public string? Content { get; set; } + [Obsolete("Use post data instead.")] [Column("extra_content")] public string? ExtraContent { get; set; } diff --git a/BackEnd/Timeline/Program.cs b/BackEnd/Timeline/Program.cs index 75bf6154..0f75908f 100644 --- a/BackEnd/Timeline/Program.cs +++ b/BackEnd/Timeline/Program.cs @@ -6,6 +6,7 @@ using Microsoft.Extensions.Hosting; using System.Resources; using Timeline.Entities; using Timeline.Services; +using Timeline.Services.Migration; [assembly: NeutralResourcesLanguage("en")] @@ -17,18 +18,16 @@ namespace Timeline { var host = CreateWebHostBuilder(args).Build(); - var env = host.Services.GetRequiredService(); + using (var scope = host.Services.CreateScope()) + { + var databaseBackupService = scope.ServiceProvider.GetRequiredService(); + databaseBackupService.BackupNow(); - var databaseBackupService = host.Services.GetRequiredService(); - databaseBackupService.BackupNow(); + var databaseContext = scope.ServiceProvider.GetRequiredService(); + databaseContext.Database.Migrate(); - if (env.IsProduction()) - { - using (var scope = host.Services.CreateScope()) - { - var databaseContext = scope.ServiceProvider.GetRequiredService(); - databaseContext.Database.Migrate(); - } + var customMigrationManager = scope.ServiceProvider.GetRequiredService(); + customMigrationManager.Migrate(); } host.Run(); diff --git a/BackEnd/Timeline/Services/Migration/CustomMigrationManager.cs b/BackEnd/Timeline/Services/Migration/CustomMigrationManager.cs new file mode 100644 index 00000000..ba86e10b --- /dev/null +++ b/BackEnd/Timeline/Services/Migration/CustomMigrationManager.cs @@ -0,0 +1,55 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using Timeline.Entities; + +namespace Timeline.Services.Migration +{ + public interface ICustomMigrationManager + { + Task Migrate(); + } + + public class CustomMigrationManager : ICustomMigrationManager + { + private IEnumerable _migrations; + private DatabaseContext _database; + + private ILogger _logger; + + public CustomMigrationManager(IEnumerable migrations, DatabaseContext database, ILogger logger) + { + _migrations = migrations; + _database = database; + _logger = logger; + } + + public async Task Migrate() + { + foreach (var migration in _migrations) + { + var name = migration.GetName(); + var did = await _database.Migrations.AnyAsync(m => m.Name == name); + + _logger.LogInformation("Found custom migration '{0}'. Did: {1}.", name, did); + + if (!did) + { + _logger.LogInformation("Begin custom migration '{0}'.", name); + + await using var transaction = await _database.Database.BeginTransactionAsync(); + + await migration.Execute(_database); + + _database.Migrations.Add(new MigrationEntity { Name = name }); + await _database.SaveChangesAsync(); + + await transaction.CommitAsync(); + + _logger.LogInformation("End custom migration '{0}'.", name); + } + } + } + } +} diff --git a/BackEnd/Timeline/Services/Migration/ICustomMigration.cs b/BackEnd/Timeline/Services/Migration/ICustomMigration.cs new file mode 100644 index 00000000..1f47df1e --- /dev/null +++ b/BackEnd/Timeline/Services/Migration/ICustomMigration.cs @@ -0,0 +1,11 @@ +using System.Threading.Tasks; +using Timeline.Entities; + +namespace Timeline.Services.Migration +{ + public interface ICustomMigration + { + string GetName(); + Task Execute(DatabaseContext database); + } +} diff --git a/BackEnd/Timeline/Services/Migration/MigationServiceCollectionExtensions.cs b/BackEnd/Timeline/Services/Migration/MigationServiceCollectionExtensions.cs new file mode 100644 index 00000000..0e6f6c0a --- /dev/null +++ b/BackEnd/Timeline/Services/Migration/MigationServiceCollectionExtensions.cs @@ -0,0 +1,14 @@ +using Microsoft.Extensions.DependencyInjection; + +namespace Timeline.Services.Migration +{ + public static class MigrationServiceCollectionExtensions + { + public static IServiceCollection AddCustomMigration(this IServiceCollection services) + { + services.AddScoped(); + services.AddScoped(); + return services; + } + } +} \ No newline at end of file diff --git a/BackEnd/Timeline/Services/Migration/TimelinePostContentToDataMigration.cs b/BackEnd/Timeline/Services/Migration/TimelinePostContentToDataMigration.cs new file mode 100644 index 00000000..de2e2183 --- /dev/null +++ b/BackEnd/Timeline/Services/Migration/TimelinePostContentToDataMigration.cs @@ -0,0 +1,69 @@ +using System.Text; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using SixLabors.ImageSharp; +using Timeline.Entities; +using Timeline.Models; + +namespace Timeline.Services.Migration +{ + public class TimelinePostContentToDataMigration : ICustomMigration + { + private readonly IDataManager _dataManager; + + public TimelinePostContentToDataMigration(IDataManager dataManager) + { + _dataManager = dataManager; + } + + public string GetName() => "TimelinePostContentToData"; + + public async Task Execute(DatabaseContext database) + { +#pragma warning disable CS0618 + var postEntities = await database.TimelinePosts.ToListAsync(); + + foreach (var postEntity in postEntities) + { + if (postEntity.Content is null) + { + postEntity.Deleted = true; + } + else + { + if (postEntity.ContentType == "text") + { + var tag = await _dataManager.RetainEntry(Encoding.UTF8.GetBytes(postEntity.Content), false); + database.TimelinePostData.Add(new TimelinePostDataEntity + { + DataTag = tag, + Kind = MimeTypes.TextPlain, + Index = 0, + PostId = postEntity.Id, + LastUpdated = postEntity.LastUpdated + }); + } + else + { + var data = await _dataManager.GetEntryAndCheck(postEntity.Content, "Old image content does not have corresponding data with the tag."); + var format = Image.DetectFormat(data); + database.TimelinePostData.Add(new TimelinePostDataEntity + { + DataTag = postEntity.Content, + Kind = format.DefaultMimeType, + Index = 0, + PostId = postEntity.Id, + LastUpdated = postEntity.LastUpdated + }); + } + } + postEntity.Content = null; + postEntity.ContentType = null; + postEntity.ExtraContent = null; + } + + await database.SaveChangesAsync(); +#pragma warning restore CS0618 + } + } +} diff --git a/BackEnd/Timeline/Startup.cs b/BackEnd/Timeline/Startup.cs index 5951dc80..26ba3bfc 100644 --- a/BackEnd/Timeline/Startup.cs +++ b/BackEnd/Timeline/Startup.cs @@ -21,6 +21,7 @@ using Timeline.Models.Converters; using Timeline.Models.Mapper; using Timeline.Routes; using Timeline.Services; +using Timeline.Services.Migration; using Timeline.Swagger; namespace Timeline @@ -86,7 +87,9 @@ namespace Timeline services.TryAddSingleton(); services.AddSingleton(); + services.AddSingleton(); + services.AddCustomMigration(); services.AddAutoMapper(GetType().Assembly); services.AddMappers(); -- cgit v1.2.3