diff options
Diffstat (limited to 'BackEnd/Timeline')
-rw-r--r-- | BackEnd/Timeline/Entities/DatabaseContext.cs | 2 | ||||
-rw-r--r-- | BackEnd/Timeline/Entities/MigrationEntity.cs | 15 | ||||
-rw-r--r-- | BackEnd/Timeline/Entities/TimelinePostEntity.cs | 3 | ||||
-rw-r--r-- | BackEnd/Timeline/Program.cs | 19 | ||||
-rw-r--r-- | BackEnd/Timeline/Services/Migration/CustomMigrationManager.cs | 55 | ||||
-rw-r--r-- | BackEnd/Timeline/Services/Migration/ICustomMigration.cs | 11 | ||||
-rw-r--r-- | BackEnd/Timeline/Services/Migration/MigationServiceCollectionExtensions.cs | 14 | ||||
-rw-r--r-- | BackEnd/Timeline/Services/Migration/TimelinePostContentToDataMigration.cs | 69 | ||||
-rw-r--r-- | BackEnd/Timeline/Startup.cs | 3 |
9 files changed, 181 insertions, 10 deletions
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<JwtTokenEntity> JwtToken { get; set; } = default!;
public DbSet<DataEntity> Data { get; set; } = default!;
+
+ public DbSet<MigrationEntity> 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<IWebHostEnvironment>();
+ using (var scope = host.Services.CreateScope())
+ {
+ var databaseBackupService = scope.ServiceProvider.GetRequiredService<IDatabaseBackupService>();
+ databaseBackupService.BackupNow();
- var databaseBackupService = host.Services.GetRequiredService<IDatabaseBackupService>();
- databaseBackupService.BackupNow();
+ var databaseContext = scope.ServiceProvider.GetRequiredService<DatabaseContext>();
+ databaseContext.Database.Migrate();
- if (env.IsProduction())
- {
- using (var scope = host.Services.CreateScope())
- {
- var databaseContext = scope.ServiceProvider.GetRequiredService<DatabaseContext>();
- databaseContext.Database.Migrate();
- }
+ var customMigrationManager = scope.ServiceProvider.GetRequiredService<ICustomMigrationManager>();
+ 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<ICustomMigration> _migrations;
+ private DatabaseContext _database;
+
+ private ILogger<CustomMigrationManager> _logger;
+
+ public CustomMigrationManager(IEnumerable<ICustomMigration> migrations, DatabaseContext database, ILogger<CustomMigrationManager> 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<ICustomMigrationManager, CustomMigrationManager>();
+ services.AddScoped<ICustomMigration, TimelinePostContentToDataMigration>();
+ 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<IActionContextAccessor, ActionContextAccessor>();
services.AddSingleton<IPathProvider, PathProvider>();
+
services.AddSingleton<IDatabaseBackupService, DatabaseBackupService>();
+ services.AddCustomMigration();
services.AddAutoMapper(GetType().Assembly);
services.AddMappers();
|